krb5 commit: Enable KDC discovery through DNS URI records

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


https://github.com/krb5/krb5/commit/c75596d01e7c78d38d0889a1a77145269ac724b2
commit c75596d01e7c78d38d0889a1a77145269ac724b2
Author: Matt Rogers <mrogers at redhat.com>
Date:   Mon Jul 18 12:13:55 2016 -0400

    Enable KDC discovery through DNS URI records
    
    Add the dns_locate_server_uri(), locate_uri(), and parse_uri_fields()
    functions to find and process KDC service information from specially
    formatted URI records detailed at
    http://k5wiki.kerberos.org/wiki/Projects/KDC_Discovery
    
    Search for URI records before searching for SRV records.  Rename
    dns_locate_server() to dns_locate_server_srv() for consistency.  Add
    URI-specific information to the t_locate_kdc host entry output.
    
    ticket: 8496

 src/lib/krb5/os/locate_kdc.c   |  183 +++++++++++++++++++++++++++++++++++++++-
 src/lib/krb5/os/t_locate_kdc.c |    6 +-
 2 files changed, 183 insertions(+), 6 deletions(-)

diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
index 6ed8fa6..477f506 100644
--- a/src/lib/krb5/os/locate_kdc.c
+++ b/src/lib/krb5/os/locate_kdc.c
@@ -509,10 +509,179 @@ prof_locate_server(krb5_context context, const krb5_data *realm,
 }
 
 #ifdef KRB5_DNS_LOOKUP
+
+/*
+ * Parse the initial part of the URI, first confirming the scheme name.  Get
+ * the transport, flags (indicating master status), and host.  The host is
+ * either an address or hostname with an optional port, or an HTTPS URL.
+ * The format is krb5srv:flags:udp|tcp|kkdcp:host
+ *
+ * Return a NULL *host_out if there are any problems parsing the URI.
+ */
+static void
+parse_uri_fields(const char *uri, k5_transport *transport_out,
+                 const char **host_out, int *master_out)
+
+{
+    k5_transport transport;
+    int master = FALSE;
+
+    *transport_out = 0;
+    *host_out = NULL;
+    *master_out = -1;
+
+    /* Confirm the scheme name. */
+    if (strncasecmp(uri, "krb5srv", 7) != 0)
+        return;
+
+    uri += 7;
+    if (*uri != ':')
+        return;
+
+    uri++;
+    if (*uri == '\0')
+        return;
+
+    /* Check the flags field for supported flags. */
+    for (; *uri != ':' && *uri != '\0'; uri++) {
+        if (*uri == 'm' || *uri == 'M')
+            master = TRUE;
+    }
+    if (*uri != ':')
+        return;
+
+    /* Look for the transport type. */
+    uri++;
+    if (strncasecmp(uri, "udp", 3) == 0) {
+        transport = UDP;
+        uri += 3;
+    } else if (strncasecmp(uri, "tcp", 3) == 0) {
+        transport = TCP;
+        uri += 3;
+    } else if (strncasecmp(uri, "kkdcp", 5) == 0) {
+        /* Currently the only MS-KKDCP transport type is HTTPS. */
+        transport = HTTPS;
+        uri += 5;
+    } else {
+        return;
+    }
+
+    if (*uri != ':')
+        return;
+
+    /* The rest of the URI is the host (with optional port) or URI. */
+    *host_out = uri + 1;
+    *transport_out = transport;
+    *master_out = master;
+}
+
+/*
+ * Collect a list of servers from DNS URI records, for the requested service
+ * and transport type.  Problematic entries are skipped.
+ */
+static krb5_error_code
+locate_uri(const krb5_data *realm, const char *req_service,
+           struct serverlist *serverlist, k5_transport req_transport,
+           int default_port, krb5_boolean master_only)
+{
+    krb5_error_code ret;
+    k5_transport transport, host_trans;
+    struct srv_dns_entry *answers, *entry;
+    char *path, *host;
+    const char *host_field;
+    int port, def_port, master;
+
+    ret = k5_make_uri_query(realm, req_service, &answers);
+    if (ret || answers == NULL)
+        return ret;
+
+    for (entry = answers; entry != NULL; entry = entry->next) {
+        def_port = default_port;
+        path = NULL;
+
+        parse_uri_fields(entry->host, &transport, &host_field, &master);
+        if (host_field == NULL)
+            continue;
+
+        /* TCP_OR_UDP allows entries of any transport type; otherwise
+         * we're asking for a match. */
+        if (req_transport != TCP_OR_UDP && req_transport != transport)
+            continue;
+
+        /* Process a MS-KKDCP target. */
+        if (transport == HTTPS) {
+            host_trans = 0;
+            def_port = 443;
+            parse_uri_if_https(host_field, &host_trans, &host_field, &path);
+            if (host_trans != HTTPS)
+                continue;
+        }
+
+        ret = k5_parse_host_string(host_field, def_port, &host, &port);
+        if (ret == ENOMEM)
+            break;
+
+        if (ret || host == NULL) {
+            ret = 0;
+            continue;
+        }
+
+        ret = add_host_to_list(serverlist, host, port, transport, AF_UNSPEC,
+                               path, master);
+        free(host);
+        if (ret)
+            break;
+    }
+
+    krb5int_free_srv_dns_data(answers);
+    return ret;
+}
+
 static krb5_error_code
