Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : #include <linux/types.h>
3 : : #include <linux/sched.h>
4 : : #include <linux/module.h>
5 : : #include <linux/sunrpc/types.h>
6 : : #include <linux/sunrpc/xdr.h>
7 : : #include <linux/sunrpc/svcsock.h>
8 : : #include <linux/sunrpc/svcauth.h>
9 : : #include <linux/sunrpc/gss_api.h>
10 : : #include <linux/sunrpc/addr.h>
11 : : #include <linux/err.h>
12 : : #include <linux/seq_file.h>
13 : : #include <linux/hash.h>
14 : : #include <linux/string.h>
15 : : #include <linux/slab.h>
16 : : #include <net/sock.h>
17 : : #include <net/ipv6.h>
18 : : #include <linux/kernel.h>
19 : : #include <linux/user_namespace.h>
20 : : #define RPCDBG_FACILITY RPCDBG_AUTH
21 : :
22 : :
23 : : #include "netns.h"
24 : :
25 : : /*
26 : : * AUTHUNIX and AUTHNULL credentials are both handled here.
27 : : * AUTHNULL is treated just like AUTHUNIX except that the uid/gid
28 : : * are always nobody (-2). i.e. we do the same IP address checks for
29 : : * AUTHNULL as for AUTHUNIX, and that is done here.
30 : : */
31 : :
32 : :
33 : : struct unix_domain {
34 : : struct auth_domain h;
35 : : /* other stuff later */
36 : : };
37 : :
38 : : extern struct auth_ops svcauth_null;
39 : : extern struct auth_ops svcauth_unix;
40 : :
41 : 0 : static void svcauth_unix_domain_release_rcu(struct rcu_head *head)
42 : : {
43 : 0 : struct auth_domain *dom = container_of(head, struct auth_domain, rcu_head);
44 : 0 : struct unix_domain *ud = container_of(dom, struct unix_domain, h);
45 : :
46 : 0 : kfree(dom->name);
47 : 0 : kfree(ud);
48 : 0 : }
49 : :
50 : 0 : static void svcauth_unix_domain_release(struct auth_domain *dom)
51 : : {
52 : 0 : call_rcu(&dom->rcu_head, svcauth_unix_domain_release_rcu);
53 : 0 : }
54 : :
55 : 0 : struct auth_domain *unix_domain_find(char *name)
56 : : {
57 : 0 : struct auth_domain *rv;
58 : 0 : struct unix_domain *new = NULL;
59 : :
60 : 0 : rv = auth_domain_find(name);
61 : 0 : while(1) {
62 [ # # ]: 0 : if (rv) {
63 [ # # # # ]: 0 : if (new && rv != &new->h)
64 : 0 : svcauth_unix_domain_release(&new->h);
65 : :
66 [ # # ]: 0 : if (rv->flavour != &svcauth_unix) {
67 : 0 : auth_domain_put(rv);
68 : 0 : return NULL;
69 : : }
70 : : return rv;
71 : : }
72 : :
73 : 0 : new = kmalloc(sizeof(*new), GFP_KERNEL);
74 [ # # ]: 0 : if (new == NULL)
75 : : return NULL;
76 : 0 : kref_init(&new->h.ref);
77 : 0 : new->h.name = kstrdup(name, GFP_KERNEL);
78 [ # # ]: 0 : if (new->h.name == NULL) {
79 : 0 : kfree(new);
80 : 0 : return NULL;
81 : : }
82 : 0 : new->h.flavour = &svcauth_unix;
83 : 0 : rv = auth_domain_lookup(name, &new->h);
84 : : }
85 : : }
86 : : EXPORT_SYMBOL_GPL(unix_domain_find);
87 : :
88 : :
89 : : /**************************************************
90 : : * cache for IP address to unix_domain
91 : : * as needed by AUTH_UNIX
92 : : */
93 : : #define IP_HASHBITS 8
94 : : #define IP_HASHMAX (1<<IP_HASHBITS)
95 : :
96 : : struct ip_map {
97 : : struct cache_head h;
98 : : char m_class[8]; /* e.g. "nfsd" */
99 : : struct in6_addr m_addr;
100 : : struct unix_domain *m_client;
101 : : struct rcu_head m_rcu;
102 : : };
103 : :
104 : 0 : static void ip_map_put(struct kref *kref)
105 : : {
106 : 0 : struct cache_head *item = container_of(kref, struct cache_head, ref);
107 : 0 : struct ip_map *im = container_of(item, struct ip_map,h);
108 : :
109 [ # # # # ]: 0 : if (test_bit(CACHE_VALID, &item->flags) &&
110 : : !test_bit(CACHE_NEGATIVE, &item->flags))
111 : 0 : auth_domain_put(&im->m_client->h);
112 [ # # ]: 0 : kfree_rcu(im, m_rcu);
113 : 0 : }
114 : :
115 : 0 : static inline int hash_ip6(const struct in6_addr *ip)
116 : : {
117 : 0 : return hash_32(ipv6_addr_hash(ip), IP_HASHBITS);
118 : : }
119 : 0 : static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
120 : : {
121 : 0 : struct ip_map *orig = container_of(corig, struct ip_map, h);
122 : 0 : struct ip_map *new = container_of(cnew, struct ip_map, h);
123 [ # # # # ]: 0 : return strcmp(orig->m_class, new->m_class) == 0 &&
124 : : ipv6_addr_equal(&orig->m_addr, &new->m_addr);
125 : : }
126 : 0 : static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
127 : : {
128 : 0 : struct ip_map *new = container_of(cnew, struct ip_map, h);
129 : 0 : struct ip_map *item = container_of(citem, struct ip_map, h);
130 : :
131 : 0 : strcpy(new->m_class, item->m_class);
132 : 0 : new->m_addr = item->m_addr;
133 : 0 : }
134 : 0 : static void update(struct cache_head *cnew, struct cache_head *citem)
135 : : {
136 : 0 : struct ip_map *new = container_of(cnew, struct ip_map, h);
137 : 0 : struct ip_map *item = container_of(citem, struct ip_map, h);
138 : :
139 : 0 : kref_get(&item->m_client->h.ref);
140 : 0 : new->m_client = item->m_client;
141 : 0 : }
142 : 0 : static struct cache_head *ip_map_alloc(void)
143 : : {
144 : 0 : struct ip_map *i = kmalloc(sizeof(*i), GFP_KERNEL);
145 [ # # ]: 0 : if (i)
146 : 0 : return &i->h;
147 : : else
148 : : return NULL;
149 : : }
150 : :
151 : 0 : static void ip_map_request(struct cache_detail *cd,
152 : : struct cache_head *h,
153 : : char **bpp, int *blen)
154 : : {
155 : 0 : char text_addr[40];
156 : 0 : struct ip_map *im = container_of(h, struct ip_map, h);
157 : :
158 [ # # ]: 0 : if (ipv6_addr_v4mapped(&(im->m_addr))) {
159 : 0 : snprintf(text_addr, 20, "%pI4", &im->m_addr.s6_addr32[3]);
160 : : } else {
161 : 0 : snprintf(text_addr, 40, "%pI6", &im->m_addr);
162 : : }
163 : 0 : qword_add(bpp, blen, im->m_class);
164 : 0 : qword_add(bpp, blen, text_addr);
165 : 0 : (*bpp)[-1] = '\n';
166 : 0 : }
167 : :
168 : : static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);
169 : : static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time64_t expiry);
170 : :
171 : 0 : static int ip_map_parse(struct cache_detail *cd,
172 : : char *mesg, int mlen)
173 : : {
174 : : /* class ipaddress [domainname] */
175 : : /* should be safe just to use the start of the input buffer
176 : : * for scratch: */
177 : 0 : char *buf = mesg;
178 : 0 : int len;
179 : 0 : char class[8];
180 : 0 : union {
181 : : struct sockaddr sa;
182 : : struct sockaddr_in s4;
183 : : struct sockaddr_in6 s6;
184 : : } address;
185 : 0 : struct sockaddr_in6 sin6;
186 : 0 : int err;
187 : :
188 : 0 : struct ip_map *ipmp;
189 : 0 : struct auth_domain *dom;
190 : 0 : time64_t expiry;
191 : :
192 [ # # ]: 0 : if (mesg[mlen-1] != '\n')
193 : : return -EINVAL;
194 : 0 : mesg[mlen-1] = 0;
195 : :
196 : : /* class */
197 : 0 : len = qword_get(&mesg, class, sizeof(class));
198 [ # # ]: 0 : if (len <= 0) return -EINVAL;
199 : :
200 : : /* ip address */
201 : 0 : len = qword_get(&mesg, buf, mlen);
202 [ # # ]: 0 : if (len <= 0) return -EINVAL;
203 : :
204 [ # # ]: 0 : if (rpc_pton(cd->net, buf, len, &address.sa, sizeof(address)) == 0)
205 : : return -EINVAL;
206 [ # # # ]: 0 : switch (address.sa.sa_family) {
207 : 0 : case AF_INET:
208 : : /* Form a mapped IPv4 address in sin6 */
209 : 0 : sin6.sin6_family = AF_INET6;
210 [ # # ]: 0 : ipv6_addr_set_v4mapped(address.s4.sin_addr.s_addr,
211 : : &sin6.sin6_addr);
212 : : break;
213 : : #if IS_ENABLED(CONFIG_IPV6)
214 : 0 : case AF_INET6:
215 : 0 : memcpy(&sin6, &address.s6, sizeof(sin6));
216 : 0 : break;
217 : : #endif
218 : : default:
219 : : return -EINVAL;
220 : : }
221 : :
222 : 0 : expiry = get_expiry(&mesg);
223 [ # # ]: 0 : if (expiry ==0)
224 : : return -EINVAL;
225 : :
226 : : /* domainname, or empty for NEGATIVE */
227 : 0 : len = qword_get(&mesg, buf, mlen);
228 [ # # ]: 0 : if (len < 0) return -EINVAL;
229 : :
230 [ # # ]: 0 : if (len) {
231 : 0 : dom = unix_domain_find(buf);
232 [ # # ]: 0 : if (dom == NULL)
233 : : return -ENOENT;
234 : : } else
235 : : dom = NULL;
236 : :
237 : : /* IPv6 scope IDs are ignored for now */
238 : 0 : ipmp = __ip_map_lookup(cd, class, &sin6.sin6_addr);
239 [ # # ]: 0 : if (ipmp) {
240 : 0 : err = __ip_map_update(cd, ipmp,
241 : 0 : container_of(dom, struct unix_domain, h),
242 : : expiry);
243 : : } else
244 : : err = -ENOMEM;
245 : :
246 [ # # ]: 0 : if (dom)
247 : 0 : auth_domain_put(dom);
248 : :
249 : 0 : cache_flush();
250 : 0 : return err;
251 : : }
252 : :
253 : 0 : static int ip_map_show(struct seq_file *m,
254 : : struct cache_detail *cd,
255 : : struct cache_head *h)
256 : : {
257 : 0 : struct ip_map *im;
258 : 0 : struct in6_addr addr;
259 : 0 : char *dom = "-no-domain-";
260 : :
261 [ # # ]: 0 : if (h == NULL) {
262 : 0 : seq_puts(m, "#class IP domain\n");
263 : 0 : return 0;
264 : : }
265 : 0 : im = container_of(h, struct ip_map, h);
266 : : /* class addr domain */
267 : 0 : addr = im->m_addr;
268 : :
269 [ # # # # ]: 0 : if (test_bit(CACHE_VALID, &h->flags) &&
270 : : !test_bit(CACHE_NEGATIVE, &h->flags))
271 : 0 : dom = im->m_client->h.name;
272 : :
273 [ # # ]: 0 : if (ipv6_addr_v4mapped(&addr)) {
274 : 0 : seq_printf(m, "%s %pI4 %s\n",
275 : 0 : im->m_class, &addr.s6_addr32[3], dom);
276 : : } else {
277 : 0 : seq_printf(m, "%s %pI6 %s\n", im->m_class, &addr, dom);
278 : : }
279 : : return 0;
280 : : }
281 : :
282 : :
283 : 0 : static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class,
284 : : struct in6_addr *addr)
285 : : {
286 : 0 : struct ip_map ip;
287 : 0 : struct cache_head *ch;
288 : :
289 : 0 : strcpy(ip.m_class, class);
290 : 0 : ip.m_addr = *addr;
291 : 0 : ch = sunrpc_cache_lookup_rcu(cd, &ip.h,
292 : 0 : hash_str(class, IP_HASHBITS) ^
293 : : hash_ip6(addr));
294 : :
295 [ # # ]: 0 : if (ch)
296 : : return container_of(ch, struct ip_map, h);
297 : : else
298 : 0 : return NULL;
299 : : }
300 : :
301 : : static inline struct ip_map *ip_map_lookup(struct net *net, char *class,
302 : : struct in6_addr *addr)
303 : : {
304 : : struct sunrpc_net *sn;
305 : :
306 : : sn = net_generic(net, sunrpc_net_id);
307 : : return __ip_map_lookup(sn->ip_map_cache, class, addr);
308 : : }
309 : :
310 : 0 : static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
311 : : struct unix_domain *udom, time64_t expiry)
312 : : {
313 : 0 : struct ip_map ip;
314 : 0 : struct cache_head *ch;
315 : :
316 : 0 : ip.m_client = udom;
317 : 0 : ip.h.flags = 0;
318 [ # # ]: 0 : if (!udom)
319 : 0 : set_bit(CACHE_NEGATIVE, &ip.h.flags);
320 : 0 : ip.h.expiry_time = expiry;
321 : 0 : ch = sunrpc_cache_update(cd, &ip.h, &ipm->h,
322 : 0 : hash_str(ipm->m_class, IP_HASHBITS) ^
323 : : hash_ip6(&ipm->m_addr));
324 [ # # ]: 0 : if (!ch)
325 : : return -ENOMEM;
326 : 0 : cache_put(ch, cd);
327 : 0 : return 0;
328 : : }
329 : :
330 : : static inline int ip_map_update(struct net *net, struct ip_map *ipm,
331 : : struct unix_domain *udom, time64_t expiry)
332 : : {
333 : : struct sunrpc_net *sn;
334 : :
335 : : sn = net_generic(net, sunrpc_net_id);
336 : : return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
337 : : }
338 : :
339 : 0 : void svcauth_unix_purge(struct net *net)
340 : : {
341 : 0 : struct sunrpc_net *sn;
342 : :
343 : 0 : sn = net_generic(net, sunrpc_net_id);
344 : 0 : cache_purge(sn->ip_map_cache);
345 : 0 : }
346 : : EXPORT_SYMBOL_GPL(svcauth_unix_purge);
347 : :
348 : : static inline struct ip_map *
349 : 0 : ip_map_cached_get(struct svc_xprt *xprt)
350 : : {
351 : 0 : struct ip_map *ipm = NULL;
352 : 0 : struct sunrpc_net *sn;
353 : :
354 [ # # ]: 0 : if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
355 : 0 : spin_lock(&xprt->xpt_lock);
356 : 0 : ipm = xprt->xpt_auth_cache;
357 [ # # ]: 0 : if (ipm != NULL) {
358 : 0 : sn = net_generic(xprt->xpt_net, sunrpc_net_id);
359 [ # # ]: 0 : if (cache_is_expired(sn->ip_map_cache, &ipm->h)) {
360 : : /*
361 : : * The entry has been invalidated since it was
362 : : * remembered, e.g. by a second mount from the
363 : : * same IP address.
364 : : */
365 : 0 : xprt->xpt_auth_cache = NULL;
366 : 0 : spin_unlock(&xprt->xpt_lock);
367 : 0 : cache_put(&ipm->h, sn->ip_map_cache);
368 : 0 : return NULL;
369 : : }
370 : 0 : cache_get(&ipm->h);
371 : : }
372 : 0 : spin_unlock(&xprt->xpt_lock);
373 : : }
374 : : return ipm;
375 : : }
376 : :
377 : : static inline void
378 : 0 : ip_map_cached_put(struct svc_xprt *xprt, struct ip_map *ipm)
379 : : {
380 [ # # ]: 0 : if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
381 : 0 : spin_lock(&xprt->xpt_lock);
382 [ # # ]: 0 : if (xprt->xpt_auth_cache == NULL) {
383 : : /* newly cached, keep the reference */
384 : 0 : xprt->xpt_auth_cache = ipm;
385 : 0 : ipm = NULL;
386 : : }
387 : 0 : spin_unlock(&xprt->xpt_lock);
388 : : }
389 [ # # ]: 0 : if (ipm) {
390 : 0 : struct sunrpc_net *sn;
391 : :
392 : 0 : sn = net_generic(xprt->xpt_net, sunrpc_net_id);
393 : 0 : cache_put(&ipm->h, sn->ip_map_cache);
394 : : }
395 : 0 : }
396 : :
397 : : void
398 : 0 : svcauth_unix_info_release(struct svc_xprt *xpt)
399 : : {
400 : 0 : struct ip_map *ipm;
401 : :
402 : 0 : ipm = xpt->xpt_auth_cache;
403 [ # # ]: 0 : if (ipm != NULL) {
404 : 0 : struct sunrpc_net *sn;
405 : :
406 : 0 : sn = net_generic(xpt->xpt_net, sunrpc_net_id);
407 : 0 : cache_put(&ipm->h, sn->ip_map_cache);
408 : : }
409 : 0 : }
410 : :
411 : : /****************************************************************************
412 : : * auth.unix.gid cache
413 : : * simple cache to map a UID to a list of GIDs
414 : : * because AUTH_UNIX aka AUTH_SYS has a max of UNX_NGROUPS
415 : : */
416 : : #define GID_HASHBITS 8
417 : : #define GID_HASHMAX (1<<GID_HASHBITS)
418 : :
419 : : struct unix_gid {
420 : : struct cache_head h;
421 : : kuid_t uid;
422 : : struct group_info *gi;
423 : : struct rcu_head rcu;
424 : : };
425 : :
426 : 0 : static int unix_gid_hash(kuid_t uid)
427 : : {
428 : 0 : return hash_long(from_kuid(&init_user_ns, uid), GID_HASHBITS);
429 : : }
430 : :
431 : 0 : static void unix_gid_put(struct kref *kref)
432 : : {
433 : 0 : struct cache_head *item = container_of(kref, struct cache_head, ref);
434 : 0 : struct unix_gid *ug = container_of(item, struct unix_gid, h);
435 [ # # # # ]: 0 : if (test_bit(CACHE_VALID, &item->flags) &&
436 : : !test_bit(CACHE_NEGATIVE, &item->flags))
437 [ # # ]: 0 : put_group_info(ug->gi);
438 [ # # ]: 0 : kfree_rcu(ug, rcu);
439 : 0 : }
440 : :
441 : 0 : static int unix_gid_match(struct cache_head *corig, struct cache_head *cnew)
442 : : {
443 : 0 : struct unix_gid *orig = container_of(corig, struct unix_gid, h);
444 : 0 : struct unix_gid *new = container_of(cnew, struct unix_gid, h);
445 : 0 : return uid_eq(orig->uid, new->uid);
446 : : }
447 : 0 : static void unix_gid_init(struct cache_head *cnew, struct cache_head *citem)
448 : : {
449 : 0 : struct unix_gid *new = container_of(cnew, struct unix_gid, h);
450 : 0 : struct unix_gid *item = container_of(citem, struct unix_gid, h);
451 : 0 : new->uid = item->uid;
452 : 0 : }
453 : 0 : static void unix_gid_update(struct cache_head *cnew, struct cache_head *citem)
454 : : {
455 : 0 : struct unix_gid *new = container_of(cnew, struct unix_gid, h);
456 : 0 : struct unix_gid *item = container_of(citem, struct unix_gid, h);
457 : :
458 : 0 : get_group_info(item->gi);
459 : 0 : new->gi = item->gi;
460 : 0 : }
461 : 0 : static struct cache_head *unix_gid_alloc(void)
462 : : {
463 : 0 : struct unix_gid *g = kmalloc(sizeof(*g), GFP_KERNEL);
464 [ # # ]: 0 : if (g)
465 : 0 : return &g->h;
466 : : else
467 : : return NULL;
468 : : }
469 : :
470 : 0 : static void unix_gid_request(struct cache_detail *cd,
471 : : struct cache_head *h,
472 : : char **bpp, int *blen)
473 : : {
474 : 0 : char tuid[20];
475 : 0 : struct unix_gid *ug = container_of(h, struct unix_gid, h);
476 : :
477 : 0 : snprintf(tuid, 20, "%u", from_kuid(&init_user_ns, ug->uid));
478 : 0 : qword_add(bpp, blen, tuid);
479 : 0 : (*bpp)[-1] = '\n';
480 : 0 : }
481 : :
482 : : static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t uid);
483 : :
484 : 0 : static int unix_gid_parse(struct cache_detail *cd,
485 : : char *mesg, int mlen)
486 : : {
487 : : /* uid expiry Ngid gid0 gid1 ... gidN-1 */
488 : 0 : int id;
489 : 0 : kuid_t uid;
490 : 0 : int gids;
491 : 0 : int rv;
492 : 0 : int i;
493 : 0 : int err;
494 : 0 : time64_t expiry;
495 : 0 : struct unix_gid ug, *ugp;
496 : :
497 [ # # ]: 0 : if (mesg[mlen - 1] != '\n')
498 : : return -EINVAL;
499 : 0 : mesg[mlen-1] = 0;
500 : :
501 : 0 : rv = get_int(&mesg, &id);
502 [ # # ]: 0 : if (rv)
503 : : return -EINVAL;
504 : 0 : uid = make_kuid(current_user_ns(), id);
505 : 0 : ug.uid = uid;
506 : :
507 : 0 : expiry = get_expiry(&mesg);
508 [ # # ]: 0 : if (expiry == 0)
509 : : return -EINVAL;
510 : :
511 : 0 : rv = get_int(&mesg, &gids);
512 [ # # # # : 0 : if (rv || gids < 0 || gids > 8192)
# # ]
513 : : return -EINVAL;
514 : :
515 : 0 : ug.gi = groups_alloc(gids);
516 [ # # ]: 0 : if (!ug.gi)
517 : : return -ENOMEM;
518 : :
519 [ # # ]: 0 : for (i = 0 ; i < gids ; i++) {
520 : 0 : int gid;
521 : 0 : kgid_t kgid;
522 : 0 : rv = get_int(&mesg, &gid);
523 : 0 : err = -EINVAL;
524 [ # # ]: 0 : if (rv)
525 : 0 : goto out;
526 [ # # ]: 0 : kgid = make_kgid(current_user_ns(), gid);
527 [ # # ]: 0 : if (!gid_valid(kgid))
528 : 0 : goto out;
529 : 0 : ug.gi->gid[i] = kgid;
530 : : }
531 : :
532 : 0 : groups_sort(ug.gi);
533 : 0 : ugp = unix_gid_lookup(cd, uid);
534 [ # # ]: 0 : if (ugp) {
535 : 0 : struct cache_head *ch;
536 : 0 : ug.h.flags = 0;
537 : 0 : ug.h.expiry_time = expiry;
538 : 0 : ch = sunrpc_cache_update(cd,
539 : : &ug.h, &ugp->h,
540 : : unix_gid_hash(uid));
541 [ # # ]: 0 : if (!ch)
542 : : err = -ENOMEM;
543 : : else {
544 : 0 : err = 0;
545 : 0 : cache_put(ch, cd);
546 : : }
547 : : } else
548 : : err = -ENOMEM;
549 : 0 : out:
550 [ # # ]: 0 : if (ug.gi)
551 [ # # ]: 0 : put_group_info(ug.gi);
552 : : return err;
553 : : }
554 : :
555 : 0 : static int unix_gid_show(struct seq_file *m,
556 : : struct cache_detail *cd,
557 : : struct cache_head *h)
558 : : {
559 : 0 : struct user_namespace *user_ns = m->file->f_cred->user_ns;
560 : 0 : struct unix_gid *ug;
561 : 0 : int i;
562 : 0 : int glen;
563 : :
564 [ # # ]: 0 : if (h == NULL) {
565 : 0 : seq_puts(m, "#uid cnt: gids...\n");
566 : 0 : return 0;
567 : : }
568 : 0 : ug = container_of(h, struct unix_gid, h);
569 [ # # # # ]: 0 : if (test_bit(CACHE_VALID, &h->flags) &&
570 : : !test_bit(CACHE_NEGATIVE, &h->flags))
571 : 0 : glen = ug->gi->ngroups;
572 : : else
573 : : glen = 0;
574 : :
575 [ # # ]: 0 : seq_printf(m, "%u %d:", from_kuid_munged(user_ns, ug->uid), glen);
576 [ # # ]: 0 : for (i = 0; i < glen; i++)
577 [ # # ]: 0 : seq_printf(m, " %d", from_kgid_munged(user_ns, ug->gi->gid[i]));
578 : 0 : seq_printf(m, "\n");
579 : 0 : return 0;
580 : : }
581 : :
582 : : static const struct cache_detail unix_gid_cache_template = {
583 : : .owner = THIS_MODULE,
584 : : .hash_size = GID_HASHMAX,
585 : : .name = "auth.unix.gid",
586 : : .cache_put = unix_gid_put,
587 : : .cache_request = unix_gid_request,
588 : : .cache_parse = unix_gid_parse,
589 : : .cache_show = unix_gid_show,
590 : : .match = unix_gid_match,
591 : : .init = unix_gid_init,
592 : : .update = unix_gid_update,
593 : : .alloc = unix_gid_alloc,
594 : : };
595 : :
596 : 3 : int unix_gid_cache_create(struct net *net)
597 : : {
598 : 3 : struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
599 : 3 : struct cache_detail *cd;
600 : 3 : int err;
601 : :
602 : 3 : cd = cache_create_net(&unix_gid_cache_template, net);
603 [ - + ]: 3 : if (IS_ERR(cd))
604 : 0 : return PTR_ERR(cd);
605 : 3 : err = cache_register_net(cd, net);
606 [ - + ]: 3 : if (err) {
607 : 0 : cache_destroy_net(cd, net);
608 : 0 : return err;
609 : : }
610 : 3 : sn->unix_gid_cache = cd;
611 : 3 : return 0;
612 : : }
613 : :
614 : 0 : void unix_gid_cache_destroy(struct net *net)
615 : : {
616 : 0 : struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
617 : 0 : struct cache_detail *cd = sn->unix_gid_cache;
618 : :
619 : 0 : sn->unix_gid_cache = NULL;
620 : 0 : cache_purge(cd);
621 : 0 : cache_unregister_net(cd, net);
622 : 0 : cache_destroy_net(cd, net);
623 : 0 : }
624 : :
625 : 0 : static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t uid)
626 : : {
627 : 0 : struct unix_gid ug;
628 : 0 : struct cache_head *ch;
629 : :
630 : 0 : ug.uid = uid;
631 : 0 : ch = sunrpc_cache_lookup_rcu(cd, &ug.h, unix_gid_hash(uid));
632 [ # # # # ]: 0 : if (ch)
633 : : return container_of(ch, struct unix_gid, h);
634 : : else
635 : 0 : return NULL;
636 : : }
637 : :
638 : 0 : static struct group_info *unix_gid_find(kuid_t uid, struct svc_rqst *rqstp)
639 : : {
640 : 0 : struct unix_gid *ug;
641 : 0 : struct group_info *gi;
642 : 0 : int ret;
643 : 0 : struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net,
644 : : sunrpc_net_id);
645 : :
646 : 0 : ug = unix_gid_lookup(sn->unix_gid_cache, uid);
647 : 0 : if (!ug)
648 : 0 : return ERR_PTR(-EAGAIN);
649 : 0 : ret = cache_check(sn->unix_gid_cache, &ug->h, &rqstp->rq_chandle);
650 [ # # # # ]: 0 : switch (ret) {
651 : : case -ENOENT:
652 : : return ERR_PTR(-ENOENT);
653 : : case -ETIMEDOUT:
654 : 0 : return ERR_PTR(-ESHUTDOWN);
655 : 0 : case 0:
656 : 0 : gi = get_group_info(ug->gi);
657 : 0 : cache_put(&ug->h, sn->unix_gid_cache);
658 : 0 : return gi;
659 : : default:
660 : 0 : return ERR_PTR(-EAGAIN);
661 : : }
662 : : }
663 : :
664 : : int
665 : 0 : svcauth_unix_set_client(struct svc_rqst *rqstp)
666 : : {
667 : 0 : struct sockaddr_in *sin;
668 : 0 : struct sockaddr_in6 *sin6, sin6_storage;
669 : 0 : struct ip_map *ipm;
670 : 0 : struct group_info *gi;
671 : 0 : struct svc_cred *cred = &rqstp->rq_cred;
672 : 0 : struct svc_xprt *xprt = rqstp->rq_xprt;
673 : 0 : struct net *net = xprt->xpt_net;
674 : 0 : struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
675 : :
676 [ # # # ]: 0 : switch (rqstp->rq_addr.ss_family) {
677 : : case AF_INET:
678 [ # # ]: 0 : sin = svc_addr_in(rqstp);
679 : 0 : sin6 = &sin6_storage;
680 [ # # ]: 0 : ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &sin6->sin6_addr);
681 : : break;
682 : : case AF_INET6:
683 : 0 : sin6 = svc_addr_in6(rqstp);
684 : 0 : break;
685 : 0 : default:
686 : 0 : BUG();
687 : : }
688 : :
689 : 0 : rqstp->rq_client = NULL;
690 [ # # ]: 0 : if (rqstp->rq_proc == 0)
691 : : return SVC_OK;
692 : :
693 : 0 : ipm = ip_map_cached_get(xprt);
694 [ # # ]: 0 : if (ipm == NULL)
695 : 0 : ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class,
696 : : &sin6->sin6_addr);
697 : :
698 [ # # ]: 0 : if (ipm == NULL)
699 : : return SVC_DENIED;
700 : :
701 [ # # # # : 0 : switch (cache_check(sn->ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
# ]
702 : 0 : default:
703 : 0 : BUG();
704 : : case -ETIMEDOUT:
705 : : return SVC_CLOSE;
706 : 0 : case -EAGAIN:
707 : 0 : return SVC_DROP;
708 : 0 : case -ENOENT:
709 : 0 : return SVC_DENIED;
710 : 0 : case 0:
711 : 0 : rqstp->rq_client = &ipm->m_client->h;
712 : 0 : kref_get(&rqstp->rq_client->ref);
713 : 0 : ip_map_cached_put(xprt, ipm);
714 : 0 : break;
715 : : }
716 : :
717 : 0 : gi = unix_gid_find(cred->cr_uid, rqstp);
718 [ # # # # ]: 0 : switch (PTR_ERR(gi)) {
719 : : case -EAGAIN:
720 : : return SVC_DROP;
721 : 0 : case -ESHUTDOWN:
722 : 0 : return SVC_CLOSE;
723 : : case -ENOENT:
724 : : break;
725 : 0 : default:
726 [ # # ]: 0 : put_group_info(cred->cr_group_info);
727 : 0 : cred->cr_group_info = gi;
728 : : }
729 : : return SVC_OK;
730 : : }
731 : :
732 : : EXPORT_SYMBOL_GPL(svcauth_unix_set_client);
733 : :
734 : : static int
735 : 0 : svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
736 : : {
737 : 0 : struct kvec *argv = &rqstp->rq_arg.head[0];
738 : 0 : struct kvec *resv = &rqstp->rq_res.head[0];
739 : 0 : struct svc_cred *cred = &rqstp->rq_cred;
740 : :
741 [ # # ]: 0 : if (argv->iov_len < 3*4)
742 : : return SVC_GARBAGE;
743 : :
744 [ # # ]: 0 : if (svc_getu32(argv) != 0) {
745 : 0 : dprintk("svc: bad null cred\n");
746 : 0 : *authp = rpc_autherr_badcred;
747 : 0 : return SVC_DENIED;
748 : : }
749 [ # # # # ]: 0 : if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
750 : 0 : dprintk("svc: bad null verf\n");
751 : 0 : *authp = rpc_autherr_badverf;
752 : 0 : return SVC_DENIED;
753 : : }
754 : :
755 : : /* Signal that mapping to nobody uid/gid is required */
756 : 0 : cred->cr_uid = INVALID_UID;
757 : 0 : cred->cr_gid = INVALID_GID;
758 : 0 : cred->cr_group_info = groups_alloc(0);
759 [ # # ]: 0 : if (cred->cr_group_info == NULL)
760 : : return SVC_CLOSE; /* kmalloc failure - client must retry */
761 : :
762 : : /* Put NULL verifier */
763 : 0 : svc_putnl(resv, RPC_AUTH_NULL);
764 : 0 : svc_putnl(resv, 0);
765 : :
766 : 0 : rqstp->rq_cred.cr_flavor = RPC_AUTH_NULL;
767 : 0 : return SVC_OK;
768 : : }
769 : :
770 : : static int
771 : 0 : svcauth_null_release(struct svc_rqst *rqstp)
772 : : {
773 [ # # ]: 0 : if (rqstp->rq_client)
774 : 0 : auth_domain_put(rqstp->rq_client);
775 : 0 : rqstp->rq_client = NULL;
776 [ # # ]: 0 : if (rqstp->rq_cred.cr_group_info)
777 [ # # ]: 0 : put_group_info(rqstp->rq_cred.cr_group_info);
778 : 0 : rqstp->rq_cred.cr_group_info = NULL;
779 : :
780 : 0 : return 0; /* don't drop */
781 : : }
782 : :
783 : :
784 : : struct auth_ops svcauth_null = {
785 : : .name = "null",
786 : : .owner = THIS_MODULE,
787 : : .flavour = RPC_AUTH_NULL,
788 : : .accept = svcauth_null_accept,
789 : : .release = svcauth_null_release,
790 : : .set_client = svcauth_unix_set_client,
791 : : };
792 : :
793 : :
794 : : static int
795 : 0 : svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
796 : : {
797 : 0 : struct kvec *argv = &rqstp->rq_arg.head[0];
798 : 0 : struct kvec *resv = &rqstp->rq_res.head[0];
799 : 0 : struct svc_cred *cred = &rqstp->rq_cred;
800 : 0 : struct user_namespace *userns;
801 : 0 : u32 slen, i;
802 : 0 : int len = argv->iov_len;
803 : :
804 [ # # ]: 0 : if ((len -= 3*4) < 0)
805 : : return SVC_GARBAGE;
806 : :
807 [ # # ]: 0 : svc_getu32(argv); /* length */
808 : 0 : svc_getu32(argv); /* time stamp */
809 [ # # ]: 0 : slen = XDR_QUADLEN(svc_getnl(argv)); /* machname length */
810 [ # # # # ]: 0 : if (slen > 64 || (len -= (slen + 3)*4) < 0)
811 : 0 : goto badcred;
812 : 0 : argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */
813 : 0 : argv->iov_len -= slen*4;
814 : : /*
815 : : * Note: we skip uid_valid()/gid_valid() checks here for
816 : : * backwards compatibility with clients that use -1 id's.
817 : : * Instead, -1 uid or gid is later mapped to the
818 : : * (export-specific) anonymous id by nfsd_setuser.
819 : : * Supplementary gid's will be left alone.
820 : : */
821 : 0 : userns = (rqstp->rq_xprt && rqstp->rq_xprt->xpt_cred) ?
822 : : rqstp->rq_xprt->xpt_cred->user_ns : &init_user_ns;
823 [ # # ]: 0 : cred->cr_uid = make_kuid(userns, svc_getnl(argv)); /* uid */
824 [ # # ]: 0 : cred->cr_gid = make_kgid(userns, svc_getnl(argv)); /* gid */
825 : 0 : slen = svc_getnl(argv); /* gids length */
826 [ # # # # ]: 0 : if (slen > UNX_NGROUPS || (len -= (slen + 2)*4) < 0)
827 : 0 : goto badcred;
828 : 0 : cred->cr_group_info = groups_alloc(slen);
829 [ # # ]: 0 : if (cred->cr_group_info == NULL)
830 : : return SVC_CLOSE;
831 [ # # ]: 0 : for (i = 0; i < slen; i++) {
832 : 0 : kgid_t kgid = make_kgid(userns, svc_getnl(argv));
833 : 0 : cred->cr_group_info->gid[i] = kgid;
834 : : }
835 : 0 : groups_sort(cred->cr_group_info);
836 [ # # # # ]: 0 : if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
837 : 0 : *authp = rpc_autherr_badverf;
838 : 0 : return SVC_DENIED;
839 : : }
840 : :
841 : : /* Put NULL verifier */
842 : 0 : svc_putnl(resv, RPC_AUTH_NULL);
843 : 0 : svc_putnl(resv, 0);
844 : :
845 : 0 : rqstp->rq_cred.cr_flavor = RPC_AUTH_UNIX;
846 : 0 : return SVC_OK;
847 : :
848 : 0 : badcred:
849 : 0 : *authp = rpc_autherr_badcred;
850 : 0 : return SVC_DENIED;
851 : : }
852 : :
853 : : static int
854 : 0 : svcauth_unix_release(struct svc_rqst *rqstp)
855 : : {
856 : : /* Verifier (such as it is) is already in place.
857 : : */
858 [ # # ]: 0 : if (rqstp->rq_client)
859 : 0 : auth_domain_put(rqstp->rq_client);
860 : 0 : rqstp->rq_client = NULL;
861 [ # # ]: 0 : if (rqstp->rq_cred.cr_group_info)
862 [ # # ]: 0 : put_group_info(rqstp->rq_cred.cr_group_info);
863 : 0 : rqstp->rq_cred.cr_group_info = NULL;
864 : :
865 : 0 : return 0;
866 : : }
867 : :
868 : :
869 : : struct auth_ops svcauth_unix = {
870 : : .name = "unix",
871 : : .owner = THIS_MODULE,
872 : : .flavour = RPC_AUTH_UNIX,
873 : : .accept = svcauth_unix_accept,
874 : : .release = svcauth_unix_release,
875 : : .domain_release = svcauth_unix_domain_release,
876 : : .set_client = svcauth_unix_set_client,
877 : : };
878 : :
879 : : static const struct cache_detail ip_map_cache_template = {
880 : : .owner = THIS_MODULE,
881 : : .hash_size = IP_HASHMAX,
882 : : .name = "auth.unix.ip",
883 : : .cache_put = ip_map_put,
884 : : .cache_request = ip_map_request,
885 : : .cache_parse = ip_map_parse,
886 : : .cache_show = ip_map_show,
887 : : .match = ip_map_match,
888 : : .init = ip_map_init,
889 : : .update = update,
890 : : .alloc = ip_map_alloc,
891 : : };
892 : :
893 : 3 : int ip_map_cache_create(struct net *net)
894 : : {
895 : 3 : struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
896 : 3 : struct cache_detail *cd;
897 : 3 : int err;
898 : :
899 : 3 : cd = cache_create_net(&ip_map_cache_template, net);
900 [ - + ]: 3 : if (IS_ERR(cd))
901 : 0 : return PTR_ERR(cd);
902 : 3 : err = cache_register_net(cd, net);
903 [ - + ]: 3 : if (err) {
904 : 0 : cache_destroy_net(cd, net);
905 : 0 : return err;
906 : : }
907 : 3 : sn->ip_map_cache = cd;
908 : 3 : return 0;
909 : : }
910 : :
911 : 0 : void ip_map_cache_destroy(struct net *net)
912 : : {
913 : 0 : struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
914 : 0 : struct cache_detail *cd = sn->ip_map_cache;
915 : :
916 : 0 : sn->ip_map_cache = NULL;
917 : 0 : cache_purge(cd);
918 : 0 : cache_unregister_net(cd, net);
919 : 0 : cache_destroy_net(cd, net);
920 : 0 : }
|