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