krb5 commit: Add DNS URI query function

Greg Hudson ghudson at mit.edu
Mon Sep 19 12:31:09 EDT 2016


https://github.com/krb5/krb5/commit/f1c9394b9a7fc237a405943c8f4b0f5fac03be4b
commit f1c9394b9a7fc237a405943c8f4b0f5fac03be4b
Author: Matt Rogers <mrogers at redhat.com>
Date:   Mon Jul 18 10:18:45 2016 -0400

    Add DNS URI query function
    
    Add the k5_make_uri_query() function for finding URI records of a
    given realm and service tag.  Turn some common code shared with
    krb5int_make_srv_query_realm() into helper functions.
    
    ticket: 8496

 src/lib/krb5/os/dnsglue.h |    8 ++
 src/lib/krb5/os/dnssrv.c  |  166 +++++++++++++++++++++++++++++++-------------
 2 files changed, 125 insertions(+), 49 deletions(-)

diff --git a/src/lib/krb5/os/dnsglue.h b/src/lib/krb5/os/dnsglue.h
index 5ab0ad8..27147a6 100644
--- a/src/lib/krb5/os/dnsglue.h
+++ b/src/lib/krb5/os/dnsglue.h
@@ -120,6 +120,10 @@
 
 #endif /* HAVE_RES_NSEARCH */
 
+#ifndef T_URI
+#define T_URI 256
+#endif
+
 /*
  * INCR_OK
  *
@@ -169,5 +173,9 @@ krb5_error_code krb5int_make_srv_query_realm(const krb5_data *realm,
                                              struct srv_dns_entry **answers);
 void krb5int_free_srv_dns_data(struct srv_dns_entry *);
 
+krb5_error_code
+k5_make_uri_query(const krb5_data *realm, const char *service,
+                  struct srv_dns_entry **answers);
+
 #endif /* KRB5_DNS_LOOKUP */
 #endif /* !defined(KRB5_DNSGLUE_H) */
diff --git a/src/lib/krb5/os/dnssrv.c b/src/lib/krb5/os/dnssrv.c
index c41b0d8..0955728 100644
--- a/src/lib/krb5/os/dnssrv.c
+++ b/src/lib/krb5/os/dnssrv.c
@@ -45,6 +45,118 @@ krb5int_free_srv_dns_data (struct srv_dns_entry *p)
     }
 }
 
