diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2013-02-02 08:18:08 -0500 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2013-02-13 09:16:06 -0500 |
commit | ab8e4aee0a3f73d1b12e6d63b42075f0586ad4fd (patch) | |
tree | dc58ca18da44877a8274e423079a9aee65dce7fa /fs/nfsd | |
parent | 7c19723e997a3990951c0db0500009fb90c0c5b9 (diff) |
nfsd: Handle kuids and kgids in the nfs4acl to posix_acl conversion
In struct nfs4_ace remove the member who and replace it with an
anonymous union holding who_uid and who_gid. Allowing typesafe
storage uids and gids.
Add a helper pace_gt for sorting posix_acl_entries.
In struct posix_user_ace_state to replace uid with a union
of kuid_t uid and kgid_t gid.
Remove all initializations of the deprecated posic_acl_entry
e_id field. Which is not present when user namespaces are enabled.
Split find_uid into two functions find_uid and find_gid that work
in a typesafe manner.
In nfs4xdr update nfsd4_encode_fattr to deal with the changes
in struct nfs4_ace.
Rewrite nfsd4_encode_name to take a kuid_t and a kgid_t instead
of a generic id and flag if it is a group or a uid. Replace
the group flag with a test for a valid gid.
Modify nfsd4_encode_user to take a kuid_t and call the modifed
nfsd4_encode_name.
Modify nfsd4_encode_group to take a kgid_t and call the modified
nfsd4_encode_name.
Modify nfsd4_encode_aclname to take an ace instead of taking the
fields of an ace broken out. This allows it to detect if the ace is
for a user or a group and to pass the appropriate value while still
being typesafe.
Cc: "J. Bruce Fields" <bfields@fieldses.org>
Cc: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4acl.c | 63 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 41 |
2 files changed, 71 insertions, 33 deletions
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 9c51aff02ae2..8a50b3c18093 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -264,7 +264,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | |||
264 | ace->flag = eflag; | 264 | ace->flag = eflag; |
265 | ace->access_mask = deny_mask_from_posix(deny, flags); | 265 | ace->access_mask = deny_mask_from_posix(deny, flags); |
266 | ace->whotype = NFS4_ACL_WHO_NAMED; | 266 | ace->whotype = NFS4_ACL_WHO_NAMED; |
267 | ace->who = pa->e_id; | 267 | ace->who_uid = pa->e_uid; |
268 | ace++; | 268 | ace++; |
269 | acl->naces++; | 269 | acl->naces++; |
270 | } | 270 | } |
@@ -273,7 +273,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | |||
273 | ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, | 273 | ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, |
274 | flags); | 274 | flags); |
275 | ace->whotype = NFS4_ACL_WHO_NAMED; | 275 | ace->whotype = NFS4_ACL_WHO_NAMED; |
276 | ace->who = pa->e_id; | 276 | ace->who_uid = pa->e_uid; |
277 | ace++; | 277 | ace++; |
278 | acl->naces++; | 278 | acl->naces++; |
279 | pa++; | 279 | pa++; |
@@ -300,7 +300,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | |||
300 | ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, | 300 | ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, |
301 | flags); | 301 | flags); |
302 | ace->whotype = NFS4_ACL_WHO_NAMED; | 302 | ace->whotype = NFS4_ACL_WHO_NAMED; |
303 | ace->who = pa->e_id; | 303 | ace->who_gid = pa->e_gid; |
304 | ace++; | 304 | ace++; |
305 | acl->naces++; | 305 | acl->naces++; |
306 | pa++; | 306 | pa++; |
@@ -329,7 +329,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | |||
329 | ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; | 329 | ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; |
330 | ace->access_mask = deny_mask_from_posix(deny, flags); | 330 | ace->access_mask = deny_mask_from_posix(deny, flags); |
331 | ace->whotype = NFS4_ACL_WHO_NAMED; | 331 | ace->whotype = NFS4_ACL_WHO_NAMED; |
332 | ace->who = pa->e_id; | 332 | ace->who_gid = pa->e_gid; |
333 | ace++; | 333 | ace++; |
334 | acl->naces++; | 334 | acl->naces++; |
335 | } | 335 | } |
@@ -345,6 +345,18 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | |||
345 | acl->naces++; | 345 | acl->naces++; |
346 | } | 346 | } |
347 | 347 | ||
348 | static bool | ||
349 | pace_gt(struct posix_acl_entry *pace1, struct posix_acl_entry *pace2) | ||
350 | { | ||
351 | if (pace1->e_tag != pace2->e_tag) | ||
352 | return pace1->e_tag > pace2->e_tag; | ||
353 | if (pace1->e_tag == ACL_USER) | ||
354 | return uid_gt(pace1->e_uid, pace2->e_uid); | ||
355 | if (pace1->e_tag == ACL_GROUP) | ||
356 | return gid_gt(pace1->e_gid, pace2->e_gid); | ||
357 | return false; | ||
358 | } | ||
359 | |||
348 | static void | 360 | static void |
349 | sort_pacl_range(struct posix_acl *pacl, int start, int end) { | 361 | sort_pacl_range(struct posix_acl *pacl, int start, int end) { |
350 | int sorted = 0, i; | 362 | int sorted = 0, i; |
@@ -355,8 +367,8 @@ sort_pacl_range(struct posix_acl *pacl, int start, int end) { | |||
355 | while (!sorted) { | 367 | while (!sorted) { |
356 | sorted = 1; | 368 | sorted = 1; |
357 | for (i = start; i < end; i++) { | 369 | for (i = start; i < end; i++) { |
358 | if (pacl->a_entries[i].e_id | 370 | if (pace_gt(&pacl->a_entries[i], |
359 | > pacl->a_entries[i+1].e_id) { | 371 | &pacl->a_entries[i+1])) { |
360 | sorted = 0; | 372 | sorted = 0; |
361 | tmp = pacl->a_entries[i]; | 373 | tmp = pacl->a_entries[i]; |
362 | pacl->a_entries[i] = pacl->a_entries[i+1]; | 374 | pacl->a_entries[i] = pacl->a_entries[i+1]; |
@@ -398,7 +410,10 @@ struct posix_ace_state { | |||
398 | }; | 410 | }; |
399 | 411 | ||
400 | struct posix_user_ace_state { | 412 | struct posix_user_ace_state { |
401 | uid_t uid; | 413 | union { |
414 | kuid_t uid; | ||
415 | kgid_t gid; | ||
416 | }; | ||
402 | struct posix_ace_state perms; | 417 | struct posix_ace_state perms; |
403 | }; | 418 | }; |
404 | 419 | ||
@@ -521,7 +536,6 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) | |||
521 | if (error) | 536 | if (error) |
522 | goto out_err; | 537 | goto out_err; |
523 | low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags); | 538 | low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags); |
524 | pace->e_id = ACL_UNDEFINED_ID; | ||
525 | 539 | ||
526 | for (i=0; i < state->users->n; i++) { | 540 | for (i=0; i < state->users->n; i++) { |
527 | pace++; | 541 | pace++; |
@@ -531,7 +545,7 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) | |||
531 | goto out_err; | 545 | goto out_err; |
532 | low_mode_from_nfs4(state->users->aces[i].perms.allow, | 546 | low_mode_from_nfs4(state->users->aces[i].perms.allow, |
533 | &pace->e_perm, flags); | 547 | &pace->e_perm, flags); |
534 | pace->e_id = state->users->aces[i].uid; | 548 | pace->e_uid = state->users->aces[i].uid; |
535 | add_to_mask(state, &state->users->aces[i].perms); | 549 | add_to_mask(state, &state->users->aces[i].perms); |
536 | } | 550 | } |
537 | 551 | ||
@@ -541,7 +555,6 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) | |||
541 | if (error) | 555 | if (error) |
542 | goto out_err; | 556 | goto out_err; |
543 | low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags); | 557 | low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags); |
544 | pace->e_id = ACL_UNDEFINED_ID; | ||
545 | add_to_mask(state, &state->group); | 558 | add_to_mask(state, &state->group); |
546 | 559 | ||
547 | for (i=0; i < state->groups->n; i++) { | 560 | for (i=0; i < state->groups->n; i++) { |
@@ -552,14 +565,13 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) | |||
552 | goto out_err; | 565 | goto out_err; |
553 | low_mode_from_nfs4(state->groups->aces[i].perms.allow, | 566 | low_mode_from_nfs4(state->groups->aces[i].perms.allow, |
554 | &pace->e_perm, flags); | 567 | &pace->e_perm, flags); |
555 | pace->e_id = state->groups->aces[i].uid; | 568 | pace->e_gid = state->groups->aces[i].gid; |
556 | add_to_mask(state, &state->groups->aces[i].perms); | 569 | add_to_mask(state, &state->groups->aces[i].perms); |
557 | } | 570 | } |
558 | 571 | ||
559 | pace++; | 572 | pace++; |
560 | pace->e_tag = ACL_MASK; | 573 | pace->e_tag = ACL_MASK; |
561 | low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); | 574 | low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); |
562 | pace->e_id = ACL_UNDEFINED_ID; | ||
563 | 575 | ||
564 | pace++; | 576 | pace++; |
565 | pace->e_tag = ACL_OTHER; | 577 | pace->e_tag = ACL_OTHER; |
@@ -567,7 +579,6 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) | |||
567 | if (error) | 579 | if (error) |
568 | goto out_err; | 580 | goto out_err; |
569 | low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags); | 581 | low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags); |
570 | pace->e_id = ACL_UNDEFINED_ID; | ||
571 | 582 | ||
572 | return pacl; | 583 | return pacl; |
573 | out_err: | 584 | out_err: |
@@ -587,12 +598,13 @@ static inline void deny_bits(struct posix_ace_state *astate, u32 mask) | |||
587 | astate->deny |= mask & ~astate->allow; | 598 | astate->deny |= mask & ~astate->allow; |
588 | } | 599 | } |
589 | 600 | ||
590 | static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid) | 601 | static int find_uid(struct posix_acl_state *state, kuid_t uid) |
591 | { | 602 | { |
603 | struct posix_ace_state_array *a = state->users; | ||
592 | int i; | 604 | int i; |
593 | 605 | ||
594 | for (i = 0; i < a->n; i++) | 606 | for (i = 0; i < a->n; i++) |
595 | if (a->aces[i].uid == uid) | 607 | if (uid_eq(a->aces[i].uid, uid)) |
596 | return i; | 608 | return i; |
597 | /* Not found: */ | 609 | /* Not found: */ |
598 | a->n++; | 610 | a->n++; |
@@ -603,6 +615,23 @@ static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array | |||
603 | return i; | 615 | return i; |
604 | } | 616 | } |
605 | 617 | ||
618 | static int find_gid(struct posix_acl_state *state, kgid_t gid) | ||
619 | { | ||
620 | struct posix_ace_state_array *a = state->groups; | ||
621 | int i; | ||
622 | |||
623 | for (i = 0; i < a->n; i++) | ||
624 | if (gid_eq(a->aces[i].gid, gid)) | ||
625 | return i; | ||
626 | /* Not found: */ | ||
627 | a->n++; | ||
628 | a->aces[i].gid = gid; | ||
629 | a->aces[i].perms.allow = state->everyone.allow; | ||
630 | a->aces[i].perms.deny = state->everyone.deny; | ||
631 | |||
632 | return i; | ||
633 | } | ||
634 | |||
606 | static void deny_bits_array(struct posix_ace_state_array *a, u32 mask) | 635 | static void deny_bits_array(struct posix_ace_state_array *a, u32 mask) |
607 | { | 636 | { |
608 | int i; | 637 | int i; |
@@ -636,7 +665,7 @@ static void process_one_v4_ace(struct posix_acl_state *state, | |||
636 | } | 665 | } |
637 | break; | 666 | break; |
638 | case ACL_USER: | 667 | case ACL_USER: |
639 | i = find_uid(state, state->users, ace->who); | 668 | i = find_uid(state, ace->who_uid); |
640 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { | 669 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { |
641 | allow_bits(&state->users->aces[i].perms, mask); | 670 | allow_bits(&state->users->aces[i].perms, mask); |
642 | } else { | 671 | } else { |
@@ -658,7 +687,7 @@ static void process_one_v4_ace(struct posix_acl_state *state, | |||
658 | } | 687 | } |
659 | break; | 688 | break; |
660 | case ACL_GROUP: | 689 | case ACL_GROUP: |
661 | i = find_uid(state, state->groups, ace->who); | 690 | i = find_gid(state, ace->who_gid); |
662 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { | 691 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { |
663 | allow_bits(&state->groups->aces[i].perms, mask); | 692 | allow_bits(&state->groups->aces[i].perms, mask); |
664 | } else { | 693 | } else { |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0dc11586682f..3812b06d24b1 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -293,13 +293,13 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
293 | ace->whotype = nfs4_acl_get_whotype(buf, dummy32); | 293 | ace->whotype = nfs4_acl_get_whotype(buf, dummy32); |
294 | status = nfs_ok; | 294 | status = nfs_ok; |
295 | if (ace->whotype != NFS4_ACL_WHO_NAMED) | 295 | if (ace->whotype != NFS4_ACL_WHO_NAMED) |
296 | ace->who = 0; | 296 | ; |
297 | else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) | 297 | else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) |
298 | status = nfsd_map_name_to_gid(argp->rqstp, | 298 | status = nfsd_map_name_to_gid(argp->rqstp, |
299 | buf, dummy32, &ace->who); | 299 | buf, dummy32, &ace->who_gid); |
300 | else | 300 | else |
301 | status = nfsd_map_name_to_uid(argp->rqstp, | 301 | status = nfsd_map_name_to_uid(argp->rqstp, |
302 | buf, dummy32, &ace->who); | 302 | buf, dummy32, &ace->who_uid); |
303 | if (status) | 303 | if (status) |
304 | return status; | 304 | return status; |
305 | } | 305 | } |
@@ -1926,7 +1926,7 @@ static u32 nfs4_file_type(umode_t mode) | |||
1926 | } | 1926 | } |
1927 | 1927 | ||
1928 | static __be32 | 1928 | static __be32 |
1929 | nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, | 1929 | nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, kuid_t uid, kgid_t gid, |
1930 | __be32 **p, int *buflen) | 1930 | __be32 **p, int *buflen) |
1931 | { | 1931 | { |
1932 | int status; | 1932 | int status; |
@@ -1935,10 +1935,10 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, | |||
1935 | return nfserr_resource; | 1935 | return nfserr_resource; |
1936 | if (whotype != NFS4_ACL_WHO_NAMED) | 1936 | if (whotype != NFS4_ACL_WHO_NAMED) |
1937 | status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1)); | 1937 | status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1)); |
1938 | else if (group) | 1938 | else if (gid_valid(gid)) |
1939 | status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1)); | 1939 | status = nfsd_map_gid_to_name(rqstp, gid, (u8 *)(*p + 1)); |
1940 | else | 1940 | else |
1941 | status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1)); | 1941 | status = nfsd_map_uid_to_name(rqstp, uid, (u8 *)(*p + 1)); |
1942 | if (status < 0) | 1942 | if (status < 0) |
1943 | return nfserrno(status); | 1943 | return nfserrno(status); |
1944 | *p = xdr_encode_opaque(*p, NULL, status); | 1944 | *p = xdr_encode_opaque(*p, NULL, status); |
@@ -1948,22 +1948,33 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group, | |||
1948 | } | 1948 | } |
1949 | 1949 | ||
1950 | static inline __be32 | 1950 | static inline __be32 |
1951 | nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen) | 1951 | nfsd4_encode_user(struct svc_rqst *rqstp, kuid_t user, __be32 **p, int *buflen) |
1952 | { | 1952 | { |
1953 | return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen); | 1953 | return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, user, INVALID_GID, |
1954 | p, buflen); | ||
1954 | } | 1955 | } |
1955 | 1956 | ||
1956 | static inline __be32 | 1957 | static inline __be32 |
1957 | nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen) | 1958 | nfsd4_encode_group(struct svc_rqst *rqstp, kgid_t group, __be32 **p, int *buflen) |
1958 | { | 1959 | { |
1959 | return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen); | 1960 | return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, INVALID_UID, group, |
1961 | p, buflen); | ||
1960 | } | 1962 | } |
1961 | 1963 | ||
1962 | static inline __be32 | 1964 | static inline __be32 |
1963 | nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group, | 1965 | nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace, |
1964 | __be32 **p, int *buflen) | 1966 | __be32 **p, int *buflen) |
1965 | { | 1967 | { |
1966 | return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen); | 1968 | kuid_t uid = INVALID_UID; |
1969 | kgid_t gid = INVALID_GID; | ||
1970 | |||
1971 | if (ace->whotype == NFS4_ACL_WHO_NAMED) { | ||
1972 | if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) | ||
1973 | gid = ace->who_gid; | ||
1974 | else | ||
1975 | uid = ace->who_uid; | ||
1976 | } | ||
1977 | return nfsd4_encode_name(rqstp, ace->whotype, uid, gid, p, buflen); | ||
1967 | } | 1978 | } |
1968 | 1979 | ||
1969 | #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ | 1980 | #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ |
@@ -2224,9 +2235,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2224 | WRITE32(ace->type); | 2235 | WRITE32(ace->type); |
2225 | WRITE32(ace->flag); | 2236 | WRITE32(ace->flag); |
2226 | WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL); | 2237 | WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL); |
2227 | status = nfsd4_encode_aclname(rqstp, ace->whotype, | 2238 | status = nfsd4_encode_aclname(rqstp, ace, &p, &buflen); |
2228 | ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP, | ||
2229 | &p, &buflen); | ||
2230 | if (status == nfserr_resource) | 2239 | if (status == nfserr_resource) |
2231 | goto out_resource; | 2240 | goto out_resource; |
2232 | if (status) | 2241 | if (status) |