diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index ee4d619..f64be5b 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; scandir_b; }; diff --git a/lib/libc/gen/getnetgrent.c b/lib/libc/gen/getnetgrent.c index 4c56461..b54c2bc 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 __FBSDID("$FreeBSD$"); +#include "namespace.h" + #include +#include +#include +#include +#include +#include #include #include #include #include +#include "nss_tls.h" + #ifdef YP /* * Notes: @@ -99,6 +108,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(). @@ -122,46 +141,183 @@ struct netgrp { #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, +struct netgr_state { + FILE *st_netf; + struct linelist *st_linehead; + struct netgrp *st_nextgrp; + struct netgrp *st_gr; + char *st_grname; }; -static FILE *netf = (FILE *)0; - -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 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_innetgr(void *, void *, va_list); +static int files_setnetgrent(void *, void *, va_list); + +struct netgr_state compat_state; +static int compat_endnetgrent(void *, void *, va_list); +static int compat_getnetgrent_r(void *, void *, va_list); +static int compat_innetgr(void *, void *, va_list); +static int compat_setnetgrent(void *, void *, va_list); + +static void clear_state(struct netgr_state *); +static int parse_netgrp(const char *, struct netgr_state *, int); +static struct linelist *read_for_group(const char *, struct netgr_state *, int); +static int _getnetgrent_r(char **, char **, char **, char *, size_t, int *, + struct netgr_state *); #define LINSIZ 1024 /* Length of netgroup file line */ +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_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 +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_innetgr(void *retval, void *mdata, va_list ap) +{ + const char *group, *host, *user, *dom; + char *h, *u, *d; + + 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 || group[0] == '\0') + return (NS_RETURN); + + setnetgrent(group); + while (getnetgrent(&h, &u, &d)) + 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)) { + endnetgrent(); + *(int *)retval = 1; + return (NS_SUCCESS); + } + endnetgrent(); + return (NS_NOTFOUND); +} + +static int +files_setnetgrent(void *retval, void *mdata, va_list ap) +{ + 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) { + endnetgrent(); + if ((st->st_netf = fopen(_PATH_NETGROUP, "re")) != NULL) { + if (parse_netgrp(group, st, 0) != 0) + endnetgrent(); + 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); +} + /* * 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 + group = va_arg(ap, const char *); + /* Sanity check */ if (group == NULL || !strlen(group)) - return; + return (NS_RETURN); - if (grouphead.gr == NULL || strcmp(group, grouphead.grname)) { + if (compat_state.st_gr == NULL || + strcmp(group, compat_state.st_grname) != 0) { endnetgrent(); #ifdef YP /* Presumed guilty until proven innocent. */ @@ -174,6 +330,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 @@ -194,79 +351,96 @@ setnetgrent(const char *group) /* dohw! */ if (netf != NULL) fclose(netf); - return; + return (NS_NOTFOUND); } #else if ((netf = fopen(_PATH_NETGROUP, "re"))) { + compat_state.st_netf = netf; #endif - if (parse_netgrp(group)) + if (parse_netgrp(group, &compat_state, 1)) endnetgrent(); else { - grouphead.grname = strdup(group); + compat_state.st_grname = strdup(group); } if (netf) fclose(netf); } } - nextgrp = grouphead.gr; + compat_state.st_nextgrp = compat_state.st_gr; + 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; + +#define COPY_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_ELEM(hostp, NG_HOST); + COPY_ELEM(userp, NG_USER); + COPY_ELEM(domp, NG_DOM); + st->st_nextgrp = st->st_nextgrp->ng_next; + return (NS_SUCCESS); + } + +#undef COPY_ELEM + + return (NS_NOTFOUND); } /* * Get the next netgroup off the list. */ -int -getnetgrent(char **hostp, char **userp, char **domp) +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 - 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); + 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)); } /* * 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); - } - grouphead.gr = NULL; - nextgrp = NULL; + netgr_endstate(&compat_state); #ifdef YP _netgr_yp_enabled = 0; #endif + return (NS_SUCCESS); } #ifdef YP @@ -344,14 +518,21 @@ _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) { + const char *group, *host, *user, *dom; char *hst, *usr, *dm; + + group = va_arg(ap, const char *); + host = va_arg(ap, const char *); + user = va_arg(ap, const char *); + dom = va_arg(ap, const char *); + /* Sanity check */ - + if (group == NULL || !strlen(group)) - return (0); + return (NS_RETURN); #ifdef YP _yp_innetgr = 1; @@ -385,14 +566,15 @@ 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); + 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) + return (NS_NOTFOUND); } setnetgrent(group); @@ -403,20 +585,21 @@ innetgr(const char *group, const char *host, const char *user, const char *dom) (user == NULL || usr == NULL || !strcmp(user, usr)) && ( dom == NULL || dm == NULL || !strcmp(dom, dm))) { endnetgrent(); - return (1); + *(int *)retval = 1; + return (NS_SUCCESS); } endnetgrent(); - return (0); + return (NS_NOTFOUND); } /* * 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 compat) { struct netgrp *grp; - struct linelist *lp = linehead; + struct linelist *lp = st->st_linehead; char **ng; char *epos, *gpos, *pos, *spos; int freepos, len, strpos; @@ -432,7 +615,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, compat)) == NULL) return (1); if (lp->l_parsed) { #ifdef DEBUG @@ -494,8 +677,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 @@ -512,10 +695,11 @@ parse_netgrp(const char *group) ng[NG_DOM] == NULL ? "" : ",", ng[NG_DOM] == NULL ? "" : ng[NG_DOM], lp->l_groupname); + } #endif } else { spos = strsep(&pos, ", \t"); - if (parse_netgrp(spos)) + if (parse_netgrp(spos, st, compat)) continue; } if (pos == NULL) @@ -531,21 +715,25 @@ 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 compat) { 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 && compat) || + fgets(line, LINSIZ, netf) != NULL) { if (_netgr_yp_enabled) { - if(!_netgr_yp_domain) + if (_netgr_yp_domain == NULL || + _netgr_yp_domain[0] == '\0') if(yp_get_default_domain(&_netgr_yp_domain)) continue; if (yp_match(_netgr_yp_domain, "netgroup", group, @@ -567,7 +755,7 @@ read_for_group(const char *group) #endif pos = (char *)&line; #ifdef YP - if (*pos == '+') { + if (compat && *pos == '+') { _netgr_yp_enabled = 1; continue; } @@ -634,8 +822,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. @@ -656,3 +844,100 @@ read_for_group(const char *group) #endif return (NULL); } + +void +endnetgrent(void) +{ + static const ns_dtab dtab[] = { + NS_FILES_CB(files_endnetgrent, NULL) + NS_COMPAT_CB(compat_endnetgrent, NULL) + { NULL, NULL, NULL } + }; + + (void)_nsdispatch(NULL, dtab, NSDB_NETGROUP, "endnetgrent", defaultsrc); +} + +int +getnetgrent_r(char **hostp, char **userp, char **domp, char *buf, size_t bufsize) +{ + static const ns_dtab dtab[] = { + NS_FILES_CB(files_getnetgrent_r, NULL) + NS_COMPAT_CB(compat_getnetgrent_r, NULL) + { NULL, NULL, NULL }, + }; + int rv, ret_errno; + + ret_errno = 0; + rv = _nsdispatch(NULL, 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); + } +} + +static char *ngrp_storage; +static size_t ngrp_storage_size; + +int +getnetgrent(char **hostp, char **userp, char **domp) +{ + int error, rv; + + if (ngrp_storage == NULL) { + ngrp_storage_size = NGRP_STORAGE_INITIAL; + ngrp_storage = malloc(ngrp_storage_size); + if (ngrp_storage == NULL) + return (0); + } + do { + rv = getnetgrent_r(hostp, userp, domp, ngrp_storage, + ngrp_storage_size); + error = errno; + if (rv == 0 && error == ERANGE) { + ngrp_storage_size *= 2; + if (ngrp_storage_size > NGRP_STORAGE_MAX) { + free(ngrp_storage); + ngrp_storage = NULL; + errno = ERANGE; + return (0); + } + ngrp_storage = realloc(ngrp_storage, ngrp_storage_size); + if (ngrp_storage == NULL) + return (0); + } + } while (rv == 0 && error == ERANGE); + + return (rv); +} + +int +innetgr(const char *netgroup, const char *host, const char *user, + const char *domain) +{ + static const ns_dtab dtab[] = { + NS_FILES_CB(files_innetgr, NULL) + NS_COMPAT_CB(compat_innetgr, NULL) + { NULL, NULL, NULL }, + }; + int result, rv; + + rv = _nsdispatch(&result, dtab, NSDB_NETGROUP, "innetgr", defaultsrc, + netgroup, host, user, domain); + return (rv == NS_SUCCESS ? result : 0); +} + +void +setnetgrent(const char *netgroup) +{ + static const ns_dtab dtab[] = { + NS_FILES_CB(files_setnetgrent, NULL) + NS_COMPAT_CB(compat_setnetgrent, NULL) + { NULL, NULL, NULL }, + }; + + (void)_nsdispatch(NULL, dtab, NSDB_NETGROUP, "setnetgrent", defaultsrc, + netgroup); +}