diff options
Diffstat (limited to 'fs/nfsd/auth.c')
| -rw-r--r-- | fs/nfsd/auth.c | 127 |
1 files changed, 77 insertions, 50 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index cfe9ce88161..72f44823adb 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -1,63 +1,90 @@ -/* - * linux/fs/nfsd/auth.c - * - * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> - */ +/* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ -#include <linux/types.h> #include <linux/sched.h> -#include <linux/sunrpc/svc.h> -#include <linux/sunrpc/svcauth.h> -#include <linux/nfsd/nfsd.h> +#include "nfsd.h" +#include "auth.h" -#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) +int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) +{ + struct exp_flavor_info *f; + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; + + for (f = exp->ex_flavors; f < end; f++) { + if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) + return f->flags; + } + return exp->ex_flags; + +} int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) { - struct svc_cred *cred = &rqstp->rq_cred; + struct group_info *rqgi; + struct group_info *gi; + struct cred *new; int i; - int ret; - - if (exp->ex_flags & NFSEXP_ALLSQUASH) { - cred->cr_uid = exp->ex_anon_uid; - cred->cr_gid = exp->ex_anon_gid; - put_group_info(cred->cr_group_info); - cred->cr_group_info = groups_alloc(0); - } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) { - struct group_info *gi; - if (!cred->cr_uid) - cred->cr_uid = exp->ex_anon_uid; - if (!cred->cr_gid) - cred->cr_gid = exp->ex_anon_gid; - gi = groups_alloc(cred->cr_group_info->ngroups); - if (gi) - for (i = 0; i < cred->cr_group_info->ngroups; i++) { - if (!GROUP_AT(cred->cr_group_info, i)) - GROUP_AT(gi, i) = exp->ex_anon_gid; - else - GROUP_AT(gi, i) = GROUP_AT(cred->cr_group_info, i); - } - put_group_info(cred->cr_group_info); - cred->cr_group_info = gi; - } + int flags = nfsexp_flags(rqstp, exp); - if (cred->cr_uid != (uid_t) -1) - current->fsuid = cred->cr_uid; - else - current->fsuid = exp->ex_anon_uid; - if (cred->cr_gid != (gid_t) -1) - current->fsgid = cred->cr_gid; - else - current->fsgid = exp->ex_anon_gid; + validate_process_creds(); - if (!cred->cr_group_info) + /* discard any old override before preparing the new set */ + revert_creds(get_cred(current->real_cred)); + new = prepare_creds(); + if (!new) return -ENOMEM; - ret = set_current_groups(cred->cr_group_info); - if ((cred->cr_uid)) { - cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; + + new->fsuid = rqstp->rq_cred.cr_uid; + new->fsgid = rqstp->rq_cred.cr_gid; + + rqgi = rqstp->rq_cred.cr_group_info; + + if (flags & NFSEXP_ALLSQUASH) { + new->fsuid = exp->ex_anon_uid; + new->fsgid = exp->ex_anon_gid; + gi = groups_alloc(0); + if (!gi) + goto oom; + } else if (flags & NFSEXP_ROOTSQUASH) { + if (uid_eq(new->fsuid, GLOBAL_ROOT_UID)) + new->fsuid = exp->ex_anon_uid; + if (gid_eq(new->fsgid, GLOBAL_ROOT_GID)) + new->fsgid = exp->ex_anon_gid; + + gi = groups_alloc(rqgi->ngroups); + if (!gi) + goto oom; + + for (i = 0; i < rqgi->ngroups; i++) { + if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i))) + GROUP_AT(gi, i) = exp->ex_anon_gid; + else + GROUP_AT(gi, i) = GROUP_AT(rqgi, i); + } } else { - cap_t(current->cap_effective) |= (CAP_NFSD_MASK & - current->cap_permitted); + gi = get_group_info(rqgi); } - return ret; + + if (uid_eq(new->fsuid, INVALID_UID)) + new->fsuid = exp->ex_anon_uid; + if (gid_eq(new->fsgid, INVALID_GID)) + new->fsgid = exp->ex_anon_gid; + + set_groups(new, gi); + put_group_info(gi); + + if (!uid_eq(new->fsuid, GLOBAL_ROOT_UID)) + new->cap_effective = cap_drop_nfsd_set(new->cap_effective); + else + new->cap_effective = cap_raise_nfsd_set(new->cap_effective, + new->cap_permitted); + validate_process_creds(); + put_cred(override_creds(new)); + put_cred(new); + validate_process_creds(); + return 0; + +oom: + abort_creds(new); + return -ENOMEM; } + |
