svn commit: r301711 - in head: etc include lib/libc/gen share/man/man5

Mark Johnston markj at FreeBSD.org
Thu Jun 9 01:28:45 UTC 2016


Author: markj
Date: Thu Jun  9 01:28:44 2016
New Revision: 301711
URL: https://svnweb.freebsd.org/changeset/base/301711

Log:
  Implement an NSS backend for netgroups and add getnetgrent_r(3).
  
  This support appears to have been documented in nsswitch.conf(5) for some
  time. The implementation adds two NSS netgroup providers to libc. The
  default, compat, provides the behaviour documented in netgroup(5), so this
  change does not make any user-visible behaviour changes. A files provider
  is also implemented.
  
  innetgr(3) is implemented as an optional NSS method so that providers such
  as NIS which are able to implement efficient reverse lookup can do so.
  A fallback implementation is used otherwise. getnetgrent_r(3) is added for
  convenience and to provide compatibility with glibc and Solaris.
  
  With a small patch to net/nss_ldap, it's possible to specify an ldap
  netgroup provider, allowing one to query nisNetgroupTriple entries.
  
  Sponsored by:	EMC / Isilon Storage Division

Modified:
  head/etc/nsswitch.conf
  head/include/netdb.h
  head/lib/libc/gen/Symbol.map
  head/lib/libc/gen/getnetgrent.3
  head/lib/libc/gen/getnetgrent.c
  head/share/man/man5/nsswitch.conf.5

Modified: head/etc/nsswitch.conf
==============================================================================
--- head/etc/nsswitch.conf	Thu Jun  9 01:11:48 2016	(r301710)
+++ head/etc/nsswitch.conf	Thu Jun  9 01:28:44 2016	(r301711)
@@ -5,6 +5,7 @@
 group: compat
 group_compat: nis
 hosts: files dns
+netgroup: compat
 networks: files
 passwd: compat
 passwd_compat: nis

