17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * Common code and structures used by name-service-switch "compat" backends.
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * Most of the code in the "compat" backend is a perverted form of code from
297c478bd9Sstevel@tonic-gate  * the "files" backend;  this file is no exception.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <bsm/libbsm.h>
397c478bd9Sstevel@tonic-gate #include <user_attr.h>
407c478bd9Sstevel@tonic-gate #include "compat_common.h"
417c478bd9Sstevel@tonic-gate #include "../../../libnsl/include/nsl_stdio_prv.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * This should be in a header.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate extern int yp_get_default_domain(char **domain);
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Routines to manage list of "-" users for get{pw, sp, gr}ent().  Current
517c478bd9Sstevel@tonic-gate  *   implementation is completely moronic; we use a linked list.  But then
527c478bd9Sstevel@tonic-gate  *   that's what it's always done in 4.x...
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate struct setofstrings {
567c478bd9Sstevel@tonic-gate 	char			*name;
577c478bd9Sstevel@tonic-gate 	struct setofstrings	*next;
587c478bd9Sstevel@tonic-gate 	/*
597c478bd9Sstevel@tonic-gate 	 * === Should get smart and malloc the string and pointer as one
607c478bd9Sstevel@tonic-gate 	 *	object rather than two.
617c478bd9Sstevel@tonic-gate 	 */
627c478bd9Sstevel@tonic-gate };
637c478bd9Sstevel@tonic-gate typedef struct setofstrings	*strset_t;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static void
667c478bd9Sstevel@tonic-gate strset_free(ssp)
677c478bd9Sstevel@tonic-gate 	strset_t	*ssp;
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	strset_t	cur, nxt;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	for (cur = *ssp;  cur != 0;  cur = nxt) {
727c478bd9Sstevel@tonic-gate 		nxt = cur->next;
737c478bd9Sstevel@tonic-gate 		free(cur->name);
747c478bd9Sstevel@tonic-gate 		free(cur);
757c478bd9Sstevel@tonic-gate 	}
767c478bd9Sstevel@tonic-gate 	*ssp = 0;
777c478bd9Sstevel@tonic-gate }
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static boolean_t
807c478bd9Sstevel@tonic-gate strset_add(ssp, nam)
817c478bd9Sstevel@tonic-gate 	strset_t	*ssp;
827c478bd9Sstevel@tonic-gate 	const char	*nam;
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate 	strset_t	new;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	if (0 == (new = (strset_t)malloc(sizeof (*new)))) {
877c478bd9Sstevel@tonic-gate 		return (B_FALSE);
887c478bd9Sstevel@tonic-gate 	}
897c478bd9Sstevel@tonic-gate 	if (0 == (new->name = malloc(strlen(nam) + 1))) {
907c478bd9Sstevel@tonic-gate 		free(new);
917c478bd9Sstevel@tonic-gate 		return (B_FALSE);
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 	strcpy(new->name, nam);
947c478bd9Sstevel@tonic-gate 	new->next = *ssp;
957c478bd9Sstevel@tonic-gate 	*ssp = new;
967c478bd9Sstevel@tonic-gate 	return (B_TRUE);
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate static boolean_t
1007c478bd9Sstevel@tonic-gate strset_in(ssp, nam)
1017c478bd9Sstevel@tonic-gate 	const strset_t	*ssp;
1027c478bd9Sstevel@tonic-gate 	const char	*nam;
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	strset_t	cur;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	for (cur = *ssp;  cur != 0;  cur = cur->next) {
1077c478bd9Sstevel@tonic-gate 		if (strcmp(cur->name, nam) == 0) {
1087c478bd9Sstevel@tonic-gate 			return (B_TRUE);
1097c478bd9Sstevel@tonic-gate 		}
1107c478bd9Sstevel@tonic-gate 	}
1117c478bd9Sstevel@tonic-gate 	return (B_FALSE);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate struct compat_backend {
1167c478bd9Sstevel@tonic-gate 	compat_backend_op_t	*ops;
1177c478bd9Sstevel@tonic-gate 	int			n_ops;
1187c478bd9Sstevel@tonic-gate 	const char		*filename;
1197c478bd9Sstevel@tonic-gate 	__NSL_FILE		*f;
1207c478bd9Sstevel@tonic-gate 	int			minbuf;
1217c478bd9Sstevel@tonic-gate 	char			*buf;
1227c478bd9Sstevel@tonic-gate 	int			linelen;	/* <== Explain use, lifetime */
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	nss_db_initf_t		db_initf;
1257c478bd9Sstevel@tonic-gate 	nss_db_root_t		*db_rootp;	/* Shared between instances */
1267c478bd9Sstevel@tonic-gate 	nss_getent_t		db_context;	/* Per-instance enumeration */
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	compat_get_name		getnamef;
1297c478bd9Sstevel@tonic-gate 	compat_merge_func	mergef;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	/* We wouldn't need all this hokey state stuff if we */
1327c478bd9Sstevel@tonic-gate 	/*   used another thread to implement a coroutine... */
1337c478bd9Sstevel@tonic-gate 	enum {
1347c478bd9Sstevel@tonic-gate 		GETENT_FILE,
1357c478bd9Sstevel@tonic-gate 		GETENT_NETGROUP,
1367c478bd9Sstevel@tonic-gate 		GETENT_ATTRDB,
1377c478bd9Sstevel@tonic-gate 		GETENT_ALL,
1387c478bd9Sstevel@tonic-gate 		GETENT_DONE
1397c478bd9Sstevel@tonic-gate 	}			state;
1407c478bd9Sstevel@tonic-gate 	strset_t		minuses;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	int			permit_netgroups;
1437c478bd9Sstevel@tonic-gate 	const char		*yp_domain;
1447c478bd9Sstevel@tonic-gate 	nss_backend_t		*getnetgrent_backend;
1457c478bd9Sstevel@tonic-gate 	char			*netgr_buffer;
1467c478bd9Sstevel@tonic-gate };
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * Lookup and enumeration routines for +@group and -@group.
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  * This code knows a lot more about lib/libc/port/gen/getnetgrent.c than
1537c478bd9Sstevel@tonic-gate  *   is really healthy.  The set/get/end routines below duplicate code
1547c478bd9Sstevel@tonic-gate  *   from that file, but keep the state information per-backend-instance
1557c478bd9Sstevel@tonic-gate  *   instead of just per-process.
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate extern void _nss_initf_netgroup(nss_db_params_t *);
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * Should really share the db_root in getnetgrent.c in order to get the
1617c478bd9Sstevel@tonic-gate  *   resource-management quotas right, but this will have to do.
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(netgr_db_root);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static boolean_t
1667c478bd9Sstevel@tonic-gate netgr_in(compat_backend_ptr_t be, const char *group, const char *user)
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate 	if (be->yp_domain == 0) {
1697c478bd9Sstevel@tonic-gate 		if (yp_get_default_domain((char **)&be->yp_domain) != 0) {
1707c478bd9Sstevel@tonic-gate 			return (B_FALSE);
1717c478bd9Sstevel@tonic-gate 		}
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 	return (innetgr(group, 0, user, be->yp_domain));
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate static boolean_t
1777c478bd9Sstevel@tonic-gate netgr_all_in(compat_backend_ptr_t be, const char *group)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	/*
1807c478bd9Sstevel@tonic-gate 	 * 4.x does this;  ours not to reason why...
1817c478bd9Sstevel@tonic-gate 	 */
1827c478bd9Sstevel@tonic-gate 	return (netgr_in(be, group, "*"));
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate static void
1867c478bd9Sstevel@tonic-gate netgr_set(be, netgroup)
1877c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
1887c478bd9Sstevel@tonic-gate 	const char		*netgroup;
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	/*
1917c478bd9Sstevel@tonic-gate 	 * ===> Need comment to explain that this first "if" is optimizing
1927c478bd9Sstevel@tonic-gate 	 *	for the same-netgroup-as-last-time case
1937c478bd9Sstevel@tonic-gate 	 */
1947c478bd9Sstevel@tonic-gate 	if (be->getnetgrent_backend != 0 &&
1957c478bd9Sstevel@tonic-gate 	    NSS_INVOKE_DBOP(be->getnetgrent_backend,
1967c478bd9Sstevel@tonic-gate 			    NSS_DBOP_SETENT,
1977c478bd9Sstevel@tonic-gate 			    (void *) netgroup) != NSS_SUCCESS) {
1987c478bd9Sstevel@tonic-gate 		NSS_INVOKE_DBOP(be->getnetgrent_backend, NSS_DBOP_DESTRUCTOR,
1997c478bd9Sstevel@tonic-gate 				0);
2007c478bd9Sstevel@tonic-gate 		be->getnetgrent_backend = 0;
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 	if (be->getnetgrent_backend == 0) {
2037c478bd9Sstevel@tonic-gate 		struct nss_setnetgrent_args	args;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		args.netgroup	= netgroup;
2067c478bd9Sstevel@tonic-gate 		args.iterator	= 0;
2077c478bd9Sstevel@tonic-gate 		nss_search(&netgr_db_root, _nss_initf_netgroup,
2087c478bd9Sstevel@tonic-gate 			NSS_DBOP_NETGROUP_SET, &args);
2097c478bd9Sstevel@tonic-gate 		be->getnetgrent_backend = args.iterator;
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate static boolean_t
2147c478bd9Sstevel@tonic-gate netgr_next_u(be, up)
2157c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
2167c478bd9Sstevel@tonic-gate 	char			**up;
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	if (be->netgr_buffer == 0 &&
2197c478bd9Sstevel@tonic-gate 	    (be->netgr_buffer = malloc(NSS_BUFLEN_NETGROUP)) == 0) {
2207c478bd9Sstevel@tonic-gate 		/* Out of memory */
2217c478bd9Sstevel@tonic-gate 		return (B_FALSE);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	do {
2257c478bd9Sstevel@tonic-gate 		struct nss_getnetgrent_args	args;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		args.buffer	= be->netgr_buffer;
2287c478bd9Sstevel@tonic-gate 		args.buflen	= NSS_BUFLEN_NETGROUP;
2297c478bd9Sstevel@tonic-gate 		args.status	= NSS_NETGR_NO;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		if (be->getnetgrent_backend != 0) {
2327c478bd9Sstevel@tonic-gate 			NSS_INVOKE_DBOP(be->getnetgrent_backend,
2337c478bd9Sstevel@tonic-gate 					NSS_DBOP_GETENT, &args);
2347c478bd9Sstevel@tonic-gate 		}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 		if (args.status == NSS_NETGR_FOUND) {
2377c478bd9Sstevel@tonic-gate 			*up	  = args.retp[NSS_NETGR_USER];
2387c478bd9Sstevel@tonic-gate 		} else {
2397c478bd9Sstevel@tonic-gate 			return (B_FALSE);
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 	} while (*up == 0);
2427c478bd9Sstevel@tonic-gate 	return (B_TRUE);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate static void
2467c478bd9Sstevel@tonic-gate netgr_end(be)
2477c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate 	if (be->getnetgrent_backend != 0) {
2507c478bd9Sstevel@tonic-gate 		NSS_INVOKE_DBOP(be->getnetgrent_backend,
2517c478bd9Sstevel@tonic-gate 				NSS_DBOP_DESTRUCTOR, 0);
2527c478bd9Sstevel@tonic-gate 		be->getnetgrent_backend = 0;
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 	if (be->netgr_buffer != 0) {
2557c478bd9Sstevel@tonic-gate 		free(be->netgr_buffer);
2567c478bd9Sstevel@tonic-gate 		be->netgr_buffer = 0;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #define	MAXFIELDS 9	/* Sufficient for passwd (7), shadow (9), group (4) */
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate static nss_status_t
2647c478bd9Sstevel@tonic-gate do_merge(be, args, instr, linelen)
2657c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
2667c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
2677c478bd9Sstevel@tonic-gate 	const char		*instr;
2687c478bd9Sstevel@tonic-gate 	int			linelen;
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	char			*fields[MAXFIELDS];
2717c478bd9Sstevel@tonic-gate 	int			i;
2727c478bd9Sstevel@tonic-gate 	int			overrides;
2737c478bd9Sstevel@tonic-gate 	const char		*p;
2747c478bd9Sstevel@tonic-gate 	const char		*end = instr + linelen;
2757c478bd9Sstevel@tonic-gate 	nss_status_t		res;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	/*
2787c478bd9Sstevel@tonic-gate 	 * Potential optimization:  only perform the field-splitting nonsense
2797c478bd9Sstevel@tonic-gate 	 *   once per input line (at present, "+" and "+@netgroup" entries
2807c478bd9Sstevel@tonic-gate 	 *   will cause us to do this multiple times in getent() requests).
2817c478bd9Sstevel@tonic-gate 	 */
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	for (i = 0;  i < MAXFIELDS;  i++) {
2847c478bd9Sstevel@tonic-gate 		fields[i] = 0;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	for (p = instr, overrides = 0, i = 0; /* no test */; i++) {
2877c478bd9Sstevel@tonic-gate 		const char	*q = memchr(p, ':', end - p);
2887c478bd9Sstevel@tonic-gate 		const char	*r = (q == 0) ? end : q;
2897c478bd9Sstevel@tonic-gate 		ssize_t		len = r - p;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		if (len > 0) {
2927c478bd9Sstevel@tonic-gate 			char	*s = malloc(len + 1);
2937c478bd9Sstevel@tonic-gate 			if (s == 0) {
2947c478bd9Sstevel@tonic-gate 				overrides = -1;	/* Indicates "you lose" */
2957c478bd9Sstevel@tonic-gate 				break;
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 			memcpy(s, p, len);
2987c478bd9Sstevel@tonic-gate 			s[len] = '\0';
2997c478bd9Sstevel@tonic-gate 			fields[i] = s;
3007c478bd9Sstevel@tonic-gate 			overrides++;
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 		if (q == 0) {
3037c478bd9Sstevel@tonic-gate 			/* End of line */
3047c478bd9Sstevel@tonic-gate 			break;
3057c478bd9Sstevel@tonic-gate 		} else {
3067c478bd9Sstevel@tonic-gate 			/* Skip the colon at (*q) */
3077c478bd9Sstevel@tonic-gate 			p = q + 1;
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 	if (overrides == 1) {
3117c478bd9Sstevel@tonic-gate 		/* No real overrides, return (*args) intact */
3127c478bd9Sstevel@tonic-gate 		res = NSS_SUCCESS;
3137c478bd9Sstevel@tonic-gate 	} else if (overrides > 1) {
3147c478bd9Sstevel@tonic-gate 		/*
3157c478bd9Sstevel@tonic-gate 		 * The zero'th field is always nonempty (+/-...), but at least
3167c478bd9Sstevel@tonic-gate 		 *   one other field was also nonempty, i.e. wants to override
3177c478bd9Sstevel@tonic-gate 		 */
3187c478bd9Sstevel@tonic-gate 		switch ((*be->mergef)(be, args, (const char **)fields)) {
3197c478bd9Sstevel@tonic-gate 		    case NSS_STR_PARSE_SUCCESS:
3207c478bd9Sstevel@tonic-gate 			args->returnval	= args->buf.result;
3217c478bd9Sstevel@tonic-gate 			args->erange	= 0;
3227c478bd9Sstevel@tonic-gate 			res = NSS_SUCCESS;
3237c478bd9Sstevel@tonic-gate 			break;
3247c478bd9Sstevel@tonic-gate 		    case NSS_STR_PARSE_ERANGE:
3257c478bd9Sstevel@tonic-gate 			args->returnval	= 0;
3267c478bd9Sstevel@tonic-gate 			args->erange	= 1;
3277c478bd9Sstevel@tonic-gate 			res = NSS_NOTFOUND;
3287c478bd9Sstevel@tonic-gate 			break;
3297c478bd9Sstevel@tonic-gate 		    case NSS_STR_PARSE_PARSE:
3307c478bd9Sstevel@tonic-gate 			args->returnval	= 0;
3317c478bd9Sstevel@tonic-gate 			args->erange	= 0;
3327c478bd9Sstevel@tonic-gate /* ===> Very likely the wrong thing to do... */
3337c478bd9Sstevel@tonic-gate 			res = NSS_NOTFOUND;
3347c478bd9Sstevel@tonic-gate 			break;
3357c478bd9Sstevel@tonic-gate 		}
3367c478bd9Sstevel@tonic-gate 	} else {
3377c478bd9Sstevel@tonic-gate 		args->returnval	= 0;
3387c478bd9Sstevel@tonic-gate 		args->erange	= 0;
3397c478bd9Sstevel@tonic-gate 		res = NSS_UNAVAIL;	/* ==> Right? */
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	for (i = 0;  i < MAXFIELDS;  i++) {
3437c478bd9Sstevel@tonic-gate 		if (fields[i] != 0) {
3447c478bd9Sstevel@tonic-gate 			free(fields[i]);
3457c478bd9Sstevel@tonic-gate 		}
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	return (res);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3527c478bd9Sstevel@tonic-gate nss_status_t
3537c478bd9Sstevel@tonic-gate _nss_compat_setent(be, dummy)
3547c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
3557c478bd9Sstevel@tonic-gate 	void			*dummy;
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	if (be->f == 0) {
3587c478bd9Sstevel@tonic-gate 		if (be->filename == 0) {
3597c478bd9Sstevel@tonic-gate 			/* Backend isn't initialized properly? */
3607c478bd9Sstevel@tonic-gate 			return (NSS_UNAVAIL);
3617c478bd9Sstevel@tonic-gate 		}
3627c478bd9Sstevel@tonic-gate 		if ((be->f = __nsl_fopen(be->filename, "r")) == 0) {
3637c478bd9Sstevel@tonic-gate 			return (NSS_UNAVAIL);
3647c478bd9Sstevel@tonic-gate 		}
3657c478bd9Sstevel@tonic-gate 	} else {
3667c478bd9Sstevel@tonic-gate 		__nsl_rewind(be->f);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 	strset_free(&be->minuses);
3697c478bd9Sstevel@tonic-gate 	/* ===> ??? nss_endent(be->db_rootp, be->db_initf, &be->db_context); */
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	if ((strcmp(be->filename, USERATTR_FILENAME) == 0) ||
3727c478bd9Sstevel@tonic-gate 	    (strcmp(be->filename, AUDITUSER_FILENAME) == 0))
3737c478bd9Sstevel@tonic-gate 		be->state = GETENT_ATTRDB;
3747c478bd9Sstevel@tonic-gate 	else
3757c478bd9Sstevel@tonic-gate 		be->state = GETENT_FILE;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	/* ===> ??  netgroup stuff? */
3787c478bd9Sstevel@tonic-gate 	return (NSS_SUCCESS);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3827c478bd9Sstevel@tonic-gate nss_status_t
3837c478bd9Sstevel@tonic-gate _nss_compat_endent(be, dummy)
3847c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
3857c478bd9Sstevel@tonic-gate 	void			*dummy;
3867c478bd9Sstevel@tonic-gate {
3877c478bd9Sstevel@tonic-gate 	if (be->f != 0) {
3887c478bd9Sstevel@tonic-gate 		__nsl_fclose(be->f);
3897c478bd9Sstevel@tonic-gate 		be->f = 0;
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 	if (be->buf != 0) {
3927c478bd9Sstevel@tonic-gate 		free(be->buf);
3937c478bd9Sstevel@tonic-gate 		be->buf = 0;
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 	nss_endent(be->db_rootp, be->db_initf, &be->db_context);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	be->state = GETENT_FILE; /* Probably superfluous but comforting */
3987c478bd9Sstevel@tonic-gate 	strset_free(&be->minuses);
3997c478bd9Sstevel@tonic-gate 	netgr_end(be);
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/*
4027c478bd9Sstevel@tonic-gate 	 * Question: from the point of view of resource-freeing vs. time to
4037c478bd9Sstevel@tonic-gate 	 *   start up again, how much should we do in endent() and how much
4047c478bd9Sstevel@tonic-gate 	 *   in the destructor?
4057c478bd9Sstevel@tonic-gate 	 */
4067c478bd9Sstevel@tonic-gate 	return (NSS_SUCCESS);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4107c478bd9Sstevel@tonic-gate nss_status_t
4117c478bd9Sstevel@tonic-gate _nss_compat_destr(be, dummy)
4127c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
4137c478bd9Sstevel@tonic-gate 	void			*dummy;
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	if (be != 0) {
4167c478bd9Sstevel@tonic-gate 		if (be->f != 0) {
4177c478bd9Sstevel@tonic-gate 			_nss_compat_endent(be, 0);
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 		nss_delete(be->db_rootp);
4207c478bd9Sstevel@tonic-gate 		nss_delete(&netgr_db_root);
4217c478bd9Sstevel@tonic-gate 		free(be);
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 	return (NSS_SUCCESS);	/* In case anyone is dumb enough to check */
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate static int
4277c478bd9Sstevel@tonic-gate read_line(f, buffer, buflen)
4287c478bd9Sstevel@tonic-gate 	__NSL_FILE		*f;
4297c478bd9Sstevel@tonic-gate 	char			*buffer;
4307c478bd9Sstevel@tonic-gate 	int			buflen;
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
4337c478bd9Sstevel@tonic-gate 	while (1) {
4347c478bd9Sstevel@tonic-gate 		int	linelen;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 		if (__nsl_fgets(buffer, buflen, f) == 0) {
4377c478bd9Sstevel@tonic-gate 			/* End of file */
4387c478bd9Sstevel@tonic-gate 			return (-1);
4397c478bd9Sstevel@tonic-gate 		}
4407c478bd9Sstevel@tonic-gate 		linelen = strlen(buffer);
4417c478bd9Sstevel@tonic-gate 		/* linelen >= 1 (since fgets didn't return 0) */
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 		if (buffer[linelen - 1] == '\n') {
4447c478bd9Sstevel@tonic-gate 			/*
4457c478bd9Sstevel@tonic-gate 			 * ===> The code below that calls read_line() doesn't
4467c478bd9Sstevel@tonic-gate 			 *	play by the rules;  it assumes in places that
4477c478bd9Sstevel@tonic-gate 			 *	the line is null-terminated.  For now we'll
4487c478bd9Sstevel@tonic-gate 			 *	humour it.
4497c478bd9Sstevel@tonic-gate 			 */
4507c478bd9Sstevel@tonic-gate 			buffer[--linelen] = '\0';
4517c478bd9Sstevel@tonic-gate 			return (linelen);
4527c478bd9Sstevel@tonic-gate 		}
4537c478bd9Sstevel@tonic-gate 		if (__nsl_feof(f)) {
4547c478bd9Sstevel@tonic-gate 			/* Line is last line in file, and has no newline */
4557c478bd9Sstevel@tonic-gate 			return (linelen);
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 		/* Line too long for buffer;  toss it and loop for next line */
4587c478bd9Sstevel@tonic-gate 		/* ===== should syslog() in cases where previous code did */
4597c478bd9Sstevel@tonic-gate 		while (__nsl_fgets(buffer, buflen, f) != 0 &&
4607c478bd9Sstevel@tonic-gate 		    buffer[strlen(buffer) - 1] != '\n') {
4617c478bd9Sstevel@tonic-gate 			;
4627c478bd9Sstevel@tonic-gate 		}
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
466*738d7c77Svk static int
467*738d7c77Svk is_nss_lookup_by_name(int attrdb, nss_dbop_t op)
468*738d7c77Svk {
4697c478bd9Sstevel@tonic-gate 	int result = 0;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	if ((attrdb != 0) &&
472*738d7c77Svk 	    ((op == NSS_DBOP_AUDITUSER_BYNAME) ||
473*738d7c77Svk 	    (op == NSS_DBOP_USERATTR_BYNAME))) {
4747c478bd9Sstevel@tonic-gate 		result = 1;
4757c478bd9Sstevel@tonic-gate 	} else if ((attrdb == 0) &&
476*738d7c77Svk 	    ((op == NSS_DBOP_GROUP_BYNAME) ||
477*738d7c77Svk 	    (op == NSS_DBOP_PASSWD_BYNAME) ||
478*738d7c77Svk 	    (op == NSS_DBOP_SHADOW_BYNAME))) {
4797c478bd9Sstevel@tonic-gate 		result = 1;
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	return (result);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4867c478bd9Sstevel@tonic-gate nss_status_t
4877c478bd9Sstevel@tonic-gate _attrdb_compat_XY_all(be, argp, netdb, check, op_num)
4887c478bd9Sstevel@tonic-gate     compat_backend_ptr_t be;
4897c478bd9Sstevel@tonic-gate     nss_XbyY_args_t *argp;
4907c478bd9Sstevel@tonic-gate     int netdb;
4917c478bd9Sstevel@tonic-gate     compat_XY_check_func check;
4927c478bd9Sstevel@tonic-gate     nss_dbop_t op_num;
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate 	int		parsestat;
4957c478bd9Sstevel@tonic-gate 	int		(*func)();
4967c478bd9Sstevel@tonic-gate 	const char	*filter = argp->key.name;
4977c478bd9Sstevel@tonic-gate 	nss_status_t	res;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate #ifdef	DEBUG
5007c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "\n[compat_common.c: _attrdb_compat_XY_all]\n");
5017c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	if (be->buf == 0 &&
5047c478bd9Sstevel@tonic-gate 	    (be->buf = malloc(be->minbuf)) == 0) {
5057c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL);
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate 	if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) {
5087c478bd9Sstevel@tonic-gate 		return (res);
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 	res = NSS_NOTFOUND;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
5137c478bd9Sstevel@tonic-gate 	while (1) {
5147c478bd9Sstevel@tonic-gate 		int	linelen;
5157c478bd9Sstevel@tonic-gate 		char	*instr	= be->buf;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		if ((linelen = read_line(be->f, instr, be->minbuf)) < 0) {
5187c478bd9Sstevel@tonic-gate 			/* End of file */
5197c478bd9Sstevel@tonic-gate 			argp->returnval = 0;
5207c478bd9Sstevel@tonic-gate 			argp->erange    = 0;
5217c478bd9Sstevel@tonic-gate 			break;
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 		if (filter != 0 && strstr(instr, filter) == 0) {
5247c478bd9Sstevel@tonic-gate 			/*
5257c478bd9Sstevel@tonic-gate 			 * Optimization:  if the entry doesn't contain the
5267c478bd9Sstevel@tonic-gate 			 * filter string then it can't be the entry we want,
5277c478bd9Sstevel@tonic-gate 			 * so don't bother looking more closely at it.
5287c478bd9Sstevel@tonic-gate 			 */
5297c478bd9Sstevel@tonic-gate 			continue;
5307c478bd9Sstevel@tonic-gate 		}
5317c478bd9Sstevel@tonic-gate 		if (netdb) {
5327c478bd9Sstevel@tonic-gate 			char	*first;
5337c478bd9Sstevel@tonic-gate 			char	*last;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 			if ((last = strchr(instr, '#')) == 0) {
5367c478bd9Sstevel@tonic-gate 				last = instr + linelen;
5377c478bd9Sstevel@tonic-gate 			}
5387c478bd9Sstevel@tonic-gate 			*last-- = '\0';		/* Nuke '\n' or #comment */
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 			/*
5417c478bd9Sstevel@tonic-gate 			 * Skip leading whitespace.  Normally there isn't
5427c478bd9Sstevel@tonic-gate 			 * any, so it's not worth calling strspn().
5437c478bd9Sstevel@tonic-gate 			 */
5447c478bd9Sstevel@tonic-gate 			for (first = instr;  isspace(*first);  first++) {
5457c478bd9Sstevel@tonic-gate 				;
5467c478bd9Sstevel@tonic-gate 			}
5477c478bd9Sstevel@tonic-gate 			if (*first == '\0') {
5487c478bd9Sstevel@tonic-gate 				continue;
5497c478bd9Sstevel@tonic-gate 			}
5507c478bd9Sstevel@tonic-gate 			/*
5517c478bd9Sstevel@tonic-gate 			 * Found something non-blank on the line.  Skip back
5527c478bd9Sstevel@tonic-gate 			 * over any trailing whitespace;  since we know
5537c478bd9Sstevel@tonic-gate 			 * there's non-whitespace earlier in the line,
5547c478bd9Sstevel@tonic-gate 			 * checking for termination is easy.
5557c478bd9Sstevel@tonic-gate 			 */
5567c478bd9Sstevel@tonic-gate 			while (isspace(*last)) {
5577c478bd9Sstevel@tonic-gate 				--last;
5587c478bd9Sstevel@tonic-gate 			}
5597c478bd9Sstevel@tonic-gate 			linelen = last - first + 1;
5607c478bd9Sstevel@tonic-gate 			if (first != instr) {
5617c478bd9Sstevel@tonic-gate 				instr = first;
5627c478bd9Sstevel@tonic-gate 			}
5637c478bd9Sstevel@tonic-gate 		}
5647c478bd9Sstevel@tonic-gate 		argp->returnval = 0;
5657c478bd9Sstevel@tonic-gate 		func = argp->str2ent;
5667c478bd9Sstevel@tonic-gate 		parsestat = (*func)(instr, linelen, argp->buf.result,
5677c478bd9Sstevel@tonic-gate 					argp->buf.buffer, argp->buf.buflen);
5687c478bd9Sstevel@tonic-gate 		if (parsestat == NSS_STR_PARSE_SUCCESS) {
5697c478bd9Sstevel@tonic-gate 			argp->returnval = argp->buf.result;
5707c478bd9Sstevel@tonic-gate 			if (check == 0 || (*check)(argp)) {
5717c478bd9Sstevel@tonic-gate 				res = NSS_SUCCESS;
5727c478bd9Sstevel@tonic-gate 				break;
5737c478bd9Sstevel@tonic-gate 			}
5747c478bd9Sstevel@tonic-gate 		} else if (parsestat == NSS_STR_PARSE_ERANGE) {
5757c478bd9Sstevel@tonic-gate 			argp->erange = 1;
5767c478bd9Sstevel@tonic-gate 			break;
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 	/*
5807c478bd9Sstevel@tonic-gate 	 * stayopen is set to 0 by default in order to close the opened
5817c478bd9Sstevel@tonic-gate 	 * file.  Some applications may break if it is set to 1.
5827c478bd9Sstevel@tonic-gate 	 */
5837c478bd9Sstevel@tonic-gate 	if (check != 0 && !argp->stayopen) {
5847c478bd9Sstevel@tonic-gate 		(void) _nss_compat_endent(be, 0);
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	if (res != NSS_SUCCESS) {
5887c478bd9Sstevel@tonic-gate 		if ((op_num == NSS_DBOP_USERATTR_BYNAME) ||
5897c478bd9Sstevel@tonic-gate 		    (op_num == NSS_DBOP_AUDITUSER_BYNAME)) {
5907c478bd9Sstevel@tonic-gate 			res = nss_search(be->db_rootp,
5917c478bd9Sstevel@tonic-gate 			    be->db_initf,
5927c478bd9Sstevel@tonic-gate 			    op_num,
5937c478bd9Sstevel@tonic-gate 			    argp);
5947c478bd9Sstevel@tonic-gate 		} else {
5957c478bd9Sstevel@tonic-gate 			res = nss_getent(be->db_rootp,
5967c478bd9Sstevel@tonic-gate 			    be->db_initf, &be->db_context, argp);
5977c478bd9Sstevel@tonic-gate 		}
5987c478bd9Sstevel@tonic-gate 		if (res != NSS_SUCCESS) {
5997c478bd9Sstevel@tonic-gate 			argp->returnval	= 0;
6007c478bd9Sstevel@tonic-gate 			argp->erange	= 0;
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	return (res);
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate nss_status_t
6087c478bd9Sstevel@tonic-gate _nss_compat_XY_all(be, args, check, op_num)
6097c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
6107c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
6117c478bd9Sstevel@tonic-gate 	compat_XY_check_func	check;
6127c478bd9Sstevel@tonic-gate 	nss_dbop_t		op_num;
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate 	nss_status_t		res;
6157c478bd9Sstevel@tonic-gate 	int			parsestat;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	if (be->buf == 0 &&
6187c478bd9Sstevel@tonic-gate 	    (be->buf = malloc(be->minbuf)) == 0) {
6197c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL); /* really panic, malloc failed */
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) {
6237c478bd9Sstevel@tonic-gate 		return (res);
6247c478bd9Sstevel@tonic-gate 	}
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	res = NSS_NOTFOUND;
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
6297c478bd9Sstevel@tonic-gate 	while (1) {
6307c478bd9Sstevel@tonic-gate 		int		linelen;
6317c478bd9Sstevel@tonic-gate 		char		*instr	= be->buf;
6327c478bd9Sstevel@tonic-gate 		char		*colon;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 		linelen = read_line(be->f, instr, be->minbuf);
6357c478bd9Sstevel@tonic-gate 		if (linelen < 0) {
6367c478bd9Sstevel@tonic-gate 			/* End of file */
6377c478bd9Sstevel@tonic-gate 			args->returnval = 0;
6387c478bd9Sstevel@tonic-gate 			args->erange    = 0;
6397c478bd9Sstevel@tonic-gate 			break;
6407c478bd9Sstevel@tonic-gate 		}
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 		args->returnval = 0;	/* reset for both types of entries */
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 		if (instr[0] != '+' && instr[0] != '-') {
6457c478bd9Sstevel@tonic-gate 			/* Simple, wholesome, God-fearing entry */
6467c478bd9Sstevel@tonic-gate 			parsestat = (*args->str2ent)(instr, linelen,
6477c478bd9Sstevel@tonic-gate 						    args->buf.result,
6487c478bd9Sstevel@tonic-gate 						    args->buf.buffer,
6497c478bd9Sstevel@tonic-gate 						    args->buf.buflen);
6507c478bd9Sstevel@tonic-gate 			if (parsestat == NSS_STR_PARSE_SUCCESS) {
6517c478bd9Sstevel@tonic-gate 				args->returnval = args->buf.result;
6527c478bd9Sstevel@tonic-gate 				if ((*check)(args) != 0) {
6537c478bd9Sstevel@tonic-gate 					res = NSS_SUCCESS;
6547c478bd9Sstevel@tonic-gate 					break;
6557c478bd9Sstevel@tonic-gate 				}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate /* ===> Check the Dani logic here... */
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 			} else if (parsestat == NSS_STR_PARSE_ERANGE) {
6607c478bd9Sstevel@tonic-gate 				args->erange = 1;
6617c478bd9Sstevel@tonic-gate 				res = NSS_NOTFOUND;
6627c478bd9Sstevel@tonic-gate 				break;
6637c478bd9Sstevel@tonic-gate 				/* should we just skip this one long line ? */
6647c478bd9Sstevel@tonic-gate 			} /* else if (parsestat == NSS_STR_PARSE_PARSE) */
6657c478bd9Sstevel@tonic-gate 				/* don't care ! */
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate /* ==> ?? */		continue;
6687c478bd9Sstevel@tonic-gate 		}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		/*
6717c478bd9Sstevel@tonic-gate 		 * Process "+", "+name", "+@netgroup", "-name" or "-@netgroup"
6727c478bd9Sstevel@tonic-gate 		 *
6737c478bd9Sstevel@tonic-gate 		 * This code is optimized for lookups by name.
6747c478bd9Sstevel@tonic-gate 		 *
6757c478bd9Sstevel@tonic-gate 		 * For lookups by identifier search key cannot be matched with
6767c478bd9Sstevel@tonic-gate 		 * the name of the "+" or "-" entry. So nss_search() is to be
6777c478bd9Sstevel@tonic-gate 		 * called before extracting the name i.e. via (*be->getnamef)().
6787c478bd9Sstevel@tonic-gate 		 *
6797c478bd9Sstevel@tonic-gate 		 * But for lookups by name, search key is compared with the name
6807c478bd9Sstevel@tonic-gate 		 * of the "+" or "-" entry to acquire a match and thus
6817c478bd9Sstevel@tonic-gate 		 * unnesessary calls to nss_search() is eliminated. Also for
6827c478bd9Sstevel@tonic-gate 		 * matching "-" entries, calls to nss_search() is eliminated.
6837c478bd9Sstevel@tonic-gate 		 */
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 		if ((colon = strchr(instr, ':')) != 0) {
6867c478bd9Sstevel@tonic-gate 			*colon = '\0';	/* terminate field to extract name */
6877c478bd9Sstevel@tonic-gate 		}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 		if (instr[1] == '@') {
6907c478bd9Sstevel@tonic-gate 			/*
6917c478bd9Sstevel@tonic-gate 			 * Case 1:
6927c478bd9Sstevel@tonic-gate 			 * The entry is of the form "+@netgroup" or
6937c478bd9Sstevel@tonic-gate 			 * "-@netgroup".  If we're performing a lookup by name,
6947c478bd9Sstevel@tonic-gate 			 * we can simply extract the name from the search key
6957c478bd9Sstevel@tonic-gate 			 * (i.e. args->key.name).  If not, then we must call
6967c478bd9Sstevel@tonic-gate 			 * nss_search() before extracting the name via the
6977c478bd9Sstevel@tonic-gate 			 * get_XXname() function. i.e. (*be->getnamef)(args).
6987c478bd9Sstevel@tonic-gate 			 */
699*738d7c77Svk 			if (is_nss_lookup_by_name(0, op_num) != 0) {
700*738d7c77Svk 				/* compare then search */
701*738d7c77Svk 				if (!be->permit_netgroups ||
702*738d7c77Svk 				    !netgr_in(be, instr + 2, args->key.name))
703*738d7c77Svk 					continue;
704*738d7c77Svk 				if (instr[0] == '+') {
705*738d7c77Svk 					/* need to search for "+" entry */
706*738d7c77Svk 					nss_search(be->db_rootp, be->db_initf,
707*738d7c77Svk 					    op_num, args);
708*738d7c77Svk 					if (args->returnval == 0)
709*738d7c77Svk 						continue;
710*738d7c77Svk 				}
711*738d7c77Svk 			} else {
712*738d7c77Svk 				/* search then compare */
7137c478bd9Sstevel@tonic-gate 				nss_search(be->db_rootp, be->db_initf, op_num,
714*738d7c77Svk 				    args);
7157c478bd9Sstevel@tonic-gate 				if (args->returnval == 0)
7167c478bd9Sstevel@tonic-gate 					continue;
717*738d7c77Svk 				if (!be->permit_netgroups ||
718*738d7c77Svk 				    !netgr_in(be, instr + 2,
719*738d7c77Svk 				    (*be->getnamef)(args)))
720*738d7c77Svk 					continue;
7217c478bd9Sstevel@tonic-gate 			}
722*738d7c77Svk 		} else if (instr[1] == '\0') {
7237c478bd9Sstevel@tonic-gate 			/*
7247c478bd9Sstevel@tonic-gate 			 * Case 2:
7257c478bd9Sstevel@tonic-gate 			 * The entry is of the form "+" or "-".  The former
7267c478bd9Sstevel@tonic-gate 			 * allows all entries from name services.  The latter
7277c478bd9Sstevel@tonic-gate 			 * is illegal and ought to be ignored.
7287c478bd9Sstevel@tonic-gate 			 */
7297c478bd9Sstevel@tonic-gate 			if (instr[0] == '-')
7307c478bd9Sstevel@tonic-gate 				continue;
7317c478bd9Sstevel@tonic-gate 			/* need to search for "+" entry */
7327c478bd9Sstevel@tonic-gate 			nss_search(be->db_rootp, be->db_initf, op_num, args);
7337c478bd9Sstevel@tonic-gate 			if (args->returnval == 0)
7347c478bd9Sstevel@tonic-gate 				continue;
735*738d7c77Svk 		} else {
7367c478bd9Sstevel@tonic-gate 			/*
7377c478bd9Sstevel@tonic-gate 			 * Case 3:
7387c478bd9Sstevel@tonic-gate 			 * The entry is of the form "+name" or "-name".
7397c478bd9Sstevel@tonic-gate 			 * If we're performing a lookup by name, we can simply
7407c478bd9Sstevel@tonic-gate 			 * extract the name from the search key
7417c478bd9Sstevel@tonic-gate 			 * (i.e. args->key.name).  If not, then we must call
7427c478bd9Sstevel@tonic-gate 			 * nss_search() before extracting the name via the
7437c478bd9Sstevel@tonic-gate 			 * get_XXname() function. i.e. (*be->getnamef)(args).
7447c478bd9Sstevel@tonic-gate 			 */
745*738d7c77Svk 			if (is_nss_lookup_by_name(0, op_num) != 0) {
7467c478bd9Sstevel@tonic-gate 				/* compare then search */
7477c478bd9Sstevel@tonic-gate 				if (strcmp(instr + 1, args->key.name) != 0)
7487c478bd9Sstevel@tonic-gate 					continue;
7497c478bd9Sstevel@tonic-gate 				if (instr[0] == '+') {
7507c478bd9Sstevel@tonic-gate 					/* need to search for "+" entry */
7517c478bd9Sstevel@tonic-gate 					nss_search(be->db_rootp, be->db_initf,
752*738d7c77Svk 					    op_num, args);
7537c478bd9Sstevel@tonic-gate 					if (args->returnval == 0)
7547c478bd9Sstevel@tonic-gate 						continue;
7557c478bd9Sstevel@tonic-gate 				}
7567c478bd9Sstevel@tonic-gate 			} else {
7577c478bd9Sstevel@tonic-gate 				/* search then compare */
7587c478bd9Sstevel@tonic-gate 				nss_search(be->db_rootp, be->db_initf, op_num,
759*738d7c77Svk 				    args);
7607c478bd9Sstevel@tonic-gate 				if (args->returnval == 0)
7617c478bd9Sstevel@tonic-gate 					continue;
7627c478bd9Sstevel@tonic-gate 				if (strcmp(instr + 1, (*be->getnamef)(args))
763*738d7c77Svk 				    != 0)
7647c478bd9Sstevel@tonic-gate 					continue;
7657c478bd9Sstevel@tonic-gate 			}
766*738d7c77Svk 		}
7677c478bd9Sstevel@tonic-gate 		if (instr[0] == '-') {
7687c478bd9Sstevel@tonic-gate 			/* no need to search for "-" entry */
7697c478bd9Sstevel@tonic-gate 			args->returnval = 0;
7707c478bd9Sstevel@tonic-gate 			args->erange = 0;
7717c478bd9Sstevel@tonic-gate 			res = NSS_NOTFOUND;
7727c478bd9Sstevel@tonic-gate 		} else {
7737c478bd9Sstevel@tonic-gate 			if (colon != 0)
774*738d7c77Svk 				*colon = ':';	/* restoration */
7757c478bd9Sstevel@tonic-gate 			res = do_merge(be, args, instr, linelen);
7767c478bd9Sstevel@tonic-gate 		}
7777c478bd9Sstevel@tonic-gate 		break;
7787c478bd9Sstevel@tonic-gate 	}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	/*
7817c478bd9Sstevel@tonic-gate 	 * stayopen is set to 0 by default in order to close the opened
7827c478bd9Sstevel@tonic-gate 	 * file.  Some applications may break if it is set to 1.
7837c478bd9Sstevel@tonic-gate 	 */
7847c478bd9Sstevel@tonic-gate 	if (!args->stayopen) {
7857c478bd9Sstevel@tonic-gate 		(void) _nss_compat_endent(be, 0);
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	return (res);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate nss_status_t
7927c478bd9Sstevel@tonic-gate _nss_compat_getent(be, a)
7937c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
7947c478bd9Sstevel@tonic-gate 	void			*a;
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t		*args = (nss_XbyY_args_t *)a;
7977c478bd9Sstevel@tonic-gate 	nss_status_t		res;
7987c478bd9Sstevel@tonic-gate 	char			*colon = 0; /* <=== need comment re lifetime */
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	if (be->f == 0) {
8017c478bd9Sstevel@tonic-gate 		if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) {
8027c478bd9Sstevel@tonic-gate 			return (res);
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	if (be->buf == 0 &&
8077c478bd9Sstevel@tonic-gate 	    (be->buf = malloc(be->minbuf)) == 0) {
8087c478bd9Sstevel@tonic-gate 		return (NSS_UNAVAIL); /* really panic, malloc failed */
8097c478bd9Sstevel@tonic-gate 	}
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
8127c478bd9Sstevel@tonic-gate 	while (1) {
8137c478bd9Sstevel@tonic-gate 		char		*instr	= be->buf;
8147c478bd9Sstevel@tonic-gate 		int		linelen;
8157c478bd9Sstevel@tonic-gate 		char		*name;	/* === Need more distinctive label */
8167c478bd9Sstevel@tonic-gate 		const char	*savename;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		/*
8197c478bd9Sstevel@tonic-gate 		 * In the code below...
8207c478bd9Sstevel@tonic-gate 		 *    break	means "I found one, I think" (i.e. goto the
8217c478bd9Sstevel@tonic-gate 		 *		code after the end of the switch statement),
8227c478bd9Sstevel@tonic-gate 		 *    continue	means "Next candidate"
8237c478bd9Sstevel@tonic-gate 		 *		(i.e. loop around to the switch statement),
8247c478bd9Sstevel@tonic-gate 		 *    return	means "I'm quite sure" (either Yes or No).
8257c478bd9Sstevel@tonic-gate 		 */
8267c478bd9Sstevel@tonic-gate 		switch (be->state) {
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 		    case GETENT_DONE:
8297c478bd9Sstevel@tonic-gate 			args->returnval	= 0;
8307c478bd9Sstevel@tonic-gate 			args->erange	= 0;
8317c478bd9Sstevel@tonic-gate 			return (NSS_NOTFOUND);
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 		    case GETENT_ATTRDB:
8347c478bd9Sstevel@tonic-gate 			res = _attrdb_compat_XY_all(be,
8357c478bd9Sstevel@tonic-gate 			    args, 1, (compat_XY_check_func)NULL, 0);
8367c478bd9Sstevel@tonic-gate 			return (res);
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 		    case GETENT_FILE:
8397c478bd9Sstevel@tonic-gate 			linelen = read_line(be->f, instr, be->minbuf);
8407c478bd9Sstevel@tonic-gate 			if (linelen < 0) {
8417c478bd9Sstevel@tonic-gate 				/* End of file */
8427c478bd9Sstevel@tonic-gate 				be->state = GETENT_DONE;
8437c478bd9Sstevel@tonic-gate 				continue;
8447c478bd9Sstevel@tonic-gate 			}
8457c478bd9Sstevel@tonic-gate 			if ((colon = strchr(instr, ':')) != 0) {
8467c478bd9Sstevel@tonic-gate 				*colon = '\0';
8477c478bd9Sstevel@tonic-gate 			}
8487c478bd9Sstevel@tonic-gate 			if (instr[0] == '-') {
8497c478bd9Sstevel@tonic-gate 				if (instr[1] != '@') {
8507c478bd9Sstevel@tonic-gate 					strset_add(&be->minuses, instr + 1);
8517c478bd9Sstevel@tonic-gate 				} else if (be->permit_netgroups) {
8527c478bd9Sstevel@tonic-gate 					netgr_set(be, instr + 2);
8537c478bd9Sstevel@tonic-gate 					while (netgr_next_u(be, &name)) {
8547c478bd9Sstevel@tonic-gate 						strset_add(&be->minuses,
8557c478bd9Sstevel@tonic-gate 							name);
8567c478bd9Sstevel@tonic-gate 					}
8577c478bd9Sstevel@tonic-gate 					netgr_end(be);
8587c478bd9Sstevel@tonic-gate 				} /* Else (silently) ignore the entry */
8597c478bd9Sstevel@tonic-gate 				continue;
8607c478bd9Sstevel@tonic-gate 			} else if (instr[0] != '+') {
8617c478bd9Sstevel@tonic-gate 				int	parsestat;
8627c478bd9Sstevel@tonic-gate 				/*
8637c478bd9Sstevel@tonic-gate 				 * Normal entry, no +/- nonsense
8647c478bd9Sstevel@tonic-gate 				 */
8657c478bd9Sstevel@tonic-gate 				if (colon != 0) {
8667c478bd9Sstevel@tonic-gate 					*colon = ':';
8677c478bd9Sstevel@tonic-gate 				}
8687c478bd9Sstevel@tonic-gate 				args->returnval = 0;
8697c478bd9Sstevel@tonic-gate 				parsestat = (*args->str2ent)(instr, linelen,
8707c478bd9Sstevel@tonic-gate 							args->buf.result,
8717c478bd9Sstevel@tonic-gate 							args->buf.buffer,
8727c478bd9Sstevel@tonic-gate 							args->buf.buflen);
8737c478bd9Sstevel@tonic-gate 				if (parsestat == NSS_STR_PARSE_SUCCESS) {
8747c478bd9Sstevel@tonic-gate 					args->returnval = args->buf.result;
8757c478bd9Sstevel@tonic-gate 					return (NSS_SUCCESS);
8767c478bd9Sstevel@tonic-gate 				}
8777c478bd9Sstevel@tonic-gate 				/* ==> ?? Treat ERANGE differently ?? */
8787c478bd9Sstevel@tonic-gate 				if (parsestat == NSS_STR_PARSE_ERANGE) {
8797c478bd9Sstevel@tonic-gate 					args->returnval = 0;
8807c478bd9Sstevel@tonic-gate 					args->erange = 1;
8817c478bd9Sstevel@tonic-gate 					return (NSS_NOTFOUND);
8827c478bd9Sstevel@tonic-gate 				}
8837c478bd9Sstevel@tonic-gate 				/* Skip the offending entry, get next */
8847c478bd9Sstevel@tonic-gate 				continue;
8857c478bd9Sstevel@tonic-gate 			} else if (instr[1] == '\0') {
8867c478bd9Sstevel@tonic-gate 				/* Plain "+" */
8877c478bd9Sstevel@tonic-gate 				nss_setent(be->db_rootp, be->db_initf,
8887c478bd9Sstevel@tonic-gate 					&be->db_context);
8897c478bd9Sstevel@tonic-gate 				be->state = GETENT_ALL;
8907c478bd9Sstevel@tonic-gate 				be->linelen = linelen;
8917c478bd9Sstevel@tonic-gate 				continue;
8927c478bd9Sstevel@tonic-gate 			} else if (instr[1] == '@') {
8937c478bd9Sstevel@tonic-gate 				/* "+@netgroup" */
8947c478bd9Sstevel@tonic-gate 				netgr_set(be, instr + 2);
8957c478bd9Sstevel@tonic-gate 				be->state = GETENT_NETGROUP;
8967c478bd9Sstevel@tonic-gate 				be->linelen = linelen;
8977c478bd9Sstevel@tonic-gate 				continue;
8987c478bd9Sstevel@tonic-gate 			} else {
8997c478bd9Sstevel@tonic-gate 				/* "+name" */
9007c478bd9Sstevel@tonic-gate 				name = instr + 1;
9017c478bd9Sstevel@tonic-gate 				break;
9027c478bd9Sstevel@tonic-gate 			}
9037c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 		    case GETENT_ALL:
9067c478bd9Sstevel@tonic-gate 			linelen = be->linelen;
9077c478bd9Sstevel@tonic-gate 			args->returnval = 0;
9087c478bd9Sstevel@tonic-gate 			nss_getent(be->db_rootp, be->db_initf,
9097c478bd9Sstevel@tonic-gate 				&be->db_context, args);
9107c478bd9Sstevel@tonic-gate 			if (args->returnval == 0) {
9117c478bd9Sstevel@tonic-gate 				/* ==> ?? Treat ERANGE differently ?? */
9127c478bd9Sstevel@tonic-gate 				nss_endent(be->db_rootp, be->db_initf,
9137c478bd9Sstevel@tonic-gate 					&be->db_context);
9147c478bd9Sstevel@tonic-gate 				be->state = GETENT_FILE;
9157c478bd9Sstevel@tonic-gate 				continue;
9167c478bd9Sstevel@tonic-gate 			}
9177c478bd9Sstevel@tonic-gate 			if (strset_in(&be->minuses, (*be->getnamef)(args))) {
9187c478bd9Sstevel@tonic-gate 				continue;
9197c478bd9Sstevel@tonic-gate 			}
9207c478bd9Sstevel@tonic-gate 			name = 0; /* tell code below we've done the lookup */
9217c478bd9Sstevel@tonic-gate 			break;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 		    case GETENT_NETGROUP:
9247c478bd9Sstevel@tonic-gate 			linelen = be->linelen;
9257c478bd9Sstevel@tonic-gate 			if (!netgr_next_u(be, &name)) {
9267c478bd9Sstevel@tonic-gate 				netgr_end(be);
9277c478bd9Sstevel@tonic-gate 				be->state = GETENT_FILE;
9287c478bd9Sstevel@tonic-gate 				continue;
9297c478bd9Sstevel@tonic-gate 			}
9307c478bd9Sstevel@tonic-gate 			/* pass "name" variable to code below... */
9317c478bd9Sstevel@tonic-gate 			break;
9327c478bd9Sstevel@tonic-gate 		}
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 		if (name != 0) {
9357c478bd9Sstevel@tonic-gate 			if (strset_in(&be->minuses, name)) {
9367c478bd9Sstevel@tonic-gate 				continue;
9377c478bd9Sstevel@tonic-gate 			}
9387c478bd9Sstevel@tonic-gate 			/*
9397c478bd9Sstevel@tonic-gate 			 * Do a getXXXnam(name).  If we were being pure,
9407c478bd9Sstevel@tonic-gate 			 *   we'd introduce yet another function-pointer
9417c478bd9Sstevel@tonic-gate 			 *   that the database-specific code had to supply
9427c478bd9Sstevel@tonic-gate 			 *   to us.  Instead we'll be grotty and hard-code
9437c478bd9Sstevel@tonic-gate 			 *   the knowledge that
9447c478bd9Sstevel@tonic-gate 			 *	(a) The username is always passwd in key.name,
9457c478bd9Sstevel@tonic-gate 			 *	(b) NSS_DBOP_PASSWD_BYNAME ==
9467c478bd9Sstevel@tonic-gate 			 *		NSS_DBOP_SHADOW_BYNAME ==
9477c478bd9Sstevel@tonic-gate 			 *		NSS_DBOP_next_iter.
9487c478bd9Sstevel@tonic-gate 			 */
9497c478bd9Sstevel@tonic-gate 			savename = args->key.name;
9507c478bd9Sstevel@tonic-gate 			args->key.name	= name;
9517c478bd9Sstevel@tonic-gate 			args->returnval	= 0;
9527c478bd9Sstevel@tonic-gate 			nss_search(be->db_rootp, be->db_initf,
9537c478bd9Sstevel@tonic-gate 				NSS_DBOP_next_iter, args);
9547c478bd9Sstevel@tonic-gate 			args->key.name = savename;  /* In case anyone cares */
9557c478bd9Sstevel@tonic-gate 		}
9567c478bd9Sstevel@tonic-gate 		/*
9577c478bd9Sstevel@tonic-gate 		 * Found one via "+", "+name" or "@netgroup".
9587c478bd9Sstevel@tonic-gate 		 * Override some fields if the /etc file says to do so.
9597c478bd9Sstevel@tonic-gate 		 */
9607c478bd9Sstevel@tonic-gate 		if (args->returnval == 0) {
9617c478bd9Sstevel@tonic-gate 			/* ==> ?? Should treat erange differently? */
9627c478bd9Sstevel@tonic-gate 			continue;
9637c478bd9Sstevel@tonic-gate 		}
9647c478bd9Sstevel@tonic-gate 		/* 'colon' was set umpteen iterations ago in GETENT_FILE */
9657c478bd9Sstevel@tonic-gate 		if (colon != 0) {
9667c478bd9Sstevel@tonic-gate 			*colon = ':';
9677c478bd9Sstevel@tonic-gate 			colon = 0;
9687c478bd9Sstevel@tonic-gate 		}
9697c478bd9Sstevel@tonic-gate 		return (do_merge(be, args, instr, linelen));
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate /* We don't use this directly;  we just copy the bits when we want to	 */
9747c478bd9Sstevel@tonic-gate /* initialize the variable (in the compat_backend struct) that we do use */
9757c478bd9Sstevel@tonic-gate static DEFINE_NSS_GETENT(context_initval);
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate nss_backend_t *
9787c478bd9Sstevel@tonic-gate _nss_compat_constr(ops, n_ops, filename, min_bufsize, rootp, initf, netgroups,
9797c478bd9Sstevel@tonic-gate 		getname_func, merge_func)
9807c478bd9Sstevel@tonic-gate 	compat_backend_op_t	ops[];
9817c478bd9Sstevel@tonic-gate 	int			n_ops;
9827c478bd9Sstevel@tonic-gate 	const char		*filename;
9837c478bd9Sstevel@tonic-gate 	int			min_bufsize;
9847c478bd9Sstevel@tonic-gate 	nss_db_root_t		*rootp;
9857c478bd9Sstevel@tonic-gate 	nss_db_initf_t		initf;
9867c478bd9Sstevel@tonic-gate 	int			netgroups;
9877c478bd9Sstevel@tonic-gate 	compat_get_name		getname_func;
9887c478bd9Sstevel@tonic-gate 	compat_merge_func	merge_func;
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate 	compat_backend_ptr_t	be;
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	if ((be = (compat_backend_ptr_t)malloc(sizeof (*be))) == 0) {
9937c478bd9Sstevel@tonic-gate 		return (0);
9947c478bd9Sstevel@tonic-gate 	}
9957c478bd9Sstevel@tonic-gate 	be->ops		= ops;
9967c478bd9Sstevel@tonic-gate 	be->n_ops	= n_ops;
9977c478bd9Sstevel@tonic-gate 	be->filename	= filename;
9987c478bd9Sstevel@tonic-gate 	be->f		= 0;
9997c478bd9Sstevel@tonic-gate 	be->minbuf	= min_bufsize;
10007c478bd9Sstevel@tonic-gate 	be->buf		= 0;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	be->db_rootp	= rootp;
10037c478bd9Sstevel@tonic-gate 	be->db_initf	= initf;
10047c478bd9Sstevel@tonic-gate 	be->db_context	= context_initval;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	be->getnamef	= getname_func;
10077c478bd9Sstevel@tonic-gate 	be->mergef	= merge_func;
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	if ((strcmp(be->filename, USERATTR_FILENAME) == 0) ||
10107c478bd9Sstevel@tonic-gate 	    (strcmp(be->filename, AUDITUSER_FILENAME) == 0))
10117c478bd9Sstevel@tonic-gate 		be->state = GETENT_ATTRDB;
10127c478bd9Sstevel@tonic-gate 	else
10137c478bd9Sstevel@tonic-gate 		be->state = GETENT_FILE;    /* i.e. do Automatic setent(); */
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	be->minuses	= 0;
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	be->permit_netgroups = netgroups;
10187c478bd9Sstevel@tonic-gate 	be->yp_domain	= 0;
10197c478bd9Sstevel@tonic-gate 	be->getnetgrent_backend	= 0;
10207c478bd9Sstevel@tonic-gate 	be->netgr_buffer = 0;
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	return ((nss_backend_t *)be);
10237c478bd9Sstevel@tonic-gate }
1024