xref: /openbmc/linux/net/sunrpc/auth_unix.c (revision 87c2ce3b)
1 /*
2  * linux/net/sunrpc/auth_unix.c
3  *
4  * UNIX-style authentication; no AUTH_SHORT support
5  *
6  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
7  */
8 
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/module.h>
12 #include <linux/sunrpc/clnt.h>
13 #include <linux/sunrpc/auth.h>
14 
15 #define NFS_NGROUPS	16
16 
17 struct unx_cred {
18 	struct rpc_cred		uc_base;
19 	gid_t			uc_gid;
20 	gid_t			uc_gids[NFS_NGROUPS];
21 };
22 #define uc_uid			uc_base.cr_uid
23 #define uc_count		uc_base.cr_count
24 #define uc_flags		uc_base.cr_flags
25 #define uc_expire		uc_base.cr_expire
26 
27 #define UNX_CRED_EXPIRE		(60 * HZ)
28 
29 #define UNX_WRITESLACK		(21 + (UNX_MAXNODENAME >> 2))
30 
31 #ifdef RPC_DEBUG
32 # define RPCDBG_FACILITY	RPCDBG_AUTH
33 #endif
34 
35 static struct rpc_auth		unix_auth;
36 static struct rpc_cred_cache	unix_cred_cache;
37 static struct rpc_credops	unix_credops;
38 
39 static struct rpc_auth *
40 unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
41 {
42 	dprintk("RPC: creating UNIX authenticator for client %p\n", clnt);
43 	if (atomic_inc_return(&unix_auth.au_count) == 0)
44 		unix_cred_cache.nextgc = jiffies + (unix_cred_cache.expire >> 1);
45 	return &unix_auth;
46 }
47 
48 static void
49 unx_destroy(struct rpc_auth *auth)
50 {
51 	dprintk("RPC: destroying UNIX authenticator %p\n", auth);
52 	rpcauth_free_credcache(auth);
53 }
54 
55 /*
56  * Lookup AUTH_UNIX creds for current process
57  */
58 static struct rpc_cred *
59 unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
60 {
61 	return rpcauth_lookup_credcache(auth, acred, flags);
62 }
63 
64 static struct rpc_cred *
65 unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
66 {
67 	struct unx_cred	*cred;
68 	int		i;
69 
70 	dprintk("RPC:      allocating UNIX cred for uid %d gid %d\n",
71 				acred->uid, acred->gid);
72 
73 	if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL)))
74 		return ERR_PTR(-ENOMEM);
75 
76 	atomic_set(&cred->uc_count, 1);
77 	cred->uc_flags = RPCAUTH_CRED_UPTODATE;
78 	if (flags & RPC_TASK_ROOTCREDS) {
79 		cred->uc_uid = 0;
80 		cred->uc_gid = 0;
81 		cred->uc_gids[0] = NOGROUP;
82 	} else {
83 		int groups = acred->group_info->ngroups;
84 		if (groups > NFS_NGROUPS)
85 			groups = NFS_NGROUPS;
86 
87 		cred->uc_uid = acred->uid;
88 		cred->uc_gid = acred->gid;
89 		for (i = 0; i < groups; i++)
90 			cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
91 		if (i < NFS_NGROUPS)
92 		  cred->uc_gids[i] = NOGROUP;
93 	}
94 	cred->uc_base.cr_ops = &unix_credops;
95 
96 	return (struct rpc_cred *) cred;
97 }
98 
99 static void
100 unx_destroy_cred(struct rpc_cred *cred)
101 {
102 	kfree(cred);
103 }
104 
105 /*
106  * Match credentials against current process creds.
107  * The root_override argument takes care of cases where the caller may
108  * request root creds (e.g. for NFS swapping).
109  */
110 static int
111 unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
112 {
113 	struct unx_cred	*cred = (struct unx_cred *) rcred;
114 	int		i;
115 
116 	if (!(taskflags & RPC_TASK_ROOTCREDS)) {
117 		int groups;
118 
119 		if (cred->uc_uid != acred->uid
120 		 || cred->uc_gid != acred->gid)
121 			return 0;
122 
123 		groups = acred->group_info->ngroups;
124 		if (groups > NFS_NGROUPS)
125 			groups = NFS_NGROUPS;
126 		for (i = 0; i < groups ; i++)
127 			if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
128 				return 0;
129 		return 1;
130 	}
131 	return (cred->uc_uid == 0
132 	     && cred->uc_gid == 0
133 	     && cred->uc_gids[0] == (gid_t) NOGROUP);
134 }
135 
136 /*
137  * Marshal credentials.
138  * Maybe we should keep a cached credential for performance reasons.
139  */
140 static u32 *
141 unx_marshal(struct rpc_task *task, u32 *p)
142 {
143 	struct rpc_clnt	*clnt = task->tk_client;
144 	struct unx_cred	*cred = (struct unx_cred *) task->tk_msg.rpc_cred;
145 	u32		*base, *hold;
146 	int		i;
147 
148 	*p++ = htonl(RPC_AUTH_UNIX);
149 	base = p++;
150 	*p++ = htonl(jiffies/HZ);
151 
152 	/*
153 	 * Copy the UTS nodename captured when the client was created.
154 	 */
155 	p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
156 
157 	*p++ = htonl((u32) cred->uc_uid);
158 	*p++ = htonl((u32) cred->uc_gid);
159 	hold = p++;
160 	for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
161 		*p++ = htonl((u32) cred->uc_gids[i]);
162 	*hold = htonl(p - hold - 1);		/* gid array length */
163 	*base = htonl((p - base - 1) << 2);	/* cred length */
164 
165 	*p++ = htonl(RPC_AUTH_NULL);
166 	*p++ = htonl(0);
167 
168 	return p;
169 }
170 
171 /*
172  * Refresh credentials. This is a no-op for AUTH_UNIX
173  */
174 static int
175 unx_refresh(struct rpc_task *task)
176 {
177 	task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
178 	return 0;
179 }
180 
181 static u32 *
182 unx_validate(struct rpc_task *task, u32 *p)
183 {
184 	rpc_authflavor_t	flavor;
185 	u32			size;
186 
187 	flavor = ntohl(*p++);
188 	if (flavor != RPC_AUTH_NULL &&
189 	    flavor != RPC_AUTH_UNIX &&
190 	    flavor != RPC_AUTH_SHORT) {
191 		printk("RPC: bad verf flavor: %u\n", flavor);
192 		return NULL;
193 	}
194 
195 	size = ntohl(*p++);
196 	if (size > RPC_MAX_AUTH_SIZE) {
197 		printk("RPC: giant verf size: %u\n", size);
198 		return NULL;
199 	}
200 	task->tk_auth->au_rslack = (size >> 2) + 2;
201 	p += (size >> 2);
202 
203 	return p;
204 }
205 
206 struct rpc_authops	authunix_ops = {
207 	.owner		= THIS_MODULE,
208 	.au_flavor	= RPC_AUTH_UNIX,
209 #ifdef RPC_DEBUG
210 	.au_name	= "UNIX",
211 #endif
212 	.create		= unx_create,
213 	.destroy	= unx_destroy,
214 	.lookup_cred	= unx_lookup_cred,
215 	.crcreate	= unx_create_cred,
216 };
217 
218 static
219 struct rpc_cred_cache	unix_cred_cache = {
220 	.expire		= UNX_CRED_EXPIRE,
221 };
222 
223 static
224 struct rpc_auth		unix_auth = {
225 	.au_cslack	= UNX_WRITESLACK,
226 	.au_rslack	= 2,			/* assume AUTH_NULL verf */
227 	.au_ops		= &authunix_ops,
228 	.au_count	= ATOMIC_INIT(0),
229 	.au_credcache	= &unix_cred_cache,
230 };
231 
232 static
233 struct rpc_credops	unix_credops = {
234 	.cr_name	= "AUTH_UNIX",
235 	.crdestroy	= unx_destroy_cred,
236 	.crmatch	= unx_match,
237 	.crmarshal	= unx_marshal,
238 	.crrefresh	= unx_refresh,
239 	.crvalidate	= unx_validate,
240 };
241