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