+/* Construct a DNS label of the form "service.[protocol.]realm.", placing the
+ * result into fixed_buf.  protocol may be NULL. */
+static krb5_error_code
+prepare_lookup_buf(const krb5_data *realm, const char *service,
+                   const char *protocol, char *fixed_buf, size_t bufsize)
+{
+    struct k5buf buf;
+
+    if (memchr(realm->data, 0, realm->length))
+        return EINVAL;
+
+    k5_buf_init_fixed(&buf, fixed_buf, bufsize);
+    k5_buf_add_fmt(&buf, "%s.", service);
+    if (protocol != NULL)
+        k5_buf_add_fmt(&buf, "%s.", protocol);
+    k5_buf_add_len(&buf, realm->data, realm->length);
+
+    /*
+     * Realm names don't (normally) end with ".", but if the query doesn't end
+     * with "." and doesn't get an answer as is, the resolv code will try
+     * appending the local domain.  Since the realm names are absolutes, let's
+     * stop that.
+     */
+
+    if (buf.len > 0 && ((char *)buf.data)[buf.len - 1] != '.')
+        k5_buf_add(&buf, ".");
+
+    return k5_buf_status(&buf);
+}
+
+/* Insert new into the list *head, ordering by priority.  Weight is not
+ * currently used. */
+static void
+place_srv_entry(struct srv_dns_entry **head, struct srv_dns_entry *new)
+{
+    struct srv_dns_entry *entry;
+
+    if (*head == NULL || (*head)->priority > new->priority) {
+        new->next = *head;
+        *head = new;
+        return;
+    }
+
+    for (entry = *head; entry != NULL; entry = entry->next) {
+        /*
+         * Insert an entry into the next spot if there is no next entry (we're
+         * at the end), or if the next entry has a higher priority (lower
+         * priorities are preferred).
+         */
+        if (entry->next == NULL || entry->next->priority > new->priority) {
+            new->next = entry->next;
+            entry->next = new;
+            break;
+        }
+    }
+}
+
+/* Query the URI RR, collecting weight, priority, and target. */
+krb5_error_code
+k5_make_uri_query(const krb5_data *realm, const char *service,
+                  struct srv_dns_entry **answers)
+{
+    const unsigned char *p = NULL, *base = NULL;
+    char host[MAXDNAME];
+    int size, ret, rdlen;
+    unsigned short priority, weight;
+    struct krb5int_dns_state *ds = NULL;
+    struct srv_dns_entry *head = NULL, *uri = NULL;
+
+    *answers = NULL;
+
+    /* Construct service.realm. */
+    ret = prepare_lookup_buf(realm, service, NULL, host, sizeof(host));
+    if (ret)
+        return 0;
+
+    size = krb5int_dns_init(&ds, host, C_IN, T_URI);
+    if (size < 0)
+        goto out;
+
+    for (;;) {
+        ret = krb5int_dns_nextans(ds, &base, &rdlen);
+        if (ret < 0 || base == NULL)
+            goto out;
+
+        p = base;
+
+        SAFE_GETUINT16(base, rdlen, p, 2, priority, out);
+        SAFE_GETUINT16(base, rdlen, p, 2, weight, out);
+
+        uri = k5alloc(sizeof(*uri), &ret);
+        if (uri == NULL)
+            goto out;
+
+        uri->priority = priority;
+        uri->weight = weight;
+        /* rdlen - 4 bytes remain after the priority and weight. */
+        uri->host = k5memdup0(p, rdlen - 4, &ret);
+        if (uri->host == NULL) {
+            ret = errno;
+            goto out;
+        }
+
+        place_srv_entry(&head, uri);
+    }
+
+out:
+    krb5int_dns_fini(ds);
+    *answers = head;
+    return 0;
+}
+
 /* Do DNS SRV query, return results in *answers.
 
    Make best effort to return all the data we can.  On memory or
@@ -62,10 +174,7 @@ krb5int_make_srv_query_realm(const krb5_data *realm,
     int size, ret, rdlen, nlen;
     unsigned short priority, weight, port;
     struct krb5int_dns_state *ds = NULL;
-    struct k5buf buf;
-
-    struct srv_dns_entry *head = NULL;
-    struct srv_dns_entry *srv = NULL, *entry = NULL;
+    struct srv_dns_entry *head = NULL, *srv = NULL;
 
     /*
      * First off, build a query of the form:
@@ -78,25 +187,8 @@ krb5int_make_srv_query_realm(const krb5_data *realm,
      *
      */
 
-    if (memchr(realm->data, 0, realm->length))
-        return 0;
-    k5_buf_init_fixed(&buf, host, sizeof(host));
-    k5_buf_add_fmt(&buf, "%s.%s.", service, protocol);
-    k5_buf_add_len(&buf, realm->data, realm->length);
-
-    /* Realm names don't (normally) end with ".", but if the query
-       doesn't end with "." and doesn't get an answer as is, the
-       resolv code will try appending the local domain.  Since the
-       realm names are absolutes, let's stop that.
-
-       But only if a name has been specified.  If we are performing
-       a search on the prefix alone then the intention is to allow
-       the local domain or domain search lists to be expanded.  */
-
-    if (buf.len > 0 && host[buf.len - 1] != '.')
-        k5_buf_add(&buf, ".");
-
-    if (k5_buf_status(&buf) != 0)
+    ret = prepare_lookup_buf(realm, service, protocol, host, sizeof(host));
+    if (ret)
         return 0;
 
 #ifdef TEST
@@ -146,35 +238,11 @@ krb5int_make_srv_query_realm(const krb5_data *realm,
             goto out;
         }
 
-        if (head == NULL || head->priority > srv->priority) {
-            srv->next = head;
-            head = srv;
-        } else {
-            /*
-             * This is confusing.  Only insert an entry into this
-             * spot if:
-             * The next person has a higher priority (lower priorities
-             * are preferred).
-             * Or
-             * There is no next entry (we're at the end)
-             */
-            for (entry = head; entry != NULL; entry = entry->next) {
-                if ((entry->next &&
-                     entry->next->priority > srv->priority) ||
-                    entry->next == NULL) {
-                    srv->next = entry->next;
-                    entry->next = srv;
-                    break;
-                }
-            }
-        }
+        place_srv_entry(&head, srv);
     }
 
 out:
-    if (ds != NULL) {
-        krb5int_dns_fini(ds);
-        ds = NULL;
-    }
+    krb5int_dns_fini(ds);
     *answers = head;
     return 0;
 }


More information about the cvs-krb5 mailing list