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