diff options
Diffstat (limited to 'nss')
-rw-r--r-- | nss/nss_files/files-hosts.c | 200 |
1 files changed, 188 insertions, 12 deletions
diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c index e73fee0b14..c96a39c38e 100644 --- a/nss/nss_files/files-hosts.c +++ b/nss/nss_files/files-hosts.c @@ -17,6 +17,7 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <assert.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> @@ -26,6 +27,7 @@ /* Get implementation for some internal functions. */ #include "../resolv/mapv4v6addr.h" +#include "../resolv/res_hconf.h" #define ENTNAME hostent @@ -74,25 +76,199 @@ 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) \ +{ \ + enum nss_status status; \ + \ + __libc_lock_lock (lock); \ + \ + /* Reset file pointer to beginning or open file. */ \ + 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. */ \ + const size_t tmp_buflen = MIN (buflen, 4096); \ + char tmp_buffer[tmp_buflen]; \ + struct hostent tmp_result_buf; \ + int naddrs = 1; \ + int naliases = 0; \ + char *bufferend; \ + \ + while (result->h_aliases[naliases] != NULL) \ + ++naliases; \ + \ + bufferend = (char *) &result->h_aliases[naliases + 1]; \ + \ + 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 users \ + problem. */ \ + if (strcmp (old_result->h_name, \ + tmp_result_buf.h_name) != 0) \ + { \ + ++newaliases; \ + newstrlen += strlen (tmp_result_buf.h_name) + 1; \ + } \ + \ + /* Now we can check whether the buffer is large enough. */ \ + if (bufferend + 16 + (naddrs + 2) * sizeof (char *) \ + + roundup (newstrlen, sizeof (char *)) \ + + (naliases + newaliases + 1) * sizeof (char *) \ + >= buffer + buflen) \ + { \ + *errnop = ERANGE; \ + status = NSS_STATUS_TRYAGAIN; \ + break; \ + } \ + \ + 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); \ + } \ + \ + 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 *))); \ + \ + /* 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); \ + } \ + } \ + \ + if (status != NSS_STATUS_TRYAGAIN) \ + status = NSS_STATUS_SUCCESS; \ + } \ + \ + \ + 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) -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) -DB_LOOKUP (hostbyname2, ,, - { - LOOKUP_NAME_CASE (h_name, h_aliases) - }, const char *name, int af) +HOST_DB_LOOKUP (hostbyname2, ,, + { + LOOKUP_NAME_CASE (h_name, h_aliases) + }, const char *name, int af) DB_LOOKUP (hostbyaddr, ,, { @@ -104,7 +280,7 @@ DB_LOOKUP (hostbyaddr, ,, #undef EXTRA_ARGS_VALUE #define EXTRA_ARGS_VALUE \ , af, flags -DB_LOOKUP (ipnodebyname, ,, - { - LOOKUP_NAME_CASE (h_name, h_aliases) - }, const char *name, int af, int flags) +HOST_DB_LOOKUP (ipnodebyname, ,, + { + LOOKUP_NAME_CASE (h_name, h_aliases) + }, const char *name, int af, int flags) |