From 1eb946b93509b94db2bddce741f2f3b483418a6d Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 10 May 2008 23:27:39 +0000 Subject: * include/resolv.h: Adjust __libc_res_nquery and __libc_res_nsend prototypes. * include/arpa/nameser_compat.h: Define T_UNSPEC. * nis/Versions (libnss_nis): Export _nss_nis_gethostbyname4_r. (libnss_nisplus): Export _nss_nisplus_gethostbyname4_r. * nis/nss_nis/nis-hosts.c (LINE_PARSER): Change to also handle af==AF_UNSPEC. (_nss_nis_gethostbyname4_r): New function. * nis/nss_nisplus/nisplus-hosts.c (_nss_nisplus_parse_hostent): Change to also handle af==AF_UNSPEC. (get_tablename): New function. Use it to avoid duplication. (_nss_nisplus_gethostbyname4_r): New function. * nscd/aicache.c (addhstaiX): Use gethostbyname4_r function is available. * nss/Versions (libnss_files): Export _nss_files_gethostbyname4_r. * nss/nss.h: Define struct gaih_addrtuple. * nss/nss_files/files-hosts.c (LINE_PARSER): Change to also handle af==AF_UNSPEC. (_nss_files_gethostbyname4_r): New function. * resolv/Versions (libnss_dns): Export _nss_dns_gethostbyname4_r. * resolv/gethnmaddr.c: Adjust __libc_res_nsearch and __libc_res_nquery calls. * resolv/res_query.c (__libc_res_nquery): Take two additional parameters for second answer buffer. Handle type=T_UNSPEC to mean look up IPv4 and IPv6. Change all callers. * resolv/res_send.c (__libc_res_nsend): Take five aditional parameters for an additional query and answer buffer. Pass to send_vc and send_dg. (send_vc): Send possibly two requests and receive two answers. (send_dg): Likewise. * resolv/nss_dns/dns-host.c: Adjust calls to __libc_res_nsearch and __libc_res_nquery. (_nss_dns_gethostbyname4_r): New function. (gaih_getanswer_slice): Likewise. (gaih_getanswer): Likewise. * resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Adjust __libc_res_nquery call. * resolv/nss_dns/dns-network.c (_nss_dns_getnetbyaddr_r): Likewise. (_nss_dns_getnetbyname_r): Adjust __libc_res_nsearch call. * sysdeps/posix/getaddrinfo.c: Use gethostbyname4_r function is available. --- nis/Versions | 3 +- nis/nss_nis/nis-hosts.c | 118 +++++++++++++++++++-- nis/nss_nisplus/nisplus-hosts.c | 222 ++++++++++++++++++++++++++-------------- 3 files changed, 254 insertions(+), 89 deletions(-) (limited to 'nis') diff --git a/nis/Versions b/nis/Versions index be4453e285..ef9a512417 100644 --- a/nis/Versions +++ b/nis/Versions @@ -95,7 +95,7 @@ libnss_nis { _nss_nis_setgrent; _nss_nis_sethostent; _nss_nis_setnetent; _nss_nis_setnetgrent; _nss_nis_setprotoent; _nss_nis_setpwent; _nss_nis_setrpcent; _nss_nis_setservent; _nss_nis_setspent; - _nss_nis_initgroups_dyn; + _nss_nis_initgroups_dyn; _nss_nis_gethostbyname4_r; } } @@ -126,5 +126,6 @@ libnss_nisplus { _nss_nisplus_setnetent; _nss_nisplus_setnetgrent; _nss_nisplus_setprotoent; _nss_nisplus_setpwent; _nss_nisplus_setrpcent; _nss_nisplus_setservent; _nss_nisplus_setspent; _nss_nisplus_initgroups_dyn; + _nss_nisplus_gethostbyname4_r; } } diff --git a/nis/nss_nis/nis-hosts.c b/nis/nss_nis/nis-hosts.c index 7bf4af786d..24d13634d7 100644 --- a/nis/nss_nis/nis-hosts.c +++ b/nis/nss_nis/nis-hosts.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007 Free Software Foundation, Inc. +/* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007, 2008 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk , 1996. @@ -17,6 +18,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include #include #include /* The following is an ugly trick to avoid a prototype declaration for @@ -61,9 +63,12 @@ LINE_PARSER STRING_FIELD (addr, isspace, 1); + assert (af == AF_INET || af == AF_INET6 || af == AF_UNSPEC); + /* Parse address. */ - if (af == AF_INET && inet_pton (AF_INET, addr, entdata->host_addr) > 0) + if (af != AF_INET6 && inet_pton (AF_INET, addr, entdata->host_addr) > 0) { + assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC); if (flags & AI_V4MAPPED) { map_v4v6_address ((char *) entdata->host_addr, @@ -77,7 +82,7 @@ LINE_PARSER result->h_length = INADDRSZ; } } - else if (af == AF_INET6 + else if (af != AF_INET && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) { result->h_addrtype = AF_INET6; @@ -102,6 +107,7 @@ static bool_t new_start = 1; static char *oldkey = NULL; static int oldkeylen = 0; + enum nss_status _nss_nis_sethostent (int stayopen) { @@ -124,6 +130,7 @@ _nss_nis_sethostent (int stayopen) is used so this makes no difference. */ strong_alias (_nss_nis_sethostent, _nss_nis_endhostent) + /* The calling function always need to get a lock first. */ static enum nss_status internal_nis_gethostent_r (struct hostent *host, char *buffer, @@ -216,6 +223,7 @@ internal_nis_gethostent_r (struct hostent *host, char *buffer, return NSS_STATUS_SUCCESS; } + enum nss_status _nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen, int *errnop, int *h_errnop) @@ -233,6 +241,7 @@ _nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen, return status; } + static enum nss_status internal_gethostbyname2_r (const char *name, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, @@ -323,16 +332,24 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, return NSS_STATUS_SUCCESS; } + enum nss_status _nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, int *h_errnop) { + if (af != AF_INET && af != AF_INET6) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop, h_errnop, ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)); } + enum nss_status _nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer, size_t buflen, int *errnop, int *h_errnop) @@ -351,6 +368,7 @@ _nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer, errnop, h_errnop, 0); } + enum nss_status _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, struct hostent *host, char *buffer, size_t buflen, @@ -430,13 +448,93 @@ _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, return NSS_STATUS_SUCCESS; } -#if 0 + enum nss_status -_nss_nis_getipnodebyname_r (const char *name, int af, int flags, - struct hostent *result, char *buffer, - size_t buflen, int *errnop, int *herrnop) +_nss_nis_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) { - return internal_gethostbyname2_r (name, af, result, buffer, buflen, - errnop, herrnop, flags); + char *domain; + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + char name2[namlen + 1]; + size_t i; + + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; + + char *result; + int len; + int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len); + + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + { + *herrnop = TRY_AGAIN; + *errnop = errno; + } + if (retval == NSS_STATUS_NOTFOUND) + *herrnop = HOST_NOT_FOUND; + return retval; + } + + struct parser_data data; + struct hostent host; + int parse_res = parse_line (result, &host, &data, buflen, errnop, AF_UNSPEC, + 0); + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) + { + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + else + { + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + } + + if (*pat == NULL) + { + uintptr_t pad = (-(uintptr_t) buffer + % __alignof__ (struct gaih_addrtuple)); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple), 0)) + { + erange: + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + + *pat = (struct gaih_addrtuple *) buffer; + buffer += sizeof (struct gaih_addrtuple); + buflen -= sizeof (struct gaih_addrtuple); + } + + (*pat)->next = NULL; + size_t h_name_len = strlen (host.h_name); + if (h_name_len >= buflen) + goto erange; + (*pat)->name = memcpy (buffer, host.h_name, h_name_len + 1); + (*pat)->family = host.h_addrtype; + memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length); + (*pat)->scopeid = 0; + assert (host.h_addr_list[1] == NULL); + + free (result); + + return NSS_STATUS_SUCCESS; } -#endif diff --git a/nis/nss_nisplus/nisplus-hosts.c b/nis/nss_nisplus/nisplus-hosts.c index f5f0ac96da..37d44773fc 100644 --- a/nis/nss_nisplus/nisplus-hosts.c +++ b/nis/nss_nisplus/nisplus-hosts.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1997-2002, 2003, 2005, 2006 Free Software Foundation, Inc. +/* Copyright (C) 1997-2003, 2005, 2006, 2008 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk , 1997. @@ -17,6 +17,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include #include #include #include @@ -58,15 +59,15 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, if (result == NULL) return 0; - if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) || - __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ || - strcmp(NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0 || - NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4) + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0 + || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4) return 0; char *data = first_unused; - if (room_left < (af == AF_INET6 || (flags & AI_V4MAPPED) != 0 + if (room_left < (af != AF_INET || (flags & AI_V4MAPPED) != 0 ? IN6ADDRSZ : INADDRSZ)) { no_more_room: @@ -75,8 +76,10 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, } /* Parse address. */ - if (af == AF_INET && inet_pton (af, NISENTRYVAL (0, 2, result), data) > 0) + if (af != AF_INET6 + && inet_pton (AF_INET, NISENTRYVAL (0, 2, result), data) > 0) { + assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC); if (flags & AI_V4MAPPED) { map_v4v6_address (data, data); @@ -89,7 +92,7 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, host->h_length = INADDRSZ; } } - else if (af == AF_INET6 + else if (af != AF_INET && inet_pton (AF_INET6, NISENTRYVAL (0, 2, result), data) > 0) { host->h_addrtype = AF_INET6; @@ -109,27 +112,33 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, first_unused = __stpncpy (first_unused, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result)); *first_unused++ = '\0'; - room_left -= NISENTRYLEN (0, 0, result) + 1; - /* XXX Rewrite at some point to allocate the array first and then - copy the strings. It wasteful to first concatenate the strings - to just split them again later. */ + room_left -= NISENTRYLEN (0, 0, result) + 1; char *line = first_unused; - for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) + + /* When this is a call to gethostbyname4_r we do not need the aliases. */ + if (af != AF_UNSPEC) { - if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0) + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It is wasteful to first concatenate the strings + to just split them again later. */ + for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) { - if (NISENTRYLEN (i, 1, result) + 2 > room_left) - goto no_more_room; - - *first_unused++ = ' '; - first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), - NISENTRYLEN (i, 1, result)); - *first_unused = '\0'; - room_left -= NISENTRYLEN (i, 1, result) + 1; + if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0) + { + if (NISENTRYLEN (i, 1, result) + 2 > room_left) + goto no_more_room; + + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, + NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + *first_unused = '\0'; + room_left -= NISENTRYLEN (i, 1, result) + 1; + } } + *first_unused++ = '\0'; } - *first_unused++ = '\0'; /* Adjust the pointer so it is aligned for storing pointers. */ @@ -147,30 +156,34 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, host->h_addr_list[1] = NULL; host->h_aliases = &host->h_addr_list[2]; - i = 0; - while (*line != '\0') + /* When this is a call to gethostbyname4_r we do not need the aliases. */ + if (af != AF_UNSPEC) { - /* Skip leading blanks. */ - while (isspace (*line)) - ++line; + i = 0; + while (*line != '\0') + { + /* Skip leading blanks. */ + while (isspace (*line)) + ++line; - if (*line == '\0') - break; + if (*line == '\0') + break; - if (room_left < sizeof (char *)) - goto no_more_room; + if (room_left < sizeof (char *)) + goto no_more_room; - room_left -= sizeof (char *); - host->h_aliases[i++] = line; + room_left -= sizeof (char *); + host->h_aliases[i++] = line; - while (*line != '\0' && *line != ' ') - ++line; + while (*line != '\0' && *line != ' ') + ++line; - if (*line == ' ') - *line++ = '\0'; - } + if (*line == ' ') + *line++ = '\0'; + } - host->h_aliases[i] = NULL; + host->h_aliases[i] = NULL; + } return 1; } @@ -204,6 +217,7 @@ _nss_create_tablename (int *errnop) return NSS_STATUS_SUCCESS; } + enum nss_status _nss_nisplus_sethostent (int stayopen) { @@ -226,6 +240,7 @@ _nss_nisplus_sethostent (int stayopen) return status; } + enum nss_status _nss_nisplus_endhostent (void) { @@ -242,6 +257,7 @@ _nss_nisplus_endhostent (void) return NSS_STATUS_SUCCESS; } + static enum nss_status internal_nisplus_gethostent_r (struct hostent *host, char *buffer, size_t buflen, int *errnop, int *herrnop) @@ -329,6 +345,7 @@ internal_nisplus_gethostent_r (struct hostent *host, char *buffer, return NSS_STATUS_SUCCESS; } + enum nss_status _nss_nisplus_gethostent_r (struct hostent *result, char *buffer, size_t buflen, int *errnop, int *herrnop) @@ -345,26 +362,33 @@ _nss_nisplus_gethostent_r (struct hostent *result, char *buffer, return status; } + +static enum nss_status +get_tablename (int *herrnop) +{ + __libc_lock_lock (lock); + + enum nss_status status = _nss_create_tablename (herrnop); + + __libc_lock_unlock (lock); + + if (status != NSS_STATUS_SUCCESS) + *herrnop = NETDB_INTERNAL; + + return status; +} + + static enum nss_status internal_gethostbyname2_r (const char *name, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, int *herrnop, int flags) { - int parse_res, retval; - if (tablename_val == NULL) { - __libc_lock_lock (lock); - - enum nss_status status = _nss_create_tablename (errnop); - - __libc_lock_unlock (lock); - + enum nss_status status = get_tablename (herrnop); if (status != NSS_STATUS_SUCCESS) - { - *herrnop = NETDB_INTERNAL; - return NSS_STATUS_UNAVAIL; - } + return status; } if (name == NULL) @@ -374,39 +398,36 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, return NSS_STATUS_NOTFOUND; } - nis_result *result; char buf[strlen (name) + 10 + tablename_len]; int olderr = errno; /* Search at first in the alias list, and use the correct name for the next search. */ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); if (result != NULL) { - char *bufptr = buf; - /* If we did not find it, try it as original name. But if the database is correct, we should find it in the first case, too. */ - if ((result->status != NIS_SUCCESS - && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val->EN_data.en_type, - "hosts_tbl") != 0 - || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) - snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); - else + char *bufptr = buf; + size_t buflen = sizeof (buf); + + if ((result->status == NIS_SUCCESS || result->status == NIS_S_SUCCESS) + && __type_of (result->objects.objects_val) == NIS_ENTRY_OBJ + && strcmp (result->objects.objects_val->EN_data.en_type, + "hosts_tbl") == 0 + && result->objects.objects_val->EN_data.en_cols.en_cols_len >= 3) { /* We need to allocate a new buffer since there is no - guarantee the returned name has a length limit. */ - const char *entryval = NISENTRYVAL(0, 0, result); - size_t buflen = strlen (entryval) + 10 + tablename_len; + guarantee the returned alias name has a length limit. */ + name = NISENTRYVAL(0, 0, result); + size_t buflen = strlen (name) + 10 + tablename_len; bufptr = alloca (buflen); - snprintf (bufptr, buflen, "[cname=%s],%s", - entryval, tablename_val); } + snprintf (bufptr, buflen, "[cname=%s],%s", name, tablename_val); + nis_freeresult (result); result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); } @@ -417,7 +438,7 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, return NSS_STATUS_TRYAGAIN; } - retval = niserr2nss (result->status); + int retval = niserr2nss (result->status); if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0)) { if (retval == NSS_STATUS_TRYAGAIN) @@ -431,8 +452,8 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, return retval; } - parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer, - buflen, errnop, flags); + int parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer, + buflen, errnop, flags); nis_freeresult (result); @@ -450,16 +471,24 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, return NSS_STATUS_NOTFOUND; } + enum nss_status _nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, int *herrnop) { + if (af != AF_INET && af != AF_INET6) + { + *herrnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop, herrnop, ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)); } + enum nss_status _nss_nisplus_gethostbyname_r (const char *name, struct hostent *host, char *buffer, size_t buflen, int *errnop, @@ -480,6 +509,7 @@ _nss_nisplus_gethostbyname_r (const char *name, struct hostent *host, buflen, errnop, h_errnop, 0); } + enum nss_status _nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, struct hostent *host, char *buffer, @@ -487,12 +517,7 @@ _nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, { if (tablename_val == NULL) { - __libc_lock_lock (lock); - - enum nss_status status = _nss_create_tablename (errnop); - - __libc_lock_unlock (lock); - + enum nss_status status = get_tablename (herrnop); if (status != NSS_STATUS_SUCCESS) return status; } @@ -547,3 +572,44 @@ _nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, __set_errno (olderr); return NSS_STATUS_NOTFOUND; } + + +enum nss_status +_nss_nisplus_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp) +{ + struct hostent host; + + enum nss_status status = internal_gethostbyname2_r (name, AF_UNSPEC, &host, + buffer, buflen, + errnop, herrnop, 0); + if (__builtin_expect (status == NSS_STATUS_SUCCESS, 1)) + { + if (*pat == NULL) + { + uintptr_t pad = (-(uintptr_t) buffer + % __alignof__ (struct gaih_addrtuple)); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple), 0)) + { + free (result); + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + return NSS_STATUS_TRYAGAIN; + } + } + + (*pat)->next = NULL; + (*pat)->name = host.h_name; + (*pat)->family = host.h_addrtype; + + memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length); + (*pat)->scopeid = 0; + assert (host.h_addr_list[1] == NULL); + } + + return status; +} -- cgit 1.4.1