1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * nis/getnetgrent.c -- "nis" backend for nsswitch "netgroup" database 28 * 29 * The API for netgroups differs sufficiently from that for the average 30 * getXXXbyYYY function that we use very few of the support routines in 31 * nis_common.h. 32 * 33 * The implementation of setnetgrent()/getnetgrent() here follows the 34 * the 4.x code, inasmuch as the setnetgrent() routine does all the work 35 * of traversing the netgroup graph and building a (potentially large) 36 * list in memory, and getnetgrent() just steps down the list. 37 * 38 * An alternative, and probably better, implementation would lazy-eval 39 * the netgroup graph in response to getnetgrent() calls (though 40 * setnetgrent() should still check for the top-level netgroup name 41 * and return NSS_SUCCESS / NSS_NOTFOUND). 42 */ 43 44 #pragma ident "%Z%%M% %I% %E% SMI" 45 46 #include "nis_common.h" 47 #include <ctype.h> 48 #include <rpcsvc/ypclnt.h> 49 #include <malloc.h> 50 #include <string.h> 51 #ifdef DEBUG 52 #include <sys/syslog.h> 53 #endif /* DEBUG */ 54 55 /* 56 * The nss_backend_t for a getnetgrent() sequence; we actually give the 57 * netgroup frontend a pointer to one of these structures in response to 58 * a (successful) setnetgrent() call on the nis_netgr_be backend 59 * described further down in this file. 60 */ 61 62 struct nis_getnetgr_be; 63 typedef nss_status_t (*nis_getnetgr_op_t)(struct nis_getnetgr_be *, void *); 64 65 struct nis_getnetgr_be { 66 nis_getnetgr_op_t *ops; 67 nss_dbop_t n_ops; 68 /* 69 * State for set/get/endnetgrent() 70 */ 71 char *netgroup; 72 struct grouplist *all_members; 73 struct grouplist *next_member; 74 }; 75 76 struct grouplist { /* One element of the list generated by a setnetgrent() */ 77 char *triple[NSS_NETGR_N]; 78 struct grouplist *gl_nxt; 79 }; 80 81 static nss_status_t 82 getnetgr_set(be, a) 83 struct nis_getnetgr_be *be; 84 void *a; 85 { 86 const char *netgroup = (const char *) a; 87 88 if (be->netgroup != 0 && 89 strcmp(be->netgroup, netgroup) == 0) { 90 /* We already have the member-list; regurgitate it */ 91 be->next_member = be->all_members; 92 return (NSS_SUCCESS); 93 } 94 return (NSS_NOTFOUND); 95 } 96 97 static nss_status_t 98 getnetgr_get(be, a) 99 struct nis_getnetgr_be *be; 100 void *a; 101 { 102 struct nss_getnetgrent_args *args = (struct nss_getnetgrent_args *)a; 103 struct grouplist *mem; 104 105 if ((mem = be->next_member) == 0) { 106 args->status = NSS_NETGR_NO; 107 } else { 108 char *buffer = args->buffer; 109 int buflen = args->buflen; 110 enum nss_netgr_argn i; 111 112 args->status = NSS_NETGR_FOUND; 113 114 for (i = 0; i < NSS_NETGR_N; i++) { 115 const char *str; 116 ssize_t len; 117 118 if ((str = mem->triple[i]) == 0) { 119 args->retp[i] = 0; 120 } else if ((len = strlen(str) + 1) <= buflen) { 121 args->retp[i] = buffer; 122 (void) memcpy(buffer, str, len); 123 buffer += len; 124 buflen -= len; 125 } else { 126 args->status = NSS_NETGR_NOMEM; 127 break; 128 } 129 } 130 be->next_member = mem->gl_nxt; 131 } 132 return (NSS_SUCCESS); /* Yup, even for end-of-list, i.e. */ 133 /* do NOT advance to next backend. */ 134 } 135 136 /*ARGSUSED*/ 137 static nss_status_t 138 getnetgr_end(be, dummy) 139 struct nis_getnetgr_be *be; 140 void *dummy; 141 { 142 struct grouplist *gl; 143 struct grouplist *next; 144 145 for (gl = be->all_members; gl != NULL; gl = next) { 146 enum nss_netgr_argn i; 147 148 next = gl->gl_nxt; 149 for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) { 150 if (gl->triple[i] != 0) { 151 free(gl->triple[i]); 152 } 153 } 154 free(gl); 155 } 156 be->all_members = 0; 157 be->next_member = 0; 158 if (be->netgroup != 0) { 159 free(be->netgroup); 160 be->netgroup = 0; 161 } 162 return (NSS_SUCCESS); 163 } 164 165 /*ARGSUSED*/ 166 static nss_status_t 167 getnetgr_destr(be, dummy) 168 struct nis_getnetgr_be *be; 169 void *dummy; 170 { 171 if (be != 0) { 172 (void) getnetgr_end(be, (void *)0); 173 free(be); 174 } 175 return (NSS_SUCCESS); 176 } 177 178 static nis_getnetgr_op_t getnetgr_ops[] = { 179 getnetgr_destr, 180 getnetgr_end, 181 getnetgr_set, 182 getnetgr_get, /* getnetgrent_r() */ 183 }; 184 185 186 /* 187 * The nss_backend_t for innetgr() and setnetgrent(). 188 */ 189 190 struct nis_netgr_be; 191 typedef nss_status_t (*nis_netgr_op_t)(struct nis_netgr_be *, void *); 192 193 struct nis_netgr_be { 194 nis_netgr_op_t *ops; 195 nss_dbop_t n_ops; 196 const char *domain; /* (default) YP domain */ 197 }; 198 199 200 /* 201 * Code to do top-down search in the graph defined by the 'netgroup' YP map 202 */ 203 204 /* 205 * ===> This code is now used for setnetgrent(), not just innetgr(). 206 * 207 * If the easy way doesn't pan out, recursively search the 'netgroup' map. 208 * In order to do this, we: 209 * 210 * - remember all the netgroup names we've seen during this search, 211 * whether or not we've expanded them yet (we want fast insertion 212 * with duplicate-detection, so use yet another chained hash table), 213 * 214 * - keep a list of all the netgroups we haven't expanded yet (we just 215 * want fast insertion and pop-first, so a linked list will do fine). 216 * If we insert at the head, we get a depth-first search; insertion 217 * at the tail gives breadth-first (?), which seems preferable (?). 218 * 219 * A netgrnam struct contains pointers for both the hash-table and the list. 220 * It also contains the netgroup name; note that we embed the name at the 221 * end of the structure rather than holding a pointer to yet another 222 * malloc()ed region. 223 * 224 * A netgrtab structure contains the hash-chain heads and the head/tail 225 * pointers for the expansion list. 226 * 227 * Most of this code is common to at least the NIS and NIS+ backends; it 228 * should be generalized and, presumably, moved into the frontend. 229 * ==> Not any longer... 230 */ 231 232 struct netgrnam { 233 struct netgrnam *hash_chain; 234 struct netgrnam *expand_next; 235 char name[1]; /* Really [strlen(name) + 1] */ 236 }; 237 238 #define HASHMOD 113 239 240 struct netgrtab { 241 struct netgrnam *expand_first; 242 struct netgrnam **expand_lastp; 243 struct netgrnam *hash_heads[HASHMOD]; 244 }; 245 246 static void 247 ngt_init(ngt) 248 struct netgrtab *ngt; 249 { 250 (void) memset((void *)ngt, 0, sizeof (*ngt)); 251 ngt->expand_lastp = &ngt->expand_first; 252 } 253 254 /* === ? Change ngt_init() and ngt_destroy() to malloc/free struct netgrtab */ 255 256 static void 257 /* ==> ? Should return 'failed' (out-of-memory) status ? */ 258 ngt_insert(ngt, name, namelen) 259 struct netgrtab *ngt; 260 const char *name; 261 size_t namelen; 262 { 263 unsigned hashval; 264 size_t i; 265 struct netgrnam *cur; 266 struct netgrnam **head; 267 268 #define dummy ((struct netgrnam *)0) 269 270 for (hashval = 0, i = 0; i < namelen; i++) { 271 hashval = (hashval << 2) + hashval + 272 ((const unsigned char *)name)[i]; 273 } 274 head = &ngt->hash_heads[hashval % HASHMOD]; 275 for (cur = *head; cur != 0; cur = cur->hash_chain) { 276 if (strncmp(cur->name, name, namelen) == 0 && 277 cur->name[namelen] == 0) { 278 return; /* Already in table, do nothing */ 279 } 280 } 281 /* Create new netgrnam struct */ 282 cur = (struct netgrnam *) 283 malloc(namelen + 1 + (char *)&dummy->name[0] - (char *)dummy); 284 if (cur == 0) { 285 return; /* Out of memory, too bad */ 286 } 287 (void) memcpy(cur->name, name, namelen); 288 cur->name[namelen] = 0; 289 290 /* Insert in hash table */ 291 cur->hash_chain = *head; 292 *head = cur; 293 294 /* Insert in expansion list (insert at end for breadth-first search */ 295 cur->expand_next = 0; 296 *ngt->expand_lastp = cur; 297 ngt->expand_lastp = &cur->expand_next; 298 299 #undef dummy 300 } 301 302 static const char * 303 ngt_next(ngt) 304 struct netgrtab *ngt; 305 { 306 struct netgrnam *first; 307 308 if ((first = ngt->expand_first) == 0) { 309 return (0); 310 } 311 if ((ngt->expand_first = first->expand_next) == 0) { 312 ngt->expand_lastp = &ngt->expand_first; 313 } 314 return (first->name); 315 } 316 317 static void 318 ngt_destroy(ngt) 319 struct netgrtab *ngt; 320 { 321 struct netgrnam *cur; 322 struct netgrnam *next; 323 int i; 324 325 for (i = 0; i < HASHMOD; i++) { 326 for (cur = ngt->hash_heads[i]; cur != 0; /* cstyle */) { 327 next = cur->hash_chain; 328 free(cur); 329 cur = next; 330 } 331 } 332 /* Don't bother zeroing pointers; must do init if we want to reuse */ 333 } 334 335 typedef const char *ccp; 336 337 static nss_status_t 338 top_down(struct nis_netgr_be *be, const char **groups, int ngroups, 339 int (*func)(ccp triple[3], void *iter_args, nss_status_t *return_val), 340 void *iter_args) 341 { 342 struct netgrtab *ngt; 343 /* netgrtab goes on the heap, not the stack, because it's large and */ 344 /* stacks may not be all that big in multi-threaded programs. */ 345 346 const char *group; 347 int nfound; 348 int done; 349 nss_status_t result; 350 351 if ((ngt = (struct netgrtab *)malloc(sizeof (*ngt))) == 0) { 352 return (NSS_UNAVAIL); 353 } 354 ngt_init(ngt); 355 356 while (ngroups > 0) { 357 ngt_insert(ngt, *groups, strlen(*groups)); 358 groups++; 359 ngroups--; 360 } 361 362 done = 0; /* Set to 1 to indicate that we cut the iteration */ 363 /* short (and 'result' holds the return value) */ 364 nfound = 0; /* Number of successful netgroup yp_match calls */ 365 366 while (!done && (group = ngt_next(ngt)) != 0) { 367 char *val; 368 int vallen; 369 char *p; 370 int yperr; 371 372 result = _nss_nis_ypmatch(be->domain, "netgroup", group, 373 &val, &vallen, &yperr); 374 if (result != NSS_SUCCESS) { 375 /*LINTED E_NOP_IF_STMT*/ 376 if (result == NSS_NOTFOUND) { 377 ; 378 #ifdef DEBUG 379 syslog(LOG_WARNING, 380 "NIS netgroup lookup: %s doesn't exist", 381 group); 382 #endif /* DEBUG */ 383 } else { 384 #ifdef DEBUG 385 syslog(LOG_WARNING, 386 "NIS netgroup lookup: yp_match returned [%s]", 387 yperr_string(yperr)); 388 #endif /* DEBUG */ 389 done = 1; /* Give up, return result */ 390 } 391 /* Don't need to clean up anything */ 392 continue; 393 } 394 395 nfound++; 396 397 if ((p = strpbrk(val, "#\n")) != 0) { 398 *p = '\0'; 399 } 400 p = val; 401 402 /* Parse val into triples and recursive netgroup references */ 403 /*CONSTCOND*/ 404 while (1) { 405 ccp triple[NSS_NETGR_N]; 406 int syntax_err; 407 enum nss_netgr_argn i; 408 409 while (isspace(*p)) { 410 p++; 411 } 412 if (*p == '\0') { 413 /* Finished processing this particular val */ 414 break; 415 } 416 if (*p != '(') { 417 /* Doesn't look like the start of a triple, */ 418 /* so assume it's a recursive netgroup. */ 419 char *start = p; 420 p = strpbrk(start, " \t"); 421 if (p == 0) { 422 /* Point p at the final '\0' */ 423 p = start + strlen(start); 424 } 425 ngt_insert(ngt, start, (size_t)(p - start)); 426 continue; 427 } 428 429 /* Main case: a (machine, user, domain) triple */ 430 p++; 431 syntax_err = 0; 432 for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) { 433 char *start; 434 char *limit; 435 const char *terminators = ",) \t"; 436 437 if (i == NSS_NETGR_DOMAIN) { 438 /* Don't allow comma */ 439 terminators++; 440 } 441 while (isspace(*p)) { 442 p++; 443 } 444 start = p; 445 limit = strpbrk(start, terminators); 446 if (limit == 0) { 447 syntax_err++; 448 break; 449 } 450 p = limit; 451 while (isspace(*p)) { 452 p++; 453 } 454 if (*p == terminators[0]) { 455 /* 456 * Successfully parsed this name and 457 * the separator after it (comma or 458 * right paren); leave p ready for 459 * next parse. 460 */ 461 p++; 462 if (start == limit) { 463 /* Wildcard */ 464 triple[i] = 0; 465 } else { 466 *limit = '\0'; 467 triple[i] = start; 468 } 469 } else { 470 syntax_err++; 471 break; 472 } 473 } 474 475 if (syntax_err) { 476 /* 477 * ===> log it; 478 * ===> try skipping past next ')'; failing that, abandon the line; 479 */ 480 break; /* Abandon this line */ 481 } else if (!(*func)(triple, iter_args, &result)) { 482 /* Return result, good or bad */ 483 done = 1; 484 break; 485 } 486 } 487 /* End of inner loop over val[] */ 488 free(val); 489 } 490 /* End of outer loop (!done && ngt_next(ngt) != 0) */ 491 492 ngt_destroy(ngt); 493 free(ngt); 494 495 if (done) { 496 return (result); 497 } else if (nfound > 0) { 498 /* ==== ? Should only do this if all the top-level groups */ 499 /* exist in YP? */ 500 return (NSS_SUCCESS); 501 } else { 502 return (NSS_NOTFOUND); 503 } 504 } 505 506 507 /* 508 * Code for setnetgrent() 509 */ 510 511 /* 512 * Iterator function for setnetgrent(): copy triple, add to be->all_members 513 */ 514 static int 515 save_triple(ccp trippp[NSS_NETGR_N], void *headp_arg, 516 nss_status_t *return_val) 517 { 518 struct grouplist **headp = headp_arg; 519 struct grouplist *gl; 520 enum nss_netgr_argn i; 521 522 if ((gl = (struct grouplist *)malloc(sizeof (*gl))) == 0) { 523 /* Out of memory */ 524 *return_val = NSS_UNAVAIL; 525 return (0); 526 } 527 for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) { 528 if (trippp[i] == 0) { 529 /* Wildcard */ 530 gl->triple[i] = 0; 531 } else if ((gl->triple[i] = strdup(trippp[i])) == 0) { 532 /* Out of memory. Free any we've allocated */ 533 enum nss_netgr_argn j; 534 535 for (j = NSS_NETGR_MACHINE; j < i; j++) { 536 if (gl->triple[j] != 0) { 537 free(gl->triple[j]); 538 } 539 } 540 *return_val = NSS_UNAVAIL; 541 return (0); 542 } 543 } 544 gl->gl_nxt = *headp; 545 *headp = gl; 546 return (1); /* Tell top_down() to keep iterating */ 547 } 548 549 static nss_status_t 550 netgr_set(be, a) 551 struct nis_netgr_be *be; 552 void *a; 553 { 554 struct nss_setnetgrent_args *args = (struct nss_setnetgrent_args *)a; 555 struct nis_getnetgr_be *get_be; 556 nss_status_t res; 557 558 get_be = (struct nis_getnetgr_be *)malloc(sizeof (*get_be)); 559 if (get_be == 0) { 560 return (NSS_UNAVAIL); 561 } 562 563 get_be->all_members = 0; 564 res = top_down(be, &args->netgroup, 1, save_triple, 565 &get_be->all_members); 566 567 if (res == NSS_SUCCESS) { 568 get_be->ops = getnetgr_ops; 569 get_be->n_ops = sizeof (getnetgr_ops) / 570 sizeof (getnetgr_ops[0]); 571 get_be->netgroup = strdup(args->netgroup); 572 get_be->next_member = get_be->all_members; 573 574 args->iterator = (nss_backend_t *)get_be; 575 } else { 576 args->iterator = 0; 577 free(get_be); 578 } 579 return (res); 580 } 581 582 583 /* 584 * Code for innetgr() 585 */ 586 587 /* 588 * Iterator function for innetgr(): Check whether triple matches args 589 */ 590 static int 591 match_triple(ccp triple[NSS_NETGR_N], void *ia_arg, nss_status_t *return_val) 592 { 593 struct nss_innetgr_args *ia = ia_arg; 594 enum nss_netgr_argn i; 595 596 for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) { 597 int (*cmpf)(const char *, const char *); 598 char **argv; 599 int n; 600 const char *name = triple[i]; 601 int argc = ia->arg[i].argc; 602 603 if (argc == 0 || name == 0) { 604 /* Wildcarded on one side or t'other */ 605 continue; 606 } 607 argv = ia->arg[i].argv; 608 cmpf = (i == NSS_NETGR_MACHINE) ? strcasecmp : strcmp; 609 for (n = 0; n < argc; n++) { 610 if ((*cmpf)(argv[n], name) == 0) { 611 break; 612 } 613 } 614 if (n >= argc) { 615 /* Match failed, tell top_down() to keep looking */ 616 return (1); 617 } 618 } 619 /* Matched on all three, so quit looking and declare victory */ 620 621 ia->status = NSS_NETGR_FOUND; 622 *return_val = NSS_SUCCESS; 623 return (0); 624 } 625 626 /* 627 * inlist() -- return 1 if at least one item from the "what" list 628 * is in the comma-separated, newline-terminated "list" 629 */ 630 static const char comma = ','; /* Don't let 'cfix' near this */ 631 632 static int 633 inlist(nwhat, pwhat, list) 634 nss_innetgr_argc nwhat; 635 nss_innetgr_argv pwhat; 636 char *list; 637 { 638 char *p; 639 nss_innetgr_argc nw; 640 nss_innetgr_argv pw; 641 642 while (*list != 0) { 643 while (*list == comma || isspace(*list)) 644 list++; 645 for (p = list; *p != 0 && *p != comma && 646 !isspace(*p); /* nothing */) 647 p++; 648 if (p != list) { 649 if (*p != 0) 650 *p++ = 0; 651 for (pw = pwhat, nw = nwhat; nw != 0; pw++, nw--) { 652 if (strcmp(list, *pw) == 0) 653 return (1); 654 } 655 list = p; 656 } 657 } 658 return (0); 659 } 660 661 /* 662 * Generate a key for a netgroup.byXXXX NIS map 663 */ 664 static void 665 makekey(key, name, domain) 666 char *key; 667 const char *name; 668 const char *domain; 669 { 670 while (*key++ = *name++) 671 ; 672 *(key-1) = '.'; 673 while (*key++ = *domain++) 674 ; 675 } 676 677 static int 678 makekey_lc(key, name, domain) 679 char *key; 680 const char *name; /* Convert this to lowercase */ 681 const char *domain; /* But not this */ 682 { 683 int found_uc = 0; 684 char c; 685 686 while (c = *name++) { 687 if (isupper(c)) { 688 ++found_uc; 689 c = tolower(c); 690 } 691 *key++ = c; 692 } 693 *key++ = '.'; 694 while (*key++ = *domain++) 695 ; 696 return (found_uc); 697 } 698 699 /* 700 * easy_way() -- try to use netgroup.byuser and netgroup.byhost maps to 701 * get answers more efficiently than by recursive search. 702 * 703 * If more than one name (username or hostname) is specified, this approach 704 * becomes less attractive; at some point it's probably cheaper to do the 705 * recursive search. We don't know what the threshold is (among other things 706 * it may depend on the site-specific struucture of netgroup information), 707 * so here's a guesstimate. 708 */ 709 710 #define NNAME_THRESHOLD 5 711 712 static int 713 easy_way(be, ia, argp, map, try_lc, statusp) 714 struct nis_netgr_be *be; 715 struct nss_innetgr_args *ia; 716 struct nss_innetgr_1arg *argp; 717 const char *map; 718 int try_lc; 719 nss_status_t *statusp; 720 { 721 nss_innetgr_argc nname = argp->argc; 722 nss_innetgr_argv pname = argp->argv; 723 const char *domain = ia->arg[NSS_NETGR_DOMAIN].argv[0]; 724 const char *wild = "*"; 725 int yperr; 726 char *val; 727 int vallen; 728 char *key; 729 int i; 730 731 /* Our caller guaranteed that nname >= 1 */ 732 while (nname > 1) { 733 struct nss_innetgr_1arg just_one; 734 735 if (nname > NNAME_THRESHOLD) { 736 return (0); /* May be cheaper to use 'netgroup' */ 737 } 738 739 just_one.argc = 1; 740 just_one.argv = pname; 741 742 if (easy_way(be, ia, &just_one, map, try_lc, statusp) && 743 ia->status == NSS_NETGR_FOUND) { 744 return (1); 745 } 746 ++pname; 747 --nname; 748 /* Fall through and do the last one inline */ 749 } 750 751 if ((key = malloc(strlen(*pname) + strlen(domain) + 2)) == 0) { 752 return (0); /* Or maybe (1) and NSS_UNAVAIL */ 753 } 754 755 for (i = 0; i < (try_lc ? 6 : 4); i++) { 756 switch (i) { 757 case 0: 758 makekey(key, *pname, domain); 759 break; 760 case 1: 761 makekey(key, wild, domain); 762 break; 763 case 2: 764 makekey(key, *pname, wild); 765 break; 766 case 3: 767 makekey(key, wild, wild); 768 break; 769 case 4: 770 if (!makekey_lc(key, *pname, domain)) { 771 try_lc = 0; /* Sleazy but effective */ 772 continue; /* i.e. quit looping */ 773 } 774 break; 775 case 5: 776 (void) makekey_lc(key, *pname, wild); 777 break; 778 } 779 *statusp = _nss_nis_ypmatch(be->domain, map, key, 780 &val, &vallen, &yperr); 781 if (*statusp == NSS_SUCCESS) { 782 if (inlist(ia->groups.argc, ia->groups.argv, val)) { 783 free(val); 784 free(key); 785 ia->status = NSS_NETGR_FOUND; 786 return (1); 787 } else { 788 free(val); 789 } 790 } else { 791 #ifdef DEBUG 792 syslog(LOG_WARNING, 793 "innetgr: yp_match(%s,%s) failed: %s", 794 map, key, yperr_string(yperr)); 795 #endif /* DEBUG */ 796 if (yperr != YPERR_KEY) { 797 free(key); 798 return (0); 799 } 800 } 801 } 802 803 free(key); 804 805 /* =====> is this (an authoritative "no") always the right thing to do? */ 806 /* Answer: yes, except for hostnames that aren't all lowercase */ 807 808 *statusp = NSS_SUCCESS; /* Yup, three different flavours of */ 809 ia->status = NSS_NETGR_NO; /* status information, so-called. */ 810 return (1); /* Silly, innit? */ 811 } 812 813 814 static nss_status_t 815 netgr_in(be, a) 816 struct nis_netgr_be *be; 817 void *a; 818 { 819 struct nss_innetgr_args *ia = (struct nss_innetgr_args *)a; 820 nss_status_t res; 821 822 ia->status = NSS_NETGR_NO; 823 824 /* Can we use netgroup.byhost or netgroup.byuser to speed things up? */ 825 826 /* ====> diddle this to try fast path for domains.argc == 0 too */ 827 if (ia->arg[NSS_NETGR_DOMAIN].argc == 1) { 828 if (ia->arg[NSS_NETGR_MACHINE].argc == 0 && 829 ia->arg[NSS_NETGR_USER ].argc != 0) { 830 if (easy_way(be, ia, &ia->arg[NSS_NETGR_USER], 831 "netgroup.byuser", 0, &res)) { 832 return (res); 833 } 834 } else if (ia->arg[NSS_NETGR_USER].argc == 0 && 835 ia->arg[NSS_NETGR_MACHINE].argc != 0) { 836 if (easy_way(be, ia, &ia->arg[NSS_NETGR_MACHINE], 837 "netgroup.byhost", 1, &res)) { 838 return (res); 839 } 840 } 841 } 842 843 /* Nope, try the slow way */ 844 ia->status = NSS_NETGR_NO; 845 res = top_down(be, (const char **)ia->groups.argv, ia->groups.argc, 846 match_triple, ia); 847 return (res); 848 } 849 850 851 /* 852 * (Almost) boilerplate for a switch backend 853 */ 854 855 /*ARGSUSED*/ 856 static nss_status_t 857 netgr_destr(be, dummy) 858 struct nis_netgr_be *be; 859 void *dummy; 860 { 861 if (be != 0) { 862 free(be); 863 } 864 return (NSS_SUCCESS); 865 } 866 867 static nis_netgr_op_t netgroup_ops[] = { 868 netgr_destr, 869 0, /* No endent, because no setent/getent */ 870 0, /* No setent; setnetgrent() is really a getXbyY() */ 871 0, /* No getent in the normal sense */ 872 873 netgr_in, /* innetgr() */ 874 netgr_set, /* setnetgrent() */ 875 }; 876 877 /*ARGSUSED*/ 878 nss_backend_t * 879 _nss_nis_netgroup_constr(dummy1, dummy2, dummy3) 880 const char *dummy1, *dummy2, *dummy3; 881 { 882 const char *domain; 883 struct nis_netgr_be *be; 884 885 if ((domain = _nss_nis_domain()) == 0 || 886 (be = (struct nis_netgr_be *)malloc(sizeof (*be))) == 0) { 887 return (0); 888 } 889 be->ops = netgroup_ops; 890 be->n_ops = sizeof (netgroup_ops) / sizeof (netgroup_ops[0]); 891 be->domain = domain; 892 893 return ((nss_backend_t *)be); 894 } 895