int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
{
struct svc_cred *cred = &rqstp->rq_cred;
- struct group_info *group_info;
- int ngroups;
int i;
int ret;
- ngroups = 0;
- if (!(exp->ex_flags & NFSEXP_ALLSQUASH)) {
- for (i = 0; i < SVC_CRED_NGROUPS; i++) {
- if (cred->cr_groups[i] == (gid_t)NOGROUP)
- break;
- ngroups++;
- }
- }
- group_info = groups_alloc(ngroups);
- if (group_info == NULL)
- return -ENOMEM;
-
if (exp->ex_flags & NFSEXP_ALLSQUASH) {
cred->cr_uid = exp->ex_anon_uid;
cred->cr_gid = exp->ex_anon_gid;
- cred->cr_groups[0] = NOGROUP;
+ cred->cr_group_info->ngroups = 0;
} else if (exp->ex_flags & NFSEXP_ROOTSQUASH) {
if (!cred->cr_uid)
cred->cr_uid = exp->ex_anon_uid;
if (!cred->cr_gid)
cred->cr_gid = exp->ex_anon_gid;
- for (i = 0; i < SVC_CRED_NGROUPS; i++)
- if (!cred->cr_groups[i])
- cred->cr_groups[i] = exp->ex_anon_gid;
+ for (i = 0; i < cred->cr_group_info->ngroups; i++)
+ if (!GROUP_AT(cred->cr_group_info, i))
+ GROUP_AT(cred->cr_group_info, i) = exp->ex_anon_gid;
}
if (cred->cr_uid != (uid_t) -1)
else
current->fsgid = exp->ex_anon_gid;
- for (i = 0; i < SVC_CRED_NGROUPS; i++) {
- gid_t group = cred->cr_groups[i];
- if (group == (gid_t) NOGROUP)
- break;
- GROUP_AT(group_info, i) = group;
+ ret = set_current_groups(cred->cr_group_info);
+ if ((cred->cr_uid)) {
+ cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
+ } else {
+ cap_t(current->cap_effective) |= (CAP_NFSD_MASK &
+ current->cap_permitted);
}
-
- ret = set_current_groups(group_info);
- if (ret == 0) {
- if ((cred->cr_uid)) {
- cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
- } else {
- cap_t(current->cap_effective) |= (CAP_NFSD_MASK &
- current->cap_permitted);
- }
- }
- put_group_info(group_info);
-
return ret;
}
static inline void
free_client(struct nfs4_client *clp)
{
+ if (clp->cl_cred.cr_group_info)
+ put_group_info(clp->cl_cred.cr_group_info);
kfree(clp->cl_name.data);
kfree(clp);
}
static void
copy_cred(struct svc_cred *target, struct svc_cred *source) {
- int i;
target->cr_uid = source->cr_uid;
target->cr_gid = source->cr_gid;
- for(i = 0; i < SVC_CRED_NGROUPS; i++)
- target->cr_groups[i] = source->cr_groups[i];
+ target->cr_group_info = source->cr_group_info;
+ get_group_info(target->cr_group_info);
}
static int
}
/* Set user creds for this exportpoint */
- nfsd_setuser(rqstp, exp);
+ error = nfsd_setuser(rqstp, exp);
+ if (error) {
+ error = nfserrno(error);
+ goto out;
+ }
/*
* Look up the dentry using the NFS file handle.
struct svc_cred {
uid_t cr_uid;
gid_t cr_gid;
- gid_t cr_groups[SVC_CRED_NGROUPS];
+ struct group_info *cr_group_info;
};
struct svc_rqst; /* forward decl */
/* Signal that mapping to nobody uid/gid is required */
rqstp->rq_cred.cr_uid = (uid_t) -1;
rqstp->rq_cred.cr_gid = (gid_t) -1;
- rqstp->rq_cred.cr_groups[0] = NOGROUP;
+ rqstp->rq_cred.cr_group_info = groups_alloc(0);
+ if (rqstp->rq_cred.cr_group_info == NULL)
+ return SVC_DROP; /* kmalloc failure - client must retry */
/* Put NULL verifier */
svc_putu32(resv, RPC_AUTH_NULL);
int rv=0;
struct ip_map key, *ipm;
+ cred->cr_group_info = NULL;
+ rqstp->rq_client = NULL;
+
if ((len -= 3*4) < 0)
return SVC_GARBAGE;
slen = ntohl(svc_getu32(argv)); /* gids length */
if (slen > 16 || (len -= (slen + 2)*4) < 0)
goto badcred;
+ cred->cr_group_info = groups_alloc(slen);
+ if (cred->cr_group_info == NULL)
+ return SVC_DROP;
for (i = 0; i < slen; i++)
- if (i < SVC_CRED_NGROUPS)
- cred->cr_groups[i] = ntohl(svc_getu32(argv));
- else
- svc_getu32(argv);
- if (i < SVC_CRED_NGROUPS)
- cred->cr_groups[i] = NOGROUP;
+ GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv));
if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
*authp = rpc_autherr_badverf;
ipm = ip_map_lookup(&key, 0);
- rqstp->rq_client = NULL;
if (ipm)
switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
case -EAGAIN:
if (rqstp->rq_client)
auth_domain_put(rqstp->rq_client);
rqstp->rq_client = NULL;
+ if (rqstp->rq_cred.cr_group_info)
+ put_group_info(rqstp->rq_cred.cr_group_info);
+ rqstp->rq_cred.cr_group_info = NULL;
return 0;
}