10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  *
260Sstevel@tonic-gate  * Common code and structures used by name-service-switch "compat" backends.
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * Most of the code in the "compat" backend is a perverted form of code from
290Sstevel@tonic-gate  * the "files" backend;  this file is no exception.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate #include <bsm/libbsm.h>
390Sstevel@tonic-gate #include <user_attr.h>
400Sstevel@tonic-gate #include "compat_common.h"
410Sstevel@tonic-gate #include "../../../libnsl/include/nsl_stdio_prv.h"
420Sstevel@tonic-gate 
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate  * This should be in a header.
450Sstevel@tonic-gate  */
460Sstevel@tonic-gate 
470Sstevel@tonic-gate extern int yp_get_default_domain(char **domain);
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Routines to manage list of "-" users for get{pw, sp, gr}ent().  Current
510Sstevel@tonic-gate  *   implementation is completely moronic; we use a linked list.  But then
520Sstevel@tonic-gate  *   that's what it's always done in 4.x...
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate 
550Sstevel@tonic-gate struct setofstrings {
560Sstevel@tonic-gate 	char			*name;
570Sstevel@tonic-gate 	struct setofstrings	*next;
580Sstevel@tonic-gate 	/*
590Sstevel@tonic-gate 	 * === Should get smart and malloc the string and pointer as one
600Sstevel@tonic-gate 	 *	object rather than two.
610Sstevel@tonic-gate 	 */
620Sstevel@tonic-gate };
630Sstevel@tonic-gate typedef struct setofstrings	*strset_t;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate static void
660Sstevel@tonic-gate strset_free(ssp)
670Sstevel@tonic-gate 	strset_t	*ssp;
680Sstevel@tonic-gate {
690Sstevel@tonic-gate 	strset_t	cur, nxt;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	for (cur = *ssp;  cur != 0;  cur = nxt) {
720Sstevel@tonic-gate 		nxt = cur->next;
730Sstevel@tonic-gate 		free(cur->name);
740Sstevel@tonic-gate 		free(cur);
750Sstevel@tonic-gate 	}
760Sstevel@tonic-gate 	*ssp = 0;
770Sstevel@tonic-gate }
780Sstevel@tonic-gate 
790Sstevel@tonic-gate static boolean_t
800Sstevel@tonic-gate strset_add(ssp, nam)
810Sstevel@tonic-gate 	strset_t	*ssp;
820Sstevel@tonic-gate 	const char	*nam;
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	strset_t	new;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	if (0 == (new = (strset_t)malloc(sizeof (*new)))) {
870Sstevel@tonic-gate 		return (B_FALSE);
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 	if (0 == (new->name = malloc(strlen(nam) + 1))) {
900Sstevel@tonic-gate 		free(new);
910Sstevel@tonic-gate 		return (B_FALSE);
920Sstevel@tonic-gate 	}
930Sstevel@tonic-gate 	strcpy(new->name, nam);
940Sstevel@tonic-gate 	new->next = *ssp;
950Sstevel@tonic-gate 	*ssp = new;
960Sstevel@tonic-gate 	return (B_TRUE);
970Sstevel@tonic-gate }
980Sstevel@tonic-gate 
990Sstevel@tonic-gate static boolean_t
1000Sstevel@tonic-gate strset_in(ssp, nam)
1010Sstevel@tonic-gate 	const strset_t	*ssp;
1020Sstevel@tonic-gate 	const char	*nam;
1030Sstevel@tonic-gate {
1040Sstevel@tonic-gate 	strset_t	cur;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	for (cur = *ssp;  cur != 0;  cur = cur->next) {
1070Sstevel@tonic-gate 		if (strcmp(cur->name, nam) == 0) {
1080Sstevel@tonic-gate 			return (B_TRUE);
1090Sstevel@tonic-gate 		}
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 	return (B_FALSE);
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate struct compat_backend {
1160Sstevel@tonic-gate 	compat_backend_op_t	*ops;
1170Sstevel@tonic-gate 	int			n_ops;
1180Sstevel@tonic-gate 	const char		*filename;
1190Sstevel@tonic-gate 	__NSL_FILE		*f;
1200Sstevel@tonic-gate 	int			minbuf;
1210Sstevel@tonic-gate 	char			*buf;
1220Sstevel@tonic-gate 	int			linelen;	/* <== Explain use, lifetime */
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	nss_db_initf_t		db_initf;
1250Sstevel@tonic-gate 	nss_db_root_t		*db_rootp;	/* Shared between instances */
1260Sstevel@tonic-gate 	nss_getent_t		db_context;	/* Per-instance enumeration */
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	compat_get_name		getnamef;
1290Sstevel@tonic-gate 	compat_merge_func	mergef;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	/* We wouldn't need all this hokey state stuff if we */
1320Sstevel@tonic-gate 	/*   used another thread to implement a coroutine... */
1330Sstevel@tonic-gate 	enum {
1340Sstevel@tonic-gate 		GETENT_FILE,
1350Sstevel@tonic-gate 		GETENT_NETGROUP,
1360Sstevel@tonic-gate 		GETENT_ATTRDB,
1370Sstevel@tonic-gate 		GETENT_ALL,
1380Sstevel@tonic-gate 		GETENT_DONE
1390Sstevel@tonic-gate 	}			state;
1400Sstevel@tonic-gate 	strset_t		minuses;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	int			permit_netgroups;
1430Sstevel@tonic-gate 	const char		*yp_domain;
1440Sstevel@tonic-gate 	nss_backend_t		*getnetgrent_backend;
1450Sstevel@tonic-gate 	char			*netgr_buffer;
1460Sstevel@tonic-gate };
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate  * Lookup and enumeration routines for +@group and -@group.
1510Sstevel@tonic-gate  *
1520Sstevel@tonic-gate  * This code knows a lot more about lib/libc/port/gen/getnetgrent.c than
1530Sstevel@tonic-gate  *   is really healthy.  The set/get/end routines below duplicate code
1540Sstevel@tonic-gate  *   from that file, but keep the state information per-backend-instance
1550Sstevel@tonic-gate  *   instead of just per-process.
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate extern void _nss_initf_netgroup(nss_db_params_t *);
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate  * Should really share the db_root in getnetgrent.c in order to get the
1610Sstevel@tonic-gate  *   resource-management quotas right, but this will have to do.
1620Sstevel@tonic-gate  */
1630Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(netgr_db_root);
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate static boolean_t
1660Sstevel@tonic-gate netgr_in(compat_backend_ptr_t be, const char *group, const char *user)
1670Sstevel@tonic-gate {
1680Sstevel@tonic-gate 	if (be->yp_domain == 0) {
1690Sstevel@tonic-gate 		if (yp_get_default_domain((char **)&be->yp_domain) != 0) {
1700Sstevel@tonic-gate 			return (B_FALSE);
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 	return (innetgr(group, 0, user, be->yp_domain));
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate static boolean_t
1770Sstevel@tonic-gate netgr_all_in(compat_backend_ptr_t be, const char *group)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate 	/*
1800Sstevel@tonic-gate 	 * 4.x does this;  ours not to reason why...
1810Sstevel@tonic-gate 	 */
1820Sstevel@tonic-gate 	return (netgr_in(be, group, "*"));
1830Sstevel@tonic-gate }
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate static void
1860Sstevel@tonic-gate netgr_set(be, netgroup)
1870Sstevel@tonic-gate 	compat_backend_ptr_t	be;
1880Sstevel@tonic-gate 	const char		*netgroup;
1890Sstevel@tonic-gate {
1900Sstevel@tonic-gate 	/*
1910Sstevel@tonic-gate 	 * ===> Need comment to explain that this first "if" is optimizing
1920Sstevel@tonic-gate 	 *	for the same-netgroup-as-last-time case
1930Sstevel@tonic-gate 	 */
1940Sstevel@tonic-gate 	if (be->getnetgrent_backend != 0 &&
1950Sstevel@tonic-gate 	    NSS_INVOKE_DBOP(be->getnetgrent_backend,
1960Sstevel@tonic-gate 			    NSS_DBOP_SETENT,
1970Sstevel@tonic-gate 			    (void *) netgroup) != NSS_SUCCESS) {
1980Sstevel@tonic-gate 		NSS_INVOKE_DBOP(be->getnetgrent_backend, NSS_DBOP_DESTRUCTOR,
1990Sstevel@tonic-gate 				0);
2000Sstevel@tonic-gate 		be->getnetgrent_backend = 0;
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 	if (be->getnetgrent_backend == 0) {
2030Sstevel@tonic-gate 		struct nss_setnetgrent_args	args;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 		args.netgroup	= netgroup;
2060Sstevel@tonic-gate 		args.iterator	= 0;
2070Sstevel@tonic-gate 		nss_search(&netgr_db_root, _nss_initf_netgroup,
2080Sstevel@tonic-gate 			NSS_DBOP_NETGROUP_SET, &args);
2090Sstevel@tonic-gate 		be->getnetgrent_backend = args.iterator;
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate static boolean_t
2140Sstevel@tonic-gate netgr_next_u(be, up)
2150Sstevel@tonic-gate 	compat_backend_ptr_t	be;
2160Sstevel@tonic-gate 	char			**up;
2170Sstevel@tonic-gate {
2180Sstevel@tonic-gate 	if (be->netgr_buffer == 0 &&
2190Sstevel@tonic-gate 	    (be->netgr_buffer = malloc(NSS_BUFLEN_NETGROUP)) == 0) {
2200Sstevel@tonic-gate 		/* Out of memory */
2210Sstevel@tonic-gate 		return (B_FALSE);
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	do {
2250Sstevel@tonic-gate 		struct nss_getnetgrent_args	args;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		args.buffer	= be->netgr_buffer;
2280Sstevel@tonic-gate 		args.buflen	= NSS_BUFLEN_NETGROUP;
2290Sstevel@tonic-gate 		args.status	= NSS_NETGR_NO;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 		if (be->getnetgrent_backend != 0) {
2320Sstevel@tonic-gate 			NSS_INVOKE_DBOP(be->getnetgrent_backend,
2330Sstevel@tonic-gate 					NSS_DBOP_GETENT, &args);
2340Sstevel@tonic-gate 		}
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 		if (args.status == NSS_NETGR_FOUND) {
2370Sstevel@tonic-gate 			*up	  = args.retp[NSS_NETGR_USER];
2380Sstevel@tonic-gate 		} else {
2390Sstevel@tonic-gate 			return (B_FALSE);
2400Sstevel@tonic-gate 		}
2410Sstevel@tonic-gate 	} while (*up == 0);
2420Sstevel@tonic-gate 	return (B_TRUE);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate static void
2460Sstevel@tonic-gate netgr_end(be)
2470Sstevel@tonic-gate 	compat_backend_ptr_t	be;
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 	if (be->getnetgrent_backend != 0) {
2500Sstevel@tonic-gate 		NSS_INVOKE_DBOP(be->getnetgrent_backend,
2510Sstevel@tonic-gate 				NSS_DBOP_DESTRUCTOR, 0);
2520Sstevel@tonic-gate 		be->getnetgrent_backend = 0;
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 	if (be->netgr_buffer != 0) {
2550Sstevel@tonic-gate 		free(be->netgr_buffer);
2560Sstevel@tonic-gate 		be->netgr_buffer = 0;
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate #define	MAXFIELDS 9	/* Sufficient for passwd (7), shadow (9), group (4) */
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate static nss_status_t
2640Sstevel@tonic-gate do_merge(be, args, instr, linelen)
2650Sstevel@tonic-gate 	compat_backend_ptr_t	be;
2660Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
2670Sstevel@tonic-gate 	const char		*instr;
2680Sstevel@tonic-gate 	int			linelen;
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate 	char			*fields[MAXFIELDS];
2710Sstevel@tonic-gate 	int			i;
2720Sstevel@tonic-gate 	int			overrides;
2730Sstevel@tonic-gate 	const char		*p;
2740Sstevel@tonic-gate 	const char		*end = instr + linelen;
2750Sstevel@tonic-gate 	nss_status_t		res;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/*
2780Sstevel@tonic-gate 	 * Potential optimization:  only perform the field-splitting nonsense
2790Sstevel@tonic-gate 	 *   once per input line (at present, "+" and "+@netgroup" entries
2800Sstevel@tonic-gate 	 *   will cause us to do this multiple times in getent() requests).
2810Sstevel@tonic-gate 	 */
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	for (i = 0;  i < MAXFIELDS;  i++) {
2840Sstevel@tonic-gate 		fields[i] = 0;
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 	for (p = instr, overrides = 0, i = 0; /* no test */; i++) {
2870Sstevel@tonic-gate 		const char	*q = memchr(p, ':', end - p);
2880Sstevel@tonic-gate 		const char	*r = (q == 0) ? end : q;
2890Sstevel@tonic-gate 		ssize_t		len = r - p;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		if (len > 0) {
2920Sstevel@tonic-gate 			char	*s = malloc(len + 1);
2930Sstevel@tonic-gate 			if (s == 0) {
2940Sstevel@tonic-gate 				overrides = -1;	/* Indicates "you lose" */
2950Sstevel@tonic-gate 				break;
2960Sstevel@tonic-gate 			}
2970Sstevel@tonic-gate 			memcpy(s, p, len);
2980Sstevel@tonic-gate 			s[len] = '\0';
2990Sstevel@tonic-gate 			fields[i] = s;
3000Sstevel@tonic-gate 			overrides++;
3010Sstevel@tonic-gate 		}
3020Sstevel@tonic-gate 		if (q == 0) {
3030Sstevel@tonic-gate 			/* End of line */
3040Sstevel@tonic-gate 			break;
3050Sstevel@tonic-gate 		} else {
3060Sstevel@tonic-gate 			/* Skip the colon at (*q) */
3070Sstevel@tonic-gate 			p = q + 1;
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 	if (overrides == 1) {
3110Sstevel@tonic-gate 		/* No real overrides, return (*args) intact */
3120Sstevel@tonic-gate 		res = NSS_SUCCESS;
3130Sstevel@tonic-gate 	} else if (overrides > 1) {
3140Sstevel@tonic-gate 		/*
3150Sstevel@tonic-gate 		 * The zero'th field is always nonempty (+/-...), but at least
3160Sstevel@tonic-gate 		 *   one other field was also nonempty, i.e. wants to override
3170Sstevel@tonic-gate 		 */
3180Sstevel@tonic-gate 		switch ((*be->mergef)(be, args, (const char **)fields)) {
3190Sstevel@tonic-gate 		    case NSS_STR_PARSE_SUCCESS:
3200Sstevel@tonic-gate 			args->returnval	= args->buf.result;
3210Sstevel@tonic-gate 			args->erange	= 0;
3220Sstevel@tonic-gate 			res = NSS_SUCCESS;
3230Sstevel@tonic-gate 			break;
3240Sstevel@tonic-gate 		    case NSS_STR_PARSE_ERANGE:
3250Sstevel@tonic-gate 			args->returnval	= 0;
3260Sstevel@tonic-gate 			args->erange	= 1;
3270Sstevel@tonic-gate 			res = NSS_NOTFOUND;
3280Sstevel@tonic-gate 			break;
3290Sstevel@tonic-gate 		    case NSS_STR_PARSE_PARSE:
3300Sstevel@tonic-gate 			args->returnval	= 0;
3310Sstevel@tonic-gate 			args->erange	= 0;
3320Sstevel@tonic-gate /* ===> Very likely the wrong thing to do... */
3330Sstevel@tonic-gate 			res = NSS_NOTFOUND;
3340Sstevel@tonic-gate 			break;
3350Sstevel@tonic-gate 		}
3360Sstevel@tonic-gate 	} else {
3370Sstevel@tonic-gate 		args->returnval	= 0;
3380Sstevel@tonic-gate 		args->erange	= 0;
3390Sstevel@tonic-gate 		res = NSS_UNAVAIL;	/* ==> Right? */
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	for (i = 0;  i < MAXFIELDS;  i++) {
3430Sstevel@tonic-gate 		if (fields[i] != 0) {
3440Sstevel@tonic-gate 			free(fields[i]);
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	return (res);
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate /*ARGSUSED*/
3520Sstevel@tonic-gate nss_status_t
3530Sstevel@tonic-gate _nss_compat_setent(be, dummy)
3540Sstevel@tonic-gate 	compat_backend_ptr_t	be;
3550Sstevel@tonic-gate 	void			*dummy;
3560Sstevel@tonic-gate {
3570Sstevel@tonic-gate 	if (be->f == 0) {
3580Sstevel@tonic-gate 		if (be->filename == 0) {
3590Sstevel@tonic-gate 			/* Backend isn't initialized properly? */
3600Sstevel@tonic-gate 			return (NSS_UNAVAIL);
3610Sstevel@tonic-gate 		}
3620Sstevel@tonic-gate 		if ((be->f = __nsl_fopen(be->filename, "r")) == 0) {
3630Sstevel@tonic-gate 			return (NSS_UNAVAIL);
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 	} else {
3660Sstevel@tonic-gate 		__nsl_rewind(be->f);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 	strset_free(&be->minuses);
3690Sstevel@tonic-gate 	/* ===> ??? nss_endent(be->db_rootp, be->db_initf, &be->db_context); */
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	if ((strcmp(be->filename, USERATTR_FILENAME) == 0) ||
3720Sstevel@tonic-gate 	    (strcmp(be->filename, AUDITUSER_FILENAME) == 0))
3730Sstevel@tonic-gate 		be->state = GETENT_ATTRDB;
3740Sstevel@tonic-gate 	else
3750Sstevel@tonic-gate 		be->state = GETENT_FILE;
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	/* ===> ??  netgroup stuff? */
3780Sstevel@tonic-gate 	return (NSS_SUCCESS);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate /*ARGSUSED*/
3820Sstevel@tonic-gate nss_status_t
3830Sstevel@tonic-gate _nss_compat_endent(be, dummy)
3840Sstevel@tonic-gate 	compat_backend_ptr_t	be;
3850Sstevel@tonic-gate 	void			*dummy;
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	if (be->f != 0) {
3880Sstevel@tonic-gate 		__nsl_fclose(be->f);
3890Sstevel@tonic-gate 		be->f = 0;
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 	if (be->buf != 0) {
3920Sstevel@tonic-gate 		free(be->buf);
3930Sstevel@tonic-gate 		be->buf = 0;
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 	nss_endent(be->db_rootp, be->db_initf, &be->db_context);
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	be->state = GETENT_FILE; /* Probably superfluous but comforting */
3980Sstevel@tonic-gate 	strset_free(&be->minuses);
3990Sstevel@tonic-gate 	netgr_end(be);
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	/*
4020Sstevel@tonic-gate 	 * Question: from the point of view of resource-freeing vs. time to
4030Sstevel@tonic-gate 	 *   start up again, how much should we do in endent() and how much
4040Sstevel@tonic-gate 	 *   in the destructor?
4050Sstevel@tonic-gate 	 */
4060Sstevel@tonic-gate 	return (NSS_SUCCESS);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate /*ARGSUSED*/
4100Sstevel@tonic-gate nss_status_t
4110Sstevel@tonic-gate _nss_compat_destr(be, dummy)
4120Sstevel@tonic-gate 	compat_backend_ptr_t	be;
4130Sstevel@tonic-gate 	void			*dummy;
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate 	if (be != 0) {
4160Sstevel@tonic-gate 		if (be->f != 0) {
4170Sstevel@tonic-gate 			_nss_compat_endent(be, 0);
4180Sstevel@tonic-gate 		}
4190Sstevel@tonic-gate 		nss_delete(be->db_rootp);
4200Sstevel@tonic-gate 		nss_delete(&netgr_db_root);
4210Sstevel@tonic-gate 		free(be);
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate 	return (NSS_SUCCESS);	/* In case anyone is dumb enough to check */
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate static int
4270Sstevel@tonic-gate read_line(f, buffer, buflen)
4280Sstevel@tonic-gate 	__NSL_FILE		*f;
4290Sstevel@tonic-gate 	char			*buffer;
4300Sstevel@tonic-gate 	int			buflen;
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate 	/*CONSTCOND*/
4330Sstevel@tonic-gate 	while (1) {
4340Sstevel@tonic-gate 		int	linelen;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 		if (__nsl_fgets(buffer, buflen, f) == 0) {
4370Sstevel@tonic-gate 			/* End of file */
4380Sstevel@tonic-gate 			return (-1);
4390Sstevel@tonic-gate 		}
4400Sstevel@tonic-gate 		linelen = strlen(buffer);
4410Sstevel@tonic-gate 		/* linelen >= 1 (since fgets didn't return 0) */
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 		if (buffer[linelen - 1] == '\n') {
4440Sstevel@tonic-gate 			/*
4450Sstevel@tonic-gate 			 * ===> The code below that calls read_line() doesn't
4460Sstevel@tonic-gate 			 *	play by the rules;  it assumes in places that
4470Sstevel@tonic-gate 			 *	the line is null-terminated.  For now we'll
4480Sstevel@tonic-gate 			 *	humour it.
4490Sstevel@tonic-gate 			 */
4500Sstevel@tonic-gate 			buffer[--linelen] = '\0';
4510Sstevel@tonic-gate 			return (linelen);
4520Sstevel@tonic-gate 		}
4530Sstevel@tonic-gate 		if (__nsl_feof(f)) {
4540Sstevel@tonic-gate 			/* Line is last line in file, and has no newline */
4550Sstevel@tonic-gate 			return (linelen);
4560Sstevel@tonic-gate 		}
4570Sstevel@tonic-gate 		/* Line too long for buffer;  toss it and loop for next line */
4580Sstevel@tonic-gate 		/* ===== should syslog() in cases where previous code did */
4590Sstevel@tonic-gate 		while (__nsl_fgets(buffer, buflen, f) != 0 &&
4600Sstevel@tonic-gate 		    buffer[strlen(buffer) - 1] != '\n') {
4610Sstevel@tonic-gate 			;
4620Sstevel@tonic-gate 		}
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
466*340Svk154806 static int
467*340Svk154806 is_nss_lookup_by_name(int attrdb, nss_dbop_t op)
468*340Svk154806 {
4690Sstevel@tonic-gate 	int result = 0;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	if ((attrdb != 0) &&
472*340Svk154806 	    ((op == NSS_DBOP_AUDITUSER_BYNAME) ||
473*340Svk154806 	    (op == NSS_DBOP_USERATTR_BYNAME))) {
4740Sstevel@tonic-gate 		result = 1;
4750Sstevel@tonic-gate 	} else if ((attrdb == 0) &&
476*340Svk154806 	    ((op == NSS_DBOP_GROUP_BYNAME) ||
477*340Svk154806 	    (op == NSS_DBOP_PASSWD_BYNAME) ||
478*340Svk154806 	    (op == NSS_DBOP_SHADOW_BYNAME))) {
4790Sstevel@tonic-gate 		result = 1;
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	return (result);
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate /*ARGSUSED*/
4860Sstevel@tonic-gate nss_status_t
4870Sstevel@tonic-gate _attrdb_compat_XY_all(be, argp, netdb, check, op_num)
4880Sstevel@tonic-gate     compat_backend_ptr_t be;
4890Sstevel@tonic-gate     nss_XbyY_args_t *argp;
4900Sstevel@tonic-gate     int netdb;
4910Sstevel@tonic-gate     compat_XY_check_func check;
4920Sstevel@tonic-gate     nss_dbop_t op_num;
4930Sstevel@tonic-gate {
4940Sstevel@tonic-gate 	int		parsestat;
4950Sstevel@tonic-gate 	int		(*func)();
4960Sstevel@tonic-gate 	const char	*filter = argp->key.name;
4970Sstevel@tonic-gate 	nss_status_t	res;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate #ifdef	DEBUG
5000Sstevel@tonic-gate 	(void) fprintf(stdout, "\n[compat_common.c: _attrdb_compat_XY_all]\n");
5010Sstevel@tonic-gate #endif	/* DEBUG */
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	if (be->buf == 0 &&
5040Sstevel@tonic-gate 	    (be->buf = malloc(be->minbuf)) == 0) {
5050Sstevel@tonic-gate 		return (NSS_UNAVAIL);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 	if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) {
5080Sstevel@tonic-gate 		return (res);
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 	res = NSS_NOTFOUND;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/*CONSTCOND*/
5130Sstevel@tonic-gate 	while (1) {
5140Sstevel@tonic-gate 		int	linelen;
5150Sstevel@tonic-gate 		char	*instr	= be->buf;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		if ((linelen = read_line(be->f, instr, be->minbuf)) < 0) {
5180Sstevel@tonic-gate 			/* End of file */
5190Sstevel@tonic-gate 			argp->returnval = 0;
5200Sstevel@tonic-gate 			argp->erange    = 0;
5210Sstevel@tonic-gate 			break;
5220Sstevel@tonic-gate 		}
5230Sstevel@tonic-gate 		if (filter != 0 && strstr(instr, filter) == 0) {
5240Sstevel@tonic-gate 			/*
5250Sstevel@tonic-gate 			 * Optimization:  if the entry doesn't contain the
5260Sstevel@tonic-gate 			 * filter string then it can't be the entry we want,
5270Sstevel@tonic-gate 			 * so don't bother looking more closely at it.
5280Sstevel@tonic-gate 			 */
5290Sstevel@tonic-gate 			continue;
5300Sstevel@tonic-gate 		}
5310Sstevel@tonic-gate 		if (netdb) {
5320Sstevel@tonic-gate 			char	*first;
5330Sstevel@tonic-gate 			char	*last;
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 			if ((last = strchr(instr, '#')) == 0) {
5360Sstevel@tonic-gate 				last = instr + linelen;
5370Sstevel@tonic-gate 			}
5380Sstevel@tonic-gate 			*last-- = '\0';		/* Nuke '\n' or #comment */
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 			/*
5410Sstevel@tonic-gate 			 * Skip leading whitespace.  Normally there isn't
5420Sstevel@tonic-gate 			 * any, so it's not worth calling strspn().
5430Sstevel@tonic-gate 			 */
5440Sstevel@tonic-gate 			for (first = instr;  isspace(*first);  first++) {
5450Sstevel@tonic-gate 				;
5460Sstevel@tonic-gate 			}
5470Sstevel@tonic-gate 			if (*first == '\0') {
5480Sstevel@tonic-gate 				continue;
5490Sstevel@tonic-gate 			}
5500Sstevel@tonic-gate 			/*
5510Sstevel@tonic-gate 			 * Found something non-blank on the line.  Skip back
5520Sstevel@tonic-gate 			 * over any trailing whitespace;  since we know
5530Sstevel@tonic-gate 			 * there's non-whitespace earlier in the line,
5540Sstevel@tonic-gate 			 * checking for termination is easy.
5550Sstevel@tonic-gate 			 */
5560Sstevel@tonic-gate 			while (isspace(*last)) {
5570Sstevel@tonic-gate 				--last;
5580Sstevel@tonic-gate 			}
5590Sstevel@tonic-gate 			linelen = last - first + 1;
5600Sstevel@tonic-gate 			if (first != instr) {
5610Sstevel@tonic-gate 				instr = first;
5620Sstevel@tonic-gate 			}
5630Sstevel@tonic-gate 		}
5640Sstevel@tonic-gate 		argp->returnval = 0;
5650Sstevel@tonic-gate 		func = argp->str2ent;
5660Sstevel@tonic-gate 		parsestat = (*func)(instr, linelen, argp->buf.result,
5670Sstevel@tonic-gate 					argp->buf.buffer, argp->buf.buflen);
5680Sstevel@tonic-gate 		if (parsestat == NSS_STR_PARSE_SUCCESS) {
5690Sstevel@tonic-gate 			argp->returnval = argp->buf.result;
5700Sstevel@tonic-gate 			if (check == 0 || (*check)(argp)) {
5710Sstevel@tonic-gate 				res = NSS_SUCCESS;
5720Sstevel@tonic-gate 				break;
5730Sstevel@tonic-gate 			}
5740Sstevel@tonic-gate 		} else if (parsestat == NSS_STR_PARSE_ERANGE) {
5750Sstevel@tonic-gate 			argp->erange = 1;
5760Sstevel@tonic-gate 			break;
5770Sstevel@tonic-gate 		}
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 	/*
5800Sstevel@tonic-gate 	 * stayopen is set to 0 by default in order to close the opened
5810Sstevel@tonic-gate 	 * file.  Some applications may break if it is set to 1.
5820Sstevel@tonic-gate 	 */
5830Sstevel@tonic-gate 	if (check != 0 && !argp->stayopen) {
5840Sstevel@tonic-gate 		(void) _nss_compat_endent(be, 0);
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	if (res != NSS_SUCCESS) {
5880Sstevel@tonic-gate 		if ((op_num == NSS_DBOP_USERATTR_BYNAME) ||
5890Sstevel@tonic-gate 		    (op_num == NSS_DBOP_AUDITUSER_BYNAME)) {
5900Sstevel@tonic-gate 			res = nss_search(be->db_rootp,
5910Sstevel@tonic-gate 			    be->db_initf,
5920Sstevel@tonic-gate 			    op_num,
5930Sstevel@tonic-gate 			    argp);
5940Sstevel@tonic-gate 		} else {
5950Sstevel@tonic-gate 			res = nss_getent(be->db_rootp,
5960Sstevel@tonic-gate 			    be->db_initf, &be->db_context, argp);
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 		if (res != NSS_SUCCESS) {
5990Sstevel@tonic-gate 			argp->returnval	= 0;
6000Sstevel@tonic-gate 			argp->erange	= 0;
6010Sstevel@tonic-gate 		}
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	return (res);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate nss_status_t
6080Sstevel@tonic-gate _nss_compat_XY_all(be, args, check, op_num)
6090Sstevel@tonic-gate 	compat_backend_ptr_t	be;
6100Sstevel@tonic-gate 	nss_XbyY_args_t		*args;
6110Sstevel@tonic-gate 	compat_XY_check_func	check;
6120Sstevel@tonic-gate 	nss_dbop_t		op_num;
6130Sstevel@tonic-gate {
6140Sstevel@tonic-gate 	nss_status_t		res;
6150Sstevel@tonic-gate 	int			parsestat;
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	if (be->buf == 0 &&
6180Sstevel@tonic-gate 	    (be->buf = malloc(be->minbuf)) == 0) {
6190Sstevel@tonic-gate 		return (NSS_UNAVAIL); /* really panic, malloc failed */
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) {
6230Sstevel@tonic-gate 		return (res);
6240Sstevel@tonic-gate 	}
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	res = NSS_NOTFOUND;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	/*CONSTCOND*/
6290Sstevel@tonic-gate 	while (1) {
6300Sstevel@tonic-gate 		int		linelen;
6310Sstevel@tonic-gate 		char		*instr	= be->buf;
6320Sstevel@tonic-gate 		char		*colon;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 		linelen = read_line(be->f, instr, be->minbuf);
6350Sstevel@tonic-gate 		if (linelen < 0) {
6360Sstevel@tonic-gate 			/* End of file */
6370Sstevel@tonic-gate 			args->returnval = 0;
6380Sstevel@tonic-gate 			args->erange    = 0;
6390Sstevel@tonic-gate 			break;
6400Sstevel@tonic-gate 		}
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		args->returnval = 0;	/* reset for both types of entries */
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 		if (instr[0] != '+' && instr[0] != '-') {
6450Sstevel@tonic-gate 			/* Simple, wholesome, God-fearing entry */
6460Sstevel@tonic-gate 			parsestat = (*args->str2ent)(instr, linelen,
6470Sstevel@tonic-gate 						    args->buf.result,
6480Sstevel@tonic-gate 						    args->buf.buffer,
6490Sstevel@tonic-gate 						    args->buf.buflen);
6500Sstevel@tonic-gate 			if (parsestat == NSS_STR_PARSE_SUCCESS) {
6510Sstevel@tonic-gate 				args->returnval = args->buf.result;
6520Sstevel@tonic-gate 				if ((*check)(args) != 0) {
6530Sstevel@tonic-gate 					res = NSS_SUCCESS;
6540Sstevel@tonic-gate 					break;
6550Sstevel@tonic-gate 				}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate /* ===> Check the Dani logic here... */
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 			} else if (parsestat == NSS_STR_PARSE_ERANGE) {
6600Sstevel@tonic-gate 				args->erange = 1;
6610Sstevel@tonic-gate 				res = NSS_NOTFOUND;
6620Sstevel@tonic-gate 				break;
6630Sstevel@tonic-gate 				/* should we just skip this one long line ? */
6640Sstevel@tonic-gate 			} /* else if (parsestat == NSS_STR_PARSE_PARSE) */
6650Sstevel@tonic-gate 				/* don't care ! */
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate /* ==> ?? */		continue;
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 		/*
6710Sstevel@tonic-gate 		 * Process "+", "+name", "+@netgroup", "-name" or "-@netgroup"
6720Sstevel@tonic-gate 		 *
6730Sstevel@tonic-gate 		 * This code is optimized for lookups by name.
6740Sstevel@tonic-gate 		 *
6750Sstevel@tonic-gate 		 * For lookups by identifier search key cannot be matched with
6760Sstevel@tonic-gate 		 * the name of the "+" or "-" entry. So nss_search() is to be
6770Sstevel@tonic-gate 		 * called before extracting the name i.e. via (*be->getnamef)().
6780Sstevel@tonic-gate 		 *
6790Sstevel@tonic-gate 		 * But for lookups by name, search key is compared with the name
6800Sstevel@tonic-gate 		 * of the "+" or "-" entry to acquire a match and thus
6810Sstevel@tonic-gate 		 * unnesessary calls to nss_search() is eliminated. Also for
6820Sstevel@tonic-gate 		 * matching "-" entries, calls to nss_search() is eliminated.
6830Sstevel@tonic-gate 		 */
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 		if ((colon = strchr(instr, ':')) != 0) {
6860Sstevel@tonic-gate 			*colon = '\0';	/* terminate field to extract name */
6870Sstevel@tonic-gate 		}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 		if (instr[1] == '@') {
6900Sstevel@tonic-gate 			/*
6910Sstevel@tonic-gate 			 * Case 1:
6920Sstevel@tonic-gate 			 * The entry is of the form "+@netgroup" or
6930Sstevel@tonic-gate 			 * "-@netgroup".  If we're performing a lookup by name,
6940Sstevel@tonic-gate 			 * we can simply extract the name from the search key
6950Sstevel@tonic-gate 			 * (i.e. args->key.name).  If not, then we must call
6960Sstevel@tonic-gate 			 * nss_search() before extracting the name via the
6970Sstevel@tonic-gate 			 * get_XXname() function. i.e. (*be->getnamef)(args).
6980Sstevel@tonic-gate 			 */
699*340Svk154806 			if (is_nss_lookup_by_name(0, op_num) != 0) {
700*340Svk154806 				/* compare then search */
701*340Svk154806 				if (!be->permit_netgroups ||
702*340Svk154806 				    !netgr_in(be, instr + 2, args->key.name))
703*340Svk154806 					continue;
704*340Svk154806 				if (instr[0] == '+') {
705*340Svk154806 					/* need to search for "+" entry */
706*340Svk154806 					nss_search(be->db_rootp, be->db_initf,
707*340Svk154806 					    op_num, args);
708*340Svk154806 					if (args->returnval == 0)
709*340Svk154806 						continue;
710*340Svk154806 				}
711*340Svk154806 			} else {
712*340Svk154806 				/* search then compare */
7130Sstevel@tonic-gate 				nss_search(be->db_rootp, be->db_initf, op_num,
714*340Svk154806 				    args);
7150Sstevel@tonic-gate 				if (args->returnval == 0)
7160Sstevel@tonic-gate 					continue;
717*340Svk154806 				if (!be->permit_netgroups ||
718*340Svk154806 				    !netgr_in(be, instr + 2,
719*340Svk154806 				    (*be->getnamef)(args)))
720*340Svk154806 					continue;
7210Sstevel@tonic-gate 			}
722*340Svk154806 		} else if (instr[1] == '\0') {
7230Sstevel@tonic-gate 			/*
7240Sstevel@tonic-gate 			 * Case 2:
7250Sstevel@tonic-gate 			 * The entry is of the form "+" or "-".  The former
7260Sstevel@tonic-gate 			 * allows all entries from name services.  The latter
7270Sstevel@tonic-gate 			 * is illegal and ought to be ignored.
7280Sstevel@tonic-gate 			 */
7290Sstevel@tonic-gate 			if (instr[0] == '-')
7300Sstevel@tonic-gate 				continue;
7310Sstevel@tonic-gate 			/* need to search for "+" entry */
7320Sstevel@tonic-gate 			nss_search(be->db_rootp, be->db_initf, op_num, args);
7330Sstevel@tonic-gate 			if (args->returnval == 0)
7340Sstevel@tonic-gate 				continue;
735*340Svk154806 		} else {
7360Sstevel@tonic-gate 			/*
7370Sstevel@tonic-gate 			 * Case 3:
7380Sstevel@tonic-gate 			 * The entry is of the form "+name" or "-name".
7390Sstevel@tonic-gate 			 * If we're performing a lookup by name, we can simply
7400Sstevel@tonic-gate 			 * extract the name from the search key
7410Sstevel@tonic-gate 			 * (i.e. args->key.name).  If not, then we must call
7420Sstevel@tonic-gate 			 * nss_search() before extracting the name via the
7430Sstevel@tonic-gate 			 * get_XXname() function. i.e. (*be->getnamef)(args).
7440Sstevel@tonic-gate 			 */
745*340Svk154806 			if (is_nss_lookup_by_name(0, op_num) != 0) {
7460Sstevel@tonic-gate 				/* compare then search */
7470Sstevel@tonic-gate 				if (strcmp(instr + 1, args->key.name) != 0)
7480Sstevel@tonic-gate 					continue;
7490Sstevel@tonic-gate 				if (instr[0] == '+') {
7500Sstevel@tonic-gate 					/* need to search for "+" entry */
7510Sstevel@tonic-gate 					nss_search(be->db_rootp, be->db_initf,
752*340Svk154806 					    op_num, args);
7530Sstevel@tonic-gate 					if (args->returnval == 0)
7540Sstevel@tonic-gate 						continue;
7550Sstevel@tonic-gate 				}
7560Sstevel@tonic-gate 			} else {
7570Sstevel@tonic-gate 				/* search then compare */
7580Sstevel@tonic-gate 				nss_search(be->db_rootp, be->db_initf, op_num,
759*340Svk154806 				    args);
7600Sstevel@tonic-gate 				if (args->returnval == 0)
7610Sstevel@tonic-gate 					continue;
7620Sstevel@tonic-gate 				if (strcmp(instr + 1, (*be->getnamef)(args))
763*340Svk154806 				    != 0)
7640Sstevel@tonic-gate 					continue;
7650Sstevel@tonic-gate 			}
766*340Svk154806 		}
7670Sstevel@tonic-gate 		if (instr[0] == '-') {
7680Sstevel@tonic-gate 			/* no need to search for "-" entry */
7690Sstevel@tonic-gate 			args->returnval = 0;
7700Sstevel@tonic-gate 			args->erange = 0;
7710Sstevel@tonic-gate 			res = NSS_NOTFOUND;
7720Sstevel@tonic-gate 		} else {
7730Sstevel@tonic-gate 			if (colon != 0)
774*340Svk154806 				*colon = ':';	/* restoration */
7750Sstevel@tonic-gate 			res = do_merge(be, args, instr, linelen);
7760Sstevel@tonic-gate 		}
7770Sstevel@tonic-gate 		break;
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	/*
7810Sstevel@tonic-gate 	 * stayopen is set to 0 by default in order to close the opened
7820Sstevel@tonic-gate 	 * file.  Some applications may break if it is set to 1.
7830Sstevel@tonic-gate 	 */
7840Sstevel@tonic-gate 	if (!args->stayopen) {
7850Sstevel@tonic-gate 		(void) _nss_compat_endent(be, 0);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	return (res);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate nss_status_t
7920Sstevel@tonic-gate _nss_compat_getent(be, a)
7930Sstevel@tonic-gate 	compat_backend_ptr_t	be;
7940Sstevel@tonic-gate 	void			*a;
7950Sstevel@tonic-gate {
7960Sstevel@tonic-gate 	nss_XbyY_args_t		*args = (nss_XbyY_args_t *)a;
7970Sstevel@tonic-gate 	nss_status_t		res;
7980Sstevel@tonic-gate 	char			*colon = 0; /* <=== need comment re lifetime */
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (be->f == 0) {
8010Sstevel@tonic-gate 		if ((res = _nss_compat_setent(be, 0)) != NSS_SUCCESS) {
8020Sstevel@tonic-gate 			return (res);
8030Sstevel@tonic-gate 		}
8040Sstevel@tonic-gate 	}
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	if (be->buf == 0 &&
8070Sstevel@tonic-gate 	    (be->buf = malloc(be->minbuf)) == 0) {
8080Sstevel@tonic-gate 		return (NSS_UNAVAIL); /* really panic, malloc failed */
8090Sstevel@tonic-gate 	}
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	/*CONSTCOND*/
8120Sstevel@tonic-gate 	while (1) {
8130Sstevel@tonic-gate 		char		*instr	= be->buf;
8140Sstevel@tonic-gate 		int		linelen;
8150Sstevel@tonic-gate 		char		*name;	/* === Need more distinctive label */
8160Sstevel@tonic-gate 		const char	*savename;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		/*
8190Sstevel@tonic-gate 		 * In the code below...
8200Sstevel@tonic-gate 		 *    break	means "I found one, I think" (i.e. goto the
8210Sstevel@tonic-gate 		 *		code after the end of the switch statement),
8220Sstevel@tonic-gate 		 *    continue	means "Next candidate"
8230Sstevel@tonic-gate 		 *		(i.e. loop around to the switch statement),
8240Sstevel@tonic-gate 		 *    return	means "I'm quite sure" (either Yes or No).
8250Sstevel@tonic-gate 		 */
8260Sstevel@tonic-gate 		switch (be->state) {
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 		    case GETENT_DONE:
8290Sstevel@tonic-gate 			args->returnval	= 0;
8300Sstevel@tonic-gate 			args->erange	= 0;
8310Sstevel@tonic-gate 			return (NSS_NOTFOUND);
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		    case GETENT_ATTRDB:
8340Sstevel@tonic-gate 			res = _attrdb_compat_XY_all(be,
8350Sstevel@tonic-gate 			    args, 1, (compat_XY_check_func)NULL, 0);
8360Sstevel@tonic-gate 			return (res);
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 		    case GETENT_FILE:
8390Sstevel@tonic-gate 			linelen = read_line(be->f, instr, be->minbuf);
8400Sstevel@tonic-gate 			if (linelen < 0) {
8410Sstevel@tonic-gate 				/* End of file */
8420Sstevel@tonic-gate 				be->state = GETENT_DONE;
8430Sstevel@tonic-gate 				continue;
8440Sstevel@tonic-gate 			}
8450Sstevel@tonic-gate 			if ((colon = strchr(instr, ':')) != 0) {
8460Sstevel@tonic-gate 				*colon = '\0';
8470Sstevel@tonic-gate 			}
8480Sstevel@tonic-gate 			if (instr[0] == '-') {
8490Sstevel@tonic-gate 				if (instr[1] != '@') {
8500Sstevel@tonic-gate 					strset_add(&be->minuses, instr + 1);
8510Sstevel@tonic-gate 				} else if (be->permit_netgroups) {
8520Sstevel@tonic-gate 					netgr_set(be, instr + 2);
8530Sstevel@tonic-gate 					while (netgr_next_u(be, &name)) {
8540Sstevel@tonic-gate 						strset_add(&be->minuses,
8550Sstevel@tonic-gate 							name);
8560Sstevel@tonic-gate 					}
8570Sstevel@tonic-gate 					netgr_end(be);
8580Sstevel@tonic-gate 				} /* Else (silently) ignore the entry */
8590Sstevel@tonic-gate 				continue;
8600Sstevel@tonic-gate 			} else if (instr[0] != '+') {
8610Sstevel@tonic-gate 				int	parsestat;
8620Sstevel@tonic-gate 				/*
8630Sstevel@tonic-gate 				 * Normal entry, no +/- nonsense
8640Sstevel@tonic-gate 				 */
8650Sstevel@tonic-gate 				if (colon != 0) {
8660Sstevel@tonic-gate 					*colon = ':';
8670Sstevel@tonic-gate 				}
8680Sstevel@tonic-gate 				args->returnval = 0;
8690Sstevel@tonic-gate 				parsestat = (*args->str2ent)(instr, linelen,
8700Sstevel@tonic-gate 							args->buf.result,
8710Sstevel@tonic-gate 							args->buf.buffer,
8720Sstevel@tonic-gate 							args->buf.buflen);
8730Sstevel@tonic-gate 				if (parsestat == NSS_STR_PARSE_SUCCESS) {
8740Sstevel@tonic-gate 					args->returnval = args->buf.result;
8750Sstevel@tonic-gate 					return (NSS_SUCCESS);
8760Sstevel@tonic-gate 				}
8770Sstevel@tonic-gate 				/* ==> ?? Treat ERANGE differently ?? */
8780Sstevel@tonic-gate 				if (parsestat == NSS_STR_PARSE_ERANGE) {
8790Sstevel@tonic-gate 					args->returnval = 0;
8800Sstevel@tonic-gate 					args->erange = 1;
8810Sstevel@tonic-gate 					return (NSS_NOTFOUND);
8820Sstevel@tonic-gate 				}
8830Sstevel@tonic-gate 				/* Skip the offending entry, get next */
8840Sstevel@tonic-gate 				continue;
8850Sstevel@tonic-gate 			} else if (instr[1] == '\0') {
8860Sstevel@tonic-gate 				/* Plain "+" */
8870Sstevel@tonic-gate 				nss_setent(be->db_rootp, be->db_initf,
8880Sstevel@tonic-gate 					&be->db_context);
8890Sstevel@tonic-gate 				be->state = GETENT_ALL;
8900Sstevel@tonic-gate 				be->linelen = linelen;
8910Sstevel@tonic-gate 				continue;
8920Sstevel@tonic-gate 			} else if (instr[1] == '@') {
8930Sstevel@tonic-gate 				/* "+@netgroup" */
8940Sstevel@tonic-gate 				netgr_set(be, instr + 2);
8950Sstevel@tonic-gate 				be->state = GETENT_NETGROUP;
8960Sstevel@tonic-gate 				be->linelen = linelen;
8970Sstevel@tonic-gate 				continue;
8980Sstevel@tonic-gate 			} else {
8990Sstevel@tonic-gate 				/* "+name" */
9000Sstevel@tonic-gate 				name = instr + 1;
9010Sstevel@tonic-gate 				break;
9020Sstevel@tonic-gate 			}
9030Sstevel@tonic-gate 			/* NOTREACHED */
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 		    case GETENT_ALL:
9060Sstevel@tonic-gate 			linelen = be->linelen;
9070Sstevel@tonic-gate 			args->returnval = 0;
9080Sstevel@tonic-gate 			nss_getent(be->db_rootp, be->db_initf,
9090Sstevel@tonic-gate 				&be->db_context, args);
9100Sstevel@tonic-gate 			if (args->returnval == 0) {
9110Sstevel@tonic-gate 				/* ==> ?? Treat ERANGE differently ?? */
9120Sstevel@tonic-gate 				nss_endent(be->db_rootp, be->db_initf,
9130Sstevel@tonic-gate 					&be->db_context);
9140Sstevel@tonic-gate 				be->state = GETENT_FILE;
9150Sstevel@tonic-gate 				continue;
9160Sstevel@tonic-gate 			}
9170Sstevel@tonic-gate 			if (strset_in(&be->minuses, (*be->getnamef)(args))) {
9180Sstevel@tonic-gate 				continue;
9190Sstevel@tonic-gate 			}
9200Sstevel@tonic-gate 			name = 0; /* tell code below we've done the lookup */
9210Sstevel@tonic-gate 			break;
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 		    case GETENT_NETGROUP:
9240Sstevel@tonic-gate 			linelen = be->linelen;
9250Sstevel@tonic-gate 			if (!netgr_next_u(be, &name)) {
9260Sstevel@tonic-gate 				netgr_end(be);
9270Sstevel@tonic-gate 				be->state = GETENT_FILE;
9280Sstevel@tonic-gate 				continue;
9290Sstevel@tonic-gate 			}
9300Sstevel@tonic-gate 			/* pass "name" variable to code below... */
9310Sstevel@tonic-gate 			break;
9320Sstevel@tonic-gate 		}
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 		if (name != 0) {
9350Sstevel@tonic-gate 			if (strset_in(&be->minuses, name)) {
9360Sstevel@tonic-gate 				continue;
9370Sstevel@tonic-gate 			}
9380Sstevel@tonic-gate 			/*
9390Sstevel@tonic-gate 			 * Do a getXXXnam(name).  If we were being pure,
9400Sstevel@tonic-gate 			 *   we'd introduce yet another function-pointer
9410Sstevel@tonic-gate 			 *   that the database-specific code had to supply
9420Sstevel@tonic-gate 			 *   to us.  Instead we'll be grotty and hard-code
9430Sstevel@tonic-gate 			 *   the knowledge that
9440Sstevel@tonic-gate 			 *	(a) The username is always passwd in key.name,
9450Sstevel@tonic-gate 			 *	(b) NSS_DBOP_PASSWD_BYNAME ==
9460Sstevel@tonic-gate 			 *		NSS_DBOP_SHADOW_BYNAME ==
9470Sstevel@tonic-gate 			 *		NSS_DBOP_next_iter.
9480Sstevel@tonic-gate 			 */
9490Sstevel@tonic-gate 			savename = args->key.name;
9500Sstevel@tonic-gate 			args->key.name	= name;
9510Sstevel@tonic-gate 			args->returnval	= 0;
9520Sstevel@tonic-gate 			nss_search(be->db_rootp, be->db_initf,
9530Sstevel@tonic-gate 				NSS_DBOP_next_iter, args);
9540Sstevel@tonic-gate 			args->key.name = savename;  /* In case anyone cares */
9550Sstevel@tonic-gate 		}
9560Sstevel@tonic-gate 		/*
9570Sstevel@tonic-gate 		 * Found one via "+", "+name" or "@netgroup".
9580Sstevel@tonic-gate 		 * Override some fields if the /etc file says to do so.
9590Sstevel@tonic-gate 		 */
9600Sstevel@tonic-gate 		if (args->returnval == 0) {
9610Sstevel@tonic-gate 			/* ==> ?? Should treat erange differently? */
9620Sstevel@tonic-gate 			continue;
9630Sstevel@tonic-gate 		}
9640Sstevel@tonic-gate 		/* 'colon' was set umpteen iterations ago in GETENT_FILE */
9650Sstevel@tonic-gate 		if (colon != 0) {
9660Sstevel@tonic-gate 			*colon = ':';
9670Sstevel@tonic-gate 			colon = 0;
9680Sstevel@tonic-gate 		}
9690Sstevel@tonic-gate 		return (do_merge(be, args, instr, linelen));
9700Sstevel@tonic-gate 	}
9710Sstevel@tonic-gate }
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate /* We don't use this directly;  we just copy the bits when we want to	 */
9740Sstevel@tonic-gate /* initialize the variable (in the compat_backend struct) that we do use */
9750Sstevel@tonic-gate static DEFINE_NSS_GETENT(context_initval);
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate nss_backend_t *
9780Sstevel@tonic-gate _nss_compat_constr(ops, n_ops, filename, min_bufsize, rootp, initf, netgroups,
9790Sstevel@tonic-gate 		getname_func, merge_func)
9800Sstevel@tonic-gate 	compat_backend_op_t	ops[];
9810Sstevel@tonic-gate 	int			n_ops;
9820Sstevel@tonic-gate 	const char		*filename;
9830Sstevel@tonic-gate 	int			min_bufsize;
9840Sstevel@tonic-gate 	nss_db_root_t		*rootp;
9850Sstevel@tonic-gate 	nss_db_initf_t		initf;
9860Sstevel@tonic-gate 	int			netgroups;
9870Sstevel@tonic-gate 	compat_get_name		getname_func;
9880Sstevel@tonic-gate 	compat_merge_func	merge_func;
9890Sstevel@tonic-gate {
9900Sstevel@tonic-gate 	compat_backend_ptr_t	be;
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	if ((be = (compat_backend_ptr_t)malloc(sizeof (*be))) == 0) {
9930Sstevel@tonic-gate 		return (0);
9940Sstevel@tonic-gate 	}
9950Sstevel@tonic-gate 	be->ops		= ops;
9960Sstevel@tonic-gate 	be->n_ops	= n_ops;
9970Sstevel@tonic-gate 	be->filename	= filename;
9980Sstevel@tonic-gate 	be->f		= 0;
9990Sstevel@tonic-gate 	be->minbuf	= min_bufsize;
10000Sstevel@tonic-gate 	be->buf		= 0;
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	be->db_rootp	= rootp;
10030Sstevel@tonic-gate 	be->db_initf	= initf;
10040Sstevel@tonic-gate 	be->db_context	= context_initval;
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	be->getnamef	= getname_func;
10070Sstevel@tonic-gate 	be->mergef	= merge_func;
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	if ((strcmp(be->filename, USERATTR_FILENAME) == 0) ||
10100Sstevel@tonic-gate 	    (strcmp(be->filename, AUDITUSER_FILENAME) == 0))
10110Sstevel@tonic-gate 		be->state = GETENT_ATTRDB;
10120Sstevel@tonic-gate 	else
10130Sstevel@tonic-gate 		be->state = GETENT_FILE;    /* i.e. do Automatic setent(); */
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	be->minuses	= 0;
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	be->permit_netgroups = netgroups;
10180Sstevel@tonic-gate 	be->yp_domain	= 0;
10190Sstevel@tonic-gate 	be->getnetgrent_backend	= 0;
10200Sstevel@tonic-gate 	be->netgr_buffer = 0;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	return ((nss_backend_t *)be);
10230Sstevel@tonic-gate }
1024