-dns_locate_server(krb5_context context, const krb5_data *realm,
-                  struct serverlist *serverlist, enum locate_service_type svc,
-                  k5_transport transport)
+dns_locate_server_uri(krb5_context context, const krb5_data *realm,
+                      struct serverlist *serverlist,
+                      enum locate_service_type svc, k5_transport transport)
+{
+    krb5_error_code ret;
+    char *svcname;
+    int def_port;
+    krb5_boolean find_master = FALSE;
+
+    if (!_krb5_use_dns_kdc(context))
+        return 0;
+
+    switch (svc) {
+    case locate_service_master_kdc:
+        find_master = TRUE;
+        /* Fall through */
+    case locate_service_kdc:
+        svcname = "_kerberos";
+        def_port = 88;
+        break;
+    case locate_service_kadmin:
+        svcname = "_kerberos-adm";
+        def_port = 749;
+        break;
+    case locate_service_kpasswd:
+        svcname = "_kpasswd";
+        def_port = 464;
+        break;
+    default:
+        return 0;
+    }
+
+    ret = locate_uri(realm, svcname, serverlist, transport, def_port,
+                     find_master);
+    if (ret)
+        Tprintf("dns URI lookup returned error %d\n", ret);
+
+    return ret;
+}
+
+static krb5_error_code
+dns_locate_server_srv(krb5_context context, const krb5_data *realm,
+                      struct serverlist *serverlist,
+                      enum locate_service_type svc, k5_transport transport)
 {
     const char *dnsname;
     int use_dns = _krb5_use_dns_kdc(context);
@@ -584,8 +753,14 @@ locate_server(krb5_context context, const krb5_data *realm,
         goto done;
 
 #ifdef KRB5_DNS_LOOKUP
+    if (list.nservers == 0) {
+        ret = dns_locate_server_uri(context, realm, &list, svc, transport);
+        if (ret)
+            goto done;
+    }
+
     if (list.nservers == 0)
-        ret = dns_locate_server(context, realm, &list, svc, transport);
+        ret = dns_locate_server_srv(context, realm, &list, svc, transport);
 #endif
 
 done:
diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c
index 3a31cce..344bb32 100644
--- a/src/lib/krb5/os/t_locate_kdc.c
+++ b/src/lib/krb5/os/t_locate_kdc.c
@@ -58,8 +58,10 @@ print_addrs (void)
         char hostbuf[NI_MAXHOST], srvbuf[NI_MAXSERV];
 
         if (entry->hostname != NULL) {
-            printf("%2d: host %s\t%s\tport %d\n", (int)i, entry->hostname,
-                   ttypename(entry->transport), entry->port);
+            printf("%2d: host %s\t%s\tport %d\tm:%d\tp:%s\n", (int)i,
+                   entry->hostname, ttypename(entry->transport),
+                   entry->port, entry->master,
+                   entry->uri_path ? entry->uri_path : "");
             continue;
         }
         err = getnameinfo((struct sockaddr *)&entry->addr, entry->addrlen,


More information about the cvs-krb5 mailing list