summaryrefslogtreecommitdiffstats
path: root/lib/libc/net
diff options
context:
space:
mode:
authornectar <nectar@FreeBSD.org>2000-09-06 18:16:48 +0000
committernectar <nectar@FreeBSD.org>2000-09-06 18:16:48 +0000
commit748554442d0ac4467fdac2ce9d42006588fd4481 (patch)
treeaed2ddbcac97f46f60ee9c2063a3345553f6a1ee /lib/libc/net
parent59ffb36b778f8e629622726f6bd32dfa4fda7e35 (diff)
downloadFreeBSD-src-748554442d0ac4467fdac2ce9d42006588fd4481.zip
FreeBSD-src-748554442d0ac4467fdac2ce9d42006588fd4481.tar.gz
Add nsswitch support. By creating an /etc/nsswitch.conf file, you can
configure FreeBSD so that various databases such as passwd and group can be looked up using flat files, NIS, or Hesiod. = Hesiod has been added to libc (see hesiod(3)). = A library routine for parsing nsswitch.conf and invoking callback functions as specified has been added to libc (see nsdispatch(3)). = The following C library functions have been modified to use nsdispatch: . getgrent, getgrnam, getgrgid . getpwent, getpwnam, getpwuid . getusershell . getaddrinfo . gethostbyname, gethostbyname2, gethostbyaddr . getnetbyname, getnetbyaddr . getipnodebyname, getipnodebyaddr, getnodebyname, getnodebyaddr = host.conf has been removed from src/etc. rc.network has been modified to warn that host.conf is no longer used at boot time. In addition, if there is a host.conf but no nsswitch.conf, the latter is created at boot time from the former. Obtained from: NetBSD
Diffstat (limited to 'lib/libc/net')
-rw-r--r--lib/libc/net/Makefile.inc28
-rw-r--r--lib/libc/net/getaddrinfo.34
-rw-r--r--lib/libc/net/getaddrinfo.c486
-rw-r--r--lib/libc/net/gethostbydns.c65
-rw-r--r--lib/libc/net/gethostbyht.c29
-rw-r--r--lib/libc/net/gethostbyname.317
-rw-r--r--lib/libc/net/gethostbynis.c62
-rw-r--r--lib/libc/net/gethostnamadr.c166
-rw-r--r--lib/libc/net/getipnodebyname.35
-rw-r--r--lib/libc/net/getnameinfo.34
-rw-r--r--lib/libc/net/getnetbydns.c41
-rw-r--r--lib/libc/net/getnetbyht.c27
-rw-r--r--lib/libc/net/getnetbynis.c50
-rw-r--r--lib/libc/net/getnetent.320
-rw-r--r--lib/libc/net/getnetnamadr.c174
-rw-r--r--lib/libc/net/hesiod.3136
-rw-r--r--lib/libc/net/hesiod.c572
-rw-r--r--lib/libc/net/name6.c264
-rw-r--r--lib/libc/net/nsdispatch.3231
-rw-r--r--lib/libc/net/nsdispatch.c270
-rw-r--r--lib/libc/net/nslexer.l116
-rw-r--r--lib/libc/net/nsparser.y175
22 files changed, 2217 insertions, 725 deletions
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
index 1d3ab66..3f84d10 100644
--- a/lib/libc/net/Makefile.inc
+++ b/lib/libc/net/Makefile.inc
@@ -9,19 +9,32 @@ SRCS+= addr2ascii.c ascii2addr.c base64.c ether_addr.c getaddrinfo.c \
getifaddrs.c getnameinfo.c \
getnetbydns.c getnetbyht.c getnetbynis.c getnetnamadr.c \
getproto.c getprotoent.c getprotoname.c getservbyname.c \
- getservbyport.c getservent.c herror.c inet_addr.c ifname.c \
- inet_lnaof.c \
+ getservbyport.c getservent.c herror.c hesiod.c inet_addr.c \
+ ifname.c inet_lnaof.c \
inet_makeaddr.c inet_net_ntop.c inet_net_pton.c inet_neta.c \
inet_netof.c inet_network.c inet_ntoa.c inet_ntop.c \
inet_pton.c ip6opt.c linkaddr.c map_v4v6.c name6.c ns_addr.c \
ns_name.c ns_netint.c \
- ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c nsap_addr.c \
- rcmd.c recv.c res_comp.c res_data.c res_debug.c \
+ ns_ntoa.c ns_parse.c ns_print.c ns_ttl.c \
+ nsdispatch.c nslexer.c nsparser.c \
+ nsap_addr.c rcmd.c recv.c res_comp.c res_data.c res_debug.c \
res_init.c res_mkquery.c res_mkupdate.c res_query.c res_send.c \
res_update.c rthdr.c send.c vars.c
# not supported: iso_addr.c
-CFLAGS+=-DINET6
+CFLAGS+=-DINET6 -I${.OBJDIR}
+
+YFLAGS+=-p_nsyy
+LFLAGS+=-P_nsyy
+
+CLEANFILES+=nsparser.c nslexer.c nsparser.h
+
+nsparser.h: nsparser.c
+ mv y.tab.h ${.TARGET}
+
+nslexer.c: nslexer.l nsparser.h
+ ${LEX} ${LFLAGS} -o/dev/stdout ${.IMPSRC} | \
+ sed -e '/YY_BUF_SIZE/s/16384/1024/' >${.TARGET}
# machine-dependent net sources
.include "${.CURDIR}/../libc/${MACHINE_ARCH}/net/Makefile.inc"
@@ -29,9 +42,10 @@ CFLAGS+=-DINET6
.if ${LIB} == "c"
MAN3+= addr2ascii.3 byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 \
getifaddrs.3 getipnodebyname.3 \
- getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 if_indextoname.3 \
+ getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 hesiod.3 \
+ if_indextoname.3 \
inet.3 inet6_option_space.3 inet6_rthdr_space.3 linkaddr.3 \
- rcmd.3 resolver.3
+ nsdispatch.3 rcmd.3 resolver.3
# not installed: iso_addr.3 ns.3
MLINKS+=addr2ascii.3 ascii2addr.3
diff --git a/lib/libc/net/getaddrinfo.3 b/lib/libc/net/getaddrinfo.3
index 1a0b5f4..deb575f 100644
--- a/lib/libc/net/getaddrinfo.3
+++ b/lib/libc/net/getaddrinfo.3
@@ -496,9 +496,9 @@ freeaddrinfo(res0);
.Ed
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index 6d23544..10ddd3a 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -1,4 +1,4 @@
-/* $FreeBSD$ */
+/* $FreeBSD$ */
/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */
/*
@@ -103,14 +103,18 @@
#include <stdio.h>
#include <errno.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
+
#if defined(__KAME__) && defined(INET6)
# define FAITH
#endif
-#define SUCCESS 0
-#define ANY 0
-#define YES 1
-#define NO 0
+#define SUCCESS 0
+#define ANY 0
+#define YES 1
+#define NO 0
static const char in_addrany[] = { 0, 0, 0, 0 };
static const char in6_addrany[] = {
@@ -127,7 +131,7 @@ static const struct afd {
int a_socklen;
int a_off;
const char *a_addrany;
- const char *a_loopback;
+ const char *a_loopback;
int a_scoped;
} afdl [] = {
#ifdef INET6
@@ -153,9 +157,9 @@ struct explore {
int e_protocol;
const char *e_protostr;
int e_wild;
-#define WILD_AF(ex) ((ex)->e_wild & 0x01)
-#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
-#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
+#define WILD_AF(ex) ((ex)->e_wild & 0x01)
+#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
+#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
};
static const struct explore explore[] = {
@@ -177,11 +181,17 @@ static const struct explore explore[] = {
};
#ifdef INET6
-#define PTON_MAX 16
+#define PTON_MAX 16
#else
-#define PTON_MAX 4
+#define PTON_MAX 4
#endif
+static const ns_src default_dns_files[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
+};
+
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
@@ -223,24 +233,22 @@ static int addrconfig __P((struct addrinfo *));
static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
#endif
-static struct addrinfo *getanswer __P((const querybuf *, int, const char *,
- int, const struct addrinfo *));
-static int _dns_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
-static struct addrinfo *_gethtent __P((FILE *fp, const char *,
- const struct addrinfo *));
-static int _files_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
+static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int,
+ const struct addrinfo *));
+static int _dns_getaddrinfo __P((void *, void *, va_list));
+static void _sethtent __P((void));
+static void _endhtent __P((void));
+static struct addrinfo *_gethtent __P((const char *, const struct addrinfo *));
+static int _files_getaddrinfo __P((void *, void *, va_list));
#ifdef YP
-static int _nis_getaddrinfo __P((const struct addrinfo *, const char *,
- struct addrinfo **));
+static struct addrinfo *_yphostent __P((char *, const struct addrinfo *));
+static int _yp_getaddrinfo __P((void *, void *, va_list));
#endif
static int res_queryN __P((const char *, struct res_target *));
static int res_searchN __P((const char *, struct res_target *));
static int res_querydomainN __P((const char *, const char *,
- struct res_target *));
-
+ struct res_target *));
static char *ai_errlist[] = {
"Success",
@@ -263,35 +271,9 @@ static char *ai_errlist[] = {
"Unknown error", /* EAI_MAX */
};
-/*
- * Select order host function.
- */
-#define MAXHOSTCONF 4
-
-#ifndef HOSTCONF
-# define HOSTCONF "/etc/host.conf"
-#endif /* !HOSTCONF */
-
-struct _hostconf {
- int (*byname)(const struct addrinfo *, const char *,
- struct addrinfo **);
-};
-
-/* default order */
-static struct _hostconf _hostconf[MAXHOSTCONF] = {
- _dns_getaddrinfo,
- _files_getaddrinfo,
-#ifdef ICMPNL
- NULL,
-#endif /* ICMPNL */
-};
-
-static int _hostconf_init_done;
-static void _hostconf_init(void);
-
/* XXX macros that make external reference is BAD. */
-#define GET_AI(ai, afd, addr) \
+#define GET_AI(ai, afd, addr) \
do { \
/* external reference: pai, error, and label free */ \
(ai) = get_ai(pai, (afd), (addr)); \
@@ -301,7 +283,7 @@ do { \
} \
} while (/*CONSTCOND*/0)
-#define GET_PORT(ai, serv) \
+#define GET_PORT(ai, serv) \
do { \
/* external reference: error and label free */ \
error = get_port((ai), (serv), 0); \
@@ -309,7 +291,7 @@ do { \
goto free; \
} while (/*CONSTCOND*/0)
-#define GET_CANONNAME(ai, str) \
+#define GET_CANONNAME(ai, str) \
do { \
/* external reference: pai, error and label free */ \
error = get_canonname(pai, (ai), (str)); \
@@ -317,7 +299,7 @@ do { \
goto free; \
} while (/*CONSTCOND*/0)
-#define ERR(err) \
+#define ERR(err) \
do { \
/* external reference: error, and label bad */ \
error = (err); \
@@ -325,9 +307,9 @@ do { \
/*NOTREACHED*/ \
} while (/*CONSTCOND*/0)
-#define MATCH_FAMILY(x, y, w) \
+#define MATCH_FAMILY(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
-#define MATCH(x, y, w) \
+#define MATCH(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
char *
@@ -470,7 +452,7 @@ getaddrinfo(hostname, servname, hints, res)
*/
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
#ifdef PF_INET6
- || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+ || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
#endif
) {
ai0 = *pai; /* backup *pai */
@@ -501,11 +483,9 @@ getaddrinfo(hostname, servname, hints, res)
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
continue;
- if (!MATCH(pai->ai_socktype, ex->e_socktype,
- WILD_SOCKTYPE(ex)))
+ if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
continue;
- if (!MATCH(pai->ai_protocol, ex->e_protocol,
- WILD_PROTOCOL(ex)))
+ if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
continue;
if (pai->ai_family == PF_UNSPEC)
@@ -518,8 +498,7 @@ getaddrinfo(hostname, servname, hints, res)
if (hostname == NULL)
error = explore_null(pai, servname, &cur->ai_next);
else
- error = explore_numeric_scope(pai, hostname, servname,
- &cur->ai_next);
+ error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
if (error)
goto free;
@@ -561,11 +540,11 @@ getaddrinfo(hostname, servname, hints, res)
continue;
if (!MATCH(pai->ai_socktype, ex->e_socktype,
- WILD_SOCKTYPE(ex))) {
+ WILD_SOCKTYPE(ex))) {
continue;
}
if (!MATCH(pai->ai_protocol, ex->e_protocol,
- WILD_PROTOCOL(ex))) {
+ WILD_PROTOCOL(ex))) {
continue;
}
@@ -574,7 +553,8 @@ getaddrinfo(hostname, servname, hints, res)
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
- error = explore_fqdn(pai, hostname, servname, &cur->ai_next);
+ error = explore_fqdn(pai, hostname, servname,
+ &cur->ai_next);
while (cur && cur->ai_next)
cur = cur->ai_next;
@@ -602,82 +582,6 @@ getaddrinfo(hostname, servname, hints, res)
return error;
}
-static char *
-_hgetword(char **pp)
-{
- char c, *p, *ret;
- const char *sp;
- static const char sep[] = "# \t\n";
-
- ret = NULL;
- for (p = *pp; (c = *p) != '\0'; p++) {
- for (sp = sep; *sp != '\0'; sp++) {
- if (c == *sp)
- break;
- }
- if (c == '#')
- p[1] = '\0'; /* ignore rest of line */
- if (ret == NULL) {
- if (*sp == '\0')
- ret = p;
- } else {
- if (*sp != '\0') {
- *p++ = '\0';
- break;
- }
- }
- }
- *pp = p;
- if (ret == NULL || *ret == '\0')
- return NULL;
- return ret;
-}
-
-/*
- * Initialize hostconf structure.
- */
-
-static void
-_hostconf_init(void)
-{
- FILE *fp;
- int n;
- char *p, *line;
- char buf[BUFSIZ];
-
- _hostconf_init_done = 1;
- n = 0;
- p = HOSTCONF;
- if ((fp = fopen(p, "r")) == NULL)
- return;
- while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
- line = buf;
- if ((p = _hgetword(&line)) == NULL)
- continue;
- do {
- if (strcmp(p, "hosts") == 0
- || strcmp(p, "local") == 0
- || strcmp(p, "file") == 0
- || strcmp(p, "files") == 0)
- _hostconf[n++].byname = _files_getaddrinfo;
- else if (strcmp(p, "dns") == 0
- || strcmp(p, "bind") == 0)
- _hostconf[n++].byname = _dns_getaddrinfo;
-#ifdef YP
- else if (strcmp(p, "nis") == 0)
- _hostconf[n++].byname = _nis_getaddrinfo;
-#endif
- } while ((p = _hgetword(&line)) != NULL);
- }
- fclose(fp);
- if (n < 0) {
- /* no keyword found. do not change default configuration */
- return;
- }
- for (; n < MAXHOSTCONF; n++)
- _hostconf[n].byname = NULL;
-}
-
/*
* FQDN hostname, DNS lookup
*/
@@ -690,10 +594,15 @@ explore_fqdn(pai, hostname, servname, res)
{
struct addrinfo *result;
struct addrinfo *cur;
- int error = 0, i;
+ int error = 0;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_getaddrinfo, NULL)
+ { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
+ NS_NIS_CB(_yp_getaddrinfo, NULL)
+ { 0 }
+ };
result = NULL;
- *res = NULL;
/*
* if the servname does not match socktype/protocol, ignore it.
@@ -701,23 +610,30 @@ explore_fqdn(pai, hostname, servname, res)
if (get_portmatch(pai, servname) != 0)
return 0;
- if (!_hostconf_init_done)
- _hostconf_init();
-
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (!_hostconf[i].byname)
- continue;
- error = (*_hostconf[i].byname)(pai, hostname, &result);
- if (error != 0)
- continue;
+ switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
+ default_dns_files, hostname, pai)) {
+ case NS_TRYAGAIN:
+ error = EAI_AGAIN;
+ goto free;
+ case NS_UNAVAIL:
+ error = EAI_FAIL;
+ goto free;
+ case NS_NOTFOUND:
+ error = EAI_NODATA;
+ goto free;
+ case NS_SUCCESS:
+ error = 0;
for (cur = result; cur; cur = cur->ai_next) {
GET_PORT(cur, servname);
/* canonname should be filled already */
}
- *res = result;
- return 0;
+ break;
}
+ *res = result;
+
+ return 0;
+
free:
if (result)
freeaddrinfo(result);
@@ -887,6 +803,7 @@ explore_numeric_scope(pai, hostname, servname, res)
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
+
if (!afd->a_scoped)
return explore_numeric(pai, hostname, servname, res);
@@ -1003,14 +920,13 @@ get_ai(pai, afd, addr)
ai->ai_addr->sa_len = afd->a_socklen;
ai->ai_addrlen = afd->a_socklen;
ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
- p = (char *)(ai->ai_addr);
+ p = (char *)(void *)(ai->ai_addr);
#ifdef FAITH
if (translate == 1)
- memcpy(p + afd->a_off, &faith_prefix, afd->a_addrlen);
+ memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen);
else
#endif
- memcpy(p + afd->a_off, addr, afd->a_addrlen);
-
+ memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
return ai;
}
@@ -1152,7 +1068,6 @@ addrconfig(pai)
else
_close(s);
}
-
}
if (af != AF_UNSPEC) {
if ((s = socket(af, SOCK_DGRAM, 0)) < 0)
@@ -1212,6 +1127,7 @@ ip6_str2scopeid(scope, sin6)
static const char AskedForGot[] =
"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
#endif
+static FILE *hostf = NULL;
static struct addrinfo *
getanswer(answer, anslen, qname, qtype, pai)
@@ -1415,17 +1331,21 @@ getanswer(answer, anslen, qname, qtype, pai)
/*ARGSUSED*/
static int
-_dns_getaddrinfo(pai, hostname, res)
- const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
+_dns_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
struct addrinfo *ai;
querybuf buf, buf2;
const char *name;
+ const struct addrinfo *pai;
struct addrinfo sentinel, *cur;
struct res_target q, q2;
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, const struct addrinfo *);
+
memset(&q, 0, sizeof(q2));
memset(&q2, 0, sizeof(q2));
memset(&sentinel, 0, sizeof(sentinel));
@@ -1457,10 +1377,10 @@ _dns_getaddrinfo(pai, hostname, res)
q.anslen = sizeof(buf);
break;
default:
- return EAI_FAIL;
+ return NS_UNAVAIL;
}
- if (res_searchN(hostname, &q) < 0)
- return EAI_NODATA;
+ if (res_searchN(name, &q) < 0)
+ return NS_NOTFOUND;
ai = getanswer(&buf, q.n, q.name, q.qtype, pai);
if (ai) {
cur->ai_next = ai;
@@ -1475,19 +1395,36 @@ _dns_getaddrinfo(pai, hostname, res)
if (sentinel.ai_next == NULL)
switch (h_errno) {
case HOST_NOT_FOUND:
- return EAI_NODATA;
+ return NS_NOTFOUND;
case TRY_AGAIN:
- return EAI_AGAIN;
+ return NS_TRYAGAIN;
default:
- return EAI_FAIL;
+ return NS_UNAVAIL;
}
- *res = sentinel.ai_next;
- return 0;
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return NS_SUCCESS;
+}
+
+static void
+_sethtent()
+{
+ if (!hostf)
+ hostf = fopen(_PATH_HOSTS, "r" );
+ else
+ rewind(hostf);
+}
+
+static void
+_endhtent()
+{
+ if (hostf) {
+ (void) fclose(hostf);
+ hostf = NULL;
+ }
}
static struct addrinfo *
-_gethtent(hostf, name, pai)
- FILE *hostf;
+_gethtent(name, pai)
const char *name;
const struct addrinfo *pai;
{
@@ -1498,6 +1435,8 @@ _gethtent(hostf, name, pai)
const char *addr;
char hostbuf[8*1024];
+ if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" )))
+ return (NULL);
again:
if (!(p = fgets(hostbuf, sizeof hostbuf, hostf)))
return (NULL);
@@ -1557,102 +1496,181 @@ found:
/*ARGSUSED*/
static int
-_files_getaddrinfo(pai, hostname, res)
- const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
+_files_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
{
- FILE *hostf;
+ const char *name;
+ const struct addrinfo *pai;
struct addrinfo sentinel, *cur;
struct addrinfo *p;
- sentinel.ai_next = NULL;
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
- if ((hostf = fopen(_PATH_HOSTS, "r")) == NULL)
- return EAI_FAIL;
- while ((p = _gethtent(hostf, hostname, pai)) != NULL) {
+ _sethtent();
+ while ((p = _gethtent(name, pai)) != NULL) {
cur->ai_next = p;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
- fclose(hostf);
+ _endhtent();
- if (!sentinel.ai_next)
- return EAI_NODATA;
-
- *res = sentinel.ai_next;
- return 0;
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ if (sentinel.ai_next == NULL)
+ return NS_NOTFOUND;
+ return NS_SUCCESS;
}
#ifdef YP
+static char *__ypdomain;
+
/*ARGSUSED*/
-static int
-_nis_getaddrinfo(pai, hostname, res)
+static struct addrinfo *
+_yphostent(line, pai)
+ char *line;
const struct addrinfo *pai;
- const char *hostname;
- struct addrinfo **res;
{
- struct hostent *hp;
- int h_error;
- int af;
struct addrinfo sentinel, *cur;
- int i;
- const struct afd *afd;
+ struct addrinfo hints, *res, *res0;
int error;
+ char *p = line;
+ const char *addr, *canonname;
+ char *nextline;
+ char *cp;
- sentinel.ai_next = NULL;
+ addr = canonname = NULL;
+
+ memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
- af = (pai->ai_family == AF_UNSPEC) ? AF_INET : pai->ai_family;
- if (af != AF_INET)
- return (EAI_ADDRFAMILY);
+nextline:
+ /* terminate line */
+ cp = strchr(p, '\n');
+ if (cp) {
+ *cp++ = '\0';
+ nextline = cp;
+ } else
+ nextline = NULL;
- if ((hp = _gethostbynisname(hostname, af)) == NULL) {
- switch (errno) {
- /* XXX: should be filled in */
- default:
- error = EAI_FAIL;
- break;
- }
- } else if (hp->h_name == NULL ||
- hp->h_name[0] == 0 || hp->h_addr_list[0] == NULL) {
- hp = NULL;
- error = EAI_FAIL;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL) {
+ if (canonname == NULL)
+ return (NULL);
+ else
+ goto done;
}
+ *cp++ = '\0';
- if (hp == NULL)
- return error;
+ addr = p;
- for (i = 0; hp->h_addr_list[i] != NULL; i++) {
- if (hp->h_addrtype != af)
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
continue;
+ }
+ if (!canonname)
+ canonname = cp;
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ }
- afd = find_afd(hp->h_addrtype);
- if (afd == NULL)
- continue;
+ hints = *pai;
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(addr, NULL, &hints, &res0);
+ if (error == 0) {
+ for (res = res0; res; res = res->ai_next) {
+ /* cover it up */
+ res->ai_flags = pai->ai_flags;
- GET_AI(cur->ai_next, afd, hp->h_addr_list[i]);
- if ((pai->ai_flags & AI_CANONNAME) != 0) {
- /*
- * RFC2553 says that ai_canonname will be set only for
- * the first element. we do it for all the elements,
- * just for convenience.
- */
- GET_CANONNAME(cur->ai_next, hp->h_name);
+ if (pai->ai_flags & AI_CANONNAME)
+ (void)get_canonname(pai, res, canonname);
}
-
+ } else
+ res0 = NULL;
+ if (res0) {
+ cur->ai_next = res0;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
- *res = sentinel.ai_next;
- return 0;
+ if (nextline) {
+ p = nextline;
+ goto nextline;
+ }
-free:
- if (sentinel.ai_next)
- freeaddrinfo(sentinel.ai_next);
- return error;
+done:
+ return sentinel.ai_next;
+}
+
+/*ARGSUSED*/
+static int
+_yp_getaddrinfo(rv, cb_data, ap)
+ void *rv;
+ void *cb_data;
+ va_list ap;
+{
+ struct addrinfo sentinel, *cur;
+ struct addrinfo *ai = NULL;
+ static char *__ypcurrent;
+ int __ypcurrentlen, r;
+ const char *name;
+ const struct addrinfo *pai;
+
+ name = va_arg(ap, char *);
+ pai = va_arg(ap, const struct addrinfo *);
+
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+
+ if (!__ypdomain) {
+ if (_yp_check(&__ypdomain) == 0)
+ return NS_UNAVAIL;
+ }
+ if (__ypcurrent)
+ free(__ypcurrent);
+ __ypcurrent = NULL;
+
+ /* hosts.byname is only for IPv4 (Solaris8) */
+ if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) {
+ r = yp_match(__ypdomain, "hosts.byname", name,
+ (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+ if (r == 0) {
+ struct addrinfo ai4;
+
+ ai4 = *pai;
+ ai4.ai_family = AF_INET;
+ ai = _yphostent(__ypcurrent, &ai4);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+ }
+
+ /* ipnodes.byname can hold both IPv4/v6 */
+ r = yp_match(__ypdomain, "ipnodes.byname", name,
+ (int)strlen(name), &__ypcurrent, &__ypcurrentlen);
+ if (r == 0) {
+ ai = _yphostent(__ypcurrent, pai);
+ if (ai) {
+ cur->ai_next = ai;
+ while (cur && cur->ai_next)
+ cur = cur->ai_next;
+ }
+ }
+
+ if (sentinel.ai_next == NULL) {
+ h_errno = HOST_NOT_FOUND;
+ return NS_NOTFOUND;
+ }
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return NS_SUCCESS;
}
#endif
diff --git a/lib/libc/net/gethostbydns.c b/lib/libc/net/gethostbydns.c
index a5a3e7b..4a56655 100644
--- a/lib/libc/net/gethostbydns.c
+++ b/lib/libc/net/gethostbydns.c
@@ -74,6 +74,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include "res_config.h"
@@ -474,19 +476,23 @@ __dns_getanswer(answer, anslen, qname, qtype)
return(gethostanswer((const querybuf *)answer, anslen, qname, qtype));
}
-struct hostent *
-_gethostbydnsname(name, af)
+int
+_dns_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
const char *name;
int af;
-{
querybuf buf;
register const char *cp;
char *bp;
int n, size, type, len;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ *(struct hostent **)rval = NULL;
+
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
switch (af) {
@@ -501,7 +507,7 @@ _gethostbydnsname(name, af)
default:
h_errno = NETDB_INTERNAL;
errno = EAFNOSUPPORT;
- return (NULL);
+ return NS_UNAVAIL;
}
host.h_addrtype = af;
@@ -531,7 +537,7 @@ _gethostbydnsname(name, af)
*/
if (inet_pton(af, name, host_addr) <= 0) {
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
strncpy(hostbuf, name, MAXDNAME);
hostbuf[MAXDNAME] = '\0';
@@ -546,7 +552,8 @@ _gethostbydnsname(name, af)
if (_res.options & RES_USE_INET6)
_map_v4v6_hostent(&host, &bp, &len);
h_errno = NETDB_SUCCESS;
- return (&host);
+ *(struct hostent **)rval = &host;
+ return NS_SUCCESS;
}
if (!isdigit((unsigned char)*cp) && *cp != '.')
break;
@@ -564,7 +571,7 @@ _gethostbydnsname(name, af)
*/
if (inet_pton(af, name, host_addr) <= 0) {
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
strncpy(hostbuf, name, MAXDNAME);
hostbuf[MAXDNAME] = '\0';
@@ -577,7 +584,8 @@ _gethostbydnsname(name, af)
h_addr_ptrs[1] = NULL;
host.h_addr_list = h_addr_ptrs;
h_errno = NETDB_SUCCESS;
- return (&host);
+ *(struct hostent **)rval = &host;
+ return NS_SUCCESS;
}
if (!isxdigit((unsigned char)*cp) && *cp != ':' && *cp != '.')
break;
@@ -585,17 +593,18 @@ _gethostbydnsname(name, af)
if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) {
dprintf("res_search failed (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
- return (gethostanswer(&buf, n, name, type));
+ *(struct hostent **)rval = gethostanswer(&buf, n, name, type);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct hostent *
-_gethostbydnsaddr(addr, len, af)
+int
+_dns_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
const char *addr; /* XXX should have been def'd as u_char! */
int len, af;
-{
- const u_char *uaddr = (const u_char *)addr;
+ const u_char *uaddr;
static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
int n, size;
@@ -608,10 +617,17 @@ _gethostbydnsaddr(addr, len, af)
u_long old_options;
char hname2[MAXDNAME+1];
#endif /*SUNSECURITY*/
+
+ addr = va_arg(ap, const char *);
+ uaddr = (const u_char *)addr;
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval = NULL;
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
if (af == AF_INET6 && len == IN6ADDRSZ &&
(!bcmp(uaddr, mapped, sizeof mapped) ||
@@ -632,12 +648,12 @@ _gethostbydnsaddr(addr, len, af)
default:
errno = EAFNOSUPPORT;
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
if (size != len) {
errno = EINVAL;
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
switch (af) {
case AF_INET:
@@ -662,14 +678,14 @@ _gethostbydnsaddr(addr, len, af)
n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf);
if (n < 0) {
dprintf("res_query failed (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
if (n > sizeof buf.buf) {
dprintf("static buffer is too small (%d)\n", n);
- return (NULL);
+ return NS_UNAVAIL;
}
if (!(hp = gethostanswer(&buf, n, qbuf, T_PTR)))
- return (NULL); /* h_errno was set by gethostanswer() */
+ return NS_NOTFOUND; /* h_errno was set by gethostanswer() */
#ifdef SUNSECURITY
if (af == AF_INET) {
/*
@@ -687,7 +703,7 @@ _gethostbydnsaddr(addr, len, af)
hname2, inet_ntoa(*((struct in_addr *)addr)));
_res.options = old_options;
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
_res.options = old_options;
for (haddr = rhp->h_addr_list; *haddr; haddr++)
@@ -698,7 +714,7 @@ _gethostbydnsaddr(addr, len, af)
"gethostbyaddr: A record of %s != PTR record [%s]",
hname2, inet_ntoa(*((struct in_addr *)addr)));
h_errno = HOST_NOT_FOUND;
- return (NULL);
+ return NS_NOTFOUND;
}
}
#endif /*SUNSECURITY*/
@@ -713,7 +729,8 @@ _gethostbydnsaddr(addr, len, af)
hp->h_length = IN6ADDRSZ;
}
h_errno = NETDB_SUCCESS;
- return (hp);
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#ifdef RESOLVSORT
diff --git a/lib/libc/net/gethostbyht.c b/lib/libc/net/gethostbyht.c
index cd5f0f4..eeecd22 100644
--- a/lib/libc/net/gethostbyht.c
+++ b/lib/libc/net/gethostbyht.c
@@ -65,6 +65,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h> /* XXX */
#include <resolv.h> /* XXX */
@@ -163,13 +165,16 @@ gethostent()
return (&host);
}
-struct hostent *
-_gethostbyhtname(name, af)
+int
+_ht_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
const char *name;
int af;
-{
register struct hostent *p;
register char **cp;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
sethostent(0);
while ((p = gethostent()) != NULL) {
@@ -183,20 +188,28 @@ _gethostbyhtname(name, af)
}
found:
endhostent();
- return (p);
+ *(struct hostent **)rval = p;
+
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct hostent *
-_gethostbyhtaddr(addr, len, af)
+int
+_ht_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
const char *addr;
int len, af;
-{
register struct hostent *p;
+ addr = va_arg(ap, const char *);
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
sethostent(0);
while ((p = gethostent()) != NULL)
if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len))
break;
endhostent();
- return (p);
+
+ *(struct hostent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
diff --git a/lib/libc/net/gethostbyname.3 b/lib/libc/net/gethostbyname.3
index e513d74..0e2006e 100644
--- a/lib/libc/net/gethostbyname.3
+++ b/lib/libc/net/gethostbyname.3
@@ -78,10 +78,15 @@ following structure describing an internet host
referenced by name or by address, respectively.
This structure contains either the information obtained from the name server,
.Xr named 8 ,
-or broken-out fields from a line in
-.Pa /etc/hosts .
-If the local name server is not running these routines do a lookup in
-.Pa /etc/hosts .
+broken-out fields from a line in
+.Pa /etc/hosts ,
+or database entries supplied by the
+.Xr yp 4
+system.
+The order of the lookups is controlled by the
+.Sq hosts
+entry in
+.Xr nsswitch.conf 5 .
.Bd -literal
struct hostent {
char *h_name; /* official name of host */
@@ -188,9 +193,9 @@ value of the
.Fa err
parameter.
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.Sh DIAGNOSTICS
diff --git a/lib/libc/net/gethostbynis.c b/lib/libc/net/gethostbynis.c
index 82e0b3d..518d512 100644
--- a/lib/libc/net/gethostbynis.c
+++ b/lib/libc/net/gethostbynis.c
@@ -39,6 +39,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
@@ -52,7 +54,6 @@ static char rcsid[] = "$FreeBSD$";
static char *host_aliases[MAXALIASES];
static char hostaddr[MAXADDRS];
static char *host_addrs[2];
-#endif /* YP */
static struct hostent *
_gethostbynis(name, map, af)
@@ -60,7 +61,6 @@ _gethostbynis(name, map, af)
char *map;
int af;
{
-#ifdef YP
register char *cp, **q;
char *result;
int resultlen,size;
@@ -122,24 +122,64 @@ _gethostbynis(name, map, af)
}
*q = NULL;
return (&h);
-#else
- return (NULL);
-#endif /* YP */
}
+#endif /* YP */
+/* XXX _gethostbynisname/_gethostbynisaddr only used by getaddrinfo */
struct hostent *
-_gethostbynisname(name, af)
- const char *name;
- int af;
+_gethostbynisname(const char *name, int af)
{
+#ifdef YP
return _gethostbynis(name, "hosts.byname", af);
+#else
+ return NULL;
+#endif
}
struct hostent *
-_gethostbynisaddr(addr, len, af)
+_gethostbynisaddr(const char *addr, int len, int af)
+{
+#ifdef YP
+ return _gethostbynis(inet_ntoa(*(struct in_addr *)addr),
+ "hosts.byaddr", af);
+#else
+ return NULL;
+#endif
+}
+
+
+int
+_nis_gethostbyname(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
+ const char *name;
+ int af;
+
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval = _gethostbynis(name, "hosts.byname", af);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
+}
+
+int
+_nis_gethostbyaddr(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
const char *addr;
int len;
int af;
-{
- return _gethostbynis(inet_ntoa(*(struct in_addr *)addr),"hosts.byaddr", af);
+
+ addr = va_arg(ap, const char *);
+ len = va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ *(struct hostent **)rval =_gethostbynis(inet_ntoa(*(struct in_addr *)addr),"hosts.byaddr", af);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
}
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index 010e4db..fcfc979 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -37,87 +37,25 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h> /* XXX hack for _res */
#include <resolv.h> /* XXX hack for _res */
-#define _PATH_HOSTCONF "/etc/host.conf"
-
-enum service_type {
- SERVICE_NONE = 0,
- SERVICE_BIND,
- SERVICE_HOSTS,
- SERVICE_NIS };
-#define SERVICE_MAX SERVICE_NIS
-
-static struct {
- const char *name;
- enum service_type type;
-} service_names[] = {
- { "hosts", SERVICE_HOSTS },
- { "/etc/hosts", SERVICE_HOSTS },
- { "hosttable", SERVICE_HOSTS },
- { "htable", SERVICE_HOSTS },
- { "bind", SERVICE_BIND },
- { "dns", SERVICE_BIND },
- { "domain", SERVICE_BIND },
- { "yp", SERVICE_NIS },
- { "yellowpages", SERVICE_NIS },
- { "nis", SERVICE_NIS },
- { 0, SERVICE_NONE }
+extern int _ht_gethostbyname(void *, void *, va_list);
+extern int _dns_gethostbyname(void *, void *, va_list);
+extern int _nis_gethostbyname(void *, void *, va_list);
+extern int _ht_gethostbyaddr(void *, void *, va_list);
+extern int _dns_gethostbyaddr(void *, void *, va_list);
+extern int _nis_gethostbyaddr(void *, void *, va_list);
+
+/* Host lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
};
-static enum service_type service_order[SERVICE_MAX + 1];
-static int service_done = 0;
-
-static enum service_type
-get_service_name(const char *name) {
- int i;
- for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
- if(!strcasecmp(name, service_names[i].name)) {
- return service_names[i].type;
- }
- }
- return SERVICE_NONE;
-}
-
-static void
-init_services()
-{
- char *cp, *p, buf[BUFSIZ];
- register int cc = 0;
- FILE *fd;
-
- if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) {
- /* make some assumptions */
- service_order[0] = SERVICE_BIND;
- service_order[1] = SERVICE_HOSTS;
- service_order[2] = SERVICE_NONE;
- } else {
- while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
- if(buf[0] == '#')
- continue;
-
- p = buf;
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- if (cp == NULL)
- continue;
- do {
- if (isalpha((unsigned char)cp[0])) {
- service_order[cc] = get_service_name(cp);
- if(service_order[cc] != SERVICE_NONE)
- cc++;
- }
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- } while(cp != NULL && cc < SERVICE_MAX);
- }
- service_order[cc] = SERVICE_NONE;
- fclose(fd);
- }
- service_done = 1;
-}
-
struct hostent *
gethostbyname(const char *name)
{
@@ -135,56 +73,44 @@ struct hostent *
gethostbyname2(const char *name, int type)
{
struct hostent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return NULL;
- case SERVICE_HOSTS:
- hp = _gethostbyhtname(name, type);
- break;
- case SERVICE_BIND:
- hp = _gethostbydnsname(name, type);
- break;
- case SERVICE_NIS:
- hp = _gethostbynisname(name, type);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_gethostbyname, NULL)
+ { NSSRC_DNS, _dns_gethostbyname, NULL },
+ NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyname",
+ default_src, name, type);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
struct hostent *
gethostbyaddr(const char *addr, int len, int type)
{
struct hostent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return 0;
- case SERVICE_HOSTS:
- hp = _gethostbyhtaddr(addr, len, type);
- break;
- case SERVICE_BIND:
- hp = _gethostbydnsaddr(addr, len, type);
- break;
- case SERVICE_NIS:
- hp = _gethostbynisaddr(addr, len, type);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_gethostbyaddr, NULL)
+ { NSSRC_DNS, _dns_gethostbyaddr, NULL },
+ NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
+ default_src, addr, len, type);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
#ifdef _THREAD_SAFE
diff --git a/lib/libc/net/getipnodebyname.3 b/lib/libc/net/getipnodebyname.3
index 618f5a3..5eec582 100644
--- a/lib/libc/net/getipnodebyname.3
+++ b/lib/libc/net/getipnodebyname.3
@@ -405,9 +405,9 @@ or
.Fn getipnodebyaddr .
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
@@ -429,6 +429,7 @@ The meanings of each error code are described in
.Xr gethostbyname 3 ,
.Xr gethostbyaddr 3 ,
.Xr hosts 5 ,
+.Xr nsswitch.conf 5 ,
.Xr services 5 ,
.Xr hostname 7 ,
.Xr named 8
diff --git a/lib/libc/net/getnameinfo.3 b/lib/libc/net/getnameinfo.3
index 113563f..0289b9f 100644
--- a/lib/libc/net/getnameinfo.3
+++ b/lib/libc/net/getnameinfo.3
@@ -226,9 +226,9 @@ printf("host=%s\\n", hbuf);
.Ed
.\"
.Sh FILES
-.Bl -tag -width /etc/resolv.conf -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/hosts
-.It Pa /etc/host.conf
+.It Pa /etc/nsswitch.conf
.It Pa /etc/resolv.conf
.El
.\"
diff --git a/lib/libc/net/getnetbydns.c b/lib/libc/net/getnetbydns.c
index 65d9d2d..5827103 100644
--- a/lib/libc/net/getnetbydns.c
+++ b/lib/libc/net/getnetbydns.c
@@ -77,6 +77,8 @@ static char rcsid[] = "$FreeBSD$";
#include <string.h>
#include <unistd.h>
#include <syslog.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include "res_config.h"
@@ -218,11 +220,11 @@ static char *net_aliases[MAXALIASES], netbuf[PACKETSZ];
return (NULL);
}
-struct netent *
-_getnetbydnsaddr(net, net_type)
- register unsigned long net;
- register int net_type;
+int
+_dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
+ unsigned long net;
+ int net_type;
unsigned int netbr[4];
int nn, anslen;
querybuf buf;
@@ -230,8 +232,13 @@ _getnetbydnsaddr(net, net_type)
unsigned long net2;
struct netent *net_entry;
+ net = va_arg(ap, unsigned long);
+ net_type = va_arg(ap, int);
+
+ *(struct netent **)rval = NULL;
+
if (net_type != AF_INET)
- return (NULL);
+ return NS_UNAVAIL;
for (nn = 4, net2 = net; net2; net2 >>= 8)
netbr[--nn] = net2 & 0xff;
@@ -257,7 +264,7 @@ _getnetbydnsaddr(net, net_type)
if (_res.options & RES_DEBUG)
printf("res_query failed\n");
#endif
- return (NULL);
+ return NS_UNAVAIL;
}
net_entry = getnetanswer(&buf, anslen, BYADDR);
if (net_entry) {
@@ -267,22 +274,27 @@ _getnetbydnsaddr(net, net_type)
while ((u_net & 0xff) == 0 && u_net != 0)
u_net >>= 8;
net_entry->n_net = u_net;
- return (net_entry);
+ *(struct netent **)rval = net_entry;
+ return NS_SUCCESS;
}
- return (NULL);
+ return NS_NOTFOUND;
}
-struct netent *
-_getnetbydnsname(net)
- register const char *net;
+int
+_dns_getnetbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *net;
int anslen;
querybuf buf;
char qbuf[MAXDNAME];
+ net = va_arg(ap, const char *);
+
+ *(struct netent**)rval = NULL;
+
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
- return (NULL);
+ return NS_UNAVAIL;
}
strncpy(qbuf, net, sizeof(qbuf) - 1);
qbuf[sizeof(qbuf) - 1] = '\0';
@@ -292,9 +304,10 @@ _getnetbydnsname(net)
if (_res.options & RES_DEBUG)
printf("res_query failed\n");
#endif
- return (NULL);
+ return NS_UNAVAIL;
}
- return getnetanswer(&buf, anslen, BYNAME);
+ *(struct netent**)rval = getnetanswer(&buf, anslen, BYNAME);
+ return (*(struct netent**)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
void
diff --git a/lib/libc/net/getnetbyht.c b/lib/libc/net/getnetbyht.c
index ab164b1..b5f73be 100644
--- a/lib/libc/net/getnetbyht.c
+++ b/lib/libc/net/getnetbyht.c
@@ -55,6 +55,8 @@ static chat rcsid[] = "$FreeBSD$";
#include <netdb.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#define MAXALIASES 35
@@ -135,13 +137,15 @@ again:
return (&net);
}
-struct netent *
-_getnetbyhtname(name)
- register const char *name;
+int
+_ht_getnetbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
register struct netent *p;
register char **cp;
+ name = va_arg(ap, const char *);
+
setnetent(_net_stayopen);
while ( (p = getnetent()) ) {
if (strcasecmp(p->n_name, name) == 0)
@@ -153,21 +157,26 @@ _getnetbyhtname(name)
found:
if (!_net_stayopen)
endnetent();
- return (p);
+ *(struct netent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-struct netent *
-_getnetbyhtaddr(net, type)
- register unsigned long net;
- register int type;
+int
+_ht_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
+ unsigned long net;
+ int type;
register struct netent *p;
+ net = va_arg(ap, unsigned long);
+ type = va_arg(ap, int);
+
setnetent(_net_stayopen);
while ( (p = getnetent()) )
if (p->n_addrtype == type && p->n_net == net)
break;
if (!_net_stayopen)
endnetent();
- return (p);
+ *(struct netent **)rval = p;
+ return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
diff --git a/lib/libc/net/getnetbynis.c b/lib/libc/net/getnetbynis.c
index 0ab7073..d226b01 100644
--- a/lib/libc/net/getnetbynis.c
+++ b/lib/libc/net/getnetbynis.c
@@ -38,6 +38,8 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <arpa/nameser.h>
#ifdef YP
#include <rpc/rpc.h>
@@ -50,15 +52,10 @@ static char rcsid[] = "$FreeBSD$";
#ifdef YP
static char *host_aliases[MAXALIASES];
-#endif /* YP */
static struct netent *
-_getnetbynis(name, map, af)
- const char *name;
- char *map;
- int af;
+_getnetbynis(const char *name, char *map, int af)
{
-#ifdef YP
register char *cp, **q;
static char *result;
int resultlen;
@@ -117,32 +114,45 @@ _getnetbynis(name, map, af)
}
*q = NULL;
return (&h);
-#else
- return (NULL);
-#endif
}
+#endif /* YP */
-struct netent *
-_getnetbynisname(name)
- const char *name;
+int
+_nis_getnetbyname(void *rval, void *cb_data, va_list ap)
{
- return _getnetbynis(name, "networks.byname", AF_INET);
+#ifdef YP
+ const char *name;
+
+ name = va_arg(ap, const char *);
+
+ *(struct netent **)rval = _getnetbynis(name, "networks.byname", AF_INET);
+ return (*(struct netent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif
+
}
-struct netent *
-_getnetbynisaddr(addr, af)
+int
+_nis_getnetbyaddr(void *rval, void *cb_data, va_list ap)
+{
+#ifdef YP
unsigned long addr;
int af;
-{
char *str, *cp;
unsigned long net2;
int nn;
unsigned int netbr[4];
char buf[MAXDNAME];
+ addr = va_arg(ap, unsigned long);
+ af = va_arg(ap, int);
+
+ *(struct netent **)rval = NULL;
+
if (af != AF_INET) {
errno = EAFNOSUPPORT;
- return (NULL);
+ return NS_UNAVAIL;
}
for (nn = 4, net2 = addr; net2; net2 >>= 8) {
@@ -173,5 +183,9 @@ _getnetbynisaddr(addr, af)
cp = str + (strlen(str) - 2);
}
- return _getnetbynis(str, "networks.byaddr", af);
+ *(struct netent **)rval = _getnetbynis(str, "networks.byaddr", af);
+ return (*(struct netent**)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
+#else
+ return NS_UNAVAIL;
+#endif /* YP */
}
diff --git a/lib/libc/net/getnetent.3 b/lib/libc/net/getnetent.3
index 086f4c3..de3e9df 100644
--- a/lib/libc/net/getnetent.3
+++ b/lib/libc/net/getnetent.3
@@ -64,10 +64,18 @@ and
.Fn getnetbyaddr
functions
each return a pointer to an object with the
-following structure
-containing the broken-out
-fields of a line in the network data base,
-.Pa /etc/networks .
+following structure describing an internet network.
+This structure contains either the information obtained
+from the nameserver,
+.Xr named 8 ,
+broken-out fields of a line in the network data base
+.Pa /etc/networks ,
+or entries supplied by the
+.Xr yp 4
+system. The order of the lookups is controlled by the
+`networks' entry in
+.Xr nsswitch.conf 5 .
+.Pp
.Bd -literal -offset indent
struct netent {
char *n_name; /* official name of net */
@@ -129,8 +137,10 @@ must be
.Dv AF_INET .
Network numbers are supplied in host order.
.Sh FILES
-.Bl -tag -width /etc/networks -compact
+.Bl -tag -width /etc/nsswitch.conf -compact
.It Pa /etc/networks
+.It Pa /etc/nsswitch.conf
+.It Pa /etc/resolv.conf
.El
.Sh DIAGNOSTICS
Null pointer
diff --git a/lib/libc/net/getnetnamadr.c b/lib/libc/net/getnetnamadr.c
index cb5871b..6d9dbfa 100644
--- a/lib/libc/net/getnetnamadr.c
+++ b/lib/libc/net/getnetnamadr.c
@@ -36,142 +36,66 @@ static char rcsid[] = "$FreeBSD$";
#include <ctype.h>
#include <errno.h>
#include <string.h>
-
-#ifndef _PATH_NETCONF
-#define _PATH_NETCONF "/etc/host.conf"
-#endif
-
-enum service_type {
- SERVICE_NONE = 0,
- SERVICE_BIND,
- SERVICE_TABLE,
- SERVICE_NIS };
-#define SERVICE_MAX SERVICE_NIS
-
-static struct {
- const char *name;
- enum service_type type;
-} service_names[] = {
- { "hosts", SERVICE_TABLE },
- { "/etc/hosts", SERVICE_TABLE },
- { "hosttable", SERVICE_TABLE },
- { "htable", SERVICE_TABLE },
- { "bind", SERVICE_BIND },
- { "dns", SERVICE_BIND },
- { "domain", SERVICE_BIND },
- { "yp", SERVICE_NIS },
- { "yellowpages", SERVICE_NIS },
- { "nis", SERVICE_NIS },
- { 0, SERVICE_NONE }
+#include <stdarg.h>
+#include <nsswitch.h>
+
+extern int _ht_getnetbyname(void *, void *, va_list);
+extern int _dns_getnetbyname(void *, void *, va_list);
+extern int _nis_getnetbyname(void *, void *, va_list);
+extern int _ht_getnetbyaddr(void *, void *, va_list);
+extern int _dns_getnetbyaddr(void *, void *, va_list);
+extern int _nis_getnetbyaddr(void *, void *, va_list);
+
+/* Network lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0 }
};
-static enum service_type service_order[SERVICE_MAX + 1];
-static int service_done = 0;
-
-static enum service_type
-get_service_name(const char *name) {
- int i;
- for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
- if(!strcasecmp(name, service_names[i].name)) {
- return service_names[i].type;
- }
- }
- return SERVICE_NONE;
-}
-
-static void
-init_services()
-{
- char *cp, *p, buf[BUFSIZ];
- register int cc = 0;
- FILE *fd;
-
- if ((fd = (FILE *)fopen(_PATH_NETCONF, "r")) == NULL) {
- /* make some assumptions */
- service_order[0] = SERVICE_TABLE;
- service_order[1] = SERVICE_NONE;
- } else {
- while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
- if(buf[0] == '#')
- continue;
-
- p = buf;
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- if (cp == NULL)
- continue;
- do {
- if (isalpha((unsigned char)cp[0])) {
- service_order[cc] = get_service_name(cp);
- if(service_order[cc] != SERVICE_NONE)
- cc++;
- }
- while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
- ;
- } while(cp != NULL && cc < SERVICE_MAX);
- }
- service_order[cc] = SERVICE_NONE;
- fclose(fd);
- }
- service_done = 1;
-}
-
struct netent *
getnetbyname(const char *name)
{
struct netent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return NULL;
- case SERVICE_TABLE:
- hp = _getnetbyhtname(name);
- break;
- case SERVICE_BIND:
- hp = _getnetbydnsname(name);
- break;
- case SERVICE_NIS:
- hp = _getnetbynisname(name);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_getnetbyname, NULL)
+ { NSSRC_DNS, _dns_getnetbyname, NULL },
+ NS_NIS_CB(_nis_getnetbyname, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_NETWORKS, "getnetbyname",
+ default_src, name);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
struct netent *
-getnetbyaddr(addr, af)
- u_long addr;
- int af;
+getnetbyaddr(u_long addr, int af)
{
struct netent *hp = 0;
- int nserv = 0;
-
- if (!service_done)
- init_services();
-
- while (!hp) {
- switch (service_order[nserv]) {
- case SERVICE_NONE:
- return 0;
- case SERVICE_TABLE:
- hp = _getnetbyhtaddr(addr, af);
- break;
- case SERVICE_BIND:
- hp = _getnetbydnsaddr(addr, af);
- break;
- case SERVICE_NIS:
- hp = _getnetbynisaddr(addr, af);
- break;
- }
- nserv++;
- }
- return hp;
+ int rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_ht_getnetbyaddr, NULL)
+ { NSSRC_DNS, _dns_getnetbyaddr, NULL },
+ NS_NIS_CB(_nis_getnetbyaddr, NULL) /* force -DHESIOD */
+ { 0 }
+ };
+
+ rval = nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "getnetbyaddr",
+ default_src, addr, af);
+
+ if (rval != NS_SUCCESS)
+ return NULL;
+ else
+ return hp;
}
void
diff --git a/lib/libc/net/hesiod.3 b/lib/libc/net/hesiod.3
new file mode 100644
index 0000000..49e7d67
--- /dev/null
+++ b/lib/libc/net/hesiod.3
@@ -0,0 +1,136 @@
+.\" $NetBSD: hesiod.3,v 1.1 1999/01/25 03:43:04 lukem Exp $
+.\" $FreeBSD$
+.\"
+.\" from: #Id: hesiod.3,v 1.9.2.1 1997/01/03 21:02:23 ghudson Exp #
+.\"
+.\" Copyright 1988, 1996 by the Massachusetts Institute of Technology.
+.\"
+.\" Permission to use, copy, modify, and distribute this
+.\" software and its documentation for any purpose and without
+.\" fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies and that both that copyright
+.\" notice and this permission notice appear in supporting
+.\" documentation, and that the name of M.I.T. not be used in
+.\" advertising or publicity pertaining to distribution of the
+.\" software without specific, written prior permission.
+.\" M.I.T. makes no representations about the suitability of
+.\" this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.TH HESIOD 3 "30 November 1996"
+.SH NAME
+hesiod, hesiod_init, hesiod_resolve, hesiod_free_list, hesiod_to_bind, hesiod_end \- Hesiod name server interface library
+.SH SYNOPSIS
+.nf
+.B #include <hesiod.h>
+.PP
+.B int hesiod_init(void **\fIcontext\fP)
+.B char **hesiod_resolve(void *\fIcontext\fP, const char *\fIname\fP,
+.B const char *\fItype\fP)
+.B void hesiod_free_list(void *\fIcontext\fP, char **\fIlist\fP);
+.B char *hesiod_to_bind(void *\fIcontext\fP, const char *\fIname\fP,
+.B const char *\fItype\fP)
+.B void hesiod_end(void *\fIcontext\fP)
+.PP
+.B cc file.c -lhesiod
+.fi
+.SH DESCRIPTION
+This family of functions allows you to perform lookups of Hesiod
+information, which is stored as text records in the Domain Name
+Service. To perform lookups, you must first initialize a
+.IR context ,
+an opaque object which stores information used internally by the
+library between calls.
+.I hesiod_init
+initializes a context, storing a pointer to the context in the
+location pointed to by the
+.I context
+argument.
+.I hesiod_end
+frees the resources used by a context.
+.PP
+.I hesiod_resolve
+is the primary interface to the library. If successful, it returns a
+list of one or more strings giving the records matching
+.I name
+and
+.IR type .
+The last element of the list is followed by a NULL pointer. It is the
+caller's responsibility to call
+.I hesiod_free_list
+to free the resources used by the returned list.
+.PP
+.I hesiod_to_bind
+converts
+.I name
+and
+.I type
+into the DNS name used by
+.IR hesiod_resolve .
+It is the caller's responsibility to free the returned string using
+.IR free .
+.SH RETURN VALUES
+If successful,
+.I hesiod_init
+returns 0; otherwise it returns \-1 and sets
+.I errno
+to indicate the error. On failure,
+.I hesiod_resolve
+and
+.I hesiod_to_bind
+return NULL and set the global variable
+.I errno
+to indicate the error.
+.SH ENVIRONMENT
+If the environment variable
+.B HES_DOMAIN
+is set, it will override the domain in the Hesiod configuration file.
+If the environment variable
+.B HESIOD_CONFIG
+is set, it specifies the location of the Hesiod configuration file.
+.SH SEE ALSO
+`Hesiod - Project Athena Technical Plan -- Name Service', named(8),
+hesiod.conf(5)
+.SH ERRORS
+Hesiod calls may fail because of:
+.IP ENOMEM
+Insufficient memory was available to carry out the requested
+operation.
+.IP ENOEXEC
+.I hesiod_init
+failed because the Hesiod configuration file was invalid.
+.IP ECONNREFUSED
+.I hesiod_resolve
+failed because no name server could be contacted to answer the query.
+.IP EMSGSIZE
+.I hesiod_resolve
+or
+.I hesiod_to_bind
+failed because the query or response was too big to fit into the
+packet buffers.
+.IP ENOENT
+.I hesiod_resolve
+failed because the name server had no text records matching
+.I name
+and
+.IR type ,
+or
+.I hesiod_to_bind
+failed because the
+.I name
+argument had a domain extension which could not be resolved with type
+``rhs-extension'' in the local Hesiod domain.
+.SH AUTHOR
+Steve Dyer, IBM/Project Athena
+.br
+Greg Hudson, MIT Team Athena
+.br
+Copyright 1987, 1988, 1995, 1996 by the Massachusetts Institute of Technology.
+.SH BUGS
+The strings corresponding to the
+.I errno
+values set by the Hesiod functions are not particularly indicative of
+what went wrong, especially for
+.I ENOEXEC
+and
+.IR ENOENT .
diff --git a/lib/libc/net/hesiod.c b/lib/libc/net/hesiod.c
new file mode 100644
index 0000000..f36757b
--- /dev/null
+++ b/lib/libc/net/hesiod.c
@@ -0,0 +1,572 @@
+/* $NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $ */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* Copyright 1996 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of the hesiod library. It implements the core
+ * portion of the hesiod resolver.
+ *
+ * This file is loosely based on an interim version of hesiod.c from
+ * the BIND IRS library, which was in turn based on an earlier version
+ * of this file. Extensive changes have been made on each step of the
+ * path.
+ *
+ * This implementation is not truly thread-safe at the moment because
+ * it uses res_send() and accesses _res.
+ */
+
+#include <sys/cdefs.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *orig_rcsid = "$NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $";
+static char *rcsid = "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <hesiod.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct hesiod_p {
+ char *lhs; /* normally ".ns" */
+ char *rhs; /* AKA the default hesiod domain */
+ int classes[2]; /* The class search order. */
+};
+
+#define MAX_HESRESP 1024
+
+static int read_config_file __P((struct hesiod_p *, const char *));
+static char **get_txt_records __P((int, const char *));
+static int init_context __P((void));
+static void translate_errors __P((void));
+
+
+/*
+ * hesiod_init --
+ * initialize a hesiod_p.
+ */
+int
+hesiod_init(context)
+ void **context;
+{
+ struct hesiod_p *ctx;
+ const char *p, *configname;
+
+ ctx = malloc(sizeof(struct hesiod_p));
+ if (ctx) {
+ *context = ctx;
+ configname = getenv("HESIOD_CONFIG");
+ if (!configname)
+ configname = _PATH_HESIOD_CONF;
+ if (read_config_file(ctx, configname) >= 0) {
+ /*
+ * The default rhs can be overridden by an
+ * environment variable.
+ */
+ p = getenv("HES_DOMAIN");
+ if (p) {
+ if (ctx->rhs)
+ free(ctx->rhs);
+ ctx->rhs = malloc(strlen(p) + 2);
+ if (ctx->rhs) {
+ *ctx->rhs = '.';
+ strcpy(ctx->rhs + 1,
+ (*p == '.') ? p + 1 : p);
+ return 0;
+ } else
+ errno = ENOMEM;
+ } else
+ return 0;
+ }
+ } else
+ errno = ENOMEM;
+
+ if (ctx->lhs)
+ free(ctx->lhs);
+ if (ctx->rhs)
+ free(ctx->rhs);
+ if (ctx)
+ free(ctx);
+ return -1;
+}
+
+/*
+ * hesiod_end --
+ * Deallocates the hesiod_p.
+ */
+void
+hesiod_end(context)
+ void *context;
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+
+ free(ctx->rhs);
+ if (ctx->lhs)
+ free(ctx->lhs);
+ free(ctx);
+}
+
+/*
+ * hesiod_to_bind --
+ * takes a hesiod (name, type) and returns a DNS
+ * name which is to be resolved.
+ */
+char *
+hesiod_to_bind(void *context, const char *name, const char *type)
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
+ const char *rhs;
+ int len;
+
+ strcpy(bindname, name);
+
+ /*
+ * Find the right right hand side to use, possibly
+ * truncating bindname.
+ */
+ p = strchr(bindname, '@');
+ if (p) {
+ *p++ = 0;
+ if (strchr(p, '.'))
+ rhs = name + (p - bindname);
+ else {
+ rhs_list = hesiod_resolve(context, p, "rhs-extension");
+ if (rhs_list)
+ rhs = *rhs_list;
+ else {
+ errno = ENOENT;
+ return NULL;
+ }
+ }
+ } else
+ rhs = ctx->rhs;
+
+ /* See if we have enough room. */
+ len = strlen(bindname) + 1 + strlen(type);
+ if (ctx->lhs)
+ len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
+ len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
+ if (len > sizeof(bindname) - 1) {
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+ errno = EMSGSIZE;
+ return NULL;
+ }
+ /* Put together the rest of the domain. */
+ strcat(bindname, ".");
+ strcat(bindname, type);
+ /* Only append lhs if it isn't empty. */
+ if (ctx->lhs && ctx->lhs[0] != '\0' ) {
+ if (ctx->lhs[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, ctx->lhs);
+ }
+ if (rhs[0] != '.')
+ strcat(bindname, ".");
+ strcat(bindname, rhs);
+
+ /* rhs_list is no longer needed, since we're done with rhs. */
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+
+ /* Make a copy of the result and return it to the caller. */
+ ret = strdup(bindname);
+ if (!ret)
+ errno = ENOMEM;
+ return ret;
+}
+
+/*
+ * hesiod_resolve --
+ * Given a hesiod name and type, return an array of strings returned
+ * by the resolver.
+ */
+char **
+hesiod_resolve(context, name, type)
+ void *context;
+ const char *name;
+ const char *type;
+{
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname, **retvec;
+
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname)
+ return NULL;
+
+ retvec = get_txt_records(ctx->classes[0], bindname);
+ if (retvec == NULL && errno == ENOENT && ctx->classes[1])
+ retvec = get_txt_records(ctx->classes[1], bindname);
+
+ free(bindname);
+ return retvec;
+}
+
+/*ARGSUSED*/
+void
+hesiod_free_list(context, list)
+ void *context;
+ char **list;
+{
+ char **p;
+
+ if (list == NULL)
+ return;
+ for (p = list; *p; p++)
+ free(*p);
+ free(list);
+}
+
+
+/* read_config_file --
+ * Parse the /etc/hesiod.conf file. Returns 0 on success,
+ * -1 on failure. On failure, it might leave values in ctx->lhs
+ * or ctx->rhs which need to be freed by the caller.
+ */
+static int
+read_config_file(ctx, filename)
+ struct hesiod_p *ctx;
+ const char *filename;
+{
+ char *key, *data, *p, **which;
+ char buf[MAXDNAME + 7];
+ int n;
+ FILE *fp;
+
+ /* Set default query classes. */
+ ctx->classes[0] = C_IN;
+ ctx->classes[1] = C_HS;
+
+ /* Try to open the configuration file. */
+ fp = fopen(filename, "r");
+ if (!fp) {
+ /* Use compiled in default domain names. */
+ ctx->lhs = strdup(DEF_LHS);
+ ctx->rhs = strdup(DEF_RHS);
+ if (ctx->lhs && ctx->rhs)
+ return 0;
+ else {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ ctx->lhs = NULL;
+ ctx->rhs = NULL;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ p = buf;
+ if (*p == '#' || *p == '\n' || *p == '\r')
+ continue;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ key = p;
+ while (*p != ' ' && *p != '\t' && *p != '=')
+ p++;
+ *p++ = 0;
+
+ while (isspace(*p) || *p == '=')
+ p++;
+ data = p;
+ while (!isspace(*p))
+ p++;
+ *p = 0;
+
+ if (strcasecmp(key, "lhs") == 0 ||
+ strcasecmp(key, "rhs") == 0) {
+ which = (strcasecmp(key, "lhs") == 0)
+ ? &ctx->lhs : &ctx->rhs;
+ *which = strdup(data);
+ if (!*which) {
+ errno = ENOMEM;
+ return -1;
+ }
+ } else {
+ if (strcasecmp(key, "classes") == 0) {
+ n = 0;
+ while (*data && n < 2) {
+ p = data;
+ while (*p && *p != ',')
+ p++;
+ if (*p)
+ *p++ = 0;
+ if (strcasecmp(data, "IN") == 0)
+ ctx->classes[n++] = C_IN;
+ else
+ if (strcasecmp(data, "HS") == 0)
+ ctx->classes[n++] =
+ C_HS;
+ data = p;
+ }
+ while (n < 2)
+ ctx->classes[n++] = 0;
+ }
+ }
+ }
+ fclose(fp);
+
+ if (!ctx->rhs || ctx->classes[0] == 0 ||
+ ctx->classes[0] == ctx->classes[1]) {
+ errno = ENOEXEC;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * get_txt_records --
+ * Given a DNS class and a DNS name, do a lookup for TXT records, and
+ * return a list of them.
+ */
+static char **
+get_txt_records(qclass, name)
+ int qclass;
+ const char *name;
+{
+ HEADER *hp;
+ unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
+ char *dst, **list;
+ int ancount, qdcount, i, j, n, skip, type, class, len;
+
+ /* Make sure the resolver is initialized. */
+ if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+ return NULL;
+
+ /* Construct the query. */
+ n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0,
+ NULL, qbuf, PACKETSZ);
+ if (n < 0)
+ return NULL;
+
+ /* Send the query. */
+ n = res_send(qbuf, n, abuf, MAX_HESRESP);
+ if (n < 0) {
+ errno = ECONNREFUSED;
+ return NULL;
+ }
+ /* Parse the header of the result. */
+ hp = (HEADER *) (void *) abuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ p = abuf + sizeof(HEADER);
+ eom = abuf + n;
+
+ /*
+ * Skip questions, trying to get to the answer section
+ * which follows.
+ */
+ for (i = 0; i < qdcount; i++) {
+ skip = dn_skipname(p, eom);
+ if (skip < 0 || p + skip + QFIXEDSZ > eom) {
+ errno = EMSGSIZE;
+ return NULL;
+ }
+ p += skip + QFIXEDSZ;
+ }
+
+ /* Allocate space for the text record answers. */
+ list = malloc((ancount + 1) * sizeof(char *));
+ if (!list) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ /* Parse the answers. */
+ j = 0;
+ for (i = 0; i < ancount; i++) {
+ /* Parse the header of this answer. */
+ skip = dn_skipname(p, eom);
+ if (skip < 0 || p + skip + 10 > eom)
+ break;
+ type = p[skip + 0] << 8 | p[skip + 1];
+ class = p[skip + 2] << 8 | p[skip + 3];
+ len = p[skip + 8] << 8 | p[skip + 9];
+ p += skip + 10;
+ if (p + len > eom) {
+ errno = EMSGSIZE;
+ break;
+ }
+ /* Skip entries of the wrong class and type. */
+ if (class != qclass || type != T_TXT) {
+ p += len;
+ continue;
+ }
+ /* Allocate space for this answer. */
+ list[j] = malloc((size_t)len);
+ if (!list[j]) {
+ errno = ENOMEM;
+ break;
+ }
+ dst = list[j++];
+
+ /* Copy answer data into the allocated area. */
+ eor = p + len;
+ while (p < eor) {
+ n = (unsigned char) *p++;
+ if (p + n > eor) {
+ errno = EMSGSIZE;
+ break;
+ }
+ memcpy(dst, p, (size_t)n);
+ p += n;
+ dst += n;
+ }
+ if (p < eor) {
+ errno = EMSGSIZE;
+ break;
+ }
+ *dst = 0;
+ }
+
+ /*
+ * If we didn't terminate the loop normally, something
+ * went wrong.
+ */
+ if (i < ancount) {
+ for (i = 0; i < j; i++)
+ free(list[i]);
+ free(list);
+ return NULL;
+ }
+ if (j == 0) {
+ errno = ENOENT;
+ free(list);
+ return NULL;
+ }
+ list[j] = NULL;
+ return list;
+}
+
+ /*
+ * COMPATIBILITY FUNCTIONS
+ */
+
+static int inited = 0;
+static void *context;
+static int errval = HES_ER_UNINIT;
+
+int
+hes_init()
+{
+ init_context();
+ return errval;
+}
+
+char *
+hes_to_bind(name, type)
+ const char *name;
+ const char *type;
+{
+ static char *bindname;
+ if (init_context() < 0)
+ return NULL;
+ if (bindname)
+ free(bindname);
+ bindname = hesiod_to_bind(context, name, type);
+ if (!bindname)
+ translate_errors();
+ return bindname;
+}
+
+char **
+hes_resolve(name, type)
+ const char *name;
+ const char *type;
+{
+ static char **list;
+
+ if (init_context() < 0)
+ return NULL;
+
+ /*
+ * In the old Hesiod interface, the caller was responsible for
+ * freeing the returned strings but not the vector of strings itself.
+ */
+ if (list)
+ free(list);
+
+ list = hesiod_resolve(context, name, type);
+ if (!list)
+ translate_errors();
+ return list;
+}
+
+int
+hes_error()
+{
+ return errval;
+}
+
+void
+hes_free(hp)
+ char **hp;
+{
+ hesiod_free_list(context, hp);
+}
+
+static int
+init_context()
+{
+ if (!inited) {
+ inited = 1;
+ if (hesiod_init(&context) < 0) {
+ errval = HES_ER_CONFIG;
+ return -1;
+ }
+ errval = HES_ER_OK;
+ }
+ return 0;
+}
+
+static void
+translate_errors()
+{
+ switch (errno) {
+ case ENOENT:
+ errval = HES_ER_NOTFOUND;
+ break;
+ case ECONNREFUSED:
+ case EMSGSIZE:
+ errval = HES_ER_NET;
+ break;
+ case ENOMEM:
+ default:
+ /* Not a good match, but the best we can do. */
+ errval = HES_ER_CONFIG;
+ break;
+ }
+}
diff --git a/lib/libc/net/name6.c b/lib/libc/net/name6.c
index 8edcb1b..ea08d92 100644
--- a/lib/libc/net/name6.c
+++ b/lib/libc/net/name6.c
@@ -109,6 +109,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+#include <nsswitch.h>
#include <unistd.h>
#ifndef _PATH_HOSTS
@@ -169,110 +171,32 @@ static char *_hgetword(char **pp);
static int _mapped_addr_enabled(void);
static FILE *_files_open(int *errp);
-static struct hostent *_files_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _files_ghbyname(void *, void *, va_list);
+static int _files_ghbyaddr(void *, void *, va_list);
static void _files_shent(int stayopen);
static void _files_ehent(void);
#ifdef YP
-static struct hostent *_nis_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _nis_ghbyname(void *, void *, va_list);
+static int _nis_ghbyaddr(void *, void *, va_list);
#endif
-static struct hostent *_dns_ghbyname(const char *name, int af, int *errp);
-static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _dns_ghbyname(void *, void *, va_list);
+static int _dns_ghbyaddr(void *, void *, va_list);
static void _dns_shent(int stayopen);
static void _dns_ehent(void);
#ifdef ICMPNL
-static struct hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp);
+static int _icmp_ghbyaddr(void *, void *, va_list);
#endif /* ICMPNL */
-/*
- * Select order host function.
- */
-#define MAXHOSTCONF 4
-
-#ifndef HOSTCONF
-# define HOSTCONF "/etc/host.conf"
-#endif /* !HOSTCONF */
-
-struct _hostconf {
- struct hostent *(*byname)(const char *name, int af, int *errp);
- struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp);
-};
-
-/* default order */
-static struct _hostconf _hostconf[MAXHOSTCONF] = {
- { _dns_ghbyname, _dns_ghbyaddr },
- { _files_ghbyname, _files_ghbyaddr },
+/* Host lookup order if nsswitch.conf is broken or nonexistant */
+static const ns_src default_src[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
#ifdef ICMPNL
- { NULL, _icmp_ghbyaddr },
-#endif /* ICMPNL */
-};
-
-static int _hostconf_init_done;
-static void _hostconf_init(void);
-
-/*
- * Initialize hostconf structure.
- */
-
-static void
-_hostconf_init(void)
-{
- FILE *fp;
- int n;
- char *p, *line;
- char buf[BUFSIZ];
-
- _hostconf_init_done = 1;
- n = 0;
- p = HOSTCONF;
- if ((fp = fopen(p, "r")) == NULL)
- return;
- while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) {
- line = buf;
- if ((p = _hgetword(&line)) == NULL)
- continue;
- do {
- if (strcmp(p, "hosts") == 0
- || strcmp(p, "local") == 0
- || strcmp(p, "file") == 0
- || strcmp(p, "files") == 0) {
- _hostconf[n].byname = _files_ghbyname;
- _hostconf[n].byaddr = _files_ghbyaddr;
- n++;
- }
- else if (strcmp(p, "dns") == 0
- || strcmp(p, "bind") == 0) {
- _hostconf[n].byname = _dns_ghbyname;
- _hostconf[n].byaddr = _dns_ghbyaddr;
- n++;
- }
-#ifdef YP
- else if (strcmp(p, "nis") == 0) {
- _hostconf[n].byname = _nis_ghbyname;
- _hostconf[n].byaddr = _nis_ghbyaddr;
- n++;
- }
+#define NSSRC_ICMP "icmp"
+ { NSSRC_ICMP, NS_SUCCESS },
#endif
-#ifdef ICMPNL
- else if (strcmp(p, "icmp") == 0) {
- _hostconf[n].byname = NULL;
- _hostconf[n].byaddr = _icmp_ghbyaddr;
- n++;
- }
-#endif /* ICMPNL */
- } while ((p = _hgetword(&line)) != NULL);
- }
- fclose(fp);
- if (n < 0) {
- /* no keyword found. do not change default configuration */
- return;
- }
- for (; n < MAXHOSTCONF; n++) {
- _hostconf[n].byname = NULL;
- _hostconf[n].byaddr = NULL;
- }
-}
+ { 0 }
+};
/*
* Check if kernel supports mapped address.
@@ -311,7 +235,14 @@ static struct hostent *
_ghbyname(const char *name, int af, int flags, int *errp)
{
struct hostent *hp;
- int i;
+ int i, rval;
+
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_ghbyname, NULL)
+ { NSSRC_DNS, _dns_ghbyname, NULL },
+ NS_NIS_CB(_nis_ghbyname, NULL)
+ { 0 }
+ };
if (flags & AI_ADDRCONFIG) {
int s;
@@ -342,13 +273,9 @@ _ghbyname(const char *name, int af, int flags, int *errp)
}
}
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (_hostconf[i].byname
- && (hp = (*_hostconf[i].byname)(name, af, errp)) != NULL)
- return hp;
- }
-
- return NULL;
+ rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src,
+ name, af, errp);
+ return (rval == NS_SUCCESS) ? hp : NULL;
}
/* getipnodebyname() internal routine for multiple query(PF_UNSPEC) support. */
@@ -392,9 +319,6 @@ _getipnodebyname_multi(const char *name, int af, int flags, int *errp)
return _hpaddr(af, name, &addrbuf, errp);
}
- if (!_hostconf_init_done)
- _hostconf_init();
-
*errp = HOST_NOT_FOUND;
hp = _ghbyname(name, af, flags, errp);
@@ -436,13 +360,23 @@ struct hostent *
getipnodebyaddr(const void *src, size_t len, int af, int *errp)
{
struct hostent *hp;
- int i;
+ int i, rval;
#ifdef INET6
struct in6_addr addrbuf;
#else
struct in_addr addrbuf;
#endif
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_files_ghbyaddr, NULL)
+ { NSSRC_DNS, _dns_ghbyaddr, NULL },
+ NS_NIS_CB(_nis_ghbyaddr, NULL)
+#ifdef ICMPNL
+ { NSSRC_ICMP, _icmp_ghbyaddr, NULL },
+#endif
+ { 0 }
+ };
+
*errp = HOST_NOT_FOUND;
switch (af) {
@@ -484,15 +418,9 @@ getipnodebyaddr(const void *src, size_t len, int af, int *errp)
return NULL;
}
- if (!_hostconf_init_done)
- _hostconf_init();
- for (i = 0; i < MAXHOSTCONF; i++) {
- if (_hostconf[i].byaddr
- && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL)
- return hp;
- }
-
- return NULL;
+ rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
+ src, len, af, errp);
+ return (rval == NS_SUCCESS) ? hp : NULL;
}
void
@@ -828,9 +756,12 @@ _files_open(int *errp)
return fp;
}
-static struct hostent *
-_files_ghbyname(const char *name, int af, int *errp)
+static int
+_files_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
int match, nalias;
char *p, *line, *addrstr, *cname;
FILE *fp;
@@ -840,8 +771,14 @@ _files_ghbyname(const char *name, int af, int *errp)
char buf[BUFSIZ];
int af0 = af;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent **)rval = NULL;
+
if ((fp = _files_open(errp)) == NULL)
- return NULL;
+ return NS_UNAVAIL;
rethp = hp = NULL;
while (fgets(buf, sizeof(buf), fp)) {
@@ -906,12 +843,17 @@ _files_ghbyname(const char *name, int af, int *errp)
rethp = _hpmerge(rethp, hp, errp);
}
fclose(fp);
- return rethp;
+ *(struct hostent **)rval = rethp;
+ return (rethp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_files_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
int nalias;
char *p, *line;
FILE *fp;
@@ -920,8 +862,15 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
union inx_addr addrbuf;
char buf[BUFSIZ];
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent**)rval = NULL;
+
if ((fp = _files_open(errp)) == NULL)
- return NULL;
+ return NS_UNAVAIL;
hp = NULL;
while (fgets(buf, sizeof(buf), fp)) {
line = buf;
@@ -950,7 +899,8 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
break;
}
fclose(fp);
- return hp;
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#ifdef YP
@@ -959,11 +909,18 @@ _files_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
*
* XXX actually a hack, these are INET4 specific.
*/
-static struct hostent *
-_nis_ghbyname(const char *name, int af, int *errp)
+static int
+_nis_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
struct hostent *hp = NULL;
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
if (af == AF_UNSPEC)
af = AF_INET;
if (af == AF_INET) {
@@ -971,21 +928,32 @@ _nis_ghbyname(const char *name, int af, int *errp)
if (hp != NULL)
hp = _hpcopy(hp, errp);
}
- return (hp);
+
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_nis_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_nis_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
struct hostent *hp = NULL;
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+
if (af == AF_INET) {
hp = _gethostbynisaddr(addr, addrlen, af);
if (hp != NULL)
hp = _hpcopy(hp, errp);
}
- return (hp);
+ *(struct hostent **)rval = hp;
+ return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
#endif
@@ -1486,14 +1454,21 @@ _res_search_multi(name, rtl, errp)
return (NULL);
}
-static struct hostent *
-_dns_ghbyname(const char *name, int af, int *errp)
+static int
+_dns_ghbyname(void *rval, void *cb_data, va_list ap)
{
+ const char *name;
+ int af;
+ int *errp;
struct __res_type_list *rtl, rtl4;
#ifdef INET6
struct __res_type_list rtl6;
#endif
+ name = va_arg(ap, const char *);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
#ifdef INET6
switch (af) {
case AF_UNSPEC:
@@ -1514,12 +1489,17 @@ _dns_ghbyname(const char *name, int af, int *errp)
SLIST_NEXT(&rtl4, rtl_entry) = NULL; rtl4.rtl_type = T_A;
rtl = &rtl4;
#endif
- return(_res_search_multi(name, rtl, errp));
+ *(struct hostent **)rval = _res_search_multi(name, rtl, errp);
+ return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND;
}
-static struct hostent *
-_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
+static int
+_dns_ghbyaddr(void *rval, void *cb_data, va_list ap)
{
+ const void *addr;
+ int addrlen;
+ int af;
+ int *errp;
int n;
struct hostent *hp;
u_char c, *cp;
@@ -1533,16 +1513,23 @@ _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
char qbuf[MAXDNAME+1];
char *hlist[2];
+ addr = va_arg(ap, const void *);
+ addrlen = va_arg(ap, int);
+ af = va_arg(ap, int);
+ errp = va_arg(ap, int *);
+
+ *(struct hostent **)rval = NULL;
+
#ifdef INET6
/* XXX */
if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr))
- return NULL;
+ return NS_NOTFOUND;
#endif
if ((_res.options & RES_INIT) == 0) {
if (res_init() < 0) {
*errp = h_errno;
- return NULL;
+ return NS_UNAVAIL;
}
}
memset(&hbuf, 0, sizeof(hbuf));
@@ -1585,17 +1572,18 @@ _dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp)
n = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
if (n < 0) {
*errp = h_errno;
- return NULL;
+ return NS_UNAVAIL;
}
hp = getanswer(&buf, n, qbuf, T_PTR, &hbuf, errp);
if (!hp)
- return NULL;
+ return NS_NOTFOUND;
hbuf.h_addrtype = af;
hbuf.h_length = addrlen;
hbuf.h_addr_list = hlist;
hlist[0] = (char *)addr;
hlist[1] = NULL;
- return _hpcopy(&hbuf, errp);
+ *(struct hostent **)rval = _hpcopy(&hbuf, errp);
+ return NS_SUCCESS;
}
static void
diff --git a/lib/libc/net/nsdispatch.3 b/lib/libc/net/nsdispatch.3
new file mode 100644
index 0000000..bd6366e
--- /dev/null
+++ b/lib/libc/net/nsdispatch.3
@@ -0,0 +1,231 @@
+.\" $NetBSD: nsdispatch.3,v 1.8 1999/03/22 19:44:53 garbled Exp $
+.\" $FreeBSD$
+.\"
+.\" 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.
+.\"
+.Dd January 19, 1999
+.Dt NSDISPATCH 3
+.Os
+.Sh NAME
+.Nm nsdispatch
+.Nd name-service switch dispatcher routine
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <nsswitch.h>
+.Ft int
+.Fo nsdispatch
+.Fa "void *retval"
+.Fa "const ns_dtab dtab[]"
+.Fa "const char *database"
+.Fa "const char *method"
+.Fa "const ns_src defaults[]"
+.Fa "..."
+.Fc
+.Sh DESCRIPTION
+The
+.Fn nsdispatch
+function invokes the callback functions specified in
+.Va dtab
+in the order given in
+.Pa /etc/nsswitch.conf
+for the database
+.Va database
+until a successful entry is found.
+.Pp
+.Va retval
+is passed to each callback function to modify as necessary
+(to pass back to the caller of
+.Fn nsdispatch )
+.Pp
+.Va dtab
+is an array of
+.Va ns_dtab
+structures, which have the following format:
+.Bd -literal -offset indent
+typedef struct {
+ const char *src;
+ int (*cb)(void *retval, void *cb_data, va_list ap);
+ void *cb_data;
+} ns_dtab;
+.Ed
+.Pp
+.Bd -ragged -offset indent
+For each source type that is implemented, an entry with
+.Va src
+set to the name of the source,
+.Va cb
+defined as a function which handles that source, and
+.Va cb_data
+is used to pass arbritrary data to the callback function.
+The last entry in
+.Va dtab
+should contain
+.Dv NULL
+values for
+.Va src ,
+.Va cb ,
+and
+.Va cb_data .
+.Ed
+.Pp
+.Va method
+is usually the name of the function calling
+.Fn nsdispatch .
+When dynamic loading is supported, a symbol constructed from
+.Va database ,
+the current source, and
+.Va method
+will be used as the name to invoke the dynamically loaded function.
+.Pp
+.Va defaults
+contains a list of default sources to try in the case of
+a missing or corrupt
+.Xr nsswitch.conf 5 ,
+or if there isn't a relevant entry for
+.Va database .
+It is an array of
+.Va ns_src
+structures, which have the following format:
+.Bd -literal -offset indent
+typedef struct {
+ const char *src;
+ u_int32_t flags;
+} ns_src;
+.Ed
+.Pp
+.Bd -ragged -offset indent
+For each default source type, an entry with
+.Va src
+set to the name of the source, and
+.Va flags
+set to the relevant flags
+(usually
+.Dv NS_SUCCESS ;
+refer to
+.Sx Callback return values
+for more information).
+The last entry in
+.Va defaults
+should have
+.Va src
+set to
+.Dv NULL
+and
+.Va flags
+set to 0.
+.Pp
+For convenience, a global variable defined as:
+.Dl extern const ns_src __nsdefaultsrc[];
+exists which contains a single default entry for
+.Sq files
+for use by callers which don't require complicated default rules.
+.Ed
+.Pp
+.Va Sq ...
+are optional extra arguments, which
+are passed to the appropriate callback function as a variable argument
+list of the type
+.Va va_list .
+.Ss Valid source types
+Whilst there is support for arbitrary sources, the following
+#defines for commonly implementated sources are available:
+.Bl -column NS_COMPAT COMPAT -offset indent
+.Sy #define value
+.It NSSRC_FILES "files"
+.It NSSRC_DNS "dns"
+.It NSSRC_NIS "nis"
+.It NSSRC_COMPAT "compat"
+.El
+.Pp
+Refer to
+.Xr nsswitch.conf 5
+for a complete description of what each source type is.
+.Pp
+.Ss Callback return values
+The callback functions should return one of the following values
+depending upon status of the lookup:
+.Bl -column NS_NOTFOUND -offset indent
+.Sy "Return value" Status code
+.It NS_SUCCESS success
+.It NS_NOTFOUND notfound
+.It NS_UNAVAIL unavail
+.It NS_TRYAGAIN tryagain
+.El
+.Pp
+Refer to
+.Xr nsswitch.conf 5
+for a complete description of what each status code is.
+.Pp
+.Nm
+returns the value of the callback that caused the dispatcher to finish,
+or NS_NOTFOUND otherwise.
+.Sh SEE ALSO
+.Xr hesiod 3 ,
+.Xr stdarg 3 ,
+.Xr ypclnt 3 ,
+.Xr nsswitch.conf 5
+.Sh HISTORY
+The
+.Nm
+routines first appeared in
+.Fx 4.1 .
+They were imported from the
+.Nx
+Project,
+where they appeared first in
+.Nx 1.4 .
+.Sh AUTHORS
+Luke Mewburn
+.Aq lukem@netbsd.org
+wrote this freely distributable name-service switch implementation,
+using ideas from the
+.Tn ULTRIX
+.Xr svc.conf 5
+and
+.Tn Solaris
+.Xr nsswitch.conf 4
+manual pages.
+.Sh BUGS
+The
+.Nm
+routines are not thread safe.
+This will be rectified in the future.
+.Pp
+Currently there is no support for dynamically loadable dispatcher callback
+functions.
+It is anticipated that this will be added in the future in the back-end
+without requiring changes to code that invokes
+.Fn nsdispatch .
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
new file mode 100644
index 0000000..311b89d
--- /dev/null
+++ b/lib/libc/net/nsdispatch.c
@@ -0,0 +1,270 @@
+/* $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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid =
+ "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fcntl.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * default sourcelist: `files'
+ */
+const ns_src __nsdefaultsrc[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { 0 },
+};
+
+
+static int _nsmapsize = 0;
+static ns_dbt *_nsmap = NULL;
+
+/*
+ * size of dynamic array chunk for _nsmap and _nsmap[x].srclist
+ */
+#define NSELEMSPERCHUNK 8
+
+
+int _nscmp __P((const void *, const void *));
+
+
+int
+_nscmp(a, b)
+ const void *a;
+ const void *b;
+{
+ return (strcasecmp(((const ns_dbt *)a)->name,
+ ((const ns_dbt *)b)->name));
+}
+
+
+void
+_nsdbtaddsrc(dbt, src)
+ ns_dbt *dbt;
+ const ns_src *src;
+{
+ if ((dbt->srclistsize % NSELEMSPERCHUNK) == 0) {
+ dbt->srclist = (ns_src *)realloc(dbt->srclist,
+ (dbt->srclistsize + NSELEMSPERCHUNK) * sizeof(ns_src));
+ if (dbt->srclist == NULL)
+ err(1, "nsdispatch: memory allocation failure");
+ }
+ memmove(&dbt->srclist[dbt->srclistsize++], src, sizeof(ns_src));
+}
+
+
+void
+_nsdbtdump(dbt)
+ const ns_dbt *dbt;
+{
+ int i;
+
+ printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
+ dbt->srclistsize == 1 ? "" : "s");
+ for (i = 0; i < 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");
+}
+
+
+const ns_dbt *
+_nsdbtget(name)
+ const char *name;
+{
+ static time_t confmod;
+
+ struct stat statbuf;
+ ns_dbt dbt;
+
+ extern FILE *_nsyyin;
+ extern int _nsyyparse __P((void));
+
+ dbt.name = name;
+
+ if (confmod) {
+ if (stat(_PATH_NS_CONF, &statbuf) == -1)
+ return (NULL);
+ if (confmod < statbuf.st_mtime) {
+ int i, j;
+
+ for (i = 0; i < _nsmapsize; i++) {
+ for (j = 0; j < _nsmap[i].srclistsize; j++) {
+ if (_nsmap[i].srclist[j].name != NULL) {
+ /*LINTED const cast*/
+ free((void *)
+ _nsmap[i].srclist[j].name);
+ }
+ }
+ if (_nsmap[i].srclist)
+ free(_nsmap[i].srclist);
+ if (_nsmap[i].name) {
+ /*LINTED const cast*/
+ free((void *)_nsmap[i].name);
+ }
+ }
+ if (_nsmap)
+ free(_nsmap);
+ _nsmap = NULL;
+ _nsmapsize = 0;
+ confmod = 0;
+ }
+ }
+ if (!confmod) {
+ if (stat(_PATH_NS_CONF, &statbuf) == -1)
+ return (NULL);
+ _nsyyin = fopen(_PATH_NS_CONF, "r");
+ if (_nsyyin == NULL)
+ return (NULL);
+ _nsyyparse();
+ (void)fclose(_nsyyin);
+ qsort(_nsmap, (size_t)_nsmapsize, sizeof(ns_dbt), _nscmp);
+ confmod = statbuf.st_mtime;
+ }
+ return (bsearch(&dbt, _nsmap, (size_t)_nsmapsize, sizeof(ns_dbt),
+ _nscmp));
+}
+
+
+void
+_nsdbtput(dbt)
+ const ns_dbt *dbt;
+{
+ int i;
+
+ for (i = 0; i < _nsmapsize; i++) {
+ if (_nscmp(dbt, &_nsmap[i]) == 0) {
+ /* overwrite existing entry */
+ if (_nsmap[i].srclist != NULL)
+ free(_nsmap[i].srclist);
+ memmove(&_nsmap[i], dbt, sizeof(ns_dbt));
+ return;
+ }
+ }
+
+ if ((_nsmapsize % NSELEMSPERCHUNK) == 0) {
+ _nsmap = (ns_dbt *)realloc(_nsmap,
+ (_nsmapsize + NSELEMSPERCHUNK) * sizeof(ns_dbt));
+ if (_nsmap == NULL)
+ err(1, "nsdispatch: memory allocation failure");
+ }
+ memmove(&_nsmap[_nsmapsize++], dbt, sizeof(ns_dbt));
+}
+
+
+int
+#if __STDC__
+nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
+ const char *method, const ns_src defaults[], ...)
+#else
+nsdispatch(retval, disp_tab, database, method, defaults, va_alist)
+ void *retval;
+ const ns_dtab disp_tab[];
+ const char *database;
+ const char *method;
+ const ns_src defaults[];
+ va_dcl
+#endif
+{
+ va_list ap;
+ int i, curdisp, result;
+ const ns_dbt *dbt;
+ const ns_src *srclist;
+ int srclistsize;
+
+ dbt = _nsdbtget(database);
+ if (dbt != NULL) {
+ srclist = dbt->srclist;
+ srclistsize = dbt->srclistsize;
+ } else {
+ srclist = defaults;
+ srclistsize = 0;
+ while (srclist[srclistsize].name != NULL)
+ srclistsize++;
+ }
+ result = 0;
+
+ for (i = 0; i < srclistsize; i++) {
+ for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++)
+ if (strcasecmp(disp_tab[curdisp].src,
+ srclist[i].name) == 0)
+ break;
+ result = 0;
+ if (disp_tab[curdisp].callback) {
+#if __STDC__
+ va_start(ap, defaults);
+#else
+ va_start(ap);
+#endif
+ result = disp_tab[curdisp].callback(retval,
+ disp_tab[curdisp].cb_data, ap);
+ va_end(ap);
+ if (result & srclist[i].flags) {
+ break;
+ }
+ }
+ }
+ return (result ? result : NS_NOTFOUND);
+}
diff --git a/lib/libc/net/nslexer.l b/lib/libc/net/nslexer.l
new file mode 100644
index 0000000..104cfbb
--- /dev/null
+++ b/lib/libc/net/nslexer.l
@@ -0,0 +1,116 @@
+%{
+/* $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$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <err.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <string.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)
+ err(1, "nsdispatch: memory allocation failure");
+
+ 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];
+
+. ; /* ignore all else */
+
+%%
+
+#undef _nsyywrap
+int
+_nsyywrap()
+{
+ return 1;
+} /* _nsyywrap */
+
+void
+_nsyyerror(msg)
+ const char *msg;
+{
+
+ warnx("%s line %d: %s at '%s'", _PATH_NS_CONF, yylineno, msg, yytext);
+} /* _nsyyerror */
diff --git a/lib/libc/net/nsparser.y b/lib/libc/net/nsparser.y
new file mode 100644
index 0000000..b39f011
--- /dev/null
+++ b/lib/libc/net/nsparser.y
@@ -0,0 +1,175 @@
+%{
+/* $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>
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid =
+ "$FreeBSD$";
+#endif /* LIBC_SCCS and not lint */
+
+#include <err.h>
+#define _NS_PRIVATE
+#include <nsswitch.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static void _nsaddsrctomap __P((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 <str> STRING
+
+%type <mapval> Status Action
+
+%%
+
+File
+ : /* empty */
+ | Lines
+ ;
+
+Lines
+ : Entry
+ | Lines Entry
+ ;
+
+Entry
+ : NL
+ | Database ':' NL
+ | Database ':' Srclist NL
+ {
+ _nsdbtput(&curdbt);
+ }
+ ;
+
+Database
+ : STRING
+ {
+ curdbt.name = yylval.str;
+ curdbt.srclist = NULL;
+ curdbt.srclistsize = 0;
+ }
+ ;
+
+Srclist
+ : Item
+ | Srclist Item
+ ;
+
+Item
+ : STRING
+ {
+ cursrc.flags = NS_SUCCESS;
+ _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 { $$ = 1L; }
+ | CONTINUE { $$ = 0L; }
+ ;
+
+%%
+
+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)) {
+ /* XXX: syslog the following */
+ warnx("%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) {
+ /* XXX: syslog the following */
+ warnx("%s line %d: duplicate source '%s'",
+ _PATH_NS_CONF, lineno, elem);
+ return;
+ }
+ }
+ cursrc.name = elem;
+ _nsdbtaddsrc(&curdbt, &cursrc);
+}
OpenPOWER on IntegriCloud