summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/nsswitch.conf1
-rw-r--r--include/netdb.h1
-rw-r--r--lib/libc/gen/Symbol.map1
-rw-r--r--lib/libc/gen/getnetgrent.34
-rw-r--r--lib/libc/gen/getnetgrent.c580
-rw-r--r--share/man/man5/nsswitch.conf.54
6 files changed, 475 insertions, 116 deletions
diff --git a/etc/nsswitch.conf b/etc/nsswitch.conf
index c95b9a4..e0f14af 100644
--- a/etc/nsswitch.conf
+++ b/etc/nsswitch.conf
@@ -5,6 +5,7 @@
group: compat
group_compat: nis
hosts: files dns
+netgroup: compat
networks: files
passwd: compat
passwd_compat: nis
diff --git a/include/netdb.h b/include/netdb.h
index 3fa5ff3..0d9cb4e 100644
--- a/include/netdb.h
+++ b/include/netdb.h
@@ -275,6 +275,7 @@ int getnetbyname_r(const char *, struct netent *, char *, size_t,
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,
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index c53b7dd..0d5dfec 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -410,6 +410,7 @@ FBSD_1.3 {
};
FBSD_1.4 {
+ getnetgrent_r;
pthread_mutex_consistent;
pthread_mutexattr_getrobust;
pthread_mutexattr_setrobust;
diff --git a/lib/libc/gen/getnetgrent.3 b/lib/libc/gen/getnetgrent.3
index 7483e4f..8547e66 100644
--- a/lib/libc/gen/getnetgrent.3
+++ b/lib/libc/gen/getnetgrent.3
@@ -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"
diff --git a/lib/libc/gen/getnetgrent.c b/lib/libc/gen/getnetgrent.c
index ab3a46f..d71928e 100644
--- a/lib/libc/gen/getnetgrent.c
+++ b/lib/libc/gen/getnetgrent.c
@@ -36,12 +36,21 @@ static char sccsid[] = "@(#)getnetgrent.c 8.2 (Berkeley) 4/27/95";
#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 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 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 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* map, const char* str,
/*
* 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 *host, const char *user, const char *dom)
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);
+}
diff --git a/share/man/man5/nsswitch.conf.5 b/share/man/man5/nsswitch.conf.5
index b1fbbd4..abeb24d 100644
--- a/share/man/man5/nsswitch.conf.5
+++ b/share/man/man5/nsswitch.conf.5
@@ -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 following C library functions:
.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
OpenPOWER on IntegriCloud