0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <linux/module.h>
0025 #include <linux/fs.h>
0026 #include <linux/gfp.h>
0027 #include <linux/sunrpc/xdr.h>
0028 #include <linux/nfsacl.h>
0029 #include <linux/nfs3.h>
0030 #include <linux/sort.h>
0031
0032 MODULE_LICENSE("GPL");
0033
0034 struct nfsacl_encode_desc {
0035 struct xdr_array2_desc desc;
0036 unsigned int count;
0037 struct posix_acl *acl;
0038 int typeflag;
0039 kuid_t uid;
0040 kgid_t gid;
0041 };
0042
0043 struct nfsacl_simple_acl {
0044 struct posix_acl acl;
0045 struct posix_acl_entry ace[4];
0046 };
0047
0048 static int
0049 xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
0050 {
0051 struct nfsacl_encode_desc *nfsacl_desc =
0052 (struct nfsacl_encode_desc *) desc;
0053 __be32 *p = elem;
0054
0055 struct posix_acl_entry *entry =
0056 &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
0057
0058 *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag);
0059 switch(entry->e_tag) {
0060 case ACL_USER_OBJ:
0061 *p++ = htonl(from_kuid(&init_user_ns, nfsacl_desc->uid));
0062 break;
0063 case ACL_GROUP_OBJ:
0064 *p++ = htonl(from_kgid(&init_user_ns, nfsacl_desc->gid));
0065 break;
0066 case ACL_USER:
0067 *p++ = htonl(from_kuid(&init_user_ns, entry->e_uid));
0068 break;
0069 case ACL_GROUP:
0070 *p++ = htonl(from_kgid(&init_user_ns, entry->e_gid));
0071 break;
0072 default:
0073 *p++ = 0;
0074 break;
0075 }
0076 *p++ = htonl(entry->e_perm & S_IRWXO);
0077 return 0;
0078 }
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092 int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
0093 struct posix_acl *acl, int encode_entries, int typeflag)
0094 {
0095 int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
0096 struct nfsacl_encode_desc nfsacl_desc = {
0097 .desc = {
0098 .elem_size = 12,
0099 .array_len = encode_entries ? entries : 0,
0100 .xcode = xdr_nfsace_encode,
0101 },
0102 .acl = acl,
0103 .typeflag = typeflag,
0104 .uid = inode->i_uid,
0105 .gid = inode->i_gid,
0106 };
0107 struct nfsacl_simple_acl aclbuf;
0108 int err;
0109
0110 if (entries > NFS_ACL_MAX_ENTRIES ||
0111 xdr_encode_word(buf, base, entries))
0112 return -EINVAL;
0113 if (encode_entries && acl && acl->a_count == 3) {
0114 struct posix_acl *acl2 = &aclbuf.acl;
0115
0116
0117
0118
0119
0120 posix_acl_init(acl2, 4);
0121
0122
0123
0124 acl2->a_entries[0] = acl->a_entries[0];
0125 acl2->a_entries[1] = acl->a_entries[1];
0126 acl2->a_entries[2] = acl->a_entries[1];
0127 acl2->a_entries[2].e_tag = ACL_MASK;
0128 acl2->a_entries[3] = acl->a_entries[2];
0129 nfsacl_desc.acl = acl2;
0130 }
0131 err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
0132 if (!err)
0133 err = 8 + nfsacl_desc.desc.elem_size *
0134 nfsacl_desc.desc.array_len;
0135 return err;
0136 }
0137 EXPORT_SYMBOL_GPL(nfsacl_encode);
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152 bool nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode,
0153 struct posix_acl *acl, int encode_entries,
0154 int typeflag)
0155 {
0156 const size_t elem_size = XDR_UNIT * 3;
0157 u32 entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
0158 struct nfsacl_encode_desc nfsacl_desc = {
0159 .desc = {
0160 .elem_size = elem_size,
0161 .array_len = encode_entries ? entries : 0,
0162 .xcode = xdr_nfsace_encode,
0163 },
0164 .acl = acl,
0165 .typeflag = typeflag,
0166 .uid = inode->i_uid,
0167 .gid = inode->i_gid,
0168 };
0169 struct nfsacl_simple_acl aclbuf;
0170 unsigned int base;
0171 int err;
0172
0173 if (entries > NFS_ACL_MAX_ENTRIES)
0174 return false;
0175 if (xdr_stream_encode_u32(xdr, entries) < 0)
0176 return false;
0177
0178 if (encode_entries && acl && acl->a_count == 3) {
0179 struct posix_acl *acl2 = &aclbuf.acl;
0180
0181
0182
0183
0184
0185 posix_acl_init(acl2, 4);
0186
0187
0188
0189 acl2->a_entries[0] = acl->a_entries[0];
0190 acl2->a_entries[1] = acl->a_entries[1];
0191 acl2->a_entries[2] = acl->a_entries[1];
0192 acl2->a_entries[2].e_tag = ACL_MASK;
0193 acl2->a_entries[3] = acl->a_entries[2];
0194 nfsacl_desc.acl = acl2;
0195 }
0196
0197 base = xdr_stream_pos(xdr);
0198 if (!xdr_reserve_space(xdr, XDR_UNIT +
0199 elem_size * nfsacl_desc.desc.array_len))
0200 return false;
0201 err = xdr_encode_array2(xdr->buf, base, &nfsacl_desc.desc);
0202 if (err)
0203 return false;
0204
0205 return true;
0206 }
0207 EXPORT_SYMBOL_GPL(nfs_stream_encode_acl);
0208
0209
0210 struct nfsacl_decode_desc {
0211 struct xdr_array2_desc desc;
0212 unsigned int count;
0213 struct posix_acl *acl;
0214 };
0215
0216 static int
0217 xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem)
0218 {
0219 struct nfsacl_decode_desc *nfsacl_desc =
0220 (struct nfsacl_decode_desc *) desc;
0221 __be32 *p = elem;
0222 struct posix_acl_entry *entry;
0223 unsigned int id;
0224
0225 if (!nfsacl_desc->acl) {
0226 if (desc->array_len > NFS_ACL_MAX_ENTRIES)
0227 return -EINVAL;
0228 nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL);
0229 if (!nfsacl_desc->acl)
0230 return -ENOMEM;
0231 nfsacl_desc->count = 0;
0232 }
0233
0234 entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
0235 entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT;
0236 id = ntohl(*p++);
0237 entry->e_perm = ntohl(*p++);
0238
0239 switch(entry->e_tag) {
0240 case ACL_USER:
0241 entry->e_uid = make_kuid(&init_user_ns, id);
0242 if (!uid_valid(entry->e_uid))
0243 return -EINVAL;
0244 break;
0245 case ACL_GROUP:
0246 entry->e_gid = make_kgid(&init_user_ns, id);
0247 if (!gid_valid(entry->e_gid))
0248 return -EINVAL;
0249 break;
0250 case ACL_USER_OBJ:
0251 case ACL_GROUP_OBJ:
0252 case ACL_OTHER:
0253 if (entry->e_perm & ~S_IRWXO)
0254 return -EINVAL;
0255 break;
0256 case ACL_MASK:
0257
0258 entry->e_perm &= S_IRWXO;
0259 break;
0260 default:
0261 return -EINVAL;
0262 }
0263
0264 return 0;
0265 }
0266
0267 static int
0268 cmp_acl_entry(const void *x, const void *y)
0269 {
0270 const struct posix_acl_entry *a = x, *b = y;
0271
0272 if (a->e_tag != b->e_tag)
0273 return a->e_tag - b->e_tag;
0274 else if ((a->e_tag == ACL_USER) && uid_gt(a->e_uid, b->e_uid))
0275 return 1;
0276 else if ((a->e_tag == ACL_USER) && uid_lt(a->e_uid, b->e_uid))
0277 return -1;
0278 else if ((a->e_tag == ACL_GROUP) && gid_gt(a->e_gid, b->e_gid))
0279 return 1;
0280 else if ((a->e_tag == ACL_GROUP) && gid_lt(a->e_gid, b->e_gid))
0281 return -1;
0282 else
0283 return 0;
0284 }
0285
0286
0287
0288
0289 static int
0290 posix_acl_from_nfsacl(struct posix_acl *acl)
0291 {
0292 struct posix_acl_entry *pa, *pe,
0293 *group_obj = NULL, *mask = NULL;
0294
0295 if (!acl)
0296 return 0;
0297
0298 sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry),
0299 cmp_acl_entry, NULL);
0300
0301
0302 FOREACH_ACL_ENTRY(pa, acl, pe) {
0303 switch(pa->e_tag) {
0304 case ACL_USER_OBJ:
0305 break;
0306 case ACL_GROUP_OBJ:
0307 group_obj = pa;
0308 break;
0309 case ACL_MASK:
0310 mask = pa;
0311 fallthrough;
0312 case ACL_OTHER:
0313 break;
0314 }
0315 }
0316 if (acl->a_count == 4 && group_obj && mask &&
0317 mask->e_perm == group_obj->e_perm) {
0318
0319 memmove(mask, mask+1, (3 - (mask - acl->a_entries)) *
0320 sizeof(struct posix_acl_entry));
0321 acl->a_count = 3;
0322 }
0323 return 0;
0324 }
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336 int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
0337 struct posix_acl **pacl)
0338 {
0339 struct nfsacl_decode_desc nfsacl_desc = {
0340 .desc = {
0341 .elem_size = 12,
0342 .xcode = pacl ? xdr_nfsace_decode : NULL,
0343 },
0344 };
0345 u32 entries;
0346 int err;
0347
0348 if (xdr_decode_word(buf, base, &entries) ||
0349 entries > NFS_ACL_MAX_ENTRIES)
0350 return -EINVAL;
0351 nfsacl_desc.desc.array_maxlen = entries;
0352 err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc);
0353 if (err)
0354 return err;
0355 if (pacl) {
0356 if (entries != nfsacl_desc.desc.array_len ||
0357 posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) {
0358 posix_acl_release(nfsacl_desc.acl);
0359 return -EINVAL;
0360 }
0361 *pacl = nfsacl_desc.acl;
0362 }
0363 if (aclcnt)
0364 *aclcnt = entries;
0365 return 8 + nfsacl_desc.desc.elem_size *
0366 nfsacl_desc.desc.array_len;
0367 }
0368 EXPORT_SYMBOL_GPL(nfsacl_decode);
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383 bool nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt,
0384 struct posix_acl **pacl)
0385 {
0386 const size_t elem_size = XDR_UNIT * 3;
0387 struct nfsacl_decode_desc nfsacl_desc = {
0388 .desc = {
0389 .elem_size = elem_size,
0390 .xcode = pacl ? xdr_nfsace_decode : NULL,
0391 },
0392 };
0393 unsigned int base;
0394 u32 entries;
0395
0396 if (xdr_stream_decode_u32(xdr, &entries) < 0)
0397 return false;
0398 if (entries > NFS_ACL_MAX_ENTRIES)
0399 return false;
0400
0401 base = xdr_stream_pos(xdr);
0402 if (!xdr_inline_decode(xdr, XDR_UNIT + elem_size * entries))
0403 return false;
0404 nfsacl_desc.desc.array_maxlen = entries;
0405 if (xdr_decode_array2(xdr->buf, base, &nfsacl_desc.desc))
0406 return false;
0407
0408 if (pacl) {
0409 if (entries != nfsacl_desc.desc.array_len ||
0410 posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) {
0411 posix_acl_release(nfsacl_desc.acl);
0412 return false;
0413 }
0414 *pacl = nfsacl_desc.acl;
0415 }
0416 if (aclcnt)
0417 *aclcnt = entries;
0418 return true;
0419 }
0420 EXPORT_SYMBOL_GPL(nfs_stream_decode_acl);