about summary refs log tree commit diff
path: root/resolv/resolv_conf.c
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2017-07-01 00:53:05 +0200
committerFlorian Weimer <fweimer@redhat.com>2017-07-03 21:01:42 +0200
commit3f853f22c87f0b671c0366eb290919719fa56c0e (patch)
tree23f8835838728d4be3efca524754c1a2f5bb0396 /resolv/resolv_conf.c
parentf30a54b21b83f254533c59ca72ad17af5249c6be (diff)
downloadglibc-3f853f22c87f0b671c0366eb290919719fa56c0e.tar.gz
glibc-3f853f22c87f0b671c0366eb290919719fa56c0e.tar.xz
glibc-3f853f22c87f0b671c0366eb290919719fa56c0e.zip
resolv: Lift domain search list limits [BZ #19569] [BZ #21475]
This change uses the extended resolver state in struct resolv_conf to
store the search list.  If applications have not patched the _res
object directly, this extended search list will be used by the stub
resolver during name resolution.
Diffstat (limited to 'resolv/resolv_conf.c')
-rw-r--r--resolv/resolv_conf.c65
1 files changed, 64 insertions, 1 deletions
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index cabe69cf1b..76d55fc32c 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -133,6 +133,34 @@ static bool
 resolv_conf_matches (const struct __res_state *resp,
                      const struct resolv_conf *conf)
 {
+  /* Check that the search list in *RESP has not been modified by the
+     application.  */
+  {
+    if (!(resp->dnsrch[0] == resp->defdname
+          && resp->dnsrch[MAXDNSRCH] == NULL))
+      return false;
+    size_t search_list_size = 0;
+    for (size_t i = 0; i < conf->search_list_size; ++i)
+      {
+        if (resp->dnsrch[i] != NULL)
+          {
+            search_list_size += strlen (resp->dnsrch[i]) + 1;
+            if (strcmp (resp->dnsrch[i], conf->search_list[i]) != 0)
+              return false;
+          }
+        else
+          {
+            /* resp->dnsrch is truncated if the number of elements
+               exceeds MAXDNSRCH, or if the combined storage space for
+               the search list exceeds what can be stored in
+               resp->defdname.  */
+            if (i == MAXDNSRCH || search_list_size > sizeof (resp->dnsrch))
+              break;
+            /* Otherwise, a mismatch indicates a match failure.  */
+            return false;
+          }
+      }
+  }
   return true;
 }
 
@@ -162,10 +190,17 @@ __resolv_conf_put (struct resolv_conf *conf)
 struct resolv_conf *
 __resolv_conf_allocate (const struct resolv_conf *init)
 {
+  /* Space needed by the strings.  */
+  size_t string_space = 0;
+  for (size_t i = 0; i < init->search_list_size; ++i)
+    string_space += strlen (init->search_list[i]) + 1;
+
   /* Allocate the buffer.  */
   void *ptr;
   struct alloc_buffer buffer = alloc_buffer_allocate
-    (sizeof (struct resolv_conf),
+    (sizeof (struct resolv_conf)
+     + init->search_list_size * sizeof (init->search_list[0])
+     + string_space,
      &ptr);
   struct resolv_conf *conf
     = alloc_buffer_alloc (&buffer, struct resolv_conf);
@@ -178,6 +213,16 @@ __resolv_conf_allocate (const struct resolv_conf *init)
   conf->__refcount = 1;
   conf->initstamp = __res_initstamp;
 
+  /* Allocate and fill the search list array.  */
+  {
+    conf->search_list_size = init->search_list_size;
+    const char **array = alloc_buffer_alloc_array
+      (&buffer, const char *, init->search_list_size);
+    conf->search_list = array;
+    for (size_t i = 0; i < init->search_list_size; ++i)
+      array[i] = alloc_buffer_copy_string (&buffer, init->search_list[i]);
+  }
+
   assert (!alloc_buffer_has_failed (&buffer));
   return conf;
 }
@@ -186,6 +231,24 @@ __resolv_conf_allocate (const struct resolv_conf *init)
 static __attribute__ ((nonnull (1, 2), warn_unused_result)) bool
 update_from_conf (struct __res_state *resp, const struct resolv_conf *conf)
 {
+  /* Fill in the prefix of the search list.  It is truncated either at
+     MAXDNSRCH, or if reps->defdname has insufficient space.  */
+  {
+    struct alloc_buffer buffer
+      = alloc_buffer_create (resp->defdname, sizeof (resp->defdname));
+    size_t size = conf->search_list_size;
+    size_t i;
+    for (i = 0; i < size && i < MAXDNSRCH; ++i)
+      {
+        resp->dnsrch[i] = alloc_buffer_copy_string
+          (&buffer, conf->search_list[i]);
+        if (resp->dnsrch[i] == NULL)
+          /* No more space in resp->defdname.  Truncate.  */
+          break;
+      }
+    resp->dnsrch[i] = NULL;
+  }
+
   /* The overlapping parts of both configurations should agree after
      initialization.  */
   assert (resolv_conf_matches (resp, conf));