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