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