diff options
author | nectar <nectar@FreeBSD.org> | 2000-09-06 18:16:48 +0000 |
---|---|---|
committer | nectar <nectar@FreeBSD.org> | 2000-09-06 18:16:48 +0000 |
commit | 748554442d0ac4467fdac2ce9d42006588fd4481 (patch) | |
tree | aed2ddbcac97f46f60ee9c2063a3345553f6a1ee /lib/libc/net | |
parent | 59ffb36b778f8e629622726f6bd32dfa4fda7e35 (diff) | |
download | FreeBSD-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.inc | 28 | ||||
-rw-r--r-- | lib/libc/net/getaddrinfo.3 | 4 | ||||
-rw-r--r-- | lib/libc/net/getaddrinfo.c | 486 | ||||
-rw-r--r-- | lib/libc/net/gethostbydns.c | 65 | ||||
-rw-r--r-- | lib/libc/net/gethostbyht.c | 29 | ||||
-rw-r--r-- | lib/libc/net/gethostbyname.3 | 17 | ||||
-rw-r--r-- | lib/libc/net/gethostbynis.c | 62 | ||||
-rw-r--r-- | lib/libc/net/gethostnamadr.c | 166 | ||||
-rw-r--r-- | lib/libc/net/getipnodebyname.3 | 5 | ||||
-rw-r--r-- | lib/libc/net/getnameinfo.3 | 4 | ||||
-rw-r--r-- | lib/libc/net/getnetbydns.c | 41 | ||||
-rw-r--r-- | lib/libc/net/getnetbyht.c | 27 | ||||
-rw-r--r-- | lib/libc/net/getnetbynis.c | 50 | ||||
-rw-r--r-- | lib/libc/net/getnetent.3 | 20 | ||||
-rw-r--r-- | lib/libc/net/getnetnamadr.c | 174 | ||||
-rw-r--r-- | lib/libc/net/hesiod.3 | 136 | ||||
-rw-r--r-- | lib/libc/net/hesiod.c | 572 | ||||
-rw-r--r-- | lib/libc/net/name6.c | 264 | ||||
-rw-r--r-- | lib/libc/net/nsdispatch.3 | 231 | ||||
-rw-r--r-- | lib/libc/net/nsdispatch.c | 270 | ||||
-rw-r--r-- | lib/libc/net/nslexer.l | 116 | ||||
-rw-r--r-- | lib/libc/net/nsparser.y | 175 |
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); +} |