xref: /linux/fs/nfsd/auth.c (revision d141ec2825b4d3ec52f27c43bdd864090159273a)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */
3 
4 #include <linux/sched.h>
5 #include "nfsd.h"
6 #include "export.h"
7 #include "auth.h"
8 
nfsexp_flags(struct svc_cred * cred,struct svc_export * exp)9 int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp)
10 {
11 	struct exp_flavor_info *f;
12 	struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
13 
14 	for (f = exp->ex_flavors; f < end; f++) {
15 		if (f->pseudoflavor == cred->cr_flavor)
16 			return f->flags;
17 	}
18 	return exp->ex_flags;
19 
20 }
21 
nfsd_setuser(struct svc_cred * cred,struct svc_export * exp)22 int nfsd_setuser(struct svc_cred *cred, struct svc_export *exp)
23 {
24 	struct group_info *rqgi;
25 	struct group_info *gi;
26 	struct cred *new;
27 	int i;
28 	int flags = nfsexp_flags(cred, exp);
29 
30 	/* discard any old override before preparing the new set */
31 	put_cred(revert_creds(get_cred(current_real_cred())));
32 	new = prepare_creds();
33 	if (!new)
34 		return -ENOMEM;
35 
36 	new->fsuid = cred->cr_uid;
37 	new->fsgid = cred->cr_gid;
38 
39 	rqgi = cred->cr_group_info;
40 
41 	if (flags & NFSEXP_ALLSQUASH) {
42 		new->fsuid = exp->ex_anon_uid;
43 		new->fsgid = exp->ex_anon_gid;
44 		gi = groups_alloc(0);
45 		if (!gi)
46 			goto oom;
47 	} else if (flags & NFSEXP_ROOTSQUASH) {
48 		if (uid_eq(new->fsuid, GLOBAL_ROOT_UID))
49 			new->fsuid = exp->ex_anon_uid;
50 		if (gid_eq(new->fsgid, GLOBAL_ROOT_GID))
51 			new->fsgid = exp->ex_anon_gid;
52 
53 		gi = groups_alloc(rqgi->ngroups);
54 		if (!gi)
55 			goto oom;
56 
57 		for (i = 0; i < rqgi->ngroups; i++) {
58 			if (gid_eq(GLOBAL_ROOT_GID, rqgi->gid[i]))
59 				gi->gid[i] = exp->ex_anon_gid;
60 			else
61 				gi->gid[i] = rqgi->gid[i];
62 		}
63 
64 		/* Each thread allocates its own gi, no race */
65 		groups_sort(gi);
66 	} else {
67 		gi = get_group_info(rqgi);
68 	}
69 
70 	if (uid_eq(new->fsuid, INVALID_UID))
71 		new->fsuid = exp->ex_anon_uid;
72 	if (gid_eq(new->fsgid, INVALID_GID))
73 		new->fsgid = exp->ex_anon_gid;
74 
75 	set_groups(new, gi);
76 	put_group_info(gi);
77 
78 	if (!uid_eq(new->fsuid, GLOBAL_ROOT_UID))
79 		new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
80 	else
81 		new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
82 							new->cap_permitted);
83 	put_cred(override_creds(new));
84 	return 0;
85 
86 oom:
87 	abort_creds(new);
88 	return -ENOMEM;
89 }
90 
91 /**
92  * nfsd_user_namespace - Get user_namespace in effect for an RPC request
93  * @rqstp: RPC execution context
94  *
95  * xpt_cred is set once at transport creation and never modified. The
96  * transport itself is reference-counted during request processing, so
97  * no explicit reference on the namespace is necessary.
98  *
99  * Return: the user_namespace from the transport credential, or
100  * init_user_ns if no credential was set. The returned namespace pointer
101  * is valid for the duration of the RPC request.
102  */
nfsd_user_namespace(const struct svc_rqst * rqstp)103 struct user_namespace *nfsd_user_namespace(const struct svc_rqst *rqstp)
104 {
105 	const struct cred *cred = rqstp->rq_xprt->xpt_cred;
106 
107 	return cred ? cred->user_ns : &init_user_ns;
108 }
109