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/getaddrinfo.c | |
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/getaddrinfo.c')
-rw-r--r-- | lib/libc/net/getaddrinfo.c | 486 |
1 files changed, 252 insertions, 234 deletions
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 |