Modified: head/include/netdb.h
==============================================================================
--- head/include/netdb.h	Thu Jun  9 01:11:48 2016	(r301710)
+++ head/include/netdb.h	Thu Jun  9 01:28:44 2016	(r301711)
@@ -275,6 +275,7 @@ int		getnetbyname_r(const char *, struct
 int		getnetent_r(struct netent *, char *, size_t, struct netent **,
     int *);
 int		getnetgrent(char **, char **, char **);
+int		getnetgrent_r(char **, char **, char **, char *, size_t);
 int		getprotobyname_r(const char *, struct protoent *, char *,
     size_t, struct protoent **);
 int		getprotobynumber_r(int, struct protoent *, char *, size_t,

Modified: head/lib/libc/gen/Symbol.map
==============================================================================
--- head/lib/libc/gen/Symbol.map	Thu Jun  9 01:11:48 2016	(r301710)
+++ head/lib/libc/gen/Symbol.map	Thu Jun  9 01:28:44 2016	(r301711)
@@ -410,6 +410,7 @@ FBSD_1.3 {
 };
 
 FBSD_1.4 {
+	getnetgrent_r;
 	pthread_mutex_consistent;
 	pthread_mutexattr_getrobust;
 	pthread_mutexattr_setrobust;

Modified: head/lib/libc/gen/getnetgrent.3
==============================================================================
--- head/lib/libc/gen/getnetgrent.3	Thu Jun  9 01:11:48 2016	(r301710)
+++ head/lib/libc/gen/getnetgrent.3	Thu Jun  9 01:28:44 2016	(r301711)
@@ -28,7 +28,7 @@
 .\"     @(#)getnetgrent.3	8.1 (Berkeley) 6/4/93
 .\" $FreeBSD$
 .\"
-.Dd June 4, 1993
+.Dd June 5, 2016
 .Dt GETNETGRENT 3
 .Os
 .Sh NAME
@@ -44,6 +44,8 @@
 .Ft int
 .Fn getnetgrent "char **host" "char **user" "char **domain"
 .Ft int
+.Fn getnetgrent_r "char **host" "char **user" "char **domain" "char *buf" "size_t bufsize"
+.Ft int
 .Fn innetgr "const char *netgroup" "const char *host" "const char *user" "const char *domain"
 .Ft void
 .Fn setnetgrent "const char *netgroup"

Modified: head/lib/libc/gen/getnetgrent.c
==============================================================================
--- head/lib/libc/gen/getnetgrent.c	Thu Jun  9 01:11:48 2016	(r301710)
+++ head/lib/libc/gen/getnetgrent.c	Thu Jun  9 01:28:44 2016	(r301711)
@@ -36,12 +36,21 @@ static char sccsid[] = "@(#)getnetgrent.
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "namespace.h"
+
 #include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <nsswitch.h>
+#include <pthread.h>
+#include <pthread_np.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+#include "nss_tls.h"
+
 #ifdef YP
 /*
  * Notes:
@@ -98,6 +107,16 @@ static int _yp_innetgr;
 #define _PATH_NETGROUP "/etc/netgroup"
 #endif
 
+enum constants {
+	NGRP_STORAGE_INITIAL	= 1 << 10, /* 1 KByte */
+	NGRP_STORAGE_MAX	= 1 << 20, /* 1 MByte */
+};
+
+static const ns_src defaultsrc[] = {
+	{ NSSRC_COMPAT, NS_SUCCESS },
+	{ NULL, 0 },
+};
+
 /*
  * Static Variables and functions used by setnetgrent(), getnetgrent() and
  * endnetgrent().
@@ -117,51 +136,212 @@ struct netgrp {
 	struct netgrp	*ng_next;	/* Chain ptr */
 	char		*ng_str[3];	/* Field pointers, see below */
 };
+
+struct netgr_state {
+	FILE		*st_netf;
+	struct linelist	*st_linehead;
+	struct netgrp	*st_nextgrp;
+	struct netgrp	*st_gr;
+	char		*st_grname;
+};
+
 #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 void	netgr_endstate(void *);
+NSS_TLS_HANDLING(netgr);
 
-static int parse_netgrp(const char *);
-static struct linelist *read_for_group(const char *);
-void setnetgrent(const char *);
-void endnetgrent(void);
-int getnetgrent(char **, char **, char **);
-int innetgr(const char *, const char *, const char *, const char *);
+static int	files_endnetgrent(void *, void *, va_list);
+static int	files_getnetgrent_r(void *, void *, va_list);
+static int	files_setnetgrent(void *, void *, va_list);
+
+static int	compat_endnetgrent(void *, void *, va_list);
+static int	compat_innetgr(void *, void *, va_list);
+static int	compat_getnetgrent_r(void *, void *, va_list);
+static int	compat_setnetgrent(void *, void *, va_list);
+
+static void	_compat_clearstate(void);
+static int	_getnetgrent_r(char **, char **, char **, char *, size_t, int *,
+		    struct netgr_state *);
+static int	_innetgr_fallback(void *, void *, const char *, const char *,
+		    const char *, const char *);
+static int	innetgr_fallback(void *, void *, va_list);
+static int	parse_netgrp(const char *, struct netgr_state *, int);
+static struct linelist *read_for_group(const char *, struct netgr_state *, int);
 
 #define	LINSIZ	1024	/* Length of netgroup file line */
 
+static const ns_dtab getnetgrent_dtab[] = {
+	NS_FILES_CB(files_getnetgrent_r, NULL)
+	NS_COMPAT_CB(compat_getnetgrent_r, NULL)
+	{ NULL, NULL, NULL },
+};
+
+static const ns_dtab setnetgrent_dtab[] = {
+	NS_FILES_CB(files_setnetgrent, NULL)
+	NS_COMPAT_CB(compat_setnetgrent, NULL)
+	{ NULL, NULL, NULL },
+};
+
+static const ns_dtab endnetgrent_dtab[] = {
+	NS_FILES_CB(files_endnetgrent, NULL)
+	NS_COMPAT_CB(compat_endnetgrent, NULL)
+	{ NULL, NULL, NULL },
+};
+
+static struct netgr_state compat_state;
+
+static void
+netgr_endstate(void *arg)
+{
+	struct linelist *lp, *olp;
+	struct netgrp *gp, *ogp;
+	struct netgr_state *st;
+
+	st = (struct netgr_state *)arg;
+	lp = st->st_linehead;
+	while (lp != NULL) {
+		olp = lp;
+		lp = lp->l_next;
+		free(olp->l_groupname);
+		free(olp->l_line);
+		free(olp);
+	}
+	st->st_linehead = NULL;
+	if (st->st_grname != NULL) {
+		free(st->st_grname);
+		st->st_grname = NULL;
+	}
+	gp = st->st_gr;
+	while (gp != NULL) {
+		ogp = gp;
+		gp = gp->ng_next;
+		free(ogp->ng_str[NG_HOST]);
+		free(ogp->ng_str[NG_USER]);
+		free(ogp->ng_str[NG_DOM]);
+		free(ogp);
+	}
+	st->st_gr = NULL;
+	st->st_nextgrp = NULL;
+}
+
+static int
+files_getnetgrent_r(void *retval, void *mdata, va_list ap)
+{
+	struct netgr_state *st;
+	char **hostp, **userp, **domp, *buf;
+	size_t bufsize;
+	int *errnop;
+
+	hostp = va_arg(ap, char **);
+	userp = va_arg(ap, char **);
+	domp = va_arg(ap, char **);
+	buf = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop = va_arg(ap, int *);
+
+	if (netgr_getstate(&st) != 0)
+		return (NS_UNAVAIL);
+
+	return (_getnetgrent_r(hostp, userp, domp, buf, bufsize, errnop, st));
+}
+
+static int
+files_setnetgrent(void *retval, void *mdata, va_list ap)
+{
+	const ns_src src[] = {
+		{ NSSRC_FILES, NS_SUCCESS },
+		{ NULL, 0 },
+	};
+	struct netgr_state *st;
+	const char *group;
+	int rv;
+
+	group = va_arg(ap, const char *);
+
+	if (group == NULL || group[0] == '\0')
+		return (NS_RETURN);
+
+	rv = netgr_getstate(&st);
+	if (rv != 0)
+		return (NS_UNAVAIL);
+
+	if (st->st_gr == NULL || strcmp(group, st->st_grname) != 0) {
+		(void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP,
+		    "endnetgrent", src);
+		if ((st->st_netf = fopen(_PATH_NETGROUP, "re")) != NULL) {
+			if (parse_netgrp(group, st, 0) != 0)
+				(void)_nsdispatch(NULL, endnetgrent_dtab,
+				    NSDB_NETGROUP, "endnetgrent", src);
+			else
+				st->st_grname = strdup(group);
+			(void)fclose(st->st_netf);
+			st->st_netf = NULL;
+		}
+	}
+	st->st_nextgrp = st->st_gr;
+	return (st->st_grname != NULL ? NS_SUCCESS : NS_NOTFOUND);
+}
+
+static int
+files_endnetgrent(void *retval, void *mdata, va_list ap)
+{
+	struct netgr_state *st;
+
+	if (netgr_getstate(&st) != 0)
+		return (NS_UNAVAIL);
+	netgr_endstate(st);
+	return (NS_SUCCESS);
+}
+
+static int
+compat_getnetgrent_r(void *retval, void *mdata, va_list ap)
+{
+	char **hostp, **userp, **domp, *buf;
+	size_t bufsize;
+	int *errnop;
+#ifdef YP
+	_yp_innetgr = 0;
+#endif
+
+	hostp = va_arg(ap, char **);
+	userp = va_arg(ap, char **);
+	domp = va_arg(ap, char **);
+	buf = va_arg(ap, char *);
+	bufsize = va_arg(ap, size_t);
+	errnop = va_arg(ap, int *);
+
+	return (_getnetgrent_r(hostp, userp, domp, buf, bufsize, errnop,
+	    &compat_state));
+}
+
 /*
- * setnetgrent()
+ * compat_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(const char *group)
+static int
+compat_setnetgrent(void *retval, void *mdata, va_list ap)
 {
+	FILE *netf;
+	const char *group;
 #ifdef YP
 	struct stat _yp_statp;
 	char _yp_plus;
 #endif
 
-	/* Sanity check */
+	group = va_arg(ap, const char *);
 
+	/* Sanity check */
 	if (group == NULL || !strlen(group))
-		return;
+		return (NS_RETURN);
+
+	if (compat_state.st_gr == NULL ||
+	    strcmp(group, compat_state.st_grname) != 0) {
+		_compat_clearstate();
 
-	if (grouphead.gr == NULL || strcmp(group, grouphead.grname)) {
-		endnetgrent();
 #ifdef YP
 		/* Presumed guilty until proven innocent. */
 		_use_only_yp = 0;
@@ -173,6 +353,7 @@ setnetgrent(const char *group)
 		    errno == ENOENT) || _yp_statp.st_size == 0)
 			_use_only_yp = _netgr_yp_enabled = 1;
 		if ((netf = fopen(_PATH_NETGROUP,"re")) != NULL ||_use_only_yp){
+			compat_state.st_netf = netf;
 		/*
 		 * Icky: grab the first character of the netgroup file
 		 * and turn on NIS if it's a '+'. rewind the stream
@@ -193,79 +374,81 @@ setnetgrent(const char *group)
 				/* dohw! */
 				if (netf != NULL)
 					fclose(netf);
-				return;
+				return (NS_RETURN);
 			}
 #else
 		if ((netf = fopen(_PATH_NETGROUP, "re"))) {
+			compat_state.st_netf = netf;
 #endif
-			if (parse_netgrp(group))
-				endnetgrent();
-			else {
-				grouphead.grname = strdup(group);
+			if (parse_netgrp(group, &compat_state, 1)) {
+				_compat_clearstate();
+			} else {
+				compat_state.st_grname = strdup(group);
 			}
 			if (netf)
 				fclose(netf);
 		}
 	}
-	nextgrp = grouphead.gr;
+	compat_state.st_nextgrp = compat_state.st_gr;
+	return (NS_SUCCESS);
 }
 
