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