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 = rqstp->rq_sock->sk_info_authunix; 387 if (ipm != NULL) { 388 if (!cache_valid(&ipm->h)) { 389 /* 390 * The entry has been invalidated since it was 391 * remembered, e.g. by a second mount from the 392 * same IP address. 393 */ 394 rqstp->rq_sock->sk_info_authunix = NULL; 395 cache_put(&ipm->h, &ip_map_cache); 396 return NULL; 397 } 398 cache_get(&ipm->h); 399 } 400 return ipm; 401 } 402 403 static inline void 404 ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm) 405 { 406 struct svc_sock *svsk = rqstp->rq_sock; 407 408 if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL) 409 svsk->sk_info_authunix = ipm; /* newly cached, keep the reference */ 410 else 411 cache_put(&ipm->h, &ip_map_cache); 412 } 413 414 void 415 svcauth_unix_info_release(void *info) 416 { 417 struct ip_map *ipm = info; 418 cache_put(&ipm->h, &ip_map_cache); 419 } 420 421 /**************************************************************************** 422 * auth.unix.gid cache 423 * simple cache to map a UID to a list of GIDs 424 * because AUTH_UNIX aka AUTH_SYS has a max of 16 425 */ 426 #define GID_HASHBITS 8 427 #define GID_HASHMAX (1<<GID_HASHBITS) 428 #define GID_HASHMASK (GID_HASHMAX - 1) 429 430 struct unix_gid { 431 struct cache_head h; 432 uid_t uid; 433 struct group_info *gi; 434 }; 435 static struct cache_head *gid_table[GID_HASHMAX]; 436 437 static void unix_gid_put(struct kref *kref) 438 { 439 struct cache_head *item = container_of(kref, struct cache_head, ref); 440 struct unix_gid *ug = container_of(item, struct unix_gid, h); 441 if (test_bit(CACHE_VALID, &item->flags) && 442 !test_bit(CACHE_NEGATIVE, &item->flags)) 443 put_group_info(ug->gi); 444 kfree(ug); 445 } 446 447 static int unix_gid_match(struct cache_head *corig, struct cache_head *cnew) 448 { 449 struct unix_gid *orig = container_of(corig, struct unix_gid, h); 450 struct unix_gid *new = container_of(cnew, struct unix_gid, h); 451 return orig->uid == new->uid; 452 } 453 static void unix_gid_init(struct cache_head *cnew, struct cache_head *citem) 454 { 455 struct unix_gid *new = container_of(cnew, struct unix_gid, h); 456 struct unix_gid *item = container_of(citem, struct unix_gid, h); 457 new->uid = item->uid; 458 } 459 static void unix_gid_update(struct cache_head *cnew, struct cache_head *citem) 460 { 461 struct unix_gid *new = container_of(cnew, struct unix_gid, h); 462 struct unix_gid *item = container_of(citem, struct unix_gid, h); 463 464 get_group_info(item->gi); 465 new->gi = item->gi; 466 } 467 static struct cache_head *unix_gid_alloc(void) 468 { 469 struct unix_gid *g = kmalloc(sizeof(*g), GFP_KERNEL); 470 if (g) 471 return &g->h; 472 else 473 return NULL; 474 } 475 476 static void unix_gid_request(struct cache_detail *cd, 477 struct cache_head *h, 478 char **bpp, int *blen) 479 { 480 char tuid[20]; 481 struct unix_gid *ug = container_of(h, struct unix_gid, h); 482 483 snprintf(tuid, 20, "%u", ug->uid); 484 qword_add(bpp, blen, tuid); 485 (*bpp)[-1] = '\n'; 486 } 487 488 static struct unix_gid *unix_gid_lookup(uid_t uid); 489 extern struct cache_detail unix_gid_cache; 490 491 static int unix_gid_parse(struct cache_detail *cd, 492 char *mesg, int mlen) 493 { 494 /* uid expiry Ngid gid0 gid1 ... gidN-1 */ 495 int uid; 496 int gids; 497 int rv; 498 int i; 499 int err; 500 time_t expiry; 501 struct unix_gid ug, *ugp; 502 503 if (mlen <= 0 || mesg[mlen-1] != '\n') 504 return -EINVAL; 505 mesg[mlen-1] = 0; 506 507 rv = get_int(&mesg, &uid); 508 if (rv) 509 return -EINVAL; 510 ug.uid = uid; 511 512 expiry = get_expiry(&mesg); 513 if (expiry == 0) 514 return -EINVAL; 515 516 rv = get_int(&mesg, &gids); 517 if (rv || gids < 0 || gids > 8192) 518 return -EINVAL; 519 520 ug.gi = groups_alloc(gids); 521 if (!ug.gi) 522 return -ENOMEM; 523 524 for (i = 0 ; i < gids ; i++) { 525 int gid; 526 rv = get_int(&mesg, &gid); 527 err = -EINVAL; 528 if (rv) 529 goto out; 530 GROUP_AT(ug.gi, i) = gid; 531 } 532 533 ugp = unix_gid_lookup(uid); 534 if (ugp) { 535 struct cache_head *ch; 536 ug.h.flags = 0; 537 ug.h.expiry_time = expiry; 538 ch = sunrpc_cache_update(&unix_gid_cache, 539 &ug.h, &ugp->h, 540 hash_long(uid, GID_HASHBITS)); 541 if (!ch) 542 err = -ENOMEM; 543 else { 544 err = 0; 545 cache_put(ch, &unix_gid_cache); 546 } 547 } else 548 err = -ENOMEM; 549 out: 550 if (ug.gi) 551 put_group_info(ug.gi); 552 return err; 553 } 554 555 static int unix_gid_show(struct seq_file *m, 556 struct cache_detail *cd, 557 struct cache_head *h) 558 { 559 struct unix_gid *ug; 560 int i; 561 int glen; 562 563 if (h == NULL) { 564 seq_puts(m, "#uid cnt: gids...\n"); 565 return 0; 566 } 567 ug = container_of(h, struct unix_gid, h); 568 if (test_bit(CACHE_VALID, &h->flags) && 569 !test_bit(CACHE_NEGATIVE, &h->flags)) 570 glen = ug->gi->ngroups; 571 else 572 glen = 0; 573 574 seq_printf(m, "%d %d:", ug->uid, glen); 575 for (i = 0; i < glen; i++) 576 seq_printf(m, " %d", GROUP_AT(ug->gi, i)); 577 seq_printf(m, "\n"); 578 return 0; 579 } 580 581 struct cache_detail unix_gid_cache = { 582 .owner = THIS_MODULE, 583 .hash_size = GID_HASHMAX, 584 .hash_table = gid_table, 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 static struct unix_gid *unix_gid_lookup(uid_t uid) 597 { 598 struct unix_gid ug; 599 struct cache_head *ch; 600 601 ug.uid = uid; 602 ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h, 603 hash_long(uid, GID_HASHBITS)); 604 if (ch) 605 return container_of(ch, struct unix_gid, h); 606 else 607 return NULL; 608 } 609 610 static int unix_gid_find(uid_t uid, struct group_info **gip, 611 struct svc_rqst *rqstp) 612 { 613 struct unix_gid *ug = unix_gid_lookup(uid); 614 if (!ug) 615 return -EAGAIN; 616 switch (cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle)) { 617 case -ENOENT: 618 *gip = NULL; 619 return 0; 620 case 0: 621 *gip = ug->gi; 622 get_group_info(*gip); 623 return 0; 624 default: 625 return -EAGAIN; 626 } 627 } 628 629 static int 630 svcauth_unix_set_client(struct svc_rqst *rqstp) 631 { 632 struct sockaddr_in *sin = svc_addr_in(rqstp); 633 struct ip_map *ipm; 634 635 rqstp->rq_client = NULL; 636 if (rqstp->rq_proc == 0) 637 return SVC_OK; 638 639 ipm = ip_map_cached_get(rqstp); 640 if (ipm == NULL) 641 ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, 642 sin->sin_addr); 643 644 if (ipm == NULL) 645 return SVC_DENIED; 646 647 switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) { 648 default: 649 BUG(); 650 case -EAGAIN: 651 case -ETIMEDOUT: 652 return SVC_DROP; 653 case -ENOENT: 654 return SVC_DENIED; 655 case 0: 656 rqstp->rq_client = &ipm->m_client->h; 657 kref_get(&rqstp->rq_client->ref); 658 ip_map_cached_put(rqstp, ipm); 659 break; 660 } 661 return SVC_OK; 662 } 663 664 static int 665 svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) 666 { 667 struct kvec *argv = &rqstp->rq_arg.head[0]; 668 struct kvec *resv = &rqstp->rq_res.head[0]; 669 struct svc_cred *cred = &rqstp->rq_cred; 670 671 cred->cr_group_info = NULL; 672 rqstp->rq_client = NULL; 673 674 if (argv->iov_len < 3*4) 675 return SVC_GARBAGE; 676 677 if (svc_getu32(argv) != 0) { 678 dprintk("svc: bad null cred\n"); 679 *authp = rpc_autherr_badcred; 680 return SVC_DENIED; 681 } 682 if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { 683 dprintk("svc: bad null verf\n"); 684 *authp = rpc_autherr_badverf; 685 return SVC_DENIED; 686 } 687 688 /* Signal that mapping to nobody uid/gid is required */ 689 cred->cr_uid = (uid_t) -1; 690 cred->cr_gid = (gid_t) -1; 691 cred->cr_group_info = groups_alloc(0); 692 if (cred->cr_group_info == NULL) 693 return SVC_DROP; /* kmalloc failure - client must retry */ 694 695 /* Put NULL verifier */ 696 svc_putnl(resv, RPC_AUTH_NULL); 697 svc_putnl(resv, 0); 698 699 return SVC_OK; 700 } 701 702 static int 703 svcauth_null_release(struct svc_rqst *rqstp) 704 { 705 if (rqstp->rq_client) 706 auth_domain_put(rqstp->rq_client); 707 rqstp->rq_client = NULL; 708 if (rqstp->rq_cred.cr_group_info) 709 put_group_info(rqstp->rq_cred.cr_group_info); 710 rqstp->rq_cred.cr_group_info = NULL; 711 712 return 0; /* don't drop */ 713 } 714 715 716 struct auth_ops svcauth_null = { 717 .name = "null", 718 .owner = THIS_MODULE, 719 .flavour = RPC_AUTH_NULL, 720 .accept = svcauth_null_accept, 721 .release = svcauth_null_release, 722 .set_client = svcauth_unix_set_client, 723 }; 724 725 726 static int 727 svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) 728 { 729 struct kvec *argv = &rqstp->rq_arg.head[0]; 730 struct kvec *resv = &rqstp->rq_res.head[0]; 731 struct svc_cred *cred = &rqstp->rq_cred; 732 u32 slen, i; 733 int len = argv->iov_len; 734 735 cred->cr_group_info = NULL; 736 rqstp->rq_client = NULL; 737 738 if ((len -= 3*4) < 0) 739 return SVC_GARBAGE; 740 741 svc_getu32(argv); /* length */ 742 svc_getu32(argv); /* time stamp */ 743 slen = XDR_QUADLEN(svc_getnl(argv)); /* machname length */ 744 if (slen > 64 || (len -= (slen + 3)*4) < 0) 745 goto badcred; 746 argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */ 747 argv->iov_len -= slen*4; 748 749 cred->cr_uid = svc_getnl(argv); /* uid */ 750 cred->cr_gid = svc_getnl(argv); /* gid */ 751 slen = svc_getnl(argv); /* gids length */ 752 if (slen > 16 || (len -= (slen + 2)*4) < 0) 753 goto badcred; 754 if (unix_gid_find(cred->cr_uid, &cred->cr_group_info, rqstp) 755 == -EAGAIN) 756 return SVC_DROP; 757 if (cred->cr_group_info == NULL) { 758 cred->cr_group_info = groups_alloc(slen); 759 if (cred->cr_group_info == NULL) 760 return SVC_DROP; 761 for (i = 0; i < slen; i++) 762 GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); 763 } else { 764 for (i = 0; i < slen ; i++) 765 svc_getnl(argv); 766 } 767 if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { 768 *authp = rpc_autherr_badverf; 769 return SVC_DENIED; 770 } 771 772 /* Put NULL verifier */ 773 svc_putnl(resv, RPC_AUTH_NULL); 774 svc_putnl(resv, 0); 775 776 return SVC_OK; 777 778 badcred: 779 *authp = rpc_autherr_badcred; 780 return SVC_DENIED; 781 } 782 783 static int 784 svcauth_unix_release(struct svc_rqst *rqstp) 785 { 786 /* Verifier (such as it is) is already in place. 787 */ 788 if (rqstp->rq_client) 789 auth_domain_put(rqstp->rq_client); 790 rqstp->rq_client = NULL; 791 if (rqstp->rq_cred.cr_group_info) 792 put_group_info(rqstp->rq_cred.cr_group_info); 793 rqstp->rq_cred.cr_group_info = NULL; 794 795 return 0; 796 } 797 798 799 struct auth_ops svcauth_unix = { 800 .name = "unix", 801 .owner = THIS_MODULE, 802 .flavour = RPC_AUTH_UNIX, 803 .accept = svcauth_unix_accept, 804 .release = svcauth_unix_release, 805 .domain_release = svcauth_unix_domain_release, 806 .set_client = svcauth_unix_set_client, 807 }; 808 809