-/*
- * Get the next netgroup off the list.
- */
-int
-getnetgrent(char **hostp, char **userp, char **domp)
+static void
+_compat_clearstate(void)
 {
+
 #ifdef YP
-	_yp_innetgr = 0;
+	_netgr_yp_enabled = 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);
+	netgr_endstate(&compat_state);
 }
 
 /*
- * endnetgrent() - cleanup
+ * compat_endnetgrent() - cleanup
  */
-void
-endnetgrent(void)
+static int
+compat_endnetgrent(void *retval, void *mdata, va_list ap)
 {
-	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(olp);
-	}
-	linehead = NULL;
-	if (grouphead.grname) {
-		free(grouphead.grname);
-		grouphead.grname = NULL;
-	}
-	gp = grouphead.gr;
-	while (gp) {
-		ogp = gp;
-		gp = gp->ng_next;
-		free(ogp->ng_str[NG_HOST]);
-		free(ogp->ng_str[NG_USER]);
-		free(ogp->ng_str[NG_DOM]);
-		free(ogp);
+	_compat_clearstate();
+	return (NS_SUCCESS);
+}
+
+int
+_getnetgrent_r(char **hostp, char **userp, char **domp, char *buf,
+    size_t bufsize, int *errnop, struct netgr_state *st)
+{
+	char *p, *src;
+	size_t len;
+	int rv;
+
+#define	COPY_NG_ELEM(dstp, i) do {					\
+	src = st->st_nextgrp->ng_str[(i)];				\
+	if (src == NULL)						\
+		src = "";						\
+	len = strlcpy(p, src, bufsize);					\
+	if (len >= bufsize) {						\
+		*errnop = ERANGE;					\
+		return (NS_RETURN);					\
+	}								\
+	*(dstp) = p;							\
+	p += len + 1;							\
+	bufsize -= len + 1;						\
+} while (0)
+
+	p = buf;
+	if (st->st_nextgrp != NULL) {
+		COPY_NG_ELEM(hostp, NG_HOST);
+		COPY_NG_ELEM(userp, NG_USER);
+		COPY_NG_ELEM(domp, NG_DOM);
+		st->st_nextgrp = st->st_nextgrp->ng_next;
+		rv = NS_SUCCESS;
+	} else {
+		rv = NS_NOTFOUND;
 	}
-	grouphead.gr = NULL;
-	nextgrp = NULL;
-#ifdef YP
-	_netgr_yp_enabled = 0;
-#endif
+#undef COPY_NG_ELEM
+
+	return (rv);
 }
 
 #ifdef YP
@@ -343,20 +526,29 @@ _revnetgr_lookup(char* lookupdom, char* 
 /*
  * Search for a match in a netgroup.
  */
-int
-innetgr(const char *group, const char *host, const char *user, const char *dom)
+static int
+compat_innetgr(void *retval, void *mdata, va_list ap)
 {
-	char *hst, *usr, *dm;
-	/* Sanity check */
-	
+#ifdef YP
+	const ns_src src[] = {
+		{ mdata, NS_SUCCESS },
+		{ NULL, 0 },
+	};
+#endif
+	const char *group, *host, *user, *dom;
+
+	group = va_arg(ap, const char *);
+	host = va_arg(ap, const char *);
+	user = va_arg(ap, const char *);
+	dom = va_arg(ap, const char *);
+
 	if (group == NULL || !strlen(group))
-		return (0);
+		return (NS_RETURN);
 
 #ifdef YP
 	_yp_innetgr = 1;
-#endif
-	setnetgrent(group);
-#ifdef YP
+	(void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent",
+	    src, group);
 	_yp_innetgr = 0;
 	/*
 	 * If we're in NIS-only mode, do the search using
@@ -384,38 +576,105 @@ innetgr(const char *group, const char *h
 	if (_use_only_yp && (host == NULL) != (user == NULL)) {
 		int ret;
 		if(yp_get_default_domain(&_netgr_yp_domain))
-			return (0);
-		ret = _revnetgr_lookup(_netgr_yp_domain, 
+			return (NS_NOTFOUND);
+		ret = _revnetgr_lookup(_netgr_yp_domain,
 				      host?"netgroup.byhost":"netgroup.byuser",
 				      host?host:user, dom, group);
-		if (ret == 1)
-			return (1);
-		else if (ret == 0 && dom != NULL)
-			return (0);
+		if (ret == 1) {
+			*(int *)retval = 1;
+			return (NS_SUCCESS);
+		} else if (ret == 0 && dom != NULL) {
+			*(int *)retval = 0;
+			return (NS_SUCCESS);
+		}
 	}
-
-	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);
+	return (_innetgr_fallback(retval, mdata, group, host, user, dom));
+}
+
+static int
+_innetgr_fallback(void *retval, void *mdata, const char *group, const char *host,
+    const char *user, const char *dom)
+{
+	const ns_src src[] = {
+		{ mdata, NS_SUCCESS },
+		{ NULL, 0 },
+	};
+	char *h, *u, *d;
+	char *buf;
+	size_t bufsize;
+	int rv, ret_errno;
+
+	if (group == NULL || group[0] == '\0')
+		return (NS_RETURN);
+
+	bufsize = NGRP_STORAGE_INITIAL;
+	buf = malloc(bufsize);
+	if (buf == NULL)
+		return (NS_UNAVAIL);
+
+	*(int *)retval = 0;
+
+	(void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent",
+	    src, group);
+
+	for (;;) {
+		do {
+			ret_errno = 0;
+			rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP,
+			    "getnetgrent_r", src, &h, &u, &d, buf, bufsize,
+			    &ret_errno);
+			if (rv != NS_SUCCESS && ret_errno == ERANGE) {
+				bufsize *= 2;
+				if (bufsize > NGRP_STORAGE_MAX ||
+				    (buf = reallocf(buf, bufsize)) == NULL)
+					goto out;
+			}
+		} while (rv != NS_SUCCESS && ret_errno == ERANGE);
+
+		if (rv != NS_SUCCESS) {
+			if (rv == NS_NOTFOUND && ret_errno == 0)
+				rv = NS_SUCCESS;
+			break;
 		}
-	endnetgrent();
-	return (0);
+
+		if ((host == NULL || h == NULL || strcmp(host, h) == 0) &&
+		    (user == NULL || u == NULL || strcmp(user, u) == 0) &&
+		    (dom == NULL || d == NULL || strcmp(dom, d) == 0)) {
+			*(int *)retval = 1;
+			break;
+		}
+	}
+
+out:
+	free(buf);
+	(void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, "endnetgrent",
+	    src);
+	return (rv);
+}
+
+static int
+innetgr_fallback(void *retval, void *mdata, va_list ap)
+{
+	const char *group, *host, *user, *dom;
+
+	group = va_arg(ap, const char *);
+	host = va_arg(ap, const char *);
+	user = va_arg(ap, const char *);
+	dom = va_arg(ap, const char *);
+
+	return (_innetgr_fallback(retval, mdata, group, host, user, dom));
 }
 
 /*
  * Parse the netgroup file setting up the linked lists.
  */
 static int
-parse_netgrp(const char *group)
+parse_netgrp(const char *group, struct netgr_state *st, int niscompat)
 {
 	struct netgrp *grp;
-	struct linelist *lp = linehead;
+	struct linelist *lp = st->st_linehead;
 	char **ng;
 	char *epos, *gpos, *pos, *spos;
 	int freepos, len, strpos;
@@ -431,7 +690,7 @@ parse_netgrp(const char *group)
 			break;
 		lp = lp->l_next;
 	}
-	if (lp == NULL && (lp = read_for_group(group)) == NULL)
+	if (lp == NULL && (lp = read_for_group(group, st, niscompat)) == NULL)
 		return (1);
 	if (lp->l_parsed) {
 #ifdef DEBUG
@@ -493,8 +752,8 @@ parse_netgrp(const char *group)
 				}
 				bcopy(spos, ng[strpos], len + 1);
 			}
-			grp->ng_next = grouphead.gr;
-			grouphead.gr = grp;
+			grp->ng_next = st->st_gr;
+			st->st_gr = grp;
 #ifdef DEBUG
 			/*
 			 * Note: on other platforms, malformed netgroup
@@ -515,7 +774,7 @@ parse_netgrp(const char *group)
 #endif
 		} else {
 			spos = strsep(&pos, ", \t");
-			if (parse_netgrp(spos))
+			if (parse_netgrp(spos, st, niscompat))
 				continue;
 		}
 		if (pos == NULL)
@@ -531,19 +790,22 @@ parse_netgrp(const char *group)
  * is found. Return 1 if eof is encountered.
  */
 static struct linelist *
-read_for_group(const char *group)
+read_for_group(const char *group, struct netgr_state *st, int niscompat)
 {
 	char *linep, *olinep, *pos, *spos;
 	int len, olen;
 	int cont;
 	struct linelist *lp;
 	char line[LINSIZ + 2];
+	FILE *netf;
 #ifdef YP
 	char *result;
 	int resultlen;
 	linep = NULL;
 
-	while (_netgr_yp_enabled || fgets(line, LINSIZ, netf) != NULL) {
+	netf = st->st_netf;
+	while ((_netgr_yp_enabled && niscompat) ||
+	    fgets(line, LINSIZ, netf) != NULL) {
 		if (_netgr_yp_enabled) {
 			if(!_netgr_yp_domain)
 				if(yp_get_default_domain(&_netgr_yp_domain))
@@ -571,7 +833,7 @@ read_for_group(const char *group)
 #endif
 		pos = (char *)&line;
 #ifdef YP
-		if (*pos == '+') {
+		if (niscompat && *pos == '+') {
 			_netgr_yp_enabled = 1;
 			continue;
 		}
@@ -588,11 +850,11 @@ read_for_group(const char *group)
 		while (*pos == ' ' || *pos == '\t')
 			pos++;
 		if (*pos != '\n' && *pos != '\0') {
-			lp = (struct linelist *)malloc(sizeof (*lp));
-			if (lp == NULL) 
+			lp = malloc(sizeof (*lp));
+			if (lp == NULL)
 				return (NULL);
 			lp->l_parsed = 0;
-			lp->l_groupname = (char *)malloc(len + 1);
+			lp->l_groupname = malloc(len + 1);
 			if (lp->l_groupname == NULL) {
 				free(lp);
 				return (NULL);
@@ -640,8 +902,8 @@ read_for_group(const char *group)
 				}
 			} while (cont);
 			lp->l_line = linep;
-			lp->l_next = linehead;
-			linehead = lp;
+			lp->l_next = st->st_linehead;
+			st->st_linehead = lp;
 
 			/*
 			 * If this is the one we wanted, we are done.
@@ -662,3 +924,93 @@ read_for_group(const char *group)
 #endif
 	return (NULL);
 }
+
+int
+getnetgrent_r(char **hostp, char **userp, char **domp, char *buf, size_t bufsize)
+{
+	int rv, ret_errno;
+
+	ret_errno = 0;
+	rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP, "getnetgrent_r",
+	    defaultsrc, hostp, userp, domp, buf, bufsize, &ret_errno);
+	if (rv == NS_SUCCESS) {
+		return (1);
+	} else {
+		errno = ret_errno;
+		return (0);
+	}
+}
+
+int
+getnetgrent(char **hostp, char **userp, char **domp)
+{
+	static char *ngrp_storage;
+	static size_t ngrp_storage_size;
+	int ret_errno, rv;
+
+	if (ngrp_storage == NULL) {
+		ngrp_storage_size = NGRP_STORAGE_INITIAL;
+		ngrp_storage = malloc(ngrp_storage_size);
+		if (ngrp_storage == NULL)
+			return (0);
+	}
+
+	do {
+		ret_errno = 0;
+		rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP,
+		    "getnetgrent_r", defaultsrc, hostp, userp, domp,
+		    ngrp_storage, ngrp_storage_size, &ret_errno);
+		if (rv != NS_SUCCESS && ret_errno == ERANGE) {
+			ngrp_storage_size *= 2;
+			if (ngrp_storage_size > NGRP_STORAGE_MAX) {
+				free(ngrp_storage);
+				ngrp_storage = NULL;
+				errno = ERANGE;
+				return (0);
+			}
+			ngrp_storage = reallocf(ngrp_storage,
+			    ngrp_storage_size);
+			if (ngrp_storage == NULL)
+				return (0);
+		}
+	} while (rv != NS_SUCCESS && ret_errno == ERANGE);
+
+	if (rv == NS_SUCCESS) {
+		return (1);
+	} else {
+		errno = ret_errno;
+		return (0);
+	}
+}
+
+void
+setnetgrent(const char *netgroup)
+{
+
+	(void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent",
+	    defaultsrc, netgroup);
+}
+
+void
+endnetgrent(void)
+{
+
+	(void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, "endnetgrent",
+	    defaultsrc);
+}
+
+int
+innetgr(const char *netgroup, const char *host, const char *user,
+    const char *domain)
+{
+	static const ns_dtab dtab[] = {
+		NS_COMPAT_CB(compat_innetgr, NULL)
+		NS_FALLBACK_CB(innetgr_fallback)
+		{ NULL, NULL, NULL },
+	};
+	int result, rv;
+
+	rv = _nsdispatch(&result, dtab, NSDB_NETGROUP, "innetgr", defaultsrc,
+	    netgroup, host, user, domain);
+	return (rv == NS_SUCCESS ? result : 0);
+}

Modified: head/share/man/man5/nsswitch.conf.5
==============================================================================
--- head/share/man/man5/nsswitch.conf.5	Thu Jun  9 01:11:48 2016	(r301710)
+++ head/share/man/man5/nsswitch.conf.5	Thu Jun  9 01:28:44 2016	(r301711)
@@ -33,7 +33,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 25, 2013
+.Dd June 6, 2016
 .Dt NSSWITCH.CONF 5
 .Os
 .Sh NAME
@@ -148,7 +148,9 @@ The following databases are used by the 
 .Xr getprotoent 3
 .It netgroup
 .Xr getnetgrent 3 ,
+.Xr getnetgrent_r 3 ,
 .Xr setnetgrent 3 ,
+.Xr endnetgrent 3 ,
 .Xr innetgr 3
 .El
 .Ss Status codes


More information about the svn-src-all mailing list