10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52830Sdjl * Common Development and Distribution License (the "License"). 62830Sdjl * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3386Smichen * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * nis/getnetgrent.c -- "nis" backend for nsswitch "netgroup" database 280Sstevel@tonic-gate * 290Sstevel@tonic-gate * The API for netgroups differs sufficiently from that for the average 300Sstevel@tonic-gate * getXXXbyYYY function that we use very few of the support routines in 310Sstevel@tonic-gate * nis_common.h. 320Sstevel@tonic-gate * 330Sstevel@tonic-gate * The implementation of setnetgrent()/getnetgrent() here follows the 340Sstevel@tonic-gate * the 4.x code, inasmuch as the setnetgrent() routine does all the work 350Sstevel@tonic-gate * of traversing the netgroup graph and building a (potentially large) 360Sstevel@tonic-gate * list in memory, and getnetgrent() just steps down the list. 370Sstevel@tonic-gate * 380Sstevel@tonic-gate * An alternative, and probably better, implementation would lazy-eval 390Sstevel@tonic-gate * the netgroup graph in response to getnetgrent() calls (though 400Sstevel@tonic-gate * setnetgrent() should still check for the top-level netgroup name 410Sstevel@tonic-gate * and return NSS_SUCCESS / NSS_NOTFOUND). 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate 440Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 450Sstevel@tonic-gate 460Sstevel@tonic-gate #include "nis_common.h" 470Sstevel@tonic-gate #include <ctype.h> 480Sstevel@tonic-gate #include <rpcsvc/ypclnt.h> 490Sstevel@tonic-gate #include <malloc.h> 500Sstevel@tonic-gate #include <string.h> 510Sstevel@tonic-gate #ifdef DEBUG 520Sstevel@tonic-gate #include <sys/syslog.h> 530Sstevel@tonic-gate #endif /* DEBUG */ 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * The nss_backend_t for a getnetgrent() sequence; we actually give the 570Sstevel@tonic-gate * netgroup frontend a pointer to one of these structures in response to 580Sstevel@tonic-gate * a (successful) setnetgrent() call on the nis_netgr_be backend 590Sstevel@tonic-gate * described further down in this file. 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate 620Sstevel@tonic-gate struct nis_getnetgr_be; 630Sstevel@tonic-gate typedef nss_status_t (*nis_getnetgr_op_t)(struct nis_getnetgr_be *, void *); 640Sstevel@tonic-gate 650Sstevel@tonic-gate struct nis_getnetgr_be { 660Sstevel@tonic-gate nis_getnetgr_op_t *ops; 670Sstevel@tonic-gate nss_dbop_t n_ops; 680Sstevel@tonic-gate /* 690Sstevel@tonic-gate * State for set/get/endnetgrent() 700Sstevel@tonic-gate */ 710Sstevel@tonic-gate char *netgroup; 720Sstevel@tonic-gate struct grouplist *all_members; 730Sstevel@tonic-gate struct grouplist *next_member; 740Sstevel@tonic-gate }; 750Sstevel@tonic-gate 760Sstevel@tonic-gate struct grouplist { /* One element of the list generated by a setnetgrent() */ 770Sstevel@tonic-gate char *triple[NSS_NETGR_N]; 780Sstevel@tonic-gate struct grouplist *gl_nxt; 790Sstevel@tonic-gate }; 800Sstevel@tonic-gate 810Sstevel@tonic-gate static nss_status_t 820Sstevel@tonic-gate getnetgr_set(be, a) 830Sstevel@tonic-gate struct nis_getnetgr_be *be; 840Sstevel@tonic-gate void *a; 850Sstevel@tonic-gate { 860Sstevel@tonic-gate const char *netgroup = (const char *) a; 870Sstevel@tonic-gate 880Sstevel@tonic-gate if (be->netgroup != 0 && 890Sstevel@tonic-gate strcmp(be->netgroup, netgroup) == 0) { 900Sstevel@tonic-gate /* We already have the member-list; regurgitate it */ 910Sstevel@tonic-gate be->next_member = be->all_members; 920Sstevel@tonic-gate return (NSS_SUCCESS); 930Sstevel@tonic-gate } 940Sstevel@tonic-gate return (NSS_NOTFOUND); 950Sstevel@tonic-gate } 960Sstevel@tonic-gate 970Sstevel@tonic-gate static nss_status_t 980Sstevel@tonic-gate getnetgr_get(be, a) 990Sstevel@tonic-gate struct nis_getnetgr_be *be; 1000Sstevel@tonic-gate void *a; 1010Sstevel@tonic-gate { 1022830Sdjl struct nss_getnetgrent_args *args = (struct nss_getnetgrent_args *)a; 1030Sstevel@tonic-gate struct grouplist *mem; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate if ((mem = be->next_member) == 0) { 1060Sstevel@tonic-gate args->status = NSS_NETGR_NO; 1070Sstevel@tonic-gate } else { 1080Sstevel@tonic-gate char *buffer = args->buffer; 1090Sstevel@tonic-gate int buflen = args->buflen; 1100Sstevel@tonic-gate enum nss_netgr_argn i; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate args->status = NSS_NETGR_FOUND; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate for (i = 0; i < NSS_NETGR_N; i++) { 1150Sstevel@tonic-gate const char *str; 1160Sstevel@tonic-gate ssize_t len; 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate if ((str = mem->triple[i]) == 0) { 1190Sstevel@tonic-gate args->retp[i] = 0; 1200Sstevel@tonic-gate } else if ((len = strlen(str) + 1) <= buflen) { 1210Sstevel@tonic-gate args->retp[i] = buffer; 1222830Sdjl (void) memcpy(buffer, str, len); 1230Sstevel@tonic-gate buffer += len; 1240Sstevel@tonic-gate buflen -= len; 1250Sstevel@tonic-gate } else { 1260Sstevel@tonic-gate args->status = NSS_NETGR_NOMEM; 1270Sstevel@tonic-gate break; 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate be->next_member = mem->gl_nxt; 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate return (NSS_SUCCESS); /* Yup, even for end-of-list, i.e. */ 1330Sstevel@tonic-gate /* do NOT advance to next backend. */ 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate /*ARGSUSED*/ 1370Sstevel@tonic-gate static nss_status_t 1380Sstevel@tonic-gate getnetgr_end(be, dummy) 1390Sstevel@tonic-gate struct nis_getnetgr_be *be; 1400Sstevel@tonic-gate void *dummy; 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate struct grouplist *gl; 1430Sstevel@tonic-gate struct grouplist *next; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate for (gl = be->all_members; gl != NULL; gl = next) { 1460Sstevel@tonic-gate enum nss_netgr_argn i; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate next = gl->gl_nxt; 1490Sstevel@tonic-gate for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) { 1500Sstevel@tonic-gate if (gl->triple[i] != 0) { 1510Sstevel@tonic-gate free(gl->triple[i]); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate free(gl); 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate be->all_members = 0; 1570Sstevel@tonic-gate be->next_member = 0; 1580Sstevel@tonic-gate if (be->netgroup != 0) { 1590Sstevel@tonic-gate free(be->netgroup); 1600Sstevel@tonic-gate be->netgroup = 0; 1610Sstevel@tonic-gate } 1620Sstevel@tonic-gate return (NSS_SUCCESS); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate /*ARGSUSED*/ 1660Sstevel@tonic-gate static nss_status_t 1670Sstevel@tonic-gate getnetgr_destr(be, dummy) 1680Sstevel@tonic-gate struct nis_getnetgr_be *be; 1690Sstevel@tonic-gate void *dummy; 1700Sstevel@tonic-gate { 1710Sstevel@tonic-gate if (be != 0) { 1722830Sdjl (void) getnetgr_end(be, (void *)0); 1730Sstevel@tonic-gate free(be); 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate return (NSS_SUCCESS); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate static nis_getnetgr_op_t getnetgr_ops[] = { 1790Sstevel@tonic-gate getnetgr_destr, 1800Sstevel@tonic-gate getnetgr_end, 1810Sstevel@tonic-gate getnetgr_set, 1820Sstevel@tonic-gate getnetgr_get, /* getnetgrent_r() */ 1830Sstevel@tonic-gate }; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* 1870Sstevel@tonic-gate * The nss_backend_t for innetgr() and setnetgrent(). 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate struct nis_netgr_be; 1910Sstevel@tonic-gate typedef nss_status_t (*nis_netgr_op_t)(struct nis_netgr_be *, void *); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate struct nis_netgr_be { 1940Sstevel@tonic-gate nis_netgr_op_t *ops; 1950Sstevel@tonic-gate nss_dbop_t n_ops; 1960Sstevel@tonic-gate const char *domain; /* (default) YP domain */ 1970Sstevel@tonic-gate }; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* 2010Sstevel@tonic-gate * Code to do top-down search in the graph defined by the 'netgroup' YP map 2020Sstevel@tonic-gate */ 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate /* 2050Sstevel@tonic-gate * ===> This code is now used for setnetgrent(), not just innetgr(). 2060Sstevel@tonic-gate * 2070Sstevel@tonic-gate * If the easy way doesn't pan out, recursively search the 'netgroup' map. 2080Sstevel@tonic-gate * In order to do this, we: 2090Sstevel@tonic-gate * 2100Sstevel@tonic-gate * - remember all the netgroup names we've seen during this search, 2110Sstevel@tonic-gate * whether or not we've expanded them yet (we want fast insertion 2120Sstevel@tonic-gate * with duplicate-detection, so use yet another chained hash table), 2130Sstevel@tonic-gate * 2140Sstevel@tonic-gate * - keep a list of all the netgroups we haven't expanded yet (we just 2150Sstevel@tonic-gate * want fast insertion and pop-first, so a linked list will do fine). 2160Sstevel@tonic-gate * If we insert at the head, we get a depth-first search; insertion 2170Sstevel@tonic-gate * at the tail gives breadth-first (?), which seems preferable (?). 2180Sstevel@tonic-gate * 2190Sstevel@tonic-gate * A netgrnam struct contains pointers for both the hash-table and the list. 2200Sstevel@tonic-gate * It also contains the netgroup name; note that we embed the name at the 2210Sstevel@tonic-gate * end of the structure rather than holding a pointer to yet another 2220Sstevel@tonic-gate * malloc()ed region. 2230Sstevel@tonic-gate * 2240Sstevel@tonic-gate * A netgrtab structure contains the hash-chain heads and the head/tail 2250Sstevel@tonic-gate * pointers for the expansion list. 2260Sstevel@tonic-gate * 2270Sstevel@tonic-gate * Most of this code is common to at least the NIS and NIS+ backends; it 2280Sstevel@tonic-gate * should be generalized and, presumably, moved into the frontend. 2290Sstevel@tonic-gate * ==> Not any longer... 2300Sstevel@tonic-gate */ 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate struct netgrnam { 2330Sstevel@tonic-gate struct netgrnam *hash_chain; 2340Sstevel@tonic-gate struct netgrnam *expand_next; 2350Sstevel@tonic-gate char name[1]; /* Really [strlen(name) + 1] */ 2360Sstevel@tonic-gate }; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate #define HASHMOD 113 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate struct netgrtab { 2410Sstevel@tonic-gate struct netgrnam *expand_first; 2420Sstevel@tonic-gate struct netgrnam **expand_lastp; 2430Sstevel@tonic-gate struct netgrnam *hash_heads[HASHMOD]; 2440Sstevel@tonic-gate }; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate static void 2470Sstevel@tonic-gate ngt_init(ngt) 2480Sstevel@tonic-gate struct netgrtab *ngt; 2490Sstevel@tonic-gate { 2502830Sdjl (void) memset((void *)ngt, 0, sizeof (*ngt)); 2510Sstevel@tonic-gate ngt->expand_lastp = &ngt->expand_first; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* === ? Change ngt_init() and ngt_destroy() to malloc/free struct netgrtab */ 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate static void 2570Sstevel@tonic-gate /* ==> ? Should return 'failed' (out-of-memory) status ? */ 2580Sstevel@tonic-gate ngt_insert(ngt, name, namelen) 2590Sstevel@tonic-gate struct netgrtab *ngt; 2600Sstevel@tonic-gate const char *name; 2610Sstevel@tonic-gate size_t namelen; 2620Sstevel@tonic-gate { 2630Sstevel@tonic-gate unsigned hashval; 2640Sstevel@tonic-gate size_t i; 2650Sstevel@tonic-gate struct netgrnam *cur; 2660Sstevel@tonic-gate struct netgrnam **head; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate #define dummy ((struct netgrnam *)0) 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate for (hashval = 0, i = 0; i < namelen; i++) { 2710Sstevel@tonic-gate hashval = (hashval << 2) + hashval + 2720Sstevel@tonic-gate ((const unsigned char *)name)[i]; 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate head = &ngt->hash_heads[hashval % HASHMOD]; 2750Sstevel@tonic-gate for (cur = *head; cur != 0; cur = cur->hash_chain) { 2760Sstevel@tonic-gate if (strncmp(cur->name, name, namelen) == 0 && 2770Sstevel@tonic-gate cur->name[namelen] == 0) { 2780Sstevel@tonic-gate return; /* Already in table, do nothing */ 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate /* Create new netgrnam struct */ 2820Sstevel@tonic-gate cur = (struct netgrnam *) 2830Sstevel@tonic-gate malloc(namelen + 1 + (char *)&dummy->name[0] - (char *)dummy); 2840Sstevel@tonic-gate if (cur == 0) { 2850Sstevel@tonic-gate return; /* Out of memory, too bad */ 2860Sstevel@tonic-gate } 2872830Sdjl (void) memcpy(cur->name, name, namelen); 2880Sstevel@tonic-gate cur->name[namelen] = 0; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate /* Insert in hash table */ 2910Sstevel@tonic-gate cur->hash_chain = *head; 2920Sstevel@tonic-gate *head = cur; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* Insert in expansion list (insert at end for breadth-first search */ 2950Sstevel@tonic-gate cur->expand_next = 0; 2960Sstevel@tonic-gate *ngt->expand_lastp = cur; 2970Sstevel@tonic-gate ngt->expand_lastp = &cur->expand_next; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate #undef dummy 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate static const char * 3030Sstevel@tonic-gate ngt_next(ngt) 3040Sstevel@tonic-gate struct netgrtab *ngt; 3050Sstevel@tonic-gate { 3060Sstevel@tonic-gate struct netgrnam *first; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if ((first = ngt->expand_first) == 0) { 3090Sstevel@tonic-gate return (0); 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate if ((ngt->expand_first = first->expand_next) == 0) { 3120Sstevel@tonic-gate ngt->expand_lastp = &ngt->expand_first; 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate return (first->name); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate static void 3180Sstevel@tonic-gate ngt_destroy(ngt) 3190Sstevel@tonic-gate struct netgrtab *ngt; 3200Sstevel@tonic-gate { 3210Sstevel@tonic-gate struct netgrnam *cur; 3220Sstevel@tonic-gate struct netgrnam *next; 3230Sstevel@tonic-gate int i; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate for (i = 0; i < HASHMOD; i++) { 3260Sstevel@tonic-gate for (cur = ngt->hash_heads[i]; cur != 0; /* cstyle */) { 3270Sstevel@tonic-gate next = cur->hash_chain; 3280Sstevel@tonic-gate free(cur); 3290Sstevel@tonic-gate cur = next; 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate /* Don't bother zeroing pointers; must do init if we want to reuse */ 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate typedef const char *ccp; 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate static nss_status_t 3380Sstevel@tonic-gate top_down(struct nis_netgr_be *be, const char **groups, int ngroups, 3390Sstevel@tonic-gate int (*func)(ccp triple[3], void *iter_args, nss_status_t *return_val), 3400Sstevel@tonic-gate void *iter_args) 3410Sstevel@tonic-gate { 3420Sstevel@tonic-gate struct netgrtab *ngt; 3430Sstevel@tonic-gate /* netgrtab goes on the heap, not the stack, because it's large and */ 3440Sstevel@tonic-gate /* stacks may not be all that big in multi-threaded programs. */ 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate const char *group; 3470Sstevel@tonic-gate int nfound; 3480Sstevel@tonic-gate int done; 3490Sstevel@tonic-gate nss_status_t result; 3500Sstevel@tonic-gate 3512830Sdjl if ((ngt = (struct netgrtab *)malloc(sizeof (*ngt))) == 0) { 3520Sstevel@tonic-gate return (NSS_UNAVAIL); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate ngt_init(ngt); 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate while (ngroups > 0) { 3570Sstevel@tonic-gate ngt_insert(ngt, *groups, strlen(*groups)); 3580Sstevel@tonic-gate groups++; 3590Sstevel@tonic-gate ngroups--; 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate done = 0; /* Set to 1 to indicate that we cut the iteration */ 3630Sstevel@tonic-gate /* short (and 'result' holds the return value) */ 3640Sstevel@tonic-gate nfound = 0; /* Number of successful netgroup yp_match calls */ 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate while (!done && (group = ngt_next(ngt)) != 0) { 3670Sstevel@tonic-gate char *val; 3680Sstevel@tonic-gate int vallen; 3690Sstevel@tonic-gate char *p; 3700Sstevel@tonic-gate int yperr; 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate result = _nss_nis_ypmatch(be->domain, "netgroup", group, 3730Sstevel@tonic-gate &val, &vallen, &yperr); 3740Sstevel@tonic-gate if (result != NSS_SUCCESS) { 3752830Sdjl /*LINTED E_NOP_IF_STMT*/ 3760Sstevel@tonic-gate if (result == NSS_NOTFOUND) { 3772830Sdjl ; 3780Sstevel@tonic-gate #ifdef DEBUG 3790Sstevel@tonic-gate syslog(LOG_WARNING, 3800Sstevel@tonic-gate "NIS netgroup lookup: %s doesn't exist", 3810Sstevel@tonic-gate group); 3820Sstevel@tonic-gate #endif /* DEBUG */ 3830Sstevel@tonic-gate } else { 3840Sstevel@tonic-gate #ifdef DEBUG 3850Sstevel@tonic-gate syslog(LOG_WARNING, 3860Sstevel@tonic-gate "NIS netgroup lookup: yp_match returned [%s]", 3870Sstevel@tonic-gate yperr_string(yperr)); 3880Sstevel@tonic-gate #endif /* DEBUG */ 3890Sstevel@tonic-gate done = 1; /* Give up, return result */ 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate /* Don't need to clean up anything */ 3920Sstevel@tonic-gate continue; 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate nfound++; 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate if ((p = strpbrk(val, "#\n")) != 0) { 3980Sstevel@tonic-gate *p = '\0'; 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate p = val; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate /* Parse val into triples and recursive netgroup references */ 4030Sstevel@tonic-gate /*CONSTCOND*/ 4040Sstevel@tonic-gate while (1) { 4050Sstevel@tonic-gate ccp triple[NSS_NETGR_N]; 4060Sstevel@tonic-gate int syntax_err; 4070Sstevel@tonic-gate enum nss_netgr_argn i; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate while (isspace(*p)) { 4100Sstevel@tonic-gate p++; 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate if (*p == '\0') { 4130Sstevel@tonic-gate /* Finished processing this particular val */ 4140Sstevel@tonic-gate break; 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate if (*p != '(') { 4170Sstevel@tonic-gate /* Doesn't look like the start of a triple, */ 4180Sstevel@tonic-gate /* so assume it's a recursive netgroup. */ 4190Sstevel@tonic-gate char *start = p; 4200Sstevel@tonic-gate p = strpbrk(start, " \t"); 4210Sstevel@tonic-gate if (p == 0) { 4220Sstevel@tonic-gate /* Point p at the final '\0' */ 4230Sstevel@tonic-gate p = start + strlen(start); 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate ngt_insert(ngt, start, (size_t)(p - start)); 4260Sstevel@tonic-gate continue; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate /* Main case: a (machine, user, domain) triple */ 4300Sstevel@tonic-gate p++; 4310Sstevel@tonic-gate syntax_err = 0; 4320Sstevel@tonic-gate for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) { 4330Sstevel@tonic-gate char *start; 4340Sstevel@tonic-gate char *limit; 4350Sstevel@tonic-gate const char *terminators = ",) \t"; 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate if (i == NSS_NETGR_DOMAIN) { 4380Sstevel@tonic-gate /* Don't allow comma */ 4390Sstevel@tonic-gate terminators++; 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate while (isspace(*p)) { 4420Sstevel@tonic-gate p++; 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate start = p; 4450Sstevel@tonic-gate limit = strpbrk(start, terminators); 4460Sstevel@tonic-gate if (limit == 0) { 4470Sstevel@tonic-gate syntax_err++; 4480Sstevel@tonic-gate break; 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate p = limit; 4510Sstevel@tonic-gate while (isspace(*p)) { 4520Sstevel@tonic-gate p++; 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate if (*p == terminators[0]) { 4550Sstevel@tonic-gate /* 4560Sstevel@tonic-gate * Successfully parsed this name and 4570Sstevel@tonic-gate * the separator after it (comma or 4580Sstevel@tonic-gate * right paren); leave p ready for 4590Sstevel@tonic-gate * next parse. 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate p++; 4620Sstevel@tonic-gate if (start == limit) { 4630Sstevel@tonic-gate /* Wildcard */ 4640Sstevel@tonic-gate triple[i] = 0; 4650Sstevel@tonic-gate } else { 4660Sstevel@tonic-gate *limit = '\0'; 4670Sstevel@tonic-gate triple[i] = start; 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate } else { 4700Sstevel@tonic-gate syntax_err++; 4710Sstevel@tonic-gate break; 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate if (syntax_err) { 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * ===> log it; 4780Sstevel@tonic-gate * ===> try skipping past next ')'; failing that, abandon the line; 4790Sstevel@tonic-gate */ 4800Sstevel@tonic-gate break; /* Abandon this line */ 4810Sstevel@tonic-gate } else if (!(*func)(triple, iter_args, &result)) { 4820Sstevel@tonic-gate /* Return result, good or bad */ 4830Sstevel@tonic-gate done = 1; 4840Sstevel@tonic-gate break; 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate /* End of inner loop over val[] */ 4880Sstevel@tonic-gate free(val); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate /* End of outer loop (!done && ngt_next(ngt) != 0) */ 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate ngt_destroy(ngt); 4930Sstevel@tonic-gate free(ngt); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate if (done) { 4960Sstevel@tonic-gate return (result); 4970Sstevel@tonic-gate } else if (nfound > 0) { 4980Sstevel@tonic-gate /* ==== ? Should only do this if all the top-level groups */ 4990Sstevel@tonic-gate /* exist in YP? */ 5000Sstevel@tonic-gate return (NSS_SUCCESS); 5010Sstevel@tonic-gate } else { 5020Sstevel@tonic-gate return (NSS_NOTFOUND); 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate /* 5080Sstevel@tonic-gate * Code for setnetgrent() 5090Sstevel@tonic-gate */ 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * Iterator function for setnetgrent(): copy triple, add to be->all_members 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate static int 5150Sstevel@tonic-gate save_triple(ccp trippp[NSS_NETGR_N], void *headp_arg, 5160Sstevel@tonic-gate nss_status_t *return_val) 5170Sstevel@tonic-gate { 5180Sstevel@tonic-gate struct grouplist **headp = headp_arg; 5190Sstevel@tonic-gate struct grouplist *gl; 5200Sstevel@tonic-gate enum nss_netgr_argn i; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate if ((gl = (struct grouplist *)malloc(sizeof (*gl))) == 0) { 5230Sstevel@tonic-gate /* Out of memory */ 5240Sstevel@tonic-gate *return_val = NSS_UNAVAIL; 5250Sstevel@tonic-gate return (0); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) { 5280Sstevel@tonic-gate if (trippp[i] == 0) { 5290Sstevel@tonic-gate /* Wildcard */ 5300Sstevel@tonic-gate gl->triple[i] = 0; 5310Sstevel@tonic-gate } else if ((gl->triple[i] = strdup(trippp[i])) == 0) { 5320Sstevel@tonic-gate /* Out of memory. Free any we've allocated */ 5330Sstevel@tonic-gate enum nss_netgr_argn j; 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate for (j = NSS_NETGR_MACHINE; j < i; j++) { 5360Sstevel@tonic-gate if (gl->triple[j] != 0) { 5370Sstevel@tonic-gate free(gl->triple[j]); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate *return_val = NSS_UNAVAIL; 5410Sstevel@tonic-gate return (0); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate gl->gl_nxt = *headp; 5450Sstevel@tonic-gate *headp = gl; 5460Sstevel@tonic-gate return (1); /* Tell top_down() to keep iterating */ 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate static nss_status_t 5500Sstevel@tonic-gate netgr_set(be, a) 5510Sstevel@tonic-gate struct nis_netgr_be *be; 5520Sstevel@tonic-gate void *a; 5530Sstevel@tonic-gate { 5542830Sdjl struct nss_setnetgrent_args *args = (struct nss_setnetgrent_args *)a; 5550Sstevel@tonic-gate struct nis_getnetgr_be *get_be; 5560Sstevel@tonic-gate nss_status_t res; 5570Sstevel@tonic-gate 5582830Sdjl get_be = (struct nis_getnetgr_be *)malloc(sizeof (*get_be)); 5590Sstevel@tonic-gate if (get_be == 0) { 5600Sstevel@tonic-gate return (NSS_UNAVAIL); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate get_be->all_members = 0; 5640Sstevel@tonic-gate res = top_down(be, &args->netgroup, 1, save_triple, 5650Sstevel@tonic-gate &get_be->all_members); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate if (res == NSS_SUCCESS) { 5680Sstevel@tonic-gate get_be->ops = getnetgr_ops; 5690Sstevel@tonic-gate get_be->n_ops = sizeof (getnetgr_ops) / 5700Sstevel@tonic-gate sizeof (getnetgr_ops[0]); 5710Sstevel@tonic-gate get_be->netgroup = strdup(args->netgroup); 5720Sstevel@tonic-gate get_be->next_member = get_be->all_members; 5730Sstevel@tonic-gate 5742830Sdjl args->iterator = (nss_backend_t *)get_be; 5750Sstevel@tonic-gate } else { 5760Sstevel@tonic-gate args->iterator = 0; 5770Sstevel@tonic-gate free(get_be); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate return (res); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate * Code for innetgr() 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate /* 5880Sstevel@tonic-gate * Iterator function for innetgr(): Check whether triple matches args 5890Sstevel@tonic-gate */ 5900Sstevel@tonic-gate static int 5910Sstevel@tonic-gate match_triple(ccp triple[NSS_NETGR_N], void *ia_arg, nss_status_t *return_val) 5920Sstevel@tonic-gate { 5930Sstevel@tonic-gate struct nss_innetgr_args *ia = ia_arg; 5940Sstevel@tonic-gate enum nss_netgr_argn i; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate for (i = NSS_NETGR_MACHINE; i < NSS_NETGR_N; i++) { 5970Sstevel@tonic-gate int (*cmpf)(const char *, const char *); 5980Sstevel@tonic-gate char **argv; 5990Sstevel@tonic-gate int n; 6000Sstevel@tonic-gate const char *name = triple[i]; 6010Sstevel@tonic-gate int argc = ia->arg[i].argc; 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate if (argc == 0 || name == 0) { 6040Sstevel@tonic-gate /* Wildcarded on one side or t'other */ 6050Sstevel@tonic-gate continue; 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate argv = ia->arg[i].argv; 6080Sstevel@tonic-gate cmpf = (i == NSS_NETGR_MACHINE) ? strcasecmp : strcmp; 6090Sstevel@tonic-gate for (n = 0; n < argc; n++) { 6100Sstevel@tonic-gate if ((*cmpf)(argv[n], name) == 0) { 6110Sstevel@tonic-gate break; 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate } 6140Sstevel@tonic-gate if (n >= argc) { 6150Sstevel@tonic-gate /* Match failed, tell top_down() to keep looking */ 6160Sstevel@tonic-gate return (1); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate /* Matched on all three, so quit looking and declare victory */ 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate ia->status = NSS_NETGR_FOUND; 6220Sstevel@tonic-gate *return_val = NSS_SUCCESS; 6230Sstevel@tonic-gate return (0); 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* 6270Sstevel@tonic-gate * inlist() -- return 1 if at least one item from the "what" list 6280Sstevel@tonic-gate * is in the comma-separated, newline-terminated "list" 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate static const char comma = ','; /* Don't let 'cfix' near this */ 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate static int 6330Sstevel@tonic-gate inlist(nwhat, pwhat, list) 6340Sstevel@tonic-gate nss_innetgr_argc nwhat; 6350Sstevel@tonic-gate nss_innetgr_argv pwhat; 6360Sstevel@tonic-gate char *list; 6370Sstevel@tonic-gate { 6380Sstevel@tonic-gate char *p; 6390Sstevel@tonic-gate nss_innetgr_argc nw; 6400Sstevel@tonic-gate nss_innetgr_argv pw; 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate while (*list != 0) { 6430Sstevel@tonic-gate while (*list == comma || isspace(*list)) 6440Sstevel@tonic-gate list++; 6450Sstevel@tonic-gate for (p = list; *p != 0 && *p != comma && 6460Sstevel@tonic-gate !isspace(*p); /* nothing */) 6470Sstevel@tonic-gate p++; 6480Sstevel@tonic-gate if (p != list) { 6490Sstevel@tonic-gate if (*p != 0) 6500Sstevel@tonic-gate *p++ = 0; 6510Sstevel@tonic-gate for (pw = pwhat, nw = nwhat; nw != 0; pw++, nw--) { 6520Sstevel@tonic-gate if (strcmp(list, *pw) == 0) 6530Sstevel@tonic-gate return (1); 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate list = p; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate return (0); 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate /* 6620Sstevel@tonic-gate * Generate a key for a netgroup.byXXXX NIS map 6630Sstevel@tonic-gate */ 6640Sstevel@tonic-gate static void 6650Sstevel@tonic-gate makekey(key, name, domain) 6660Sstevel@tonic-gate char *key; 6670Sstevel@tonic-gate const char *name; 6680Sstevel@tonic-gate const char *domain; 6690Sstevel@tonic-gate { 6700Sstevel@tonic-gate while (*key++ = *name++) 6710Sstevel@tonic-gate ; 6720Sstevel@tonic-gate *(key-1) = '.'; 6730Sstevel@tonic-gate while (*key++ = *domain++) 6740Sstevel@tonic-gate ; 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate static int 6780Sstevel@tonic-gate makekey_lc(key, name, domain) 6790Sstevel@tonic-gate char *key; 6800Sstevel@tonic-gate const char *name; /* Convert this to lowercase */ 6810Sstevel@tonic-gate const char *domain; /* But not this */ 6820Sstevel@tonic-gate { 6830Sstevel@tonic-gate int found_uc = 0; 6840Sstevel@tonic-gate char c; 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate while (c = *name++) { 6870Sstevel@tonic-gate if (isupper(c)) { 6880Sstevel@tonic-gate ++found_uc; 6890Sstevel@tonic-gate c = tolower(c); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate *key++ = c; 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate *key++ = '.'; 6940Sstevel@tonic-gate while (*key++ = *domain++) 6950Sstevel@tonic-gate ; 6960Sstevel@tonic-gate return (found_uc); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate /* 7000Sstevel@tonic-gate * easy_way() -- try to use netgroup.byuser and netgroup.byhost maps to 7010Sstevel@tonic-gate * get answers more efficiently than by recursive search. 7020Sstevel@tonic-gate * 7030Sstevel@tonic-gate * If more than one name (username or hostname) is specified, this approach 7040Sstevel@tonic-gate * becomes less attractive; at some point it's probably cheaper to do the 7050Sstevel@tonic-gate * recursive search. We don't know what the threshold is (among other things 7060Sstevel@tonic-gate * it may depend on the site-specific struucture of netgroup information), 7070Sstevel@tonic-gate * so here's a guesstimate. 7080Sstevel@tonic-gate */ 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate #define NNAME_THRESHOLD 5 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate static int 7130Sstevel@tonic-gate easy_way(be, ia, argp, map, try_lc, statusp) 7140Sstevel@tonic-gate struct nis_netgr_be *be; 7150Sstevel@tonic-gate struct nss_innetgr_args *ia; 7160Sstevel@tonic-gate struct nss_innetgr_1arg *argp; 7170Sstevel@tonic-gate const char *map; 7180Sstevel@tonic-gate int try_lc; 7190Sstevel@tonic-gate nss_status_t *statusp; 7200Sstevel@tonic-gate { 7210Sstevel@tonic-gate nss_innetgr_argc nname = argp->argc; 7220Sstevel@tonic-gate nss_innetgr_argv pname = argp->argv; 7230Sstevel@tonic-gate const char *domain = ia->arg[NSS_NETGR_DOMAIN].argv[0]; 7240Sstevel@tonic-gate const char *wild = "*"; 7250Sstevel@tonic-gate int yperr; 7260Sstevel@tonic-gate char *val; 7270Sstevel@tonic-gate int vallen; 7280Sstevel@tonic-gate char *key; 7290Sstevel@tonic-gate int i; 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate /* Our caller guaranteed that nname >= 1 */ 7320Sstevel@tonic-gate while (nname > 1) { 7330Sstevel@tonic-gate struct nss_innetgr_1arg just_one; 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate if (nname > NNAME_THRESHOLD) { 7360Sstevel@tonic-gate return (0); /* May be cheaper to use 'netgroup' */ 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate just_one.argc = 1; 7400Sstevel@tonic-gate just_one.argv = pname; 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate if (easy_way(be, ia, &just_one, map, try_lc, statusp) && 7430Sstevel@tonic-gate ia->status == NSS_NETGR_FOUND) { 7440Sstevel@tonic-gate return (1); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate ++pname; 7470Sstevel@tonic-gate --nname; 7480Sstevel@tonic-gate /* Fall through and do the last one inline */ 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate if ((key = malloc(strlen(*pname) + strlen(domain) + 2)) == 0) { 7520Sstevel@tonic-gate return (0); /* Or maybe (1) and NSS_UNAVAIL */ 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate for (i = 0; i < (try_lc ? 6 : 4); i++) { 7560Sstevel@tonic-gate switch (i) { 7570Sstevel@tonic-gate case 0: 7580Sstevel@tonic-gate makekey(key, *pname, domain); 7590Sstevel@tonic-gate break; 7600Sstevel@tonic-gate case 1: 7610Sstevel@tonic-gate makekey(key, wild, domain); 7620Sstevel@tonic-gate break; 7630Sstevel@tonic-gate case 2: 7640Sstevel@tonic-gate makekey(key, *pname, wild); 7650Sstevel@tonic-gate break; 7660Sstevel@tonic-gate case 3: 7670Sstevel@tonic-gate makekey(key, wild, wild); 7680Sstevel@tonic-gate break; 7690Sstevel@tonic-gate case 4: 7700Sstevel@tonic-gate if (!makekey_lc(key, *pname, domain)) { 7710Sstevel@tonic-gate try_lc = 0; /* Sleazy but effective */ 7720Sstevel@tonic-gate continue; /* i.e. quit looping */ 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate break; 7750Sstevel@tonic-gate case 5: 7760Sstevel@tonic-gate (void) makekey_lc(key, *pname, wild); 7770Sstevel@tonic-gate break; 7780Sstevel@tonic-gate } 7790Sstevel@tonic-gate *statusp = _nss_nis_ypmatch(be->domain, map, key, 7800Sstevel@tonic-gate &val, &vallen, &yperr); 7810Sstevel@tonic-gate if (*statusp == NSS_SUCCESS) { 7820Sstevel@tonic-gate if (inlist(ia->groups.argc, ia->groups.argv, val)) { 7830Sstevel@tonic-gate free(val); 7840Sstevel@tonic-gate free(key); 7850Sstevel@tonic-gate ia->status = NSS_NETGR_FOUND; 7860Sstevel@tonic-gate return (1); 7870Sstevel@tonic-gate } else { 7880Sstevel@tonic-gate free(val); 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate } else { 7910Sstevel@tonic-gate #ifdef DEBUG 7920Sstevel@tonic-gate syslog(LOG_WARNING, 7930Sstevel@tonic-gate "innetgr: yp_match(%s,%s) failed: %s", 7940Sstevel@tonic-gate map, key, yperr_string(yperr)); 7950Sstevel@tonic-gate #endif /* DEBUG */ 7960Sstevel@tonic-gate if (yperr != YPERR_KEY) { 7970Sstevel@tonic-gate free(key); 7980Sstevel@tonic-gate return (0); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate free(key); 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate /* =====> is this (an authoritative "no") always the right thing to do? */ 8060Sstevel@tonic-gate /* Answer: yes, except for hostnames that aren't all lowercase */ 8070Sstevel@tonic-gate 808*3386Smichen *statusp = NSS_NOTFOUND; /* Yup, three different flavours of */ 8090Sstevel@tonic-gate ia->status = NSS_NETGR_NO; /* status information, so-called. */ 8100Sstevel@tonic-gate return (1); /* Silly, innit? */ 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate static nss_status_t 8150Sstevel@tonic-gate netgr_in(be, a) 8160Sstevel@tonic-gate struct nis_netgr_be *be; 8170Sstevel@tonic-gate void *a; 8180Sstevel@tonic-gate { 8192830Sdjl struct nss_innetgr_args *ia = (struct nss_innetgr_args *)a; 8200Sstevel@tonic-gate nss_status_t res; 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate ia->status = NSS_NETGR_NO; 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate /* Can we use netgroup.byhost or netgroup.byuser to speed things up? */ 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate /* ====> diddle this to try fast path for domains.argc == 0 too */ 8270Sstevel@tonic-gate if (ia->arg[NSS_NETGR_DOMAIN].argc == 1) { 8280Sstevel@tonic-gate if (ia->arg[NSS_NETGR_MACHINE].argc == 0 && 8290Sstevel@tonic-gate ia->arg[NSS_NETGR_USER ].argc != 0) { 8300Sstevel@tonic-gate if (easy_way(be, ia, &ia->arg[NSS_NETGR_USER], 8310Sstevel@tonic-gate "netgroup.byuser", 0, &res)) { 8320Sstevel@tonic-gate return (res); 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate } else if (ia->arg[NSS_NETGR_USER].argc == 0 && 8350Sstevel@tonic-gate ia->arg[NSS_NETGR_MACHINE].argc != 0) { 8360Sstevel@tonic-gate if (easy_way(be, ia, &ia->arg[NSS_NETGR_MACHINE], 8370Sstevel@tonic-gate "netgroup.byhost", 1, &res)) { 8380Sstevel@tonic-gate return (res); 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate } 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate /* Nope, try the slow way */ 8440Sstevel@tonic-gate ia->status = NSS_NETGR_NO; 8450Sstevel@tonic-gate res = top_down(be, (const char **)ia->groups.argv, ia->groups.argc, 8460Sstevel@tonic-gate match_triple, ia); 8470Sstevel@tonic-gate return (res); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate /* 8520Sstevel@tonic-gate * (Almost) boilerplate for a switch backend 8530Sstevel@tonic-gate */ 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate /*ARGSUSED*/ 8562830Sdjl static nss_status_t 8570Sstevel@tonic-gate netgr_destr(be, dummy) 8580Sstevel@tonic-gate struct nis_netgr_be *be; 8590Sstevel@tonic-gate void *dummy; 8600Sstevel@tonic-gate { 8610Sstevel@tonic-gate if (be != 0) { 8620Sstevel@tonic-gate free(be); 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate return (NSS_SUCCESS); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate static nis_netgr_op_t netgroup_ops[] = { 8680Sstevel@tonic-gate netgr_destr, 8690Sstevel@tonic-gate 0, /* No endent, because no setent/getent */ 8700Sstevel@tonic-gate 0, /* No setent; setnetgrent() is really a getXbyY() */ 8710Sstevel@tonic-gate 0, /* No getent in the normal sense */ 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate netgr_in, /* innetgr() */ 8740Sstevel@tonic-gate netgr_set, /* setnetgrent() */ 8750Sstevel@tonic-gate }; 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate /*ARGSUSED*/ 8780Sstevel@tonic-gate nss_backend_t * 8790Sstevel@tonic-gate _nss_nis_netgroup_constr(dummy1, dummy2, dummy3) 8800Sstevel@tonic-gate const char *dummy1, *dummy2, *dummy3; 8810Sstevel@tonic-gate { 8820Sstevel@tonic-gate const char *domain; 8830Sstevel@tonic-gate struct nis_netgr_be *be; 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate if ((domain = _nss_nis_domain()) == 0 || 8862830Sdjl (be = (struct nis_netgr_be *)malloc(sizeof (*be))) == 0) { 8870Sstevel@tonic-gate return (0); 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate be->ops = netgroup_ops; 8900Sstevel@tonic-gate be->n_ops = sizeof (netgroup_ops) / sizeof (netgroup_ops[0]); 8910Sstevel@tonic-gate be->domain = domain; 8920Sstevel@tonic-gate 8932830Sdjl return ((nss_backend_t *)be); 8940Sstevel@tonic-gate } 895