Index: /trunk/src/emx/src/lib/bsd/gen/getgrent.c
===================================================================
--- /trunk/src/emx/src/lib/bsd/gen/getgrent.c	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/gen/getgrent.c	(revision 1499)
@@ -0,0 +1,1149 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/gen/getgrent.c,v 1.31 2003/05/01 19:03:13 nectar Exp $");
+
+#include "namespace.h"
+#include <sys/param.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#include <grp.h>
+#include <nsswitch.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "nss_tls.h"
+
+
+enum constants {
+	GRP_STORAGE_INITIAL	= 1 << 10, /* 1 KByte */
+	GRP_STORAGE_MAX		= 1 << 20, /* 1 MByte */
+	SETGRENT		= 1,
+	ENDGRENT		= 2,
+	HESIOD_NAME_MAX		= 256,
+};
+
+static const ns_src defaultsrc[] = {
+	{ NSSRC_COMPAT, NS_SUCCESS },
+	{ NULL, 0 }
+};
+
+int	 __gr_match_entry(const char *, size_t, enum nss_lookup_type,
+	    const char *, gid_t);
+int	 __gr_parse_entry(char *, size_t, struct group *, char *, size_t,
+	    int *);
+
+static	int	 is_comment_line(const char *, size_t);
+
+union key {
+	const char	*name;
+	gid_t		 gid;
+};
+static	struct group *getgr(int (*)(union key, struct group *, char *, size_t,
+		    struct group **), union key);
+static	int	 wrap_getgrnam_r(union key, struct group *, char *, size_t,
+		    struct group **);
+static	int	 wrap_getgrgid_r(union key, struct group *, char *, size_t,
+		    struct group **);
+static	int	 wrap_getgrent_r(union key, struct group *, char *, size_t,
+		    struct group **);
+
+struct files_state {
+	FILE	*fp;
+	int	 stayopen;
+};
+static	void	 files_endstate(void *);
+NSS_TLS_HANDLING(files);
+static	int	 files_setgrent(void *, void *, va_list);
+static	int	 files_group(void *, void *, va_list);
+
+
+#ifdef HESIOD
+struct dns_state {
+	long	counter;
+};
+static	void	 dns_endstate(void *);
+NSS_TLS_HANDLING(dns);
+static	int	 dns_setgrent(void *, void *, va_list);
+static	int	 dns_group(void *, void *, va_list);
+#endif
+
+
+#ifdef YP
+struct nis_state {
+	char	 domain[MAXHOSTNAMELEN];
+	int	 done;
+	char	*key;
+	int	 keylen;
+};
+static	void	 nis_endstate(void *);
+NSS_TLS_HANDLING(nis);
+static	int	 nis_setgrent(void *, void *, va_list);
+static	int	 nis_group(void *, void *, va_list);
+#endif
+
+struct compat_state {
+	FILE	*fp;
+	int	 stayopen;
+	char	*name;
+	enum _compat {
+		COMPAT_MODE_OFF = 0,
+		COMPAT_MODE_ALL,
+		COMPAT_MODE_NAME
+	}	 compat;
+};
+static	void	 compat_endstate(void *);
+NSS_TLS_HANDLING(compat);
+static	int	 compat_setgrent(void *, void *, va_list);
+static	int	 compat_group(void *, void *, va_list);
+
+
+/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */
+int				
+setgrent(void)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_setgrent, (void *)SETGRENT },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
+#endif
+		{ NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
+		{ NULL, NULL, NULL }
+	};
+	(void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
+	return (1);
+}
+
+
+int
+setgroupent(int stayopen)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_setgrent, (void *)SETGRENT },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
+#endif
+		{ NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
+		{ NULL, NULL, NULL }
+	};
+	(void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc,
+	    stayopen);
+	return (1);
+}
+
+
+void
+endgrent(void)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_setgrent, (void *)ENDGRENT },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_setgrent, (void *)ENDGRENT },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_setgrent, (void *)ENDGRENT },
+#endif
+		{ NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT },
+		{ NULL, NULL, NULL }
+	};
+	(void)_nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent", defaultsrc);
+}
+
+
+int
+getgrent_r(struct group *grp, char *buffer, size_t bufsize,
+    struct group **result)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_group, (void *)nss_lt_all },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_group, (void *)nss_lt_all },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_group, (void *)nss_lt_all },
+#endif
+		{ NSSRC_COMPAT, compat_group, (void *)nss_lt_all },
+		{ NULL, NULL, NULL }
+	};
+	int	rv, ret_errno;
+
+	ret_errno = 0;
+	*result = NULL;
+	rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrent_r", defaultsrc,
+	    grp, buffer, bufsize, &ret_errno);
+	if (rv == NS_SUCCESS)
+		return (0);
+	else
+		return (ret_errno);
+}
+
+
+int
+getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize,
+    struct group **result)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_group, (void *)nss_lt_name },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_group, (void *)nss_lt_name },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_group, (void *)nss_lt_name },
+#endif
+		{ NSSRC_COMPAT, compat_group, (void *)nss_lt_name },
+		{ NULL, NULL, NULL }
+	};
+	int	rv, ret_errno;
+
+	ret_errno = 0;
+	*result = NULL;
+	rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc,
+	    name, grp, buffer, bufsize, &ret_errno);
+	if (rv == NS_SUCCESS)
+		return (0);
+	else
+		return (ret_errno);
+}
+
+
+int
+getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
+    struct group **result)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_group, (void *)nss_lt_id },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_group, (void *)nss_lt_id },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_group, (void *)nss_lt_id },
+#endif
+		{ NSSRC_COMPAT, compat_group, (void *)nss_lt_id },
+		{ NULL, NULL, NULL }
+	};
+	int	rv, ret_errno;
+
+	ret_errno = 0;
+	*result = NULL;
+	rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc,
+	    gid, grp, buffer, bufsize, &ret_errno);
+	if (rv == NS_SUCCESS)
+		return (0);
+	else
+		return (ret_errno);
+}
+
+
+static struct group	 grp;
+static char		*grp_storage;
+static size_t		 grp_storage_size;
+
+static struct group *
+getgr(int (*fn)(union key, struct group *, char *, size_t, struct group **),
+    union key key)
+{
+	int		 rv;
+	struct group	*res;
+
+	if (grp_storage == NULL) {
+		grp_storage = malloc(GRP_STORAGE_INITIAL);
+		if (grp_storage == NULL)
+			return (NULL);
+		grp_storage_size = GRP_STORAGE_INITIAL;
+	}
+	do {
+		rv = fn(key, &grp, grp_storage, grp_storage_size, &res);
+		if (res == NULL && rv == ERANGE) {
+			free(grp_storage);
+			if ((grp_storage_size << 1) > GRP_STORAGE_MAX) {
+				grp_storage = NULL;
+				return (NULL);
+			}
+			grp_storage_size <<= 1;
+			grp_storage = malloc(grp_storage_size);
+			if (grp_storage == NULL)
+				return (NULL);
+		}
+	} while (res == NULL && rv == ERANGE);
+	return (res);
+}
+
+
+static int
+wrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize,
+    struct group **res)
+{
+	return (getgrnam_r(key.name, grp, buffer, bufsize, res));
+}
+
+
+static int
+wrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize,
+    struct group **res)
+{
+	return (getgrgid_r(key.gid, grp, buffer, bufsize, res));
+}
+
+
+static int
+wrap_getgrent_r(union key key __unused, struct group *grp, char *buffer,
+    size_t bufsize, struct group **res)
+{
+	return (getgrent_r(grp, buffer, bufsize, res));
+}
+
+
+struct group *
+getgrnam(const char *name)
+{
+	union key key;
+
+	key.name = name;
+	return (getgr(wrap_getgrnam_r, key));
+}
+
+
+struct group *
+getgrgid(gid_t gid)
+{
+	union key key;
+
+	key.gid = gid;
+	return (getgr(wrap_getgrgid_r, key));
+}
+
+
+struct group *
+getgrent(void)
+{
+	union key key;
+
+	key.gid = 0; /* not used */
+	return (getgr(wrap_getgrent_r, key));
+}
+
+
+static int
+is_comment_line(const char *s, size_t n)
+{
+	const char	*eom;
+
+	eom = &s[n];
+
+	for (; s < eom; s++)
+		if (*s == '#' || !isspace((unsigned char)*s))
+			break;
+	return (*s == '#' || s == eom);
+}
+
+
+/*
+ * files backend
+ */
+static void
+files_endstate(void *p)
+{
+
+	if (p == NULL)
+		return;
+	if (((struct files_state *)p)->fp != NULL)
+		fclose(((struct files_state *)p)->fp);
+	free(p);
+}
+
+
+static int
+files_setgrent(void *retval, void *mdata, va_list ap)
+{
+	struct files_state *st;
+	int		 rv, stayopen;
+
+	rv = files_getstate(&st);
+	if (rv != 0) 
+		return (NS_UNAVAIL);
+	switch ((enum constants)mdata) {
+	case SETGRENT:
+		stayopen = va_arg(ap, int);
+		if (st->fp != NULL)
+			rewind(st->fp);
+		else if (stayopen)
+			st->fp = fopen(_PATH_GROUP, "r");
+		break;
+	case ENDGRENT:
+		if (st->fp != NULL) {
+			fclose(st->fp);
+			st->fp = NULL;
+		}
+		break;
+	default:
+		break;
+	}
+	return (NS_UNAVAIL);
+}
+
+
+static int
+files_group(void *retval, void *mdata, va_list ap)
+{
+	struct files_state	*st;
+	enum nss_lookup_type	 how;
+	const char		*name, *line;
+	struct group		*grp;
+	gid_t			 gid;
+	char			*buffer;
+	size_t			 bufsize, linesize;
+	int			 rv, stayopen, *errnop;
+
+	name = NULL;
+	gid = (gid_t)-1;
+	how = (enum nss_lookup_type)mdata;
+	switch (how) {
+	case nss_lt_name:
+		name = va_arg(ap, const char *);
+		break;
+	case nss_lt_id:
+		gid = va_arg(ap, gid_t);
+		break;
+	case nss_lt_all:
+		break;
+	default:
+		return (NS_NOTFOUND);
+	}
+	grp = va_arg(ap, struct group *);
+	buffer = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop = va_arg(ap, int *);
+	*errnop = files_getstate(&st);
+	if (*errnop != 0)
+		return (NS_UNAVAIL);
+	if (st->fp == NULL &&
+	    ((st->fp = fopen(_PATH_GROUP, "r")) == NULL)) {
+		*errnop = errno;
+		return (NS_UNAVAIL);
+	}
+	if (how == nss_lt_all)
+		stayopen = 1;
+	else {
+		rewind(st->fp);
+		stayopen = st->stayopen;
+	}
+	rv = NS_NOTFOUND;
+	while ((line = fgetln(st->fp, &linesize)) != NULL) {
+		if (line[linesize-1] == '\n')
+			linesize--;
+		rv = __gr_match_entry(line, linesize, how, name, gid);
+		if (rv != NS_SUCCESS)
+			continue;
+		/* We need room at least for the line, a string NUL
+		 * terminator, alignment padding, and one (char *)
+		 * pointer for the member list terminator.
+		 */
+		if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
+			*errnop = ERANGE;
+			rv = NS_RETURN;
+			break;
+		}
+		memcpy(buffer, line, linesize);
+		buffer[linesize] = '\0';
+		rv = __gr_parse_entry(buffer, linesize, grp, 
+		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+		if (rv & NS_TERMINATE)
+			break;
+	}
+	if (!stayopen && st->fp != NULL) {
+		fclose(st->fp);
+		st->fp = NULL;
+	}
+	if (rv == NS_SUCCESS && retval != NULL)
+		*(struct group **)retval = grp;
+	return (rv);
+}
+
+
+#ifdef HESIOD
+/*
+ * dns backend
+ */
+static void
+dns_endstate(void *p)
+{
+
+	free(p);
+}
+
+
+static int
+dns_setgrent(void *retval, void *cb_data, va_list ap)
+{
+	struct dns_state	*st;
+	int			 rv;
+
+	rv = dns_getstate(&st);
+	if (rv != 0)
+		return (NS_UNAVAIL);
+	st->counter = 0;
+	return (NS_UNAVAIL);
+}
+
+
+static int
+dns_group(void *retval, void *mdata, va_list ap)
+{
+	char			 buf[HESIOD_NAME_MAX];
+	struct dns_state	*st;
+	struct group		*grp;
+	const char		*name, *label;
+	void			*ctx;
+	char			*buffer, **hes;
+	size_t			 bufsize, adjsize, linesize;
+	gid_t			 gid;
+	enum nss_lookup_type	 how;
+	int			 rv, *errnop;
+
+	ctx = NULL;
+	hes = NULL;
+	name = NULL;
+	gid = (gid_t)-1;
+	how = (enum nss_lookup_type)mdata;
+	switch (how) {
+	case nss_lt_name:
+		name = va_arg(ap, const char *);
+		break;
+	case nss_lt_id:
+		gid = va_arg(ap, gid_t);
+		break;
+	case nss_lt_all:
+		break;
+	}
+	grp     = va_arg(ap, struct group *);
+	buffer  = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop  = va_arg(ap, int *);
+	*errnop = dns_getstate(&st);
+	if (*errnop != 0)
+		return (NS_UNAVAIL);
+	if (hesiod_init(&ctx) != 0) {
+		*errnop = errno;
+		rv = NS_UNAVAIL;
+		goto fin;
+	}
+	do {
+		rv = NS_NOTFOUND;
+		switch (how) {
+		case nss_lt_name:
+			label = name;
+			break;
+		case nss_lt_id:
+			if (snprintf(buf, sizeof(buf), "%lu",
+			    (unsigned long)gid) >= sizeof(buf))
+				goto fin;
+			label = buf;
+			break;
+		case nss_lt_all:
+			if (st->counter < 0)
+				goto fin;
+			if (snprintf(buf, sizeof(buf), "group-%ld",
+			    st->counter++) >= sizeof(buf))
+				goto fin;
+			label = buf;
+			break;
+		}
+		hes = hesiod_resolve(ctx, label,
+		    how == nss_lt_id ? "gid" : "group");
+		if ((how == nss_lt_id && hes == NULL &&
+		    (hes = hesiod_resolve(ctx, buf, "group")) == NULL) ||
+		    hes == NULL) {
+			if (how == nss_lt_all)
+				st->counter = -1;
+			if (errno != ENOENT)
+				*errnop = errno;
+			goto fin;
+		}
+		rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid);
+		if (rv != NS_SUCCESS) {
+			hesiod_free_list(ctx, hes);
+			hes = NULL;
+			continue;
+		}
+		/* We need room at least for the line, a string NUL
+		 * terminator, alignment padding, and one (char *)
+		 * pointer for the member list terminator.
+		 */
+		adjsize = bufsize - _ALIGNBYTES - sizeof(char *);
+		linesize = strlcpy(buffer, hes[0], adjsize);
+		if (linesize >= adjsize) {
+			*errnop = ERANGE;
+			rv = NS_RETURN;
+			goto fin;
+		}
+		hesiod_free_list(ctx, hes);
+		hes = NULL;
+		rv = __gr_parse_entry(buffer, linesize, grp,
+		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+	if (hes != NULL)
+		hesiod_free_list(ctx, hes);
+	if (ctx != NULL)
+		hesiod_end(ctx);
+	if (rv == NS_SUCCESS && retval != NULL)
+		*(struct group **)retval = grp;
+	return (rv);
+}
+#endif /* HESIOD */
+
+
+#ifdef YP
+/*
+ * nis backend
+ */
+static void
+nis_endstate(void *p)
+{
+
+	if (p == NULL)
+		return;
+	free(((struct nis_state *)p)->key);
+	free(p);
+}
+
+
+static int
+nis_setgrent(void *retval, void *cb_data, va_list ap)
+{
+	struct nis_state	*st;
+	int			 rv;
+
+	rv = nis_getstate(&st);
+	if (rv != 0)
+		return (NS_UNAVAIL);
+	st->done = 0;
+	free(st->key);
+	st->key = NULL;
+	return (NS_UNAVAIL);
+}
+
+
+static int
+nis_group(void *retval, void *mdata, va_list ap)
+{
+	char		 *map;
+	struct nis_state *st;
+	struct group	*grp;
+	const char	*name;
+	char		*buffer, *key, *result;
+	size_t		 bufsize;
+	gid_t		 gid;
+	enum nss_lookup_type how;
+	int		*errnop, keylen, resultlen, rv;
+	
+	name = NULL;
+	gid = (gid_t)-1;
+	how = (enum nss_lookup_type)mdata;
+	switch (how) {
+	case nss_lt_name:
+		name = va_arg(ap, const char *);
+		map = "group.byname";
+		break;
+	case nss_lt_id:
+		gid = va_arg(ap, gid_t);
+		map = "group.bygid";
+		break;
+	case nss_lt_all:
+		map = "group.byname";
+		break;
+	}
+	grp     = va_arg(ap, struct group *);
+	buffer  = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop  = va_arg(ap, int *);
+	*errnop = nis_getstate(&st);
+	if (*errnop != 0)
+		return (NS_UNAVAIL);
+	if (st->domain[0] == '\0') {
+		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
+			*errnop = errno;
+			return (NS_UNAVAIL);
+		}
+	}
+	result = NULL;
+	do {
+		rv = NS_NOTFOUND;
+		switch (how) {
+		case nss_lt_name:
+			if (strlcpy(buffer, name, bufsize) >= bufsize)
+				goto erange;
+			break;
+		case nss_lt_id:
+			if (snprintf(buffer, bufsize, "%lu",
+			    (unsigned long)gid) >= bufsize)
+				goto erange;
+			break;
+		case nss_lt_all:
+			if (st->done)
+				goto fin;
+			break;
+		}
+		result = NULL;
+		if (how == nss_lt_all) {
+			if (st->key == NULL)
+				rv = yp_first(st->domain, map, &st->key,
+				    &st->keylen, &result, &resultlen);
+			else {
+				key = st->key;
+				keylen = st->keylen;
+				st->key = NULL;
+				rv = yp_next(st->domain, map, key, keylen,
+				    &st->key, &st->keylen, &result,
+				    &resultlen);
+				free(key);
+			}
+			if (rv != 0) {
+				free(result);
+				free(st->key);
+				st->key = NULL;
+				if (rv == YPERR_NOMORE) {
+					st->done = 1;
+					rv = NS_NOTFOUND;
+				} else
+					rv = NS_UNAVAIL;
+				goto fin;
+			}
+		} else {
+			rv = yp_match(st->domain, map, buffer, strlen(buffer),
+			    &result, &resultlen);
+			if (rv == YPERR_KEY) {
+				rv = NS_NOTFOUND;
+				continue;
+			} else if (rv != 0) {
+				free(result);
+				rv = NS_UNAVAIL;
+				continue;
+			}
+		}
+		/* We need room at least for the line, a string NUL
+		 * terminator, alignment padding, and one (char *)
+		 * pointer for the member list terminator.
+		 */
+		if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *))
+			goto erange;
+		memcpy(buffer, result, resultlen);
+		buffer[resultlen] = '\0';
+		free(result);
+		rv = __gr_match_entry(buffer, resultlen, how, name, gid);
+		if (rv == NS_SUCCESS)
+			rv = __gr_parse_entry(buffer, resultlen, grp,
+			    &buffer[resultlen+1], bufsize - resultlen - 1,
+			    errnop);
+	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+	if (rv == NS_SUCCESS && retval != NULL)
+		*(struct group **)retval = grp;
+	return (rv);	
+erange:
+	*errnop = ERANGE;
+	return (NS_RETURN);
+}
+#endif /* YP */
+
+
+
+/*
+ * compat backend
+ */
+static void
+compat_endstate(void *p)
+{
+	struct compat_state *st;
+
+	if (p == NULL)
+		return;
+	st = (struct compat_state *)p;
+	free(st->name);
+	if (st->fp != NULL)
+		fclose(st->fp);
+	free(p);
+}
+
+
+static int
+compat_setgrent(void *retval, void *mdata, va_list ap)
+{
+	static const ns_src compatsrc[] = {
+#ifdef YP
+		{ NSSRC_NIS, NS_SUCCESS },
+#endif
+		{ NULL, 0 }
+	};
+	ns_dtab dtab[] = {
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_setgrent, NULL },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_setgrent, NULL },
+#endif
+		{ NULL, NULL, NULL }
+	};
+	struct compat_state *st;
+	int		 rv, stayopen;
+
+#define set_setent(x, y) do {	 				\
+	int i;							\
+								\
+	for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++)	\
+		x[i].mdata = (void *)y;				\
+} while (0)
+
+	rv = compat_getstate(&st);
+	if (rv != 0) 
+		return (NS_UNAVAIL);
+	switch ((enum constants)mdata) {
+	case SETGRENT:
+		stayopen = va_arg(ap, int);
+		if (st->fp != NULL)
+			rewind(st->fp);
+		else if (stayopen)
+			st->fp = fopen(_PATH_GROUP, "r");
+		set_setent(dtab, mdata);
+		(void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
+		    compatsrc, 0);
+		break;
+	case ENDGRENT:
+		if (st->fp != NULL) {
+			fclose(st->fp);
+			st->fp = NULL;
+		}
+		set_setent(dtab, mdata);
+		(void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
+		    compatsrc, 0);
+		break;
+	default:
+		break;
+	}
+	st->compat = COMPAT_MODE_OFF;
+	free(st->name);
+	st->name = NULL;
+	return (NS_UNAVAIL);
+#undef set_setent
+}
+
+
+static int
+compat_group(void *retval, void *mdata, va_list ap)
+{
+	static const ns_src compatsrc[] = {
+#ifdef YP
+		{ NSSRC_NIS, NS_SUCCESS },
+#endif
+		{ NULL, 0 }
+	};
+	ns_dtab dtab[] = {
+#ifdef YP
+		{ NSSRC_NIS, nis_group, NULL },
+#endif
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_group, NULL },
+#endif
+		{ NULL, NULL, NULL }
+	};
+	struct compat_state	*st;
+	enum nss_lookup_type	 how;
+	const char		*name, *line;
+	struct group		*grp;
+	gid_t			 gid;
+	char			*buffer, *p;
+	void			*discard;
+	size_t			 bufsize, linesize;
+	int			 rv, stayopen, *errnop;
+
+#define set_lookup_type(x, y) do { 				\
+	int i;							\
+								\
+	for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++)	\
+		x[i].mdata = (void *)y;				\
+} while (0)
+
+	name = NULL;
+	gid = (gid_t)-1;
+	how = (enum nss_lookup_type)mdata;
+	switch (how) {
+	case nss_lt_name:
+		name = va_arg(ap, const char *);
+		break;
+	case nss_lt_id:
+		gid = va_arg(ap, gid_t);
+		break;
+	case nss_lt_all:
+		break;
+	default:
+		return (NS_NOTFOUND);
+	}
+	grp = va_arg(ap, struct group *);
+	buffer = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop = va_arg(ap, int *);
+	*errnop = compat_getstate(&st);
+	if (*errnop != 0)
+		return (NS_UNAVAIL);
+	if (st->fp == NULL &&
+	    ((st->fp = fopen(_PATH_GROUP, "r")) == NULL)) {
+		*errnop = errno;
+		rv = NS_UNAVAIL;
+		goto fin;
+	}
+	if (how == nss_lt_all)
+		stayopen = 1;
+	else {
+		rewind(st->fp);
+		stayopen = st->stayopen;
+	}
+docompat:
+	switch (st->compat) {
+	case COMPAT_MODE_ALL:
+		set_lookup_type(dtab, how);
+		switch (how) {
+		case nss_lt_all:
+			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+			    "getgrent_r", compatsrc, grp, buffer, bufsize,
+			    errnop);
+			break;
+		case nss_lt_id:
+			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+			    "getgrgid_r", compatsrc, gid, grp, buffer, bufsize,
+			    errnop);
+			break;
+		case nss_lt_name:
+			rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+			    "getgrnam_r", compatsrc, name, grp, buffer,
+			    bufsize, errnop);
+			break;
+		}
+		if (rv & NS_TERMINATE)
+			goto fin;
+		st->compat = COMPAT_MODE_OFF;
+		break;
+	case COMPAT_MODE_NAME:
+		set_lookup_type(dtab, nss_lt_name);
+		rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+		    "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize,
+		    errnop);
+		switch (rv) {
+		case NS_SUCCESS:
+			switch (how) {
+			case nss_lt_name:
+				if (strcmp(name, grp->gr_name) != 0)
+					rv = NS_NOTFOUND;
+				break;
+			case nss_lt_id:
+				if (gid != grp->gr_gid)
+					rv = NS_NOTFOUND;
+				break;
+			default:
+				break;
+			}
+			break;
+		case NS_RETURN:
+			goto fin;
+		default:
+			break;
+		}
+		free(st->name);
+		st->name = NULL;
+		st->compat = COMPAT_MODE_OFF;
+		if (rv == NS_SUCCESS)
+			goto fin;
+		break;
+	default:
+		break;
+	}
+	rv = NS_NOTFOUND;
+	while ((line = fgetln(st->fp, &linesize)) != NULL) {
+		if (line[linesize-1] == '\n')
+			linesize--;
+		if (linesize > 2 && line[0] == '+') {
+			p = memchr(&line[1], ':', linesize);
+			if (p == NULL || p == &line[1])
+				st->compat = COMPAT_MODE_ALL;
+			else {
+				st->name = malloc(p - line);
+				if (st->name == NULL) {
+					syslog(LOG_ERR,
+					 "getgrent memory allocation failure");
+					*errnop = ENOMEM;
+					rv = NS_UNAVAIL;
+					break;
+				}
+				memcpy(st->name, &line[1], p - line - 1);
+				st->name[p - line - 1] = '\0';
+				st->compat = COMPAT_MODE_NAME;
+			}
+			goto docompat;
+		} 
+		rv = __gr_match_entry(line, linesize, how, name, gid);
+		if (rv != NS_SUCCESS)
+			continue;
+		/* We need room at least for the line, a string NUL
+		 * terminator, alignment padding, and one (char *)
+		 * pointer for the member list terminator.
+		 */
+		if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
+			*errnop = ERANGE;
+			rv = NS_RETURN;
+			break;
+		}
+		memcpy(buffer, line, linesize);
+		buffer[linesize] = '\0';
+		rv = __gr_parse_entry(buffer, linesize, grp, 
+		    &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+		if (rv & NS_TERMINATE)
+			break;
+	}
+fin:
+	if (!stayopen && st->fp != NULL) {
+		fclose(st->fp);
+		st->fp = NULL;
+	}
+	if (rv == NS_SUCCESS && retval != NULL)
+		*(struct group **)retval = grp;
+	return (rv);
+#undef set_lookup_type
+}
+
+
+/*
+ * common group line matching and parsing
+ */
+int
+__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how,
+    const char *name, gid_t gid)
+{
+	size_t		 namesize;
+	const char	*p, *eol;
+	char		*q;
+	unsigned long	 n;
+	int		 i, needed;
+
+	if (linesize == 0 || is_comment_line(line, linesize))
+		return (NS_NOTFOUND);
+	switch (how) {
+	case nss_lt_name:	needed = 1; break;
+	case nss_lt_id:		needed = 2; break;
+	default:		needed = 2; break;
+	}
+	eol = &line[linesize];
+	for (p = line, i = 0; i < needed && p < eol; p++)
+		if (*p == ':')
+			i++;
+	if (i < needed)
+		return (NS_NOTFOUND);
+	switch (how) {
+	case nss_lt_name:
+		namesize = strlen(name);
+		if (namesize + 1 == (size_t)(p - line) &&
+		    memcmp(line, name, namesize) == 0)
+			return (NS_SUCCESS);
+		break;
+	case nss_lt_id:
+		n = strtoul(p, &q, 10);
+		if (q < eol && *q == ':' && gid == (gid_t)n)
+			return (NS_SUCCESS);
+		break;
+	case nss_lt_all:
+		return (NS_SUCCESS);
+	default:
+		break;
+	}
+	return (NS_NOTFOUND);
+}
+
+
+int
+__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
+    size_t membufsize, int *errnop)
+{
+	char	       *s_gid, *s_mem, *p, **members;
+	unsigned long	n;
+	int		maxmembers;
+
+	memset(grp, 0, sizeof(*grp));
+	members = (char **)_ALIGN(membuf);
+	membufsize -= (char *)members - membuf;
+	maxmembers = membufsize / sizeof(*members);
+	if (maxmembers <= 0 ||
+	    (grp->gr_name = strsep(&line, ":")) == NULL ||
+	    grp->gr_name[0] == '\0' ||
+	    (grp->gr_passwd = strsep(&line, ":")) == NULL ||
+	    (s_gid = strsep(&line, ":")) == NULL ||
+	    s_gid[0] == '\0')
+		return (NS_NOTFOUND);
+	s_mem = line;
+	n = strtoul(s_gid, &s_gid, 10);
+	if (s_gid[0] != '\0')
+		return (NS_NOTFOUND);
+	grp->gr_gid = (gid_t)n;
+	grp->gr_mem = members;
+	while (maxmembers > 1 && s_mem != NULL) {
+		p = strsep(&s_mem, ",");
+		if (p != NULL && *p != '\0') {
+			*members++ = p;
+			maxmembers--;
+		}
+	}
+	*members = NULL;
+	if (s_mem == NULL)
+		return (NS_SUCCESS);
+	else {
+		*errnop = ERANGE;
+		return (NS_RETURN);
+	}
+}
Index: /trunk/src/emx/src/lib/bsd/gen/getnetgrent.c
===================================================================
--- /trunk/src/emx/src/lib/bsd/gen/getnetgrent.c	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/gen/getnetgrent.c	(revision 1499)
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getnetgrent.c	8.2 (Berkeley) 4/27/95";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/gen/getnetgrent.c,v 1.30 2003/01/03 23:55:58 tjr Exp $");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef YP
+/*
+ * Notes:
+ * We want to be able to use NIS netgroups properly while retaining
+ * the ability to use a local /etc/netgroup file. Unfortunately, you
+ * can't really do both at the same time - at least, not efficiently.
+ * NetBSD deals with this problem by creating a netgroup database
+ * using Berkeley DB (just like the password database) that allows
+ * for lookups using netgroup, netgroup.byuser or netgroup.byhost
+ * searches. This is a neat idea, but I don't have time to implement
+ * something like that now. (I think ultimately it would be nice
+ * if we DB-fied the group and netgroup stuff all in one shot, but
+ * for now I'm satisfied just to have something that works well
+ * without requiring massive code changes.)
+ * 
+ * Therefore, to still permit the use of the local file and maintain
+ * optimum NIS performance, we allow for the following conditions:
+ *
+ * - If /etc/netgroup does not exist and NIS is turned on, we use
+ *   NIS netgroups only.
+ *
+ * - If /etc/netgroup exists but is empty, we use NIS netgroups
+ *   only.
+ *
+ * - If /etc/netgroup exists and contains _only_ a '+', we use
+ *   NIS netgroups only.
+ *
+ * - If /etc/netgroup exists, contains locally defined netgroups
+ *   and a '+', we use a mixture of NIS and the local entries.
+ *   This method should return the same NIS data as just using
+ *   NIS alone, but it will be slower if the NIS netgroup database
+ *   is large (innetgr() in particular will suffer since extra
+ *   processing has to be done in order to determine memberships
+ *   using just the raw netgroup data).
+ *
+ * - If /etc/netgroup exists and contains only locally defined
+ *   netgroup entries, we use just those local entries and ignore
+ *   NIS (this is the original, pre-NIS behavior).
+ */
+
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+static char *_netgr_yp_domain;
+int _use_only_yp;
+static int _netgr_yp_enabled;
+static int _yp_innetgr;
+#endif
+
+#ifndef _PATH_NETGROUP
+#define _PATH_NETGROUP "/etc/netgroup"
+#endif
+
+/*
+ * Static Variables and functions used by setnetgrent(), getnetgrent() and
+ * endnetgrent().
+ * There are two linked lists:
+ * - linelist is just used by setnetgrent() to parse the net group file via.
+ *   parse_netgrp()
+ * - netgrp is the list of entries for the current netgroup
+ */
+struct linelist {
+	struct linelist	*l_next;	/* Chain ptr. */
+	int		l_parsed;	/* Flag for cycles */
+	char		*l_groupname;	/* Name of netgroup */
+	char		*l_line;	/* Netgroup entrie(s) to be parsed */
+};
+
+struct netgrp {
+	struct netgrp	*ng_next;	/* Chain ptr */
+	char		*ng_str[3];	/* Field pointers, see below */
+};
+#define NG_HOST		0	/* Host name */
+#define NG_USER		1	/* User name */
+#define NG_DOM		2	/* and Domain name */
+
+static struct linelist	*linehead = (struct linelist *)0;
+static struct netgrp	*nextgrp = (struct netgrp *)0;
+static struct {
+	struct netgrp	*gr;
+	char		*grname;
+} grouphead = {
+	(struct netgrp *)0,
+	(char *)0,
+};
+static FILE *netf = (FILE *)0;
+static int parse_netgrp();
+static struct linelist *read_for_group();
+void setnetgrent(), endnetgrent();
+int getnetgrent(), innetgr();
+
+#define	LINSIZ	1024	/* Length of netgroup file line */
+
+/*
+ * setnetgrent()
+ * Parse the netgroup file looking for the netgroup and build the list
+ * of netgrp structures. Let parse_netgrp() and read_for_group() do
+ * most of the work.
+ */
+void
+setnetgrent(group)
+	char *group;
+{
+#ifdef YP
+	struct stat _yp_statp;
+	char _yp_plus;
+#endif
+
+	/* Sanity check */
+
+	if (group == NULL || !strlen(group))
+		return;
+
+	if (grouphead.gr == (struct netgrp *)0 ||
+		strcmp(group, grouphead.grname)) {
+		endnetgrent();
+#ifdef YP
+		/* Presumed guilty until proven innocent. */
+		_use_only_yp = 0;
+		/*
+		 * If /etc/netgroup doesn't exist or is empty,
+		 * use NIS exclusively.
+		 */
+		if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) &&
+			errno == ENOENT) || _yp_statp.st_size == 0)
+			_use_only_yp = _netgr_yp_enabled = 1;
+		if ((netf = fopen(_PATH_NETGROUP,"r")) != NULL ||_use_only_yp){
+		/*
+		 * Icky: grab the first character of the netgroup file
+		 * and turn on NIS if it's a '+'. rewind the stream
+		 * afterwards so we don't goof up read_for_group() later.
+		 */
+			if (netf) {
+				fscanf(netf, "%c", &_yp_plus);
+				rewind(netf);
+				if (_yp_plus == '+')
+					_use_only_yp = _netgr_yp_enabled = 1;
+			}
+		/*
+		 * If we were called specifically for an innetgr()
+		 * lookup and we're in NIS-only mode, short-circuit
+		 * parse_netgroup() and cut directly to the chase.
+		 */
+			if (_use_only_yp && _yp_innetgr) {
+				/* dohw! */
+				if (netf != NULL)
+					fclose(netf);
+				return;
+			}
+#else
+		if (netf = fopen(_PATH_NETGROUP, "r")) {
+#endif
+			if (parse_netgrp(group))
+				endnetgrent();
+			else {
+				grouphead.grname = (char *)
+					malloc(strlen(group) + 1);
+				strcpy(grouphead.grname, group);
+			}
+			if (netf)
+				fclose(netf);
+		}
+	}
+	nextgrp = grouphead.gr;
+}
+
+/*
+ * Get the next netgroup off the list.
+ */
+int
+getnetgrent(hostp, userp, domp)
+	char **hostp, **userp, **domp;
+{
+#ifdef YP
+	_yp_innetgr = 0;
+#endif
+
+	if (nextgrp) {
+		*hostp = nextgrp->ng_str[NG_HOST];
+		*userp = nextgrp->ng_str[NG_USER];
+		*domp = nextgrp->ng_str[NG_DOM];
+		nextgrp = nextgrp->ng_next;
+		return (1);
+	}
+	return (0);
+}
+
+/*
+ * endnetgrent() - cleanup
+ */
+void
+endnetgrent()
+{
+	struct linelist *lp, *olp;
+	struct netgrp *gp, *ogp;
+
+	lp = linehead;
+	while (lp) {
+		olp = lp;
+		lp = lp->l_next;
+		free(olp->l_groupname);
+		free(olp->l_line);
+		free((char *)olp);
+	}
+	linehead = (struct linelist *)0;
+	if (grouphead.grname) {
+		free(grouphead.grname);
+		grouphead.grname = (char *)0;
+	}
+	gp = grouphead.gr;
+	while (gp) {
+		ogp = gp;
+		gp = gp->ng_next;
+		if (ogp->ng_str[NG_HOST])
+			free(ogp->ng_str[NG_HOST]);
+		if (ogp->ng_str[NG_USER])
+			free(ogp->ng_str[NG_USER]);
+		if (ogp->ng_str[NG_DOM])
+			free(ogp->ng_str[NG_DOM]);
+		free((char *)ogp);
+	}
+	grouphead.gr = (struct netgrp *)0;
+#ifdef YP
+	_netgr_yp_enabled = 0;
+#endif
+}
+
+#ifdef YP
+static int _listmatch(list, group, len)
+	char *list, *group;
+	int len;
+{
+	char *ptr = list, *cptr;
+	int glen = strlen(group);
+
+	/* skip possible leading whitespace */
+	while(isspace((unsigned char)*ptr))
+		ptr++;
+
+	while (ptr < list + len) {
+		cptr = ptr;
+		while(*ptr != ','  && *ptr != '\0' && !isspace((unsigned char)*ptr))
+			ptr++;
+		if (strncmp(cptr, group, glen) == 0 && glen == (ptr - cptr))
+			return(1);
+		while(*ptr == ','  || isspace((unsigned char)*ptr))
+			ptr++;
+	}
+
+	return(0);
+}
+
+static int _buildkey(key, str, dom, rotation)
+char *key, *str, *dom;
+int *rotation;
+{
+	(*rotation)++;
+	if (*rotation > 4)
+		return(0);
+	switch(*rotation) {
+		case(1): sprintf((char *)key, "%s.%s", str, dom ? dom : "*");
+			 break;
+		case(2): sprintf((char *)key, "%s.*", str);
+			 break;
+		case(3): sprintf((char *)key, "*.%s", dom ? dom : "*");
+			 break;
+		case(4): sprintf((char *)key, "*.*");
+			 break;
+	}
+	return(1);
+}
+#endif
+
+/*
+ * Search for a match in a netgroup.
+ */
+int
+innetgr(group, host, user, dom)
+	const char *group, *host, *user, *dom;
+{
+	char *hst, *usr, *dm;
+#ifdef YP
+	char *result;
+	int resultlen;
+	int rv;
+#endif
+	/* Sanity check */
+	
+	if (group == NULL || !strlen(group))
+		return (0);
+
+#ifdef YP
+	_yp_innetgr = 1;
+#endif
+	setnetgrent(group);
+#ifdef YP
+	_yp_innetgr = 0;
+	/*
+	 * If we're in NIS-only mode, do the search using
+	 * NIS 'reverse netgroup' lookups.
+	 */
+	if (_use_only_yp) {
+		char _key[MAXHOSTNAMELEN];
+		int rot = 0, y = 0;
+
+		if(yp_get_default_domain(&_netgr_yp_domain))
+			return(0);
+		while(_buildkey(_key, user ? user : host, dom, &rot)) {
+			y = yp_match(_netgr_yp_domain, user? "netgroup.byuser":
+			    "netgroup.byhost", _key, strlen(_key), &result,
+			    	&resultlen);
+			if (y) {
+				/*
+				 * If we get an error other than 'no
+				 * such key in map' then something is
+				 * wrong and we should stop the search.
+				 */
+				if (y != YPERR_KEY)
+					break;
+			} else {
+				rv = _listmatch(result, group, resultlen);
+				free(result);
+				if (rv)
+					return(1);
+				else
+					return(0);
+			}
+		}
+		/*
+		 * Couldn't match using NIS-exclusive mode. If the error
+	 	 * was YPERR_MAP, then the failure happened because there
+	 	 * was no netgroup.byhost or netgroup.byuser map. The odds
+		 * are we are talking to a Sun NIS+ server in YP emulation
+		 * mode; if this is the case, then we have to do the check
+		 * the 'old-fashioned' way by grovelling through the netgroup
+		 * map and resolving memberships on the fly.
+		 */
+		if (y != YPERR_MAP)
+			return(0);
+	}
+
+	setnetgrent(group);
+#endif /* YP */
+
+	while (getnetgrent(&hst, &usr, &dm))
+		if ((host == NULL || hst == NULL || !strcmp(host, hst)) &&
+		    (user == NULL || usr == NULL || !strcmp(user, usr)) &&
+		    ( dom == NULL ||  dm == NULL || !strcmp(dom, dm))) {
+			endnetgrent();
+			return (1);
+		}
+	endnetgrent();
+	return (0);
+}
+
+/*
+ * Parse the netgroup file setting up the linked lists.
+ */
+static int
+parse_netgrp(group)
+	char *group;
+{
+	char *spos, *epos;
+	int len, strpos;
+#ifdef DEBUG
+	int fields;
+#endif
+	char *pos, *gpos;
+	struct netgrp *grp;
+	struct linelist *lp = linehead;
+
+	/*
+	 * First, see if the line has already been read in.
+	 */
+	while (lp) {
+		if (!strcmp(group, lp->l_groupname))
+			break;
+		lp = lp->l_next;
+	}
+	if (lp == (struct linelist *)0 &&
+	    (lp = read_for_group(group)) == (struct linelist *)0)
+		return (1);
+	if (lp->l_parsed) {
+#ifdef DEBUG
+		/*
+		 * This error message is largely superflous since the
+		 * code handles the error condition sucessfully, and
+		 * spewing it out from inside libc can actually hose
+		 * certain programs.
+		 */
+		fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
+#endif
+		return (1);
+	} else
+		lp->l_parsed = 1;
+	pos = lp->l_line;
+	/* Watch for null pointer dereferences, dammit! */
+	while (pos != NULL && *pos != '\0') {
+		if (*pos == '(') {
+			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
+			bzero((char *)grp, sizeof (struct netgrp));
+			grp->ng_next = grouphead.gr;
+			grouphead.gr = grp;
+			pos++;
+			gpos = strsep(&pos, ")");
+#ifdef DEBUG
+			fields = 0;
+#endif
+			for (strpos = 0; strpos < 3; strpos++) {
+				if ((spos = strsep(&gpos, ","))) {
+#ifdef DEBUG
+					fields++;
+#endif
+					while (*spos == ' ' || *spos == '\t')
+						spos++;
+					if ((epos = strpbrk(spos, " \t"))) {
+						*epos = '\0';
+						len = epos - spos;
+					} else
+						len = strlen(spos);
+					if (len > 0) {
+						grp->ng_str[strpos] =  (char *)
+							malloc(len + 1);
+						bcopy(spos, grp->ng_str[strpos],
+							len + 1);
+					}
+				} else {
+					/*
+					 * All other systems I've tested
+					 * return NULL for empty netgroup
+					 * fields. It's up to user programs
+					 * to handle the NULLs appropriately.
+					 */
+					grp->ng_str[strpos] = NULL;
+				}
+			}
+#ifdef DEBUG
+			/*
+			 * Note: on other platforms, malformed netgroup
+			 * entries are not normally flagged. While we
+			 * can catch bad entries and report them, we should
+			 * stay silent by default for compatibility's sake.
+			 */
+			if (fields < 3)
+					fprintf(stderr, "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n",
+						grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
+						grp->ng_str[NG_USER] == NULL ? "" : ",",
+						grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
+						grp->ng_str[NG_DOM] == NULL ? "" : ",",
+						grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
+						lp->l_groupname);
+#endif
+		} else {
+			spos = strsep(&pos, ", \t");
+			if (parse_netgrp(spos))
+				continue;
+		}
+		if (pos == NULL)
+			break;
+		while (*pos == ' ' || *pos == ',' || *pos == '\t')
+			pos++;
+	}
+	return (0);
+}
+
+/*
+ * Read the netgroup file and save lines until the line for the netgroup
+ * is found. Return 1 if eof is encountered.
+ */
+static struct linelist *
+read_for_group(group)
+	char *group;
+{
+	char *pos, *spos, *linep, *olinep;
+	int len, olen;
+	int cont;
+	struct linelist *lp;
+	char line[LINSIZ + 2];
+#ifdef YP
+	char *result;
+	int resultlen;
+
+	while (_netgr_yp_enabled || fgets(line, LINSIZ, netf) != NULL) {
+		if (_netgr_yp_enabled) {
+			if(!_netgr_yp_domain)
+				if(yp_get_default_domain(&_netgr_yp_domain))
+					continue;
+			if (yp_match(_netgr_yp_domain, "netgroup", group,
+					strlen(group), &result, &resultlen)) {
+				free(result);
+				if (_use_only_yp)
+					return ((struct linelist *)0);
+				else {
+					_netgr_yp_enabled = 0;
+					continue;
+				}
+			}
+			snprintf(line, LINSIZ, "%s %s", group, result);
+			free(result);
+		}
+#else
+	while (fgets(line, LINSIZ, netf) != NULL) {
+#endif
+		pos = (char *)&line;
+#ifdef YP
+		if (*pos == '+') {
+			_netgr_yp_enabled = 1;
+			continue;
+		}
+#endif
+		if (*pos == '#')
+			continue;
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		spos = pos;
+		while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
+			*pos != '\0')
+			pos++;
+		len = pos - spos;
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		if (*pos != '\n' && *pos != '\0') {
+			lp = (struct linelist *)malloc(sizeof (*lp));
+			lp->l_parsed = 0;
+			lp->l_groupname = (char *)malloc(len + 1);
+			bcopy(spos, lp->l_groupname, len);
+			*(lp->l_groupname + len) = '\0';
+			len = strlen(pos);
+			olen = 0;
+
+			/*
+			 * Loop around handling line continuations.
+			 */
+			do {
+				if (*(pos + len - 1) == '\n')
+					len--;
+				if (*(pos + len - 1) == '\\') {
+					len--;
+					cont = 1;
+				} else
+					cont = 0;
+				if (len > 0) {
+					linep = (char *)malloc(olen + len + 1);
+					if (olen > 0) {
+						bcopy(olinep, linep, olen);
+						free(olinep);
+					}
+					bcopy(pos, linep + olen, len);
+					olen += len;
+					*(linep + olen) = '\0';
+					olinep = linep;
+				}
+				if (cont) {
+					if (fgets(line, LINSIZ, netf)) {
+						pos = line;
+						len = strlen(pos);
+					} else
+						cont = 0;
+				}
+			} while (cont);
+			lp->l_line = linep;
+			lp->l_next = linehead;
+			linehead = lp;
+
+			/*
+			 * If this is the one we wanted, we are done.
+			 */
+			if (!strcmp(lp->l_groupname, group))
+				return (lp);
+		}
+	}
+#ifdef YP
+	/*
+	 * Yucky. The recursive nature of this whole mess might require
+	 * us to make more than one pass through the netgroup file.
+	 * This might be best left outside the #ifdef YP, but YP is
+	 * defined by default anyway, so I'll leave it like this
+	 * until I know better.
+	 */
+	rewind(netf);
+#endif
+	return ((struct linelist *)0);
+}
Index: /trunk/src/emx/src/lib/bsd/gen/getpwent.c
===================================================================
--- /trunk/src/emx/src/lib/bsd/gen/getpwent.c	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/gen/getpwent.c	(revision 1499)
@@ -0,0 +1,1728 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/gen/getpwent.c,v 1.83 2003/07/18 23:51:15 wpaul Exp $");
+
+#include "namespace.h"
+#include <sys/param.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#include <netdb.h>
+#include <nsswitch.h>
+#include <pthread.h>
+#include <pthread_np.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include <db.h>
+#include "libc_private.h"
+#include "pw_scan.h"
+#include "nss_tls.h"
+
+#ifndef CTASSERT
+#define CTASSERT(x)		_CTASSERT(x, __LINE__)
+#define _CTASSERT(x, y)		__CTASSERT(x, y)
+#define __CTASSERT(x, y)	typedef char __assert_ ## y [(x) ? 1 : -1]
+#endif
+
+/* Counter as stored in /etc/pwd.db */
+typedef	int		pwkeynum;
+
+CTASSERT(MAXLOGNAME > sizeof(uid_t));
+CTASSERT(MAXLOGNAME > sizeof(pwkeynum));
+
+enum constants {
+	PWD_STORAGE_INITIAL	= 1 << 10, /* 1 KByte */
+	PWD_STORAGE_MAX		= 1 << 20, /* 1 MByte */
+	SETPWENT		= 1,
+	ENDPWENT		= 2,
+	HESIOD_NAME_MAX		= 256
+};
+
+static const ns_src defaultsrc[] = {
+	{ NSSRC_COMPAT, NS_SUCCESS },
+	{ NULL, 0 }
+};
+
+int	__pw_match_entry(const char *, size_t, enum nss_lookup_type,
+	    const char *, uid_t);
+int	__pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop);
+
+static	void	 pwd_init(struct passwd *);
+
+union key {
+	const char	*name;
+	uid_t		 uid;
+};
+
+static	struct passwd *getpw(int (*fn)(union key, struct passwd *, char *,
+		    size_t, struct passwd **), union key);
+static	int	 wrap_getpwnam_r(union key, struct passwd *, char *,
+		    size_t, struct passwd **);
+static	int	 wrap_getpwuid_r(union key, struct passwd *, char *, size_t,
+		    struct passwd **);
+static	int	 wrap_getpwent_r(union key, struct passwd *, char *, size_t,
+		    struct passwd **);
+
+static	int	 pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type,
+		    const char *, uid_t);
+static	int	 pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *);
+static	int	 pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type,
+		    const char *, uid_t);
+static	int	 pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *);
+
+
+struct {
+	int	(*match)(char *, size_t, enum nss_lookup_type, const char *,
+		    uid_t);
+	int	(*parse)(char *, size_t, struct passwd *, int *);
+} pwdb_versions[] = {
+	{ NULL, NULL },					/* version 0 */
+	{ NULL, NULL },					/* version 1 */
+	{ NULL, NULL },					/* version 2 */
+	{ pwdb_match_entry_v3, pwdb_parse_entry_v3 },	/* version 3 */
+	{ pwdb_match_entry_v4, pwdb_parse_entry_v4 },	/* version 4 */
+};
+
+
+struct files_state {
+	DB		*db;
+	pwkeynum	 keynum;
+	int		 stayopen;
+	int		 version;
+};
+static	void	files_endstate(void *);
+NSS_TLS_HANDLING(files);
+static	DB	*pwdbopen(int *);
+static	void	 files_endstate(void *);
+static	int	 files_setpwent(void *, void *, va_list);
+static	int	 files_passwd(void *, void *, va_list);
+
+
+#ifdef HESIOD
+struct dns_state {
+	long	counter;
+};
+static	void	dns_endstate(void *);
+NSS_TLS_HANDLING(dns);
+static	int	 dns_setpwent(void *, void *, va_list);
+static	int	 dns_passwd(void *, void *, va_list);
+#endif
+
+
+#ifdef YP
+struct nis_state {
+	char	 domain[MAXHOSTNAMELEN];
+	int	 done;
+	char	*key;
+	int	 keylen;
+};
+static	void	 nis_endstate(void *);
+NSS_TLS_HANDLING(nis);
+static	int	 nis_setpwent(void *, void *, va_list);
+static	int	 nis_passwd(void *, void *, va_list);
+static	int	 nis_map(char *, enum nss_lookup_type, char *, size_t, int *);
+static	int	 nis_adjunct(char *, const char *, char *, size_t);
+#endif
+
+
+struct compat_state {
+	DB		*db;
+	pwkeynum	 keynum;
+	int		 stayopen;
+	int		 version;
+	DB		*exclude;
+	struct passwd	 template;
+	char		*name;
+	enum _compat {
+		COMPAT_MODE_OFF = 0,
+		COMPAT_MODE_ALL,
+		COMPAT_MODE_NAME,
+		COMPAT_MODE_NETGROUP
+	}		 compat;
+};
+static	void	 compat_endstate(void *);
+NSS_TLS_HANDLING(compat);
+static	int	 compat_setpwent(void *, void *, va_list);
+static	int	 compat_passwd(void *, void *, va_list);
+static	void	 compat_clear_template(struct passwd *);
+static	int	 compat_set_template(struct passwd *, struct passwd *);
+static	int	 compat_use_template(struct passwd *, struct passwd *, char *,
+		    size_t);
+static	int	 compat_redispatch(struct compat_state *, enum nss_lookup_type,
+		    enum nss_lookup_type, const char *, const char *, uid_t,
+		    struct passwd *, char *, size_t, int *);
+void
+setpwent(void)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
+#endif
+		{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
+		{ NULL, NULL, NULL }
+	};
+	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0);
+}
+
+
+int
+setpassent(int stayopen)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
+#endif
+		{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
+		{ NULL, NULL, NULL }
+	};
+	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc,
+	    stayopen);
+	return (1);
+}
+
+
+void
+endpwent(void)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_setpwent, (void *)ENDPWENT },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_setpwent, (void *)ENDPWENT },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_setpwent, (void *)ENDPWENT },
+#endif
+		{ NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT },
+		{ NULL, NULL, NULL }
+	};
+	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc);
+}
+
+
+int
+getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
+    struct passwd **result)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_passwd, (void *)nss_lt_all },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_all },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_all },
+#endif
+		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all },
+		{ NULL, NULL, NULL }
+	};
+	int	rv, ret_errno;
+
+	pwd_init(pwd);
+	ret_errno = 0;
+	*result = NULL;
+	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc,
+	    pwd, buffer, bufsize, &ret_errno);
+	if (rv == NS_SUCCESS)
+		return (0);
+	else
+		return (ret_errno);
+}
+
+
+int
+getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize,
+    struct passwd **result)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_passwd, (void *)nss_lt_name },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_name },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_name },
+#endif
+		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name },
+		{ NULL, NULL, NULL }
+	};
+	int	rv, ret_errno;
+
+	pwd_init(pwd);
+	ret_errno = 0;
+	*result = NULL;
+	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc,
+	    name, pwd, buffer, bufsize, &ret_errno);
+	if (rv == NS_SUCCESS)
+		return (0);
+	else
+		return (ret_errno);
+}
+
+
+int
+getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
+    struct passwd **result)
+{
+	static const ns_dtab dtab[] = {
+		{ NSSRC_FILES, files_passwd, (void *)nss_lt_id },
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_id },
+#endif
+#ifdef YP
+		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_id },
+#endif
+		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id },
+		{ NULL, NULL, NULL }
+	};
+	int	rv, ret_errno;
+
+	pwd_init(pwd);
+	ret_errno = 0;
+	*result = NULL;
+	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc,
+	    uid, pwd, buffer, bufsize, &ret_errno);
+	if (rv == NS_SUCCESS)
+		return (0);
+	else
+		return (ret_errno);
+}
+
+
+static void
+pwd_init(struct passwd *pwd)
+{
+	static char nul[] = "";
+
+	memset(pwd, 0, sizeof(*pwd));
+	pwd->pw_uid = (uid_t)-1;  /* Considered least likely to lead to */
+	pwd->pw_gid = (gid_t)-1;  /* a security issue.                  */
+	pwd->pw_name = nul;
+	pwd->pw_passwd = nul;
+	pwd->pw_class = nul;
+	pwd->pw_gecos = nul;
+	pwd->pw_dir = nul;
+	pwd->pw_shell = nul;
+}
+
+
+static struct passwd	 pwd;
+static char		*pwd_storage;
+static size_t		 pwd_storage_size;
+
+
+static struct passwd *
+getpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **),
+    union key key)
+{
+	int		 rv;
+	struct passwd	*res;
+
+	if (pwd_storage == NULL) {
+		pwd_storage = malloc(PWD_STORAGE_INITIAL);
+		if (pwd_storage == NULL)
+			return (NULL);
+		pwd_storage_size = PWD_STORAGE_INITIAL;
+	}
+	do {
+		rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res);
+		if (res == NULL && rv == ERANGE) {
+			free(pwd_storage);
+			if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) {
+				pwd_storage = NULL;
+				return (NULL);
+			}
+			pwd_storage_size <<= 1;
+			pwd_storage = malloc(pwd_storage_size);
+			if (pwd_storage == NULL)
+				return (NULL);
+		}
+	} while (res == NULL && rv == ERANGE);
+	return (res);
+}
+
+
+static int
+wrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer,
+    size_t bufsize, struct passwd **res)
+{
+	return (getpwnam_r(key.name, pwd, buffer, bufsize, res));
+}
+
+
+static int
+wrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer,
+    size_t bufsize, struct passwd **res)
+{
+	return (getpwuid_r(key.uid, pwd, buffer, bufsize, res));
+}
+
+
+static int
+wrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer,
+    size_t bufsize, struct passwd **res)
+{
+	return (getpwent_r(pwd, buffer, bufsize, res));
+}
+
+
+struct passwd *
+getpwnam(const char *name)
+{
+	union key key;
+
+	key.name = name;
+	return (getpw(wrap_getpwnam_r, key));
+}
+
+
+struct passwd *
+getpwuid(uid_t uid)
+{
+	union key key;
+
+	key.uid = uid;
+	return (getpw(wrap_getpwuid_r, key));
+}
+
+
+struct passwd *
+getpwent(void)
+{
+	union key key;
+
+	key.uid = 0; /* not used */
+	return (getpw(wrap_getpwent_r, key));
+}
+
+
+/*
+ * files backend
+ */
+static DB *
+pwdbopen(int *version)
+{
+	DB	*res;
+	DBT	 key, entry;
+	int	 rv;
+
+	if (geteuid() != 0 ||
+	    (res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
+		res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
+	if (res == NULL)
+		return (NULL);
+	key.data = _PWD_VERSION_KEY;
+	key.size = strlen(_PWD_VERSION_KEY);
+	rv = res->get(res, &key, &entry, 0);
+	if (rv == 0)
+		*version = *(unsigned char *)entry.data;
+	else
+		*version = 3;
+	if (*version < 3 ||
+	    *version >= sizeof(pwdb_versions)/sizeof(pwdb_versions[0])) {
+		syslog(LOG_CRIT, "Unsupported password database version %d",
+		    *version);
+		res->close(res);
+		res = NULL;
+	}
+	return (res);
+}
+
+
+static void
+files_endstate(void *p)
+{
+	DB	*db;
+
+	if (p == NULL)
+		return;
+	db = ((struct files_state *)p)->db;
+	if (db != NULL)
+		db->close(db);
+	free(p);
+}
+
+
+static int
+files_setpwent(void *retval, void *mdata, va_list ap)
+{
+	struct files_state	*st;
+	int			 rv, stayopen;
+
+	rv = files_getstate(&st);
+	if (rv != 0)
+		return (NS_UNAVAIL);
+	switch ((enum constants)mdata) {
+	case SETPWENT:
+		stayopen = va_arg(ap, int);
+		st->keynum = 0;
+		if (stayopen)
+			st->db = pwdbopen(&st->version);
+		st->stayopen = stayopen;
+		break;
+	case ENDPWENT:
+		if (st->db != NULL) {
+			(void)st->db->close(st->db);
+			st->db = NULL;
+		}
+		break;
+	default:
+		break;
+	}
+	return (NS_UNAVAIL);
+}
+
+
+static int
+files_passwd(void *retval, void *mdata, va_list ap)
+{
+	char			 keybuf[MAXLOGNAME + 1];
+	DBT			 key, entry;
+	struct files_state	*st;
+	enum nss_lookup_type	 how;
+	const char		*name;
+	struct passwd		*pwd;
+	char			*buffer;
+	size_t			 bufsize, namesize;
+	uid_t			 uid;
+	uint32_t		 store;
+	int			 rv, stayopen, *errnop;
+
+	name = NULL;
+	uid = (uid_t)-1;
+	how = (enum nss_lookup_type)mdata;
+	switch (how) {
+	case nss_lt_name:
+		name = va_arg(ap, const char *);
+		keybuf[0] = _PW_KEYBYNAME;
+		break;
+	case nss_lt_id:
+		uid = va_arg(ap, uid_t);
+		keybuf[0] = _PW_KEYBYUID;
+		break;
+	case nss_lt_all:
+		keybuf[0] = _PW_KEYBYNUM;
+		break;
+	default:
+		rv = NS_NOTFOUND;
+		goto fin;
+	}
+	pwd = va_arg(ap, struct passwd *);
+	buffer = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop = va_arg(ap, int *);
+	*errnop = files_getstate(&st);
+	if (*errnop != 0)
+		return (NS_UNAVAIL);
+	if (how == nss_lt_all && st->keynum < 0) {
+		rv = NS_NOTFOUND;
+		goto fin;
+	}
+	if (st->db == NULL &&
+	    (st->db = pwdbopen(&st->version)) == NULL) {
+		*errnop = errno;
+		rv = NS_UNAVAIL;
+		goto fin;
+	}
+	if (how == nss_lt_all)
+		stayopen = 1;
+	else
+		stayopen = st->stayopen;
+	key.data = keybuf;
+	do {
+		switch (how) {
+		case nss_lt_name:
+			/* MAXLOGNAME includes NUL byte, but we do not
+			 * include the NUL byte in the key.
+			 */
+			namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1);
+			if (namesize >= sizeof(keybuf)-1) {
+				*errnop = EINVAL;
+				rv = NS_NOTFOUND;
+				goto fin;
+			}
+			key.size = namesize + 1;
+			break;
+		case nss_lt_id:
+			if (st->version < _PWD_CURRENT_VERSION) {
+				memcpy(&keybuf[1], &uid, sizeof(uid));
+				key.size = sizeof(uid) + 1;
+			} else {
+				store = htonl(uid);
+				memcpy(&keybuf[1], &store, sizeof(store));
+				key.size = sizeof(store) + 1;
+			}
+			break;
+		case nss_lt_all:
+			st->keynum++;
+			if (st->version < _PWD_CURRENT_VERSION) {
+				memcpy(&keybuf[1], &st->keynum,
+				    sizeof(st->keynum));
+				key.size = sizeof(st->keynum) + 1;
+			} else {
+				store = htonl(st->keynum);
+				memcpy(&keybuf[1], &store, sizeof(store));
+				key.size = sizeof(store) + 1;
+			}
+			break;
+		}
+		keybuf[0] = _PW_VERSIONED(keybuf[0], st->version);
+		rv = st->db->get(st->db, &key, &entry, 0);
+		if (rv < 0 || rv > 1) { /* should never return > 1 */
+			*errnop = errno;
+			rv = NS_UNAVAIL;
+			goto fin;
+		} else if (rv == 1) {
+			if (how == nss_lt_all)
+				st->keynum = -1;
+			rv = NS_NOTFOUND;
+			goto fin;
+		}
+		rv = pwdb_versions[st->version].match(entry.data, entry.size,
+		    how, name, uid);
+		if (rv != NS_SUCCESS)
+			continue;
+		if (entry.size > bufsize) {
+			*errnop = ERANGE;
+			rv = NS_RETURN;
+			break;
+		}
+		memcpy(buffer, entry.data, entry.size);
+		rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
+		    errnop);
+	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+	if (!stayopen && st->db != NULL) {
+		(void)st->db->close(st->db);
+		st->db = NULL;
+	}
+	if (rv == NS_SUCCESS) {
+		pwd->pw_fields &= ~_PWF_SOURCE;
+		pwd->pw_fields |= _PWF_FILES;
+		if (retval != NULL)
+			*(struct passwd **)retval = pwd;
+	}
+	return (rv);
+}
+
+
+static int
+pwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how, 
+    const char *name, uid_t uid)
+{
+	const char	*p, *eom;
+	uid_t		 uid2;
+
+	eom = &entry[entrysize];
+	for (p = entry; p < eom; p++)
+		if (*p == '\0')
+			break;
+	if (*p != '\0')
+		return (NS_NOTFOUND);
+	if (how == nss_lt_all)
+		return (NS_SUCCESS);
+	if (how == nss_lt_name) 
+		return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
+	for (p++; p < eom; p++)
+		if (*p == '\0')
+			break;
+	if (*p != '\0' || (++p) + sizeof(uid) >= eom)
+		return (NS_NOTFOUND);
+	memcpy(&uid2, p, sizeof(uid2));
+	return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND);
+}
+
+
+static int
+pwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd,
+    int *errnop)
+{
+	char		*p, *eom;
+	int32_t		 pw_change, pw_expire;
+
+	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
+	p = buffer;
+	eom = &buffer[bufsize];
+#define STRING(field)	do {			\
+		(field) = p;			\
+		while (p < eom && *p != '\0')	\
+			p++;			\
+		if (p >= eom)			\
+			return (NS_NOTFOUND);	\
+		p++;				\
+	} while (0)
+#define SCALAR(field)	do {				\
+		if (p + sizeof(field) > eom)		\
+			return (NS_NOTFOUND);		\
+		memcpy(&(field), p, sizeof(field));	\
+		p += sizeof(field);			\
+	} while (0)
+	STRING(pwd->pw_name);
+	STRING(pwd->pw_passwd);
+	SCALAR(pwd->pw_uid);
+	SCALAR(pwd->pw_gid);
+	SCALAR(pw_change);
+	STRING(pwd->pw_class);
+	STRING(pwd->pw_gecos);
+	STRING(pwd->pw_dir);
+	STRING(pwd->pw_shell);
+	SCALAR(pw_expire);
+	SCALAR(pwd->pw_fields);
+#undef STRING
+#undef SCALAR
+	pwd->pw_change = pw_change;
+	pwd->pw_expire = pw_expire;
+	return (NS_SUCCESS);
+}
+
+
+static int
+pwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how, 
+    const char *name, uid_t uid)
+{
+	const char	*p, *eom;
+	uint32_t	 uid2;
+
+	eom = &entry[entrysize];
+	for (p = entry; p < eom; p++)
+		if (*p == '\0')
+			break;
+	if (*p != '\0')
+		return (NS_NOTFOUND);
+	if (how == nss_lt_all)
+		return (NS_SUCCESS);
+	if (how == nss_lt_name) 
+		return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
+	for (p++; p < eom; p++)
+		if (*p == '\0')
+			break;
+	if (*p != '\0' || (++p) + sizeof(uid) >= eom)
+		return (NS_NOTFOUND);
+	memcpy(&uid2, p, sizeof(uid2));
+	uid2 = ntohl(uid2);
+	return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND);
+}
+
+
+static int
+pwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd,
+    int *errnop)
+{
+	char		*p, *eom;
+	uint32_t	 n;
+
+	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
+	p = buffer;
+	eom = &buffer[bufsize];
+#define STRING(field)	do {			\
+		(field) = p;			\
+		while (p < eom && *p != '\0')	\
+			p++;			\
+		if (p >= eom)			\
+			return (NS_NOTFOUND);	\
+		p++;				\
+	} while (0)
+#define SCALAR(field)	do {				\
+		if (p + sizeof(n) > eom)		\
+			return (NS_NOTFOUND);		\
+		memcpy(&n, p, sizeof(n));		\
+		(field) = ntohl(n);			\
+		p += sizeof(n);				\
+	} while (0)
+	STRING(pwd->pw_name);
+	STRING(pwd->pw_passwd);
+	SCALAR(pwd->pw_uid);
+	SCALAR(pwd->pw_gid);
+	SCALAR(pwd->pw_change);
+	STRING(pwd->pw_class);
+	STRING(pwd->pw_gecos);
+	STRING(pwd->pw_dir);
+	STRING(pwd->pw_shell);
+	SCALAR(pwd->pw_expire);
+	SCALAR(pwd->pw_fields);
+#undef STRING
+#undef SCALAR
+	return (NS_SUCCESS);
+}
+
+
+#ifdef HESIOD
+/*
+ * dns backend
+ */
+static void
+dns_endstate(void *p)
+{
+	free(p);
+}
+
+
+static int
+dns_setpwent(void *retval, void *mdata, va_list ap)
+{
+	struct dns_state	*st;
+	int			 rv;
+
+	rv = dns_getstate(&st);
+	if (rv != 0)
+		return (NS_UNAVAIL);
+	st->counter = 0;
+	return (NS_UNAVAIL);
+}
+
+
+static int
+dns_passwd(void *retval, void *mdata, va_list ap)
+{
+	char			 buf[HESIOD_NAME_MAX];
+	struct dns_state	*st;
+	struct passwd		*pwd;
+	const char		*name, *label;
+	void			*ctx;
+	char			*buffer, **hes;
+	size_t			 bufsize, linesize;
+	uid_t			 uid;
+	enum nss_lookup_type	 how;
+	int			 rv, *errnop;
+
+	ctx = NULL;
+	hes = NULL;
+	name = NULL;
+	uid = (uid_t)-1;
+	how = (enum nss_lookup_type)mdata;
+	switch (how) {
+	case nss_lt_name:
+		name = va_arg(ap, const char *);
+		break;
+	case nss_lt_id:
+		uid = va_arg(ap, uid_t);
+		break;
+	case nss_lt_all:
+		break;
+	}
+	pwd     = va_arg(ap, struct passwd *);
+	buffer  = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop  = va_arg(ap, int *);
+	*errnop = dns_getstate(&st);
+	if (*errnop != 0)
+		return (NS_UNAVAIL);
+	if (hesiod_init(&ctx) != 0) {
+		*errnop = errno;
+		rv = NS_UNAVAIL;
+		goto fin;
+	}
+	do {
+		rv = NS_NOTFOUND;
+		switch (how) {
+		case nss_lt_name:
+			label = name;
+			break;
+		case nss_lt_id:
+			if (snprintf(buf, sizeof(buf), "%lu",
+			    (unsigned long)uid) >= sizeof(buf))
+				goto fin;
+			label = buf;
+			break;
+		case nss_lt_all:
+			if (st->counter < 0)
+				goto fin;
+			if (snprintf(buf, sizeof(buf), "passwd-%ld",
+			    st->counter++) >= sizeof(buf))
+				goto fin;
+			label = buf;
+			break;
+		}
+		hes = hesiod_resolve(ctx, label,
+		    how == nss_lt_id ? "uid" : "passwd");
+		if (hes == NULL) {
+			if (how == nss_lt_all)
+				st->counter = -1;
+			if (errno != ENOENT)
+				*errnop = errno;
+			goto fin;
+		}
+		rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid);
+		if (rv != NS_SUCCESS) {
+			hesiod_free_list(ctx, hes);
+			hes = NULL;
+			continue;
+		}
+		linesize = strlcpy(buffer, hes[0], bufsize);
+		if (linesize >= bufsize) {
+			*errnop = ERANGE;
+			rv = NS_RETURN;
+			continue;
+		}
+		hesiod_free_list(ctx, hes);
+		hes = NULL;
+		rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop);
+	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+	if (hes != NULL)
+		hesiod_free_list(ctx, hes);
+	if (ctx != NULL)
+		hesiod_end(ctx);
+	if (rv == NS_SUCCESS) {
+		pwd->pw_fields &= ~_PWF_SOURCE;
+		pwd->pw_fields |= _PWF_HESIOD;
+		if (retval != NULL)
+			*(struct passwd **)retval = pwd;
+	}
+	return (rv);
+}
+#endif /* HESIOD */
+
+
+#ifdef YP
+/*
+ * nis backend
+ */
+static void
+nis_endstate(void *p)
+{
+	free(((struct nis_state *)p)->key);
+	free(p);
+}
+
+/*
+ * Test for the presence of special FreeBSD-specific master.passwd.by*
+ * maps. We do this using yp_order(). If it fails, then either the server
+ * doesn't have the map, or the YPPROC_ORDER procedure isn't supported by
+ * the server (Sun NIS+ servers in YP compat mode behave this way). If
+ * the master.passwd.by* maps don't exist, then let the lookup routine try
+ * the regular passwd.by* maps instead. If the lookup routine fails, it
+ * can return an error as needed.
+ */
+static int
+nis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize,
+    int *master)
+{
+	int	rv, order;
+
+	*master = 0;
+	if (geteuid() == 0) {
+		if (snprintf(buffer, bufsize, "master.passwd.by%s",
+		    (how == nss_lt_id) ? "uid" : "name") >= bufsize)
+			return (NS_UNAVAIL);
+		rv = yp_order(domain, buffer, &order);
+		if (rv == 0) {
+			*master = 1;
+			return (NS_SUCCESS);
+		}
+	}
+
+	if (snprintf(buffer, bufsize, "passwd.by%s",
+	    (how == nss_lt_id) ? "uid" : "name") >= bufsize)
+		return (NS_UNAVAIL);
+
+	return (NS_SUCCESS);
+}
+
+
+static int
+nis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize)
+{
+	int	 rv;
+	char	*result, *p, *q, *eor;
+	int	 resultlen;
+
+	result = NULL;
+	rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name),
+	    &result, &resultlen);
+	if (rv != 0)
+		rv = 1;
+	else {
+		eor = &result[resultlen];
+		p = memchr(result, ':', eor - result);
+		if (p != NULL && ++p < eor &&
+		    (q = memchr(p, ':', eor - p)) != NULL) {
+			if (q - p >= bufsize)
+				rv = -1;
+			else {
+				memcpy(buffer, p, q - p);
+				buffer[q - p] ='\0';
+			}
+		} else
+			rv = 1;
+	} 
+	free(result);
+	return (rv);
+}
+
+
+static int
+nis_setpwent(void *retval, void *mdata, va_list ap)
+{
+	struct nis_state	*st;
+	int			 rv;
+
+	rv = nis_getstate(&st);
+	if (rv != 0)
+		return (NS_UNAVAIL);
+	st->done = 0;
+	free(st->key);
+	st->key = NULL;
+	return (NS_UNAVAIL);
+}
+
+
+static int
+nis_passwd(void *retval, void *mdata, va_list ap)
+{
+	char		 map[YPMAXMAP];
+	struct nis_state *st;
+	struct passwd	*pwd;
+	const char	*name;
+	char		*buffer, *key, *result;
+	size_t		 bufsize;
+	uid_t		 uid;
+	enum nss_lookup_type how;
+	int		*errnop, keylen, resultlen, rv, master;
+	  
+	name = NULL;
+	uid = (uid_t)-1;
+	how = (enum nss_lookup_type)mdata;
+	switch (how) {
+	case nss_lt_name:
+		name = va_arg(ap, const char *);
+		break;
+	case nss_lt_id:
+		uid = va_arg(ap, uid_t);
+		break;
+	case nss_lt_all:
+		break;
+	}
+	pwd     = va_arg(ap, struct passwd *);
+	buffer  = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop  = va_arg(ap, int *);
+	*errnop = nis_getstate(&st);
+	if (*errnop != 0)
+		return (NS_UNAVAIL);
+	if (st->domain[0] == '\0') {
+		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
+			*errnop = errno;
+			return (NS_UNAVAIL);
+		}
+	}
+	rv = nis_map(st->domain, how, map, sizeof(map), &master);
+	if (rv != NS_SUCCESS)
+		return (rv);
+	result = NULL;
+	do {
+		rv = NS_NOTFOUND;
+		switch (how) {
+		case nss_lt_name:
+			if (strlcpy(buffer, name, bufsize) >= bufsize)
+				goto erange;
+			break;
+		case nss_lt_id:
+			if (snprintf(buffer, bufsize, "%lu",
+			    (unsigned long)uid) >= bufsize)
+				goto erange;
+			break;
+		case nss_lt_all:
+			if (st->done)
+				goto fin;
+			break;
+		}
+		result = NULL;
+		if (how == nss_lt_all) {
+			if (st->key == NULL)
+				rv = yp_first(st->domain, map, &st->key,
+				    &st->keylen, &result, &resultlen);
+			else {
+				key = st->key;
+				keylen = st->keylen;
+				st->key = NULL;
+				rv = yp_next(st->domain, map, key, keylen,
+				    &st->key, &st->keylen, &result,
+				    &resultlen);
+				free(key);
+			}
+			if (rv != 0) {
+				free(result);
+				free(st->key);
+				st->key = NULL;
+				if (rv == YPERR_NOMORE)
+					st->done = 1;
+				else
+					rv = NS_UNAVAIL;
+				goto fin;
+			}
+		} else {
+			rv = yp_match(st->domain, map, buffer, strlen(buffer),
+			    &result, &resultlen);
+			if (rv == YPERR_KEY) {
+				rv = NS_NOTFOUND;
+				continue;
+			} else if (rv != 0) {
+				free(result);
+				rv = NS_UNAVAIL;
+				continue;
+			}
+		}
+		if (resultlen >= bufsize)
+			goto erange;
+		memcpy(buffer, result, resultlen);
+		buffer[resultlen] = '\0';
+		free(result);
+		rv = __pw_match_entry(buffer, resultlen, how, name, uid);
+		if (rv == NS_SUCCESS)
+			rv = __pw_parse_entry(buffer, resultlen, pwd, master,
+			    errnop);
+	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:	
+	if (rv == NS_SUCCESS) {
+		if (strstr(pwd->pw_passwd, "##") != NULL) {
+			rv = nis_adjunct(st->domain, name,
+			    &buffer[resultlen+1], bufsize-resultlen-1);
+			if (rv < 0)
+				goto erange;
+			else if (rv == 0)
+				pwd->pw_passwd = &buffer[resultlen+1];
+		}
+		pwd->pw_fields &= ~_PWF_SOURCE;
+		pwd->pw_fields |= _PWF_NIS;
+		if (retval != NULL)
+			*(struct passwd **)retval = pwd;
+	}
+	return (rv);	
+erange:
+	*errnop = ERANGE;
+	return (NS_RETURN);
+}
+#endif /* YP */
+
+
+/*
+ * compat backend
+ */
+static void
+compat_clear_template(struct passwd *template)
+{
+
+	free(template->pw_passwd);
+	free(template->pw_gecos);
+	free(template->pw_dir);
+	free(template->pw_shell);
+	memset(template, 0, sizeof(*template));
+}
+
+
+static int
+compat_set_template(struct passwd *src, struct passwd *template)
+{
+
+	compat_clear_template(template);
+#ifdef PW_OVERRIDE_PASSWD
+	if ((src->pw_fields & _PWF_PASSWD) &&
+	    (template->pw_passwd = strdup(src->pw_passwd)) == NULL)
+		goto enomem;
+#endif
+	if (src->pw_fields & _PWF_UID)
+		template->pw_uid = src->pw_uid;
+	if (src->pw_fields & _PWF_GID)
+		template->pw_gid = src->pw_gid;
+	if ((src->pw_fields & _PWF_GECOS) &&
+	    (template->pw_gecos = strdup(src->pw_gecos)) == NULL)
+		goto enomem;
+	if ((src->pw_fields & _PWF_DIR) &&
+	    (template->pw_dir = strdup(src->pw_dir)) == NULL)
+		goto enomem;
+	if ((src->pw_fields & _PWF_SHELL) &&
+	    (template->pw_shell = strdup(src->pw_shell)) == NULL)
+		goto enomem;
+	template->pw_fields = src->pw_fields;
+	return (0);
+enomem:
+	syslog(LOG_ERR, "getpwent memory allocation failure");
+	return (-1);
+}
+
+
+static int
+compat_use_template(struct passwd *pwd, struct passwd *template, char *buffer,
+    size_t bufsize)
+{
+	struct passwd hold;
+	char	*copy, *p, *q, *eob;
+	size_t	 n;
+
+	/* We cannot know the layout of the password fields in `buffer',
+	 * so we have to copy everything.
+	 */
+	if (template->pw_fields == 0) /* nothing to fill-in */
+		return (0);
+	n = 0;
+	n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0;
+	n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0;
+	n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0;
+	n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0;
+	n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0;
+	n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0;
+	copy = malloc(n);
+	if (copy == NULL) {
+		syslog(LOG_ERR, "getpwent memory allocation failure");
+		return (ENOMEM);
+	}
+	p = copy;
+	eob = &copy[n];
+#define COPY(field) do {				\
+	if (pwd->field == NULL)				\
+		hold.field = NULL;			\
+	else {						\
+		hold.field = p;				\
+		p += strlcpy(p, pwd->field, eob-p) + 1;	\
+	}						\
+} while (0)
+	COPY(pw_name);
+	COPY(pw_passwd);
+	COPY(pw_class);
+	COPY(pw_gecos);
+	COPY(pw_dir);
+	COPY(pw_shell);
+#undef COPY
+	p = buffer;
+	eob = &buffer[bufsize];
+#define COPY(field, flag) do {						 \
+	q = (template->pw_fields & flag) ? template->field : hold.field; \
+	if (q == NULL)							 \
+		pwd->field = NULL;					 \
+	else {								 \
+		pwd->field = p;						 \
+		if ((n = strlcpy(p, q, eob-p)) >= eob-p) {		 \
+			free(copy);					 \
+			return (ERANGE);				 \
+		}							 \
+		p += n + 1;						 \
+	}								 \
+} while (0)
+	COPY(pw_name, 0);
+#ifdef PW_OVERRIDE_PASSWD
+	COPY(pw_passwd, _PWF_PASSWD);
+#else
+	COPY(pw_passwd, 0);
+#endif
+	COPY(pw_class, 0);
+	COPY(pw_gecos, _PWF_GECOS);
+	COPY(pw_dir, _PWF_DIR);
+	COPY(pw_shell, _PWF_SHELL);
+#undef COPY
+#define COPY(field, flag) do {			\
+	if (template->pw_fields & flag)		\
+		pwd->field = template->field;	\
+} while (0)
+	COPY(pw_uid, _PWF_UID);
+	COPY(pw_gid, _PWF_GID);
+#undef COPY
+	free(copy);
+	return (0);
+}
+
+
+static int
+compat_exclude(const char *name, DB **db)
+{
+	DBT	key, data;
+
+	if (*db == NULL &&
+	    (*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL)
+		return (errno);
+	key.size = strlen(name);
+	key.data = (char *)name;
+	data.size = 0;
+	data.data = NULL;
+
+	if ((*db)->put(*db, &key, &data, 0) == -1)
+		return (errno);
+	return (0);
+}
+
+
+static int
+compat_is_excluded(const char *name, DB *db)
+{
+	DBT	key, data;
+
+	if (db == NULL)
+		return (0);
+	key.size = strlen(name);
+	key.data = (char *)name;
+	return (db->get(db, &key, &data, 0) == 0);
+}
+
+
+static int
+compat_redispatch(struct compat_state *st, enum nss_lookup_type how,
+    enum nss_lookup_type lookup_how, const char *name, const char *lookup_name,
+    uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop)
+{
+	static const ns_src compatsrc[] = {
+#ifdef YP
+		{ NSSRC_NIS, NS_SUCCESS },
+#endif
+		{ NULL, 0 }
+	};
+	ns_dtab dtab[] = {
+#ifdef YP
+		{ NSSRC_NIS, nis_passwd, NULL },
+#endif
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_passwd, NULL },
+#endif
+		{ NULL, NULL, NULL }
+	};
+	void		*discard;
+	int		 rv, e, i;
+
+	for (i = 0; i < sizeof(dtab)/sizeof(dtab[0]) - 1; i++)
+		dtab[i].mdata = (void *)lookup_how;
+more:
+	pwd_init(pwd);
+	switch (lookup_how) {
+	case nss_lt_all:
+		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
+		    "getpwent_r", compatsrc, pwd, buffer, bufsize,
+		    errnop);
+		break;
+	case nss_lt_id:
+		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
+		    "getpwuid_r", compatsrc, uid, pwd, buffer,
+		    bufsize, errnop);
+		break;
+	case nss_lt_name:
+		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
+		    "getpwnam_r", compatsrc, lookup_name, pwd, buffer,
+		    bufsize, errnop);
+		break;
+	default:
+		return (NS_UNAVAIL);
+	}
+	if (rv != NS_SUCCESS)
+		return (rv);
+	if (compat_is_excluded(pwd->pw_name, st->exclude)) {
+		if (how == nss_lt_all)
+			goto more;
+		return (NS_NOTFOUND);
+	}
+	e = compat_use_template(pwd, &st->template, buffer, bufsize);
+	if (e != 0) {
+		*errnop = e;
+		if (e == ERANGE)
+			return (NS_RETURN);
+		else
+			return (NS_UNAVAIL);
+	}
+	switch (how) {
+	case nss_lt_name:
+		if (strcmp(name, pwd->pw_name) != 0)
+			return (NS_NOTFOUND);
+		break;
+	case nss_lt_id:
+		if (uid != pwd->pw_uid)
+			return (NS_NOTFOUND);
+		break;
+	default:
+		break;
+	}
+	return (NS_SUCCESS);
+}
+
+
+static void
+compat_endstate(void *p)
+{
+	struct compat_state *st;
+
+	if (p == NULL)
+		return;
+	st = (struct compat_state *)p;
+	if (st->db != NULL)
+		st->db->close(st->db);
+	if (st->exclude != NULL)
+		st->exclude->close(st->exclude);
+	compat_clear_template(&st->template);
+	free(p);
+}
+
+
+static int
+compat_setpwent(void *retval, void *mdata, va_list ap)
+{
+	static const ns_src compatsrc[] = {
+#ifdef YP
+		{ NSSRC_NIS, NS_SUCCESS },
+#endif
+		{ NULL, 0 }
+	};
+	ns_dtab dtab[] = {
+#ifdef YP
+		{ NSSRC_NIS, nis_setpwent, NULL },
+#endif
+#ifdef HESIOD
+		{ NSSRC_DNS, dns_setpwent, NULL },
+#endif
+		{ NULL, NULL, NULL }
+	};
+	struct compat_state	*st;
+	int			 rv, stayopen;
+
+#define set_setent(x, y) do {	 				\
+	int i;							\
+								\
+	for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++)	\
+		x[i].mdata = (void *)y;				\
+} while (0)
+
+	rv = compat_getstate(&st);
+	if (rv != 0)
+		return (NS_UNAVAIL);
+	switch ((enum constants)mdata) {
+	case SETPWENT:
+		stayopen = va_arg(ap, int);
+		st->keynum = 0;
+		if (stayopen)
+			st->db = pwdbopen(&st->version);
+		st->stayopen = stayopen;
+		set_setent(dtab, mdata);
+		(void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpwent",
+		    compatsrc, 0);
+		break;
+	case ENDPWENT:
+		if (st->db != NULL) {
+			(void)st->db->close(st->db);
+			st->db = NULL;
+		}
+		set_setent(dtab, mdata);
+		(void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
+		    compatsrc, 0);
+		break;
+	default:
+		break;
+	}
+	return (NS_UNAVAIL);
+#undef set_setent
+}
+
+
+static int
+compat_passwd(void *retval, void *mdata, va_list ap)
+{
+	char			 keybuf[MAXLOGNAME + 1];
+	DBT			 key, entry;
+	struct compat_state	*st;
+	enum nss_lookup_type	 how;
+	const char		*name;
+	struct passwd		*pwd;
+	char			*buffer, *pw_name;
+	char			*host, *user, *domain;
+	size_t			 bufsize;
+	uid_t			 uid;
+	uint32_t		 store;
+	int			 rv, from_compat, stayopen, *errnop;
+
+	from_compat = 0;
+	name = NULL;
+	uid = (uid_t)-1;
+	how = (enum nss_lookup_type)mdata;
+	switch (how) {
+	case nss_lt_name:
+		name = va_arg(ap, const char *);
+		break;
+	case nss_lt_id:
+		uid = va_arg(ap, uid_t);
+		break;
+	case nss_lt_all:
+		break;
+	default:
+		rv = NS_NOTFOUND;
+		goto fin;
+	}
+	pwd = va_arg(ap, struct passwd *);
+	buffer = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop = va_arg(ap, int *);
+	*errnop = compat_getstate(&st);
+	if (*errnop != 0)
+		return (NS_UNAVAIL);
+	if (how == nss_lt_all && st->keynum < 0) {
+		rv = NS_NOTFOUND;
+		goto fin;
+	}
+	if (st->db == NULL &&
+	    (st->db = pwdbopen(&st->version)) == NULL) {
+		*errnop = errno;
+		rv = NS_UNAVAIL;
+		goto fin;
+	}
+	if (how == nss_lt_all) {
+		if (st->keynum < 0) {
+			rv = NS_NOTFOUND;
+			goto fin;
+		}
+		stayopen = 1;
+	} else {
+		st->keynum = 0;
+		stayopen = st->stayopen;
+	}
+docompat:
+	rv = NS_NOTFOUND;
+	switch (st->compat) {
+	case COMPAT_MODE_ALL:
+		rv = compat_redispatch(st, how, how, name, name, uid, pwd,
+		    buffer, bufsize, errnop);
+		if (rv != NS_SUCCESS)
+			st->compat = COMPAT_MODE_OFF;
+		break;
+	case COMPAT_MODE_NETGROUP:
+		/* XXX getnetgrent is not thread-safe. */
+		do {
+			rv = getnetgrent(&host, &user, &domain);
+			if (rv == 0) {
+				endnetgrent();
+				st->compat = COMPAT_MODE_OFF;
+				rv = NS_NOTFOUND;
+				continue;
+			} else if (user == NULL || user[0] == '\0')
+				continue;
+			rv = compat_redispatch(st, how, nss_lt_name, name,
+			    user, uid, pwd, buffer, bufsize, errnop);
+		} while (st->compat == COMPAT_MODE_NETGROUP &&
+		    !(rv & NS_TERMINATE));
+		break;
+	case COMPAT_MODE_NAME:
+		rv = compat_redispatch(st, how, nss_lt_name, name, st->name,
+		    uid, pwd, buffer, bufsize, errnop);
+		free(st->name);
+		st->name = NULL;
+		st->compat = COMPAT_MODE_OFF;
+		break;
+	default:
+		break;
+	}
+	if (rv & NS_TERMINATE) {
+		from_compat = 1;
+		goto fin;
+	}
+	key.data = keybuf;
+	rv = NS_NOTFOUND;
+	while (st->keynum >= 0) {
+		st->keynum++;
+		if (st->version < _PWD_CURRENT_VERSION) {
+			memcpy(&keybuf[1], &st->keynum, sizeof(st->keynum));
+			key.size = sizeof(st->keynum) + 1;
+		} else {
+			store = htonl(st->keynum);
+			memcpy(&keybuf[1], &store, sizeof(store));
+			key.size = sizeof(store) + 1;
+		}
+		keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version);
+		rv = st->db->get(st->db, &key, &entry, 0);
+		if (rv < 0 || rv > 1) { /* should never return > 1 */
+			*errnop = errno;
+			rv = NS_UNAVAIL;
+			goto fin;
+		} else if (rv == 1) {
+			st->keynum = -1;
+			rv = NS_NOTFOUND;
+			goto fin;
+		}
+		pw_name = (char *)entry.data;
+		switch (pw_name[0]) {
+		case '+':
+			switch (pw_name[1]) {
+			case '\0':
+				st->compat = COMPAT_MODE_ALL;
+				break;
+			case '@':
+				setnetgrent(&pw_name[2]);
+				st->compat = COMPAT_MODE_NETGROUP;
+				break;
+			default:
+				st->name = strdup(&pw_name[1]);
+				if (st->name == NULL) {
+					syslog(LOG_ERR,
+					 "getpwent memory allocation failure");
+					*errnop = ENOMEM;
+					rv = NS_UNAVAIL;
+					break;
+				}
+				st->compat = COMPAT_MODE_NAME;
+			}
+			if (entry.size > bufsize) {
+				*errnop = ERANGE;
+				rv = NS_RETURN;
+				goto fin;
+			}
+			memcpy(buffer, entry.data, entry.size);
+			rv = pwdb_versions[st->version].parse(buffer,
+			    entry.size, pwd, errnop);
+			if (rv != NS_SUCCESS)
+				;
+			else if (compat_set_template(pwd, &st->template) < 0) {
+				*errnop = ENOMEM;
+				rv = NS_UNAVAIL;
+				goto fin;
+			}
+			goto docompat;
+		case '-':
+			switch (pw_name[1]) {
+			case '\0':
+				/* XXX Maybe syslog warning */
+				continue;
+			case '@':
+				setnetgrent(&pw_name[2]);
+				while (getnetgrent(&host, &user, &domain) !=
+				    NULL) {
+					if (user != NULL && user[0] != '\0')
+						compat_exclude(user,
+						    &st->exclude);
+				}
+				endnetgrent();
+				continue;
+			default:
+				compat_exclude(&pw_name[1], &st->exclude);
+				continue;
+			}
+			break;
+		default:
+			break;
+		}
+		if (compat_is_excluded((char *)entry.data, st->exclude))
+			continue;
+		rv = pwdb_versions[st->version].match(entry.data, entry.size,
+		    how, name, uid);
+		if (rv == NS_RETURN)
+			break;
+		else if (rv != NS_SUCCESS)
+			continue;
+		if (entry.size > bufsize) {
+			*errnop = ERANGE;
+			rv = NS_RETURN;
+			break;
+		}
+		memcpy(buffer, entry.data, entry.size);
+		rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
+		    errnop);
+		if (rv & NS_TERMINATE)
+			break;
+	}
+fin:
+	if (!stayopen && st->db != NULL) {
+		(void)st->db->close(st->db);
+		st->db = NULL;
+	}
+	if (rv == NS_SUCCESS) { 
+		if (!from_compat) {
+			pwd->pw_fields &= ~_PWF_SOURCE;
+			pwd->pw_fields |= _PWF_FILES;
+		}
+		if (retval != NULL)
+			*(struct passwd **)retval = pwd;
+	}
+	return (rv);
+}
+
+
+/*
+ * common passwd line matching and parsing
+ */
+int
+__pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how,
+    const char *name, uid_t uid)
+{
+	const char	*p, *eom;
+	char		*q;
+	size_t		 len;
+	unsigned long	 m;
+
+	eom = entry + entrysize;
+	for (p = entry; p < eom; p++)
+		if (*p == ':')
+			break;
+	if (*p != ':')
+		return (NS_NOTFOUND);
+	if (how == nss_lt_all)
+		return (NS_SUCCESS);
+	if (how == nss_lt_name) {
+		len = strlen(name);
+		if (len == (p - entry) && memcmp(name, entry, len) == 0)
+			return (NS_SUCCESS);
+		else
+			return (NS_NOTFOUND);
+	}
+	for (p++; p < eom; p++)
+		if (*p == ':')
+			break;
+	if (*p != ':')
+		return (NS_NOTFOUND);
+	m = strtoul(++p, &q, 10);
+	if (q[0] != ':' || (uid_t)m != uid)
+		return (NS_NOTFOUND);
+	else
+		return (NS_SUCCESS);
+}
+
+
+/* XXX buffer must be NUL-terminated.  errnop is not set correctly. */
+int
+__pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd,
+    int master, int *errnop __unused)
+{
+
+	if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0)
+		return (NS_NOTFOUND);
+	else
+		return (NS_SUCCESS);
+}
Index: /trunk/src/emx/src/lib/bsd/gen/getusershell.c
===================================================================
--- /trunk/src/emx/src/lib/bsd/gen/getusershell.c	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/gen/getusershell.c	(revision 1499)
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 1985, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getusershell.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+/*	$NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem Exp $	*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/gen/getusershell.c,v 1.9 2003/04/24 20:16:21 nectar Exp $");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/file.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <nsswitch.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+#endif
+#include "un-namespace.h"
+
+/*
+ * Local shells should NOT be added here.  They should be added in
+ * /etc/shells.
+ */
+
+static const char *const okshells[] = { _PATH_BSHELL, _PATH_CSHELL, NULL };
+static const char *const *curshell;
+static StringList	 *sl;
+
+static const char *const *initshells(void);
+
+/*
+ * Get a list of shells from "shells" nsswitch database
+ */
+char *
+getusershell(void)
+{
+	char *ret;
+
+	if (curshell == NULL)
+		curshell = initshells();
+	/*LINTED*/
+	ret = (char *)*curshell;
+	if (ret != NULL)
+		curshell++;
+	return (ret);
+}
+
+void
+endusershell(void)
+{
+	if (sl) {
+		sl_free(sl, 1);
+		sl = NULL;
+	}
+	curshell = NULL;
+}
+
+void
+setusershell(void)
+{
+
+	curshell = initshells();
+}
+
+
+static int	_local_initshells(void *, void *, va_list);
+
+/*ARGSUSED*/
+static int
+_local_initshells(rv, cb_data, ap)
+	void	*rv;
+	void	*cb_data;
+	va_list	 ap;
+{
+	char	*sp, *cp;
+	FILE	*fp;
+	char	 line[MAXPATHLEN + 2];
+
+	if (sl)
+		sl_free(sl, 1);
+	sl = sl_init();
+
+	if ((fp = fopen(_PATH_SHELLS, "r")) == NULL)
+		return NS_UNAVAIL;
+
+	sp = cp = line;
+	while (fgets(cp, MAXPATHLEN + 1, fp) != NULL) {
+		while (*cp != '#' && *cp != '/' && *cp != '\0')
+			cp++;
+		if (*cp == '#' || *cp == '\0')
+			continue;
+		sp = cp;
+		while (!isspace(*cp) && *cp != '#' && *cp != '\0')
+			cp++;
+		*cp++ = '\0';
+		sl_add(sl, strdup(sp));
+	}
+	(void)fclose(fp);
+	return NS_SUCCESS;
+}
+
+#ifdef HESIOD
+static int	_dns_initshells(void *, void *, va_list);
+
+/*ARGSUSED*/
+static int
+_dns_initshells(rv, cb_data, ap)
+	void	*rv;
+	void	*cb_data;
+	va_list	 ap;
+{
+	char	  shellname[] = "shells-XXXXX";
+	int	  hsindex, hpi, r;
+	char	**hp;
+	void	 *context;
+
+	if (sl)
+		sl_free(sl, 1);
+	sl = sl_init();
+	r = NS_UNAVAIL;
+	if (hesiod_init(&context) == -1)
+		return (r);
+
+	for (hsindex = 0; ; hsindex++) {
+		snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex);
+		hp = hesiod_resolve(context, shellname, "shells");
+		if (hp == NULL) {
+			if (errno == ENOENT) {
+				if (hsindex == 0)
+					r = NS_NOTFOUND;
+				else
+					r = NS_SUCCESS;
+			}
+			break;
+		} else {
+			for (hpi = 0; hp[hpi]; hpi++)
+				sl_add(sl, hp[hpi]);
+			free(hp);
+		}
+	}
+	hesiod_end(context);
+	return (r);
+}
+#endif /* HESIOD */
+
+#ifdef YP
+static int	_nis_initshells(void *, void *, va_list);
+
+/*ARGSUSED*/
+static int
+_nis_initshells(rv, cb_data, ap)
+	void	*rv;
+	void	*cb_data;
+	va_list	 ap;
+{
+	static char *ypdomain;
+	char	*key, *data;
+	char	*lastkey;
+	int	 keylen, datalen;
+	int	 r;
+
+	if (sl)
+		sl_free(sl, 1);
+	sl = sl_init();
+
+	if (ypdomain == NULL) {
+		switch (yp_get_default_domain(&ypdomain)) {
+		case 0:
+			break;
+		case YPERR_RESRC:
+			return NS_TRYAGAIN;
+		default:
+			return NS_UNAVAIL;
+		}
+	}
+
+	/*
+	 * `key' and `data' point to strings dynamically allocated by
+	 * the yp_... functions.
+	 * `data' is directly put into the stringlist of shells.
+	 */
+	key = data = NULL;
+	if (yp_first(ypdomain, "shells", &key, &keylen, &data, &datalen))
+		return NS_UNAVAIL;
+	do {
+		data[datalen] = '\0';		/* clear trailing \n */
+		sl_add(sl, data);
+
+		lastkey = key;
+		r = yp_next(ypdomain, "shells", lastkey, keylen,
+		    &key, &keylen, &data, &datalen);
+		free(lastkey);
+	} while (r == 0);
+	
+	if (r == YPERR_NOMORE) {
+		/*
+		 * `data' and `key' ought to be NULL - do not try to free them.
+		 */
+		return NS_SUCCESS;
+	}
+
+	return NS_UNAVAIL;
+}
+#endif /* YP */
+
+static const char *const *
+initshells()
+{
+	static const ns_dtab dtab[] = {
+		NS_FILES_CB(_local_initshells, NULL)
+		NS_DNS_CB(_dns_initshells, NULL)
+		NS_NIS_CB(_nis_initshells, NULL)
+		{ 0 }
+	};
+	if (sl)
+		sl_free(sl, 1);
+	sl = sl_init();
+
+	if (_nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc)
+	    != NS_SUCCESS) {
+		if (sl)
+			sl_free(sl, 1);
+		sl = NULL;
+		return (okshells);
+	}
+	sl_add(sl, NULL);
+
+	return (const char *const *)(sl->sl_str);
+}
Index: /trunk/src/emx/src/lib/bsd/gen/pw_scan.c
===================================================================
--- /trunk/src/emx/src/lib/bsd/gen/pw_scan.c	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/gen/pw_scan.c	(revision 1499)
@@ -0,0 +1,203 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)pw_scan.c	8.3 (Berkeley) 4/2/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/gen/pw_scan.c,v 1.24 2002/10/11 11:35:30 maxim Exp $");
+
+/*
+ * This module is used to "verify" password entries by chpass(1) and
+ * pwd_mkdb(8).
+ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pw_scan.h"
+
+/*
+ * Some software assumes that IDs are short.  We should emit warnings
+ * for id's which cannot be stored in a short, but we are more liberal
+ * by default, warning for IDs greater than USHRT_MAX.
+ *
+ * If pw_big_ids_warning is -1 on entry to pw_scan(), it will be set based
+ * on the existence of PW_SCAN_BIG_IDS in the environment.
+ */
+static int	pw_big_ids_warning = -1;
+
+int
+__pw_scan(char *bp, struct passwd *pw, int flags)
+{
+	uid_t id;
+	int root;
+	char *ep, *p, *sh;
+
+	if (pw_big_ids_warning == -1)
+		pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0;
+
+	pw->pw_fields = 0;
+	if (!(pw->pw_name = strsep(&bp, ":")))		/* login */
+		goto fmt;
+	root = !strcmp(pw->pw_name, "root");
+	if (pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0'))
+		pw->pw_fields |= _PWF_NAME;
+
+	if (!(pw->pw_passwd = strsep(&bp, ":")))	/* passwd */
+		goto fmt;
+	if (pw->pw_passwd[0])
+		pw->pw_fields |= _PWF_PASSWD;
+
+	if (!(p = strsep(&bp, ":")))			/* uid */
+		goto fmt;
+	if (p[0])
+		pw->pw_fields |= _PWF_UID;
+	else {
+		if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
+			if (flags & _PWSCAN_WARN)
+				warnx("no uid for user %s", pw->pw_name);
+			return (0);
+		}
+	}
+	id = strtoul(p, &ep, 10);
+	if (errno == ERANGE) {
+		if (flags & _PWSCAN_WARN)
+			warnx("%s > max uid value (%lu)", p, ULONG_MAX);
+		return (0);
+	}
+	if (*ep != '\0') {
+		if (flags & _PWSCAN_WARN)
+			warnx("%s uid is incorrect", p);
+		return (0);
+	}
+	if (root && id) {
+		if (flags & _PWSCAN_WARN)
+			warnx("root uid should be 0");
+		return (0);
+	}
+	if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
+		warnx("%s > recommended max uid value (%u)", p, USHRT_MAX);
+		/*return (0);*/ /* THIS SHOULD NOT BE FATAL! */
+	}
+	pw->pw_uid = id;
+
+	if (!(p = strsep(&bp, ":")))			/* gid */
+		goto fmt;
+	if (p[0])
+		pw->pw_fields |= _PWF_GID;
+	else {
+		if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
+			if (flags & _PWSCAN_WARN)
+				warnx("no gid for user %s", pw->pw_name);
+			return (0);
+		}
+	}
+	id = strtoul(p, &ep, 10);
+	if (errno == ERANGE) {
+		if (flags & _PWSCAN_WARN)
+			warnx("%s > max gid value (%lu)", p, ULONG_MAX);
+		return (0);
+	}
+	if (*ep != '\0') {
+		if (flags & _PWSCAN_WARN)
+			warnx("%s gid is incorrect", p);
+		return (0);
+	}
+	if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
+		warnx("%s > recommended max gid value (%u)", p, USHRT_MAX);
+		/* return (0); This should not be fatal! */
+	}
+	pw->pw_gid = id;
+
+	if (flags & _PWSCAN_MASTER ) {
+		if (!(pw->pw_class = strsep(&bp, ":")))	/* class */
+			goto fmt;
+		if (pw->pw_class[0])
+			pw->pw_fields |= _PWF_CLASS;
+		
+		if (!(p = strsep(&bp, ":")))		/* change */
+			goto fmt;
+		if (p[0])
+			pw->pw_fields |= _PWF_CHANGE;
+		pw->pw_change = atol(p);
+		
+		if (!(p = strsep(&bp, ":")))		/* expire */
+			goto fmt;
+		if (p[0])
+			pw->pw_fields |= _PWF_EXPIRE;
+		pw->pw_expire = atol(p);
+	}
+	if (!(pw->pw_gecos = strsep(&bp, ":")))		/* gecos */
+		goto fmt;
+	if (pw->pw_gecos[0])
+		pw->pw_fields |= _PWF_GECOS;
+
+	if (!(pw->pw_dir = strsep(&bp, ":")))		/* directory */
+		goto fmt;
+	if (pw->pw_dir[0])
+		pw->pw_fields |= _PWF_DIR;
+
+	if (!(pw->pw_shell = strsep(&bp, ":")))		/* shell */
+		goto fmt;
+
+	p = pw->pw_shell;
+	if (root && *p)					/* empty == /bin/sh */
+		for (setusershell();;) {
+			if (!(sh = getusershell())) {
+				if (flags & _PWSCAN_WARN)
+					warnx("warning, unknown root shell");
+				break;
+			}
+			if (!strcmp(p, sh))
+				break;
+		}
+	if (p[0])
+		pw->pw_fields |= _PWF_SHELL;
+
+	if ((p = strsep(&bp, ":"))) {			/* too many */
+fmt:		
+		if (flags & _PWSCAN_WARN)
+			warnx("corrupted entry");
+		return (0);
+	}
+	return (1);
+}
Index: /trunk/src/emx/src/lib/bsd/gen/pw_scan.h
===================================================================
--- /trunk/src/emx/src/lib/bsd/gen/pw_scan.h	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/gen/pw_scan.h	(revision 1499)
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)pw_scan.h	8.1 (Berkeley) 4/1/94
+ * $FreeBSD: src/lib/libc/gen/pw_scan.h,v 1.6 2002/03/22 23:41:42 obrien Exp $
+ */
+
+#define _PWSCAN_MASTER 0x01
+#define _PWSCAN_WARN   0x02
+
+extern int	__pw_scan(char *, struct passwd *, int);
Index: /trunk/src/emx/src/lib/bsd/gen/stringlist.c
===================================================================
--- /trunk/src/emx/src/lib/bsd/gen/stringlist.c	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/gen/stringlist.c	(revision 1499)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1994 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Christos Zoulas.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$NetBSD: stringlist.c,v 1.2 1997/01/17 07:26:20 lukem Exp $";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/gen/stringlist.c,v 1.7 2003/01/19 01:16:01 obrien Exp $");
+
+#include "namespace.h"
+#include <stdio.h>
+#include <string.h>
+#include <err.h>
+#include <stdlib.h>
+#include <stringlist.h>
+#include "un-namespace.h"
+
+#define _SL_CHUNKSIZE	20
+
+/*
+ * sl_init(): Initialize a string list
+ */
+StringList *
+sl_init()
+{
+	StringList *sl;
+
+	sl = malloc(sizeof(StringList));
+	if (sl == NULL)
+		_err(1, "stringlist: %m");
+
+	sl->sl_cur = 0;
+	sl->sl_max = _SL_CHUNKSIZE;
+	sl->sl_str = malloc(sl->sl_max * sizeof(char *));
+	if (sl->sl_str == NULL)
+		_err(1, "stringlist: %m");
+	return sl;
+}
+
+
+/*
+ * sl_add(): Add an item to the string list
+ */
+int
+sl_add(sl, name)
+	StringList *sl;
+	char *name;
+{
+	if (sl->sl_cur == sl->sl_max - 1) {
+		sl->sl_max += _SL_CHUNKSIZE;
+		sl->sl_str = reallocf(sl->sl_str, sl->sl_max * sizeof(char *));
+		if (sl->sl_str == NULL)
+			return (-1);
+	}
+	sl->sl_str[sl->sl_cur++] = name;
+	return (0);
+}
+
+
+/*
+ * sl_free(): Free a stringlist
+ */
+void
+sl_free(sl, all)
+	StringList *sl;
+	int all;
+{
+	size_t i;
+
+	if (sl == NULL)
+		return;
+	if (sl->sl_str) {
+		if (all)
+			for (i = 0; i < sl->sl_cur; i++)
+				free(sl->sl_str[i]);
+		free(sl->sl_str);
+	}
+	free(sl);
+}
+
+
+/*
+ * sl_find(): Find a name in the string list
+ */
+char *
+sl_find(sl, name)
+	StringList *sl;
+	char *name;
+{
+	size_t i;
+
+	for (i = 0; i < sl->sl_cur; i++)
+		if (strcmp(sl->sl_str[i], name) == 0)
+			return sl->sl_str[i];
+
+	return NULL;
+}
Index: /trunk/src/emx/src/lib/bsd/net/nsdispatch.c
===================================================================
--- /trunk/src/emx/src/lib/bsd/net/nsdispatch.c	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/net/nsdispatch.c	(revision 1499)
@@ -0,0 +1,611 @@
+/*	$NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/net/nsdispatch.c,v 1.8 2003/04/24 19:57:31 nectar Exp $");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "un-namespace.h"
+
+enum _nss_constants {
+	/* Number of elements allocated when we grow a vector */
+	ELEMSPERCHUNK =	8
+};
+
+/*
+ * Global NSS data structures are mostly read-only, but we update
+ * them when we read or re-read the nsswitch.conf.
+ */
+static	pthread_rwlock_t	nss_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/*
+ * Runtime determination of whether we are dynamically linked or not.
+ */
+extern	int		_DYNAMIC __attribute__ ((weak));
+#define	is_dynamic()	(&_DYNAMIC != NULL)
+
+/*
+ * default sourcelist: `files'
+ */
+const ns_src __nsdefaultsrc[] = {
+	{ NSSRC_FILES, NS_SUCCESS },
+	{ 0 },
+};
+
+/* Database, source mappings. */
+static	unsigned int		 _nsmapsize;
+static	ns_dbt			*_nsmap = NULL;
+
+/* NSS modules. */
+static	unsigned int		 _nsmodsize;
+static	ns_mod			*_nsmod;
+
+/* Placeholder for builtin modules' dlopen `handle'. */
+static	int			 __nss_builtin_handle;
+static	void			*nss_builtin_handle = &__nss_builtin_handle;
+
+/*
+ * Attempt to spew relatively uniform messages to syslog.
+ */
+#define nss_log(level, fmt, ...) \
+	syslog((level), "NSSWITCH(%s): " fmt, __func__, __VA_ARGS__)
+#define nss_log_simple(level, s) \
+	syslog((level), "NSSWITCH(%s): " s, __func__)
+
+/*
+ * Dynamically growable arrays are used for lists of databases, sources,
+ * and modules.  The following `vector' interface is used to isolate the
+ * common operations.
+ */
+typedef	int	(*vector_comparison)(const void *, const void *);
+typedef	void	(*vector_free_elem)(void *);
+static	void	  vector_sort(void *, unsigned int, size_t,
+		    vector_comparison);
+static	void	  vector_free(void **, unsigned int *, size_t,
+		    vector_free_elem);
+static	void	 *vector_ref(unsigned int, void *, unsigned int, size_t);
+static	void	 *vector_search(const void *, void *, unsigned int, size_t,
+		    vector_comparison);
+static	int	  vector_append(const void *, void **, unsigned int *, size_t);
+
+
+/*
+ * Internal interfaces.
+ */
+static	int	 string_compare(const void *, const void *);
+static	int	 mtab_compare(const void *, const void *);
+static	int	 nss_configure(void);
+static	void	 ns_dbt_free(ns_dbt *);
+static	void	 ns_mod_free(ns_mod *);
+static	void	 ns_src_free(ns_src **, int);
+static	void	 nss_load_builtin_modules(void);
+static	void	 nss_load_module(const char *, nss_module_register_fn);
+static	void	 nss_atexit(void);
+/* nsparser */
+extern	FILE	*_nsyyin;
+
+
+/*
+ * The vector operations
+ */
+static void
+vector_sort(void *vec, unsigned int count, size_t esize,
+    vector_comparison comparison)
+{
+	qsort(vec, count, esize, comparison);
+}
+
+
+static void *
+vector_search(const void *key, void *vec, unsigned int count, size_t esize,
+    vector_comparison comparison)
+{
+	return (bsearch(key, vec, count, esize, comparison));
+}
+
+
+static int
+vector_append(const void *elem, void **vec, unsigned int *count, size_t esize)
+{
+	void	*p;
+
+	if ((*count % ELEMSPERCHUNK) == 0) {
+		p = realloc(*vec, (*count + ELEMSPERCHUNK) * esize);
+		if (p == NULL) {
+			nss_log_simple(LOG_ERR, "memory allocation failure");
+			return (0);
+		} else
+			*vec = p;
+	}
+	memmove((void *)(((uintptr_t)*vec) + (*count * esize)),
+	    elem, esize);
+	(*count)++;
+	return (1);
+}
+
+
+static void *
+vector_ref(unsigned int i, void *vec, unsigned int count, size_t esize)
+{
+	if (i < count)
+		return (void *)((uintptr_t)vec + (i * esize));
+	else
+		return (NULL);
+}
+
+
+static void
+vector_free(void **vec, unsigned int *count, size_t esize,
+    vector_free_elem free_elem)
+{
+	unsigned int	 i;
+	void		*elem;
+
+	for (i = 0; i < *count; i++) {
+		elem = vector_ref(i, *vec, *count, esize);
+		if (elem != NULL)
+			free_elem(elem);
+	}
+	free(*vec);
+	*vec = NULL;
+	*count = 0;
+}
+
+
+
+/*
+ * Comparison functions for vector_search.
+ */
+static int
+string_compare(const void *a, const void *b)
+{
+      return (strcasecmp(*(const char * const *)a, *(const char * const *)b));
+}
+
+
+static int
+mtab_compare(const void *a, const void *b)
+{
+      int     cmp;
+      
+      cmp = strcmp(((const ns_mtab *)a)->name, ((const ns_mtab *)b)->name);
+      if (cmp != 0)
+	      return (cmp);
+      else
+	      return (strcmp(((const ns_mtab *)a)->database,
+		  ((const ns_mtab *)b)->database));
+}
+
+
+
+/*
+ * NSS nsmap management.
+ */
+void
+_nsdbtaddsrc(ns_dbt *dbt, const ns_src *src)
+{
+	const ns_mod	*modp;
+
+	vector_append(src, (void **)&dbt->srclist, &dbt->srclistsize,
+	    sizeof(*src));
+	modp = vector_search(&src->name, _nsmod, _nsmodsize, sizeof(*_nsmod),
+	    string_compare);
+	if (modp == NULL)
+		nss_load_module(src->name, NULL);
+}
+
+
+#ifdef _NSS_DEBUG
+void
+_nsdbtdump(const ns_dbt *dbt)
+{
+	int i;
+
+	printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
+	    dbt->srclistsize == 1 ? "" : "s");
+	for (i = 0; i < (int)dbt->srclistsize; i++) {
+		printf(" %s", dbt->srclist[i].name);
+		if (!(dbt->srclist[i].flags &
+		    (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
+		    (dbt->srclist[i].flags & NS_SUCCESS))
+			continue;
+		printf(" [");
+		if (!(dbt->srclist[i].flags & NS_SUCCESS))
+			printf(" SUCCESS=continue");
+		if (dbt->srclist[i].flags & NS_UNAVAIL)
+			printf(" UNAVAIL=return");
+		if (dbt->srclist[i].flags & NS_NOTFOUND)
+			printf(" NOTFOUND=return");
+		if (dbt->srclist[i].flags & NS_TRYAGAIN)
+			printf(" TRYAGAIN=return");
+		printf(" ]");
+	}
+	printf("\n");
+}
+#endif
+
+
+/* 
+ * The first time nsdispatch is called (during a process's lifetime,
+ * or after nsswitch.conf has been updated), nss_configure will
+ * prepare global data needed by NSS.
+ */
+static int
+nss_configure(void)
+{
+	static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER;
+	static time_t	 confmod;
+	struct stat	 statbuf;
+	int		 result;
+	const char	*path;
+
+#if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT)
+	/* NOTE WELL:  THIS IS A SECURITY HOLE. This must only be built
+	 * for debugging purposes and MUST NEVER be used in production.
+	 */
+	path = getenv("NSSWITCH_CONF");
+	if (path == NULL)
+#endif
+	path = _PATH_NS_CONF;
+	if (stat(path, &statbuf) != 0)
+		return (0);
+	if (statbuf.st_mtime <= confmod)
+		return (0);
+	result = _pthread_mutex_trylock(&conf_lock);
+	if (result != 0)
+		return (0);
+	(void)_pthread_rwlock_unlock(&nss_lock);
+	result = _pthread_rwlock_wrlock(&nss_lock);
+	if (result != 0)
+		goto fin2;
+	_nsyyin = fopen(path, "r");
+	if (_nsyyin == NULL)
+		goto fin;
+	vector_free((void **)&_nsmap, &_nsmapsize, sizeof(*_nsmap),
+	    (vector_free_elem)ns_dbt_free);
+	vector_free((void **)&_nsmod, &_nsmodsize, sizeof(*_nsmod),
+	    (vector_free_elem)ns_mod_free);
+	nss_load_builtin_modules();
+	_nsyyparse();
+	(void)fclose(_nsyyin);
+	vector_sort(_nsmap, _nsmapsize, sizeof(*_nsmap), string_compare);
+	if (confmod == 0)
+		(void)atexit(nss_atexit);
+	confmod = statbuf.st_mtime;
+fin:
+	(void)_pthread_rwlock_unlock(&nss_lock);
+	result = _pthread_rwlock_rdlock(&nss_lock);
+fin2:
+	(void)_pthread_mutex_unlock(&conf_lock);
+	return (result);
+}
+
+
+void
+_nsdbtput(const ns_dbt *dbt)
+{
+	unsigned int	 i;
+	ns_dbt		*p;
+
+	for (i = 0; i < _nsmapsize; i++) {
+		p = vector_ref(i, _nsmap, _nsmapsize, sizeof(*_nsmap));
+		if (string_compare(&dbt->name, &p->name) == 0) {
+			/* overwrite existing entry */
+			if (p->srclist != NULL)
+				ns_src_free(&p->srclist, p->srclistsize);
+			memmove(p, dbt, sizeof(*dbt));
+			return;
+		}
+	}
+	vector_append(dbt, (void **)&_nsmap, &_nsmapsize, sizeof(*_nsmap));
+}
+
+
+static void
+ns_dbt_free(ns_dbt *dbt)
+{
+	ns_src_free(&dbt->srclist, dbt->srclistsize);
+}
+
+
+static void
+ns_src_free(ns_src **src, int srclistsize)
+{
+	int	i;
+
+	for (i = 0; i < srclistsize; i++)
+		if ((*src)[i].name != NULL)
+			/* This one was allocated by nslexer. You'll just
+			 * have to trust me.
+			 */
+			free((void *)((*src)[i].name));
+	free(*src);
+	*src = NULL;
+}
+
+
+
+/*
+ * NSS module management.
+ */
+/* The built-in NSS modules are all loaded at once. */
+#define NSS_BACKEND(name, reg) \
+ns_mtab	*reg(unsigned int *, nss_module_unregister_fn *);
+#include "nss_backends.h"
+#undef NSS_BACKEND
+
+static void
+nss_load_builtin_modules(void)
+{
+#define NSS_BACKEND(name, reg) nss_load_module(#name, reg);
+#include "nss_backends.h"
+#undef NSS_BACKEND
+}
+
+
+/* Load a built-in or dynamically linked module.  If the `reg_fn'
+ * argument is non-NULL, assume a built-in module and use reg_fn to
+ * register it.  Otherwise, search for a dynamic NSS module.
+ */
+static void
+nss_load_module(const char *source, nss_module_register_fn reg_fn)
+{
+	char		 buf[PATH_MAX];
+	ns_mod		 mod;
+	nss_module_register_fn fn;
+	
+	memset(&mod, 0, sizeof(mod));
+	mod.name = strdup(source);
+	if (mod.name == NULL) {
+		nss_log_simple(LOG_ERR, "memory allocation failure");
+		return;
+	}
+	if (reg_fn != NULL) {
+		/* The placeholder is required, as a NULL handle 
+		 * represents an invalid module.
+		 */
+		mod.handle = nss_builtin_handle;
+		fn = reg_fn;
+	} else if (!is_dynamic())
+		goto fin;
+	else {
+		if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name,
+		    NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf))
+			goto fin;
+		mod.handle = dlopen(buf, RTLD_LOCAL|RTLD_LAZY);
+		if (mod.handle == NULL) {
+#ifdef _NSS_DEBUG
+			/* This gets pretty annoying since the built-in
+			 * sources aren't modules yet.
+			 */
+			nss_log(LOG_DEBUG, "%s, %s", mod.name, dlerror());
+#endif
+			goto fin;
+		}
+		fn = (nss_module_register_fn)dlfunc(mod.handle,
+		    "nss_module_register");
+		if (fn == NULL) {
+			(void)dlclose(mod.handle);
+			mod.handle = NULL;
+			nss_log(LOG_ERR, "%s, %s", mod.name, dlerror());
+			goto fin;
+		}
+	}
+	mod.mtab = fn(mod.name, &mod.mtabsize, &mod.unregister);
+	if (mod.mtab == NULL || mod.mtabsize == 0) {
+		if (mod.handle != nss_builtin_handle)
+			(void)dlclose(mod.handle);
+		mod.handle = NULL;
+		nss_log(LOG_ERR, "%s, registration failed", mod.name);
+		goto fin;
+	}
+	if (mod.mtabsize > 1)
+		qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]),
+		    mtab_compare);
+fin:
+	vector_append(&mod, (void **)&_nsmod, &_nsmodsize, sizeof(*_nsmod));
+	vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare);
+}
+
+
+
+static void
+ns_mod_free(ns_mod *mod)
+{
+
+	free(mod->name);
+	if (mod->handle == NULL)
+		return;
+	if (mod->unregister != NULL)
+		mod->unregister(mod->mtab, mod->mtabsize);
+	if (mod->handle != nss_builtin_handle)
+		(void)dlclose(mod->handle);
+}
+
+
+
+/*
+ * Cleanup
+ */
+static void
+nss_atexit(void)
+{
+	(void)_pthread_rwlock_wrlock(&nss_lock);
+	vector_free((void **)&_nsmap, &_nsmapsize, sizeof(*_nsmap),
+	    (vector_free_elem)ns_dbt_free);
+	vector_free((void **)&_nsmod, &_nsmodsize, sizeof(*_nsmod),
+	    (vector_free_elem)ns_mod_free);
+	(void)_pthread_rwlock_unlock(&nss_lock);
+}
+
+
+
+/*
+ * Finally, the actual implementation.
+ */
+static nss_method
+nss_method_lookup(const char *source, const char *database,
+    const char *method, const ns_dtab disp_tab[], void **mdata)
+{
+	ns_mod	*mod;
+	ns_mtab	*match, key;
+	int	 i;
+
+	if (disp_tab != NULL)
+		for (i = 0; disp_tab[i].src != NULL; i++)
+			if (strcasecmp(source, disp_tab[i].src) == 0) {
+				*mdata = disp_tab[i].mdata;
+				return (disp_tab[i].method);
+			}
+	mod = vector_search(&source, _nsmod, _nsmodsize, sizeof(*_nsmod),
+	    string_compare);
+	if (mod != NULL && mod->handle != NULL) {
+		key.database = database;
+		key.name = method;
+		match = bsearch(&key, mod->mtab, mod->mtabsize,
+		    sizeof(mod->mtab[0]), mtab_compare);
+		if (match != NULL) {
+			*mdata = match->mdata;
+			return (match->method);
+		}
+	}
+	if (is_dynamic())
+		nss_log(LOG_DEBUG, "%s, %s, %s, not found", source, database,
+		    method);
+	*mdata = NULL;
+	return (NULL);
+}
+
+
+__weak_reference(_nsdispatch, nsdispatch);
+
+int
+_nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
+	    const char *method_name, const ns_src defaults[], ...)
+{
+	va_list		 ap;
+	const ns_dbt	*dbt;
+	const ns_src	*srclist;
+	nss_method	 method;
+	void		*mdata;
+	int		 serrno, i, result, srclistsize;
+
+	serrno = errno;
+	result = _pthread_rwlock_rdlock(&nss_lock);
+	if (result != 0) {
+		result = NS_UNAVAIL;
+		goto fin;
+	}
+	result = nss_configure();
+	if (result != 0) {
+		result = NS_UNAVAIL;
+		goto fin;
+	}
+	dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap),
+	    string_compare);
+	if (dbt != NULL) {
+		srclist = dbt->srclist;
+		srclistsize = dbt->srclistsize;
+	} else {
+		srclist = defaults;
+		srclistsize = 0;
+		while (srclist[srclistsize].name != NULL)
+			srclistsize++;
+	}
+	for (i = 0; i < srclistsize; i++) {
+		result = NS_NOTFOUND;
+		method = nss_method_lookup(srclist[i].name, database,
+		    method_name, disp_tab, &mdata);
+		if (method != NULL) {
+			va_start(ap, defaults);
+			result = method(retval, mdata, ap);
+			va_end(ap);
+			if (result & (srclist[i].flags))
+				break;
+		}
+	}
+	(void)_pthread_rwlock_unlock(&nss_lock);
+fin:
+	errno = serrno;
+	return (result);
+}
Index: /trunk/src/emx/src/lib/bsd/net/nslexer.l
===================================================================
--- /trunk/src/emx/src/lib/bsd/net/nslexer.l	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/net/nslexer.l	(revision 1499)
@@ -0,0 +1,119 @@
+%{
+/*	$NetBSD: nslexer.l,v 1.3 1999/01/25 00:16:17 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = 
+  "$FreeBSD: src/lib/libc/net/nslexer.l,v 1.5 2003/04/17 14:14:22 nectar Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <ctype.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <string.h>
+#include <syslog.h>
+#include "un-namespace.h"
+
+#include "nsparser.h"
+
+#define YY_NO_UNPUT
+
+%}
+
+%option yylineno
+
+BLANK		[ \t]
+CR		\n
+STRING		[a-zA-Z][a-zA-Z0-9_]*
+
+%%
+
+{BLANK}+	;			/* skip whitespace */
+
+#.*		;			/* skip comments */
+
+\\{CR}		;			/* allow continuation */
+
+{CR}		return NL;
+
+[sS][uU][cC][cC][eE][sS][sS]		return SUCCESS;
+[uU][nN][aA][vV][aA][iI][lL]		return UNAVAIL;
+[nN][oO][tT][fF][oO][uU][nN][dD]	return NOTFOUND;
+[tT][rR][yY][aA][gG][aA][iI][nN]	return TRYAGAIN;
+
+[rR][eE][tT][uU][rR][nN]		return RETURN;
+[cC][oO][nN][tT][iI][nN][uU][eE]	return CONTINUE;
+
+{STRING}	{
+			char *p;
+			int i;
+
+			if ((p = strdup(yytext)) == NULL) {
+				syslog(LOG_ERR,
+			       "NSSWITCH(nslexer): memory allocation failure");
+				return ERRORTOKEN;
+			}
+			for (i = 0; i < strlen(p); i++) {
+				if (isupper((unsigned char)p[i]))
+					p[i] = tolower((unsigned char)p[i]);
+			}
+			_nsyylval.str = p;
+			return STRING;
+		}
+
+.		return yytext[0];
+
+%%
+
+#undef _nsyywrap
+int
+_nsyywrap()
+{
+	return 1;
+} /* _nsyywrap */
+
+void
+_nsyyerror(msg)
+	const char *msg;
+{
+
+	 syslog(LOG_ERR, "NSSWITCH(nslexer): %s line %d: %s at '%s'",
+	     _PATH_NS_CONF, yylineno, msg, yytext);
+} /* _nsyyerror */
Index: /trunk/src/emx/src/lib/bsd/net/nsparser.y
===================================================================
--- /trunk/src/emx/src/lib/bsd/net/nsparser.y	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/net/nsparser.y	(revision 1499)
@@ -0,0 +1,178 @@
+%{
+/*	$NetBSD: nsparser.y,v 1.3 1999/01/25 00:16:18 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/net/nsparser.y,v 1.4 2003/04/17 14:14:22 nectar Exp $");
+
+#include "namespace.h"
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include "un-namespace.h"
+
+static	void	_nsaddsrctomap(const char *);
+
+static	ns_dbt		curdbt;
+static	ns_src		cursrc;
+%}
+
+%union {
+	char *str;
+	int   mapval;
+}
+
+%token	NL
+%token	SUCCESS UNAVAIL NOTFOUND TRYAGAIN
+%token	RETURN CONTINUE
+%token  ERRORTOKEN
+%token	<str> STRING
+
+%type	<mapval> Status Action
+
+%%
+
+File
+	:	/* empty */
+	| Lines
+	;
+
+Lines
+	: Entry
+	| Lines Entry
+	;
+
+Entry
+	: NL
+	| Database ':' NL
+	| Database ':' Srclist NL
+		{
+			_nsdbtput(&curdbt);
+		}
+	| error NL
+		{
+			yyerrok;
+		}
+	;
+
+Database
+	: STRING
+		{
+			curdbt.name = yylval.str;
+			curdbt.srclist = NULL;
+			curdbt.srclistsize = 0;
+		}
+	;
+
+Srclist
+	: Item
+	| Srclist Item
+	;
+
+Item
+	: STRING
+		{
+			cursrc.flags = NS_TERMINATE;
+			_nsaddsrctomap($1);
+		}
+	| STRING '[' { cursrc.flags = NS_SUCCESS; } Criteria ']'
+		{
+			_nsaddsrctomap($1);
+		}
+	;
+
+Criteria
+	: Criterion
+	| Criteria Criterion
+	;
+
+Criterion
+	: Status '=' Action
+		{
+			if ($3)	     /* if action == RETURN set RETURN bit */
+				cursrc.flags |= $1;  
+			else	     /* else unset it */
+				cursrc.flags &= ~$1;
+		}
+	;
+
+Status
+	: SUCCESS	{ $$ = NS_SUCCESS; }
+	| UNAVAIL	{ $$ = NS_UNAVAIL; }
+	| NOTFOUND	{ $$ = NS_NOTFOUND; }
+	| TRYAGAIN	{ $$ = NS_TRYAGAIN; }
+	;
+
+Action
+	: RETURN	{ $$ = NS_ACTION_RETURN; }
+	| CONTINUE	{ $$ = NS_ACTION_CONTINUE; }
+	;
+
+%%
+
+static void
+_nsaddsrctomap(elem)
+	const char *elem;
+{
+	int		i, lineno;
+	extern int	_nsyylineno;
+	extern char *	_nsyytext;
+
+	lineno = _nsyylineno - (*_nsyytext == '\n' ? 1 : 0);
+	if (curdbt.srclistsize > 0) {
+		if ((strcasecmp(elem, NSSRC_COMPAT) == 0) ||
+		    (strcasecmp(curdbt.srclist[0].name, NSSRC_COMPAT) == 0)) {
+			syslog(LOG_ERR,
+	    "NSSWITCH(nsparser): %s line %d: 'compat' used with other sources",
+			    _PATH_NS_CONF, lineno);
+			return;
+		}
+	}
+	for (i = 0; i < curdbt.srclistsize; i++) {
+		if (strcasecmp(curdbt.srclist[i].name, elem) == 0) {
+			syslog(LOG_ERR,
+		       "NSSWITCH(nsparser): %s line %d: duplicate source '%s'",
+			    _PATH_NS_CONF, lineno, elem);
+			return;
+		}
+	}
+	cursrc.name = elem;
+	_nsdbtaddsrc(&curdbt, &cursrc);
+}
Index: /trunk/src/emx/src/lib/bsd/net/nss_backends.h
===================================================================
--- /trunk/src/emx/src/lib/bsd/net/nss_backends.h	(revision 1499)
+++ /trunk/src/emx/src/lib/bsd/net/nss_backends.h	(revision 1499)
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/net/nss_backends.h,v 1.1 2003/04/17 14:14:22 nectar Exp $
+ */
+/*
+ * Eventually, the implementations of existing built-in NSS functions
+ * may be moved into NSS modules and live here.
+ */
+#if 0
+NSS_BACKEND(	files,	_files_nss_module_register	)
+NSS_BACKEND(	dns,	_dns_nss_module_register	)
+NSS_BACKEND(	nis,	_nis_nss_module_register	)
+NSS_BACKEND(	compat,	_compat_nss_module_register	)
+#endif
