diff options
author | Siddhesh Poyarekar <siddhesh@redhat.com> | 2013-11-28 17:18:12 +0530 |
---|---|---|
committer | Siddhesh Poyarekar <siddhesh@redhat.com> | 2013-11-28 17:18:12 +0530 |
commit | 5a4c6d53f50b264d60cf6453576ca2810c7890b7 (patch) | |
tree | bdb73e524e4b77c297b766c5be1c6967fe332381 | |
parent | 897b98ba4dacb02edc3c8775f207a9c9a25fc1e4 (diff) | |
download | glibc-5a4c6d53f50b264d60cf6453576ca2810c7890b7.tar.gz glibc-5a4c6d53f50b264d60cf6453576ca2810c7890b7.tar.xz glibc-5a4c6d53f50b264d60cf6453576ca2810c7890b7.zip |
Get canonical name in getaddrinfo from hosts file for AF_INET (fixes 16077)
AF_INET lookup in hosts file uses _nss_files_gethostbyname2_r, which is not capable of returning a canonical name if it has found one. This change adds _nss_files_gethostbyname3_r, which wraps around _nss_files_gethostbyname2_r and then returns result.h_name as the canonical name.
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | nss/Versions | 1 | ||||
-rw-r--r-- | nss/nss_files/files-hosts.c | 507 |
4 files changed, 272 insertions, 252 deletions
diff --git a/ChangeLog b/ChangeLog index 4c4e8e8a2c..7e46a66919 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2013-11-28 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #16077] + * nss/Versions (libnss_files): Add + _nss_files_gethostbyname3_r. + * nss/nss_files/files-hosts.c (_nss_files_gethostbyname3_r): + New function. + (HOST_DB_LOOKUP): Remove macro. + (_nss_files_gethostbyname_r): Implement function without the + HOST_DB_LOOKUP macro. + (_nss_files_gethostbyname2_r): Likewise. + 2013-11-28 Ondřej Bílka <neleai@seznam.cz> * malloc/malloc.c (__libc_calloc): Make memset a tail call. diff --git a/NEWS b/NEWS index f4efb6a7c3..b45fa53165 100644 --- a/NEWS +++ b/NEWS @@ -18,8 +18,8 @@ Version 2.19 15856, 15857, 15859, 15867, 15886, 15887, 15890, 15892, 15893, 15895, 15897, 15905, 15909, 15917, 15919, 15921, 15923, 15939, 15948, 15963, 15966, 15985, 15988, 15997, 16032, 16034, 16036, 16037, 16041, 16055, - 16071, 16072, 16074, 16078, 16103, 16112, 16143, 16144, 16146, 16150, - 16151, 16153, 16167, 16172, 16245. + 16071, 16072, 16074, 16077, 16078, 16103, 16112, 16143, 16144, 16146, + 16150, 16151, 16153, 16167, 16172, 16245. * The public headers no longer use __unused nor __block. This change is to support compiling programs that are derived from BSD sources and use diff --git a/nss/Versions b/nss/Versions index d13d570079..f8ababccc7 100644 --- a/nss/Versions +++ b/nss/Versions @@ -40,6 +40,7 @@ libnss_files { _nss_files_endhostent; _nss_files_gethostbyaddr_r; _nss_files_gethostbyname2_r; + _nss_files_gethostbyname3_r; _nss_files_gethostbyname4_r; _nss_files_gethostbyname_r; _nss_files_gethostent_r; diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c index 6db2535159..957c9aa036 100644 --- a/nss/nss_files/files-hosts.c +++ b/nss/nss_files/files-hosts.c @@ -97,262 +97,12 @@ LINE_PARSER STRING_FIELD (result->h_name, isspace, 1); }) - - -#define HOST_DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \ -enum nss_status \ -_nss_files_get##name##_r (proto, \ - struct STRUCTURE *result, char *buffer, \ - size_t buflen, int *errnop H_ERRNO_PROTO) \ -{ \ - uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data); \ - buffer += pad; \ - buflen = buflen > pad ? buflen - pad : 0; \ - \ - __libc_lock_lock (lock); \ - \ - /* Reset file pointer to beginning or open file. */ \ - enum nss_status status = internal_setent (keep_stream); \ - \ - if (status == NSS_STATUS_SUCCESS) \ - { \ - /* Tell getent function that we have repositioned the file pointer. */ \ - last_use = getby; \ - \ - while ((status = internal_getent (result, buffer, buflen, errnop \ - H_ERRNO_ARG EXTRA_ARGS_VALUE)) \ - == NSS_STATUS_SUCCESS) \ - { break_if_match } \ - \ - if (status == NSS_STATUS_SUCCESS \ - && _res_hconf.flags & HCONF_FLAG_MULTI) \ - { \ - /* We have to get all host entries from the file. */ \ - size_t tmp_buflen = MIN (buflen, 4096); \ - char tmp_buffer_stack[tmp_buflen] \ - __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));\ - char *tmp_buffer = tmp_buffer_stack; \ - struct hostent tmp_result_buf; \ - int naddrs = 1; \ - int naliases = 0; \ - char *bufferend; \ - bool tmp_buffer_malloced = false; \ - \ - while (result->h_aliases[naliases] != NULL) \ - ++naliases; \ - \ - bufferend = (char *) &result->h_aliases[naliases + 1]; \ - \ - again: \ - while ((status = internal_getent (&tmp_result_buf, tmp_buffer, \ - tmp_buflen, errnop H_ERRNO_ARG \ - EXTRA_ARGS_VALUE)) \ - == NSS_STATUS_SUCCESS) \ - { \ - int matches = 1; \ - struct hostent *old_result = result; \ - result = &tmp_result_buf; \ - /* The following piece is a bit clumsy but we want to use the \ - `break_if_match' value. The optimizer should do its \ - job. */ \ - do \ - { \ - break_if_match \ - result = old_result; \ - } \ - while ((matches = 0)); \ - \ - if (matches) \ - { \ - /* We could be very clever and try to recycle a few bytes \ - in the buffer instead of generating new arrays. But \ - we are not doing this here since it's more work than \ - it's worth. Simply let the user provide a bit bigger \ - buffer. */ \ - char **new_h_addr_list; \ - char **new_h_aliases; \ - int newaliases = 0; \ - size_t newstrlen = 0; \ - int cnt; \ - \ - /* Count the new aliases and the length of the strings. */ \ - while (tmp_result_buf.h_aliases[newaliases] != NULL) \ - { \ - char *cp = tmp_result_buf.h_aliases[newaliases]; \ - ++newaliases; \ - newstrlen += strlen (cp) + 1; \ - } \ - /* If the real name is different add it also to the \ - aliases. This means that there is a duplication \ - in the alias list but this is really the user's \ - problem. */ \ - if (strcmp (old_result->h_name, \ - tmp_result_buf.h_name) != 0) \ - { \ - ++newaliases; \ - newstrlen += strlen (tmp_result_buf.h_name) + 1; \ - } \ - \ - /* Make sure bufferend is aligned. */ \ - assert ((bufferend - (char *) 0) % sizeof (char *) == 0); \ - \ - /* Now we can check whether the buffer is large enough. \ - 16 is the maximal size of the IP address. */ \ - if (bufferend + 16 + (naddrs + 2) * sizeof (char *) \ - + roundup (newstrlen, sizeof (char *)) \ - + (naliases + newaliases + 1) * sizeof (char *) \ - >= buffer + buflen) \ - { \ - *errnop = ERANGE; \ - *herrnop = NETDB_INTERNAL; \ - status = NSS_STATUS_TRYAGAIN; \ - goto out; \ - } \ - \ - new_h_addr_list = \ - (char **) (bufferend \ - + roundup (newstrlen, sizeof (char *)) \ - + 16); \ - new_h_aliases = \ - (char **) ((char *) new_h_addr_list \ - + (naddrs + 2) * sizeof (char *)); \ - \ - /* Copy the old data in the new arrays. */ \ - for (cnt = 0; cnt < naddrs; ++cnt) \ - new_h_addr_list[cnt] = old_result->h_addr_list[cnt]; \ - \ - for (cnt = 0; cnt < naliases; ++cnt) \ - new_h_aliases[cnt] = old_result->h_aliases[cnt]; \ - \ - /* Store the new strings. */ \ - cnt = 0; \ - while (tmp_result_buf.h_aliases[cnt] != NULL) \ - { \ - new_h_aliases[naliases++] = bufferend; \ - bufferend = (__stpcpy (bufferend, \ - tmp_result_buf.h_aliases[cnt]) \ - + 1); \ - ++cnt; \ - } \ - \ - if (cnt < newaliases) \ - { \ - new_h_aliases[naliases++] = bufferend; \ - bufferend = __stpcpy (bufferend, \ - tmp_result_buf.h_name) + 1; \ - } \ - \ - /* Final NULL pointer. */ \ - new_h_aliases[naliases] = NULL; \ - \ - /* Round up the buffer end address. */ \ - bufferend += (sizeof (char *) \ - - ((bufferend - (char *) 0) \ - % sizeof (char *))) % sizeof (char *); \ - \ - /* Now the new address. */ \ - new_h_addr_list[naddrs++] = \ - memcpy (bufferend, tmp_result_buf.h_addr, \ - tmp_result_buf.h_length); \ - \ - /* Also here a final NULL pointer. */ \ - new_h_addr_list[naddrs] = NULL; \ - \ - /* Store the new array pointers. */ \ - old_result->h_aliases = new_h_aliases; \ - old_result->h_addr_list = new_h_addr_list; \ - \ - /* Compute the new buffer end. */ \ - bufferend = (char *) &new_h_aliases[naliases + 1]; \ - assert (bufferend <= buffer + buflen); \ - \ - result = old_result; \ - } \ - } \ - \ - if (status == NSS_STATUS_TRYAGAIN) \ - { \ - size_t newsize = 2 * tmp_buflen; \ - if (tmp_buffer_malloced) \ - { \ - char *newp = realloc (tmp_buffer, newsize); \ - if (newp != NULL) \ - { \ - assert ((((uintptr_t) newp) \ - & (__alignof__ (struct hostent_data) - 1)) \ - == 0); \ - tmp_buffer = newp; \ - tmp_buflen = newsize; \ - goto again; \ - } \ - } \ - else if (!__libc_use_alloca (buflen + newsize)) \ - { \ - tmp_buffer = malloc (newsize); \ - if (tmp_buffer != NULL) \ - { \ - assert ((((uintptr_t) tmp_buffer) \ - & (__alignof__ (struct hostent_data) - 1)) \ - == 0); \ - tmp_buffer_malloced = true; \ - tmp_buflen = newsize; \ - goto again; \ - } \ - } \ - else \ - { \ - tmp_buffer \ - = extend_alloca (tmp_buffer, tmp_buflen, \ - newsize \ - + __alignof__ (struct hostent_data)); \ - tmp_buffer = (char *) (((uintptr_t) tmp_buffer \ - + __alignof__ (struct hostent_data) \ - - 1) \ - & ~(__alignof__ (struct hostent_data)\ - - 1)); \ - goto again; \ - } \ - } \ - else \ - status = NSS_STATUS_SUCCESS; \ - out: \ - if (tmp_buffer_malloced) \ - free (tmp_buffer); \ - } \ - \ - \ - if (! keep_stream) \ - internal_endent (); \ - } \ - \ - __libc_lock_unlock (lock); \ - \ - return status; \ -} - - #define EXTRA_ARGS_VALUE \ , ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET), \ ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0) #include "files-XXX.c" -HOST_DB_LOOKUP (hostbyname, ,, - { - LOOKUP_NAME_CASE (h_name, h_aliases) - }, const char *name) #undef EXTRA_ARGS_VALUE - -/* XXX Is using _res to determine whether we want to convert IPv4 addresses - to IPv6 addresses really the right thing to do? */ -#define EXTRA_ARGS_VALUE \ - , af, ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0) -HOST_DB_LOOKUP (hostbyname2, ,, - { - LOOKUP_NAME_CASE (h_name, h_aliases) - }, const char *name, int af) -#undef EXTRA_ARGS_VALUE - - /* We only need to consider IPv4 mapped addresses if the input to the gethostbyaddr() function is an IPv6 address. */ #define EXTRA_ARGS_VALUE \ @@ -365,6 +115,263 @@ DB_LOOKUP (hostbyaddr, ,,, }, const void *addr, socklen_t len, int af) #undef EXTRA_ARGS_VALUE +enum nss_status +_nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop, int32_t *ttlp, char **canonp) +{ + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data); + buffer += pad; + buflen = buflen > pad ? buflen - pad : 0; + + __libc_lock_lock (lock); + + /* Reset file pointer to beginning or open file. */ + enum nss_status status = internal_setent (keep_stream); + + if (status == NSS_STATUS_SUCCESS) + { + /* XXX Is using _res to determine whether we want to convert IPv4 + addresses to IPv6 addresses really the right thing to do? */ + int flags = ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0); + + /* Tell getent function that we have repositioned the file pointer. */ + last_use = getby; + + while ((status = internal_getent (result, buffer, buflen, errnop, + herrnop, af, flags)) + == NSS_STATUS_SUCCESS) + { + LOOKUP_NAME_CASE (h_name, h_aliases) + } + + if (status == NSS_STATUS_SUCCESS + && _res_hconf.flags & HCONF_FLAG_MULTI) + { + /* We have to get all host entries from the file. */ + size_t tmp_buflen = MIN (buflen, 4096); + char tmp_buffer_stack[tmp_buflen] + __attribute__ ((__aligned__ (__alignof__ (struct hostent_data)))); + char *tmp_buffer = tmp_buffer_stack; + struct hostent tmp_result_buf; + int naddrs = 1; + int naliases = 0; + char *bufferend; + bool tmp_buffer_malloced = false; + + while (result->h_aliases[naliases] != NULL) + ++naliases; + + bufferend = (char *) &result->h_aliases[naliases + 1]; + + again: + while ((status = internal_getent (&tmp_result_buf, tmp_buffer, + tmp_buflen, errnop, herrnop, af, + flags)) + == NSS_STATUS_SUCCESS) + { + int matches = 1; + struct hostent *old_result = result; + result = &tmp_result_buf; + /* The following piece is a bit clumsy but we want to use the + `LOOKUP_NAME_CASE' value. The optimizer should do its + job. */ + do + { + LOOKUP_NAME_CASE (h_name, h_aliases) + result = old_result; + } + while ((matches = 0)); + + if (matches) + { + /* We could be very clever and try to recycle a few bytes + in the buffer instead of generating new arrays. But + we are not doing this here since it's more work than + it's worth. Simply let the user provide a bit bigger + buffer. */ + char **new_h_addr_list; + char **new_h_aliases; + int newaliases = 0; + size_t newstrlen = 0; + int cnt; + + /* Count the new aliases and the length of the strings. */ + while (tmp_result_buf.h_aliases[newaliases] != NULL) + { + char *cp = tmp_result_buf.h_aliases[newaliases]; + ++newaliases; + newstrlen += strlen (cp) + 1; + } + /* If the real name is different add it also to the + aliases. This means that there is a duplication + in the alias list but this is really the user's + problem. */ + if (strcmp (old_result->h_name, + tmp_result_buf.h_name) != 0) + { + ++newaliases; + newstrlen += strlen (tmp_result_buf.h_name) + 1; + } + + /* Make sure bufferend is aligned. */ + assert ((bufferend - (char *) 0) % sizeof (char *) == 0); + + /* Now we can check whether the buffer is large enough. + 16 is the maximal size of the IP address. */ + if (bufferend + 16 + (naddrs + 2) * sizeof (char *) + + roundup (newstrlen, sizeof (char *)) + + (naliases + newaliases + 1) * sizeof (char *) + >= buffer + buflen) + { + *errnop = ERANGE; + *herrnop = NETDB_INTERNAL; + status = NSS_STATUS_TRYAGAIN; + goto out; + } + + new_h_addr_list = + (char **) (bufferend + + roundup (newstrlen, sizeof (char *)) + + 16); + new_h_aliases = + (char **) ((char *) new_h_addr_list + + (naddrs + 2) * sizeof (char *)); + + /* Copy the old data in the new arrays. */ + for (cnt = 0; cnt < naddrs; ++cnt) + new_h_addr_list[cnt] = old_result->h_addr_list[cnt]; + + for (cnt = 0; cnt < naliases; ++cnt) + new_h_aliases[cnt] = old_result->h_aliases[cnt]; + + /* Store the new strings. */ + cnt = 0; + while (tmp_result_buf.h_aliases[cnt] != NULL) + { + new_h_aliases[naliases++] = bufferend; + bufferend = (__stpcpy (bufferend, + tmp_result_buf.h_aliases[cnt]) + + 1); + ++cnt; + } + + if (cnt < newaliases) + { + new_h_aliases[naliases++] = bufferend; + bufferend = __stpcpy (bufferend, + tmp_result_buf.h_name) + 1; + } + + /* Final NULL pointer. */ + new_h_aliases[naliases] = NULL; + + /* Round up the buffer end address. */ + bufferend += (sizeof (char *) + - ((bufferend - (char *) 0) + % sizeof (char *))) % sizeof (char *); + + /* Now the new address. */ + new_h_addr_list[naddrs++] = + memcpy (bufferend, tmp_result_buf.h_addr, + tmp_result_buf.h_length); + + /* Also here a final NULL pointer. */ + new_h_addr_list[naddrs] = NULL; + + /* Store the new array pointers. */ + old_result->h_aliases = new_h_aliases; + old_result->h_addr_list = new_h_addr_list; + + /* Compute the new buffer end. */ + bufferend = (char *) &new_h_aliases[naliases + 1]; + assert (bufferend <= buffer + buflen); + + result = old_result; + } + } + + if (status == NSS_STATUS_TRYAGAIN) + { + size_t newsize = 2 * tmp_buflen; + if (tmp_buffer_malloced) + { + char *newp = realloc (tmp_buffer, newsize); + if (newp != NULL) + { + assert ((((uintptr_t) newp) + & (__alignof__ (struct hostent_data) - 1)) + == 0); + tmp_buffer = newp; + tmp_buflen = newsize; + goto again; + } + } + else if (!__libc_use_alloca (buflen + newsize)) + { + tmp_buffer = malloc (newsize); + if (tmp_buffer != NULL) + { + assert ((((uintptr_t) tmp_buffer) + & (__alignof__ (struct hostent_data) - 1)) + == 0); + tmp_buffer_malloced = true; + tmp_buflen = newsize; + goto again; + } + } + else + { + tmp_buffer + = extend_alloca (tmp_buffer, tmp_buflen, + newsize + + __alignof__ (struct hostent_data)); + tmp_buffer = (char *) (((uintptr_t) tmp_buffer + + __alignof__ (struct hostent_data) + - 1) + & ~(__alignof__ (struct hostent_data) + - 1)); + goto again; + } + } + else + status = NSS_STATUS_SUCCESS; + out: + if (tmp_buffer_malloced) + free (tmp_buffer); + } + + if (! keep_stream) + internal_endent (); + } + + if (canonp && status == NSS_STATUS_SUCCESS) + *canonp = result->h_name; + + __libc_lock_unlock (lock); + + return status; +} + +enum nss_status +_nss_files_gethostbyname_r (const char *name, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + int af = ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET); + + return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen, + errnop, herrnop, NULL, NULL); +} + +enum nss_status +_nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result, + char *buffer, size_t buflen, int *errnop, + int *herrnop) +{ + return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen, + errnop, herrnop, NULL, NULL); +} enum nss_status _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, |