162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/sched.h> 562306a36Sopenharmony_ci#include "nfsd.h" 662306a36Sopenharmony_ci#include "auth.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ciint nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) 962306a36Sopenharmony_ci{ 1062306a36Sopenharmony_ci struct exp_flavor_info *f; 1162306a36Sopenharmony_ci struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci for (f = exp->ex_flavors; f < end; f++) { 1462306a36Sopenharmony_ci if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) 1562306a36Sopenharmony_ci return f->flags; 1662306a36Sopenharmony_ci } 1762306a36Sopenharmony_ci return exp->ex_flags; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciint nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct group_info *rqgi; 2462306a36Sopenharmony_ci struct group_info *gi; 2562306a36Sopenharmony_ci struct cred *new; 2662306a36Sopenharmony_ci int i; 2762306a36Sopenharmony_ci int flags = nfsexp_flags(rqstp, exp); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* discard any old override before preparing the new set */ 3062306a36Sopenharmony_ci revert_creds(get_cred(current_real_cred())); 3162306a36Sopenharmony_ci new = prepare_creds(); 3262306a36Sopenharmony_ci if (!new) 3362306a36Sopenharmony_ci return -ENOMEM; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci new->fsuid = rqstp->rq_cred.cr_uid; 3662306a36Sopenharmony_ci new->fsgid = rqstp->rq_cred.cr_gid; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci rqgi = rqstp->rq_cred.cr_group_info; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (flags & NFSEXP_ALLSQUASH) { 4162306a36Sopenharmony_ci new->fsuid = exp->ex_anon_uid; 4262306a36Sopenharmony_ci new->fsgid = exp->ex_anon_gid; 4362306a36Sopenharmony_ci gi = groups_alloc(0); 4462306a36Sopenharmony_ci if (!gi) 4562306a36Sopenharmony_ci goto oom; 4662306a36Sopenharmony_ci } else if (flags & NFSEXP_ROOTSQUASH) { 4762306a36Sopenharmony_ci if (uid_eq(new->fsuid, GLOBAL_ROOT_UID)) 4862306a36Sopenharmony_ci new->fsuid = exp->ex_anon_uid; 4962306a36Sopenharmony_ci if (gid_eq(new->fsgid, GLOBAL_ROOT_GID)) 5062306a36Sopenharmony_ci new->fsgid = exp->ex_anon_gid; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci gi = groups_alloc(rqgi->ngroups); 5362306a36Sopenharmony_ci if (!gi) 5462306a36Sopenharmony_ci goto oom; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci for (i = 0; i < rqgi->ngroups; i++) { 5762306a36Sopenharmony_ci if (gid_eq(GLOBAL_ROOT_GID, rqgi->gid[i])) 5862306a36Sopenharmony_ci gi->gid[i] = exp->ex_anon_gid; 5962306a36Sopenharmony_ci else 6062306a36Sopenharmony_ci gi->gid[i] = rqgi->gid[i]; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Each thread allocates its own gi, no race */ 6462306a36Sopenharmony_ci groups_sort(gi); 6562306a36Sopenharmony_ci } else { 6662306a36Sopenharmony_ci gi = get_group_info(rqgi); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (uid_eq(new->fsuid, INVALID_UID)) 7062306a36Sopenharmony_ci new->fsuid = exp->ex_anon_uid; 7162306a36Sopenharmony_ci if (gid_eq(new->fsgid, INVALID_GID)) 7262306a36Sopenharmony_ci new->fsgid = exp->ex_anon_gid; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci set_groups(new, gi); 7562306a36Sopenharmony_ci put_group_info(gi); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (!uid_eq(new->fsuid, GLOBAL_ROOT_UID)) 7862306a36Sopenharmony_ci new->cap_effective = cap_drop_nfsd_set(new->cap_effective); 7962306a36Sopenharmony_ci else 8062306a36Sopenharmony_ci new->cap_effective = cap_raise_nfsd_set(new->cap_effective, 8162306a36Sopenharmony_ci new->cap_permitted); 8262306a36Sopenharmony_ci put_cred(override_creds(new)); 8362306a36Sopenharmony_ci put_cred(new); 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cioom: 8762306a36Sopenharmony_ci abort_creds(new); 8862306a36Sopenharmony_ci return -ENOMEM; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 91