nfsd_setuser() sets both the rqstp->cred and the current tasks uid, gid, and groups according to an exports squash rules (all_squash, root_squash). nfsd_setuser() is called in fh_verify() to correctly set the current's threads access to an export's directories and files. setting the rqstp->cred is problematic for SETCLIENTID which is required to store the principal used for it's call, and whcih has client-wide scope, not export wide scope. under the current scheme, the rqstp->cred could be set by nfsd_setuser or not, depending on the other previous NFSv4 operatios in the SETCLIENTID compound. in order to pass confirmation of a clientid, SETCLIENTID_CONFIRM compares the rqstp->cred with the credentials stored by SETCLIENTID. again, setting the rqstp->cred with nfsd_user() is probelmatic. this patch changes nfsd_setuser() to set only the current threads uid, gid, and groups, leaving the rqstp->cred untouched. "Signed-off-by: Andy Adamson " --- --- diff -puN fs/nfsd/auth.c~nfsd_setuser-fix fs/nfsd/auth.c --- linux-2.6.16-rc4/fs/nfsd/auth.c~nfsd_setuser-fix 2006-03-01 19:16:34.000000000 -0500 +++ linux-2.6.16-rc4-andros/fs/nfsd/auth.c 2006-03-01 19:18:07.000000000 -0500 @@ -17,43 +17,43 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_cred *cred = &rqstp->rq_cred; int i; int ret; + uid_t luid = cred->cr_uid; + gid_t lgid = cred->cr_gid; + struct group_info *gi = NULL; 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); + luid = exp->ex_anon_uid; + lgid = exp->ex_anon_gid; + gi = 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; + luid = exp->ex_anon_uid; if (!cred->cr_gid) - cred->cr_gid = exp->ex_anon_gid; + lgid = 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; + if (!gi) + return -ENOMEM; + 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); + } } - if (cred->cr_uid != (uid_t) -1) - current->fsuid = cred->cr_uid; + if (luid != (uid_t) -1) + current->fsuid = luid; else current->fsuid = exp->ex_anon_uid; - if (cred->cr_gid != (gid_t) -1) - current->fsgid = cred->cr_gid; + if (lgid != (gid_t) -1) + current->fsgid = lgid; else current->fsgid = exp->ex_anon_gid; - if (!cred->cr_group_info) - return -ENOMEM; - ret = set_current_groups(cred->cr_group_info); - if ((cred->cr_uid)) { + if (!gi) + gi = cred->cr_group_info; + ret = set_current_groups(gi); + if ((luid)) { cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; } else { cap_t(current->cap_effective) |= (CAP_NFSD_MASK & _