You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
555 lines
19 KiB
555 lines
19 KiB
commit 5a4c6d53f50b264d60cf6453576ca2810c7890b7 |
|
Author: Siddhesh Poyarekar <siddhesh@redhat.com> |
|
Date: Thu Nov 28 17:18:12 2013 +0530 |
|
|
|
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. |
|
|
|
diff --git glibc-2.17-c758a686/nss/Versions glibc-2.17-c758a686/nss/Versions |
|
index d13d570..f8ababc 100644 |
|
--- glibc-2.17-c758a686/nss/Versions |
|
+++ glibc-2.17-c758a686/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 glibc-2.17-c758a686/nss/nss_files/files-hosts.c glibc-2.17-c758a686/nss/nss_files/files-hosts.c |
|
index 6db2535..957c9aa 100644 |
|
--- glibc-2.17-c758a686/nss/nss_files/files-hosts.c |
|
+++ glibc-2.17-c758a686/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,
|
|
|