Blame SOURCES/0002-Add-helper-to-determine-if-a-KDC-is-the-master.patch

4be148
From f4b1a7e7b80ce68e57912edcd48c39ea62c73e43 Mon Sep 17 00:00:00 2001
4be148
From: Greg Hudson <ghudson@mit.edu>
4be148
Date: Sun, 6 Apr 2014 18:06:14 -0400
4be148
Subject: [PATCH 02/13] Add helper to determine if a KDC is the master
4be148
4be148
Add a new function k5_kdc_is_master in locate_kdc.c to determine
4be148
whether a KDC matches one of the masters, and use it in
4be148
krb5_sendto_kdc.
4be148
---
4be148
 src/lib/krb5/os/locate_kdc.c | 110 +++++++++++++++++++++++++++++--------------
4be148
 src/lib/krb5/os/os-proto.h   |   3 ++
4be148
 src/lib/krb5/os/sendto_kdc.c |  31 +-----------
4be148
 3 files changed, 80 insertions(+), 64 deletions(-)
4be148
4be148
diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
4be148
index 88d55a8..4479465 100644
4be148
--- a/src/lib/krb5/os/locate_kdc.c
4be148
+++ b/src/lib/krb5/os/locate_kdc.c
4be148
@@ -166,6 +166,24 @@ add_host_to_list(struct serverlist *list, const char *hostname, int port,
4be148
     return 0;
4be148
 }
4be148
 
4be148
+/* Return true if server is identical to an entry in list. */
4be148
+static krb5_boolean
4be148
+server_list_contains(struct serverlist *list, struct server_entry *server)
4be148
+{
4be148
+    struct server_entry *ent;
4be148
+
4be148
+    for (ent = list->servers; ent < list->servers + list->nservers; ent++) {
4be148
+        if (server->hostname != NULL && ent->hostname != NULL &&
4be148
+            strcmp(server->hostname, ent->hostname) == 0)
4be148
+            return TRUE;
4be148
+        if (server->hostname == NULL && ent->hostname == NULL &&
4be148
+            server->addrlen == ent->addrlen &&
4be148
+            memcmp(&server->addr, &ent->addr, server->addrlen) == 0)
4be148
+            return TRUE;
4be148
+    }
4be148
+    return FALSE;
4be148
+}
4be148
+
4be148
 static krb5_error_code
4be148
 locate_srv_conf_1(krb5_context context, const krb5_data *realm,
4be148
                   const char * name, struct serverlist *serverlist,
4be148
@@ -529,6 +547,41 @@ dns_locate_server(krb5_context context, const krb5_data *realm,
4be148
 }
4be148
 #endif /* KRB5_DNS_LOOKUP */
4be148
 
4be148
+static krb5_error_code
4be148
+locate_server(krb5_context context, const krb5_data *realm,
4be148
+              struct serverlist *serverlist, enum locate_service_type svc,
4be148
+              int socktype)
4be148
+{
4be148
+    krb5_error_code ret;
4be148
+    struct serverlist list = SERVERLIST_INIT;
4be148
+
4be148
+    *serverlist = list;
4be148
+
4be148
+    /* Try modules.  If a module returns 0 but leaves the list empty, return an
4be148
+     * empty list. */
4be148
+    ret = module_locate_server(context, realm, &list, svc, socktype);
4be148
+    if (ret != KRB5_PLUGIN_NO_HANDLE)
4be148
+        goto done;
4be148
+
4be148
+    /* Try the profile.  Fall back to DNS if it returns an empty list. */
4be148
+    ret = prof_locate_server(context, realm, &list, svc, socktype);
4be148
+    if (ret)
4be148
+        goto done;
4be148
+
4be148
+#ifdef KRB5_DNS_LOOKUP
4be148
+    if (list.nservers == 0)
4be148
+        ret = dns_locate_server(context, realm, &list, svc, socktype);
4be148
+#endif
4be148
+
4be148
+done:
4be148
+    if (ret) {
4be148
+        k5_free_serverlist(&list);
4be148
+        return ret;
4be148
+    }
4be148
+    *serverlist = list;
4be148
+    return 0;
4be148
+}
4be148
+
4be148
 /*
4be148
  * Wrapper function for the various backends
4be148
  */
4be148
@@ -538,54 +591,26 @@ k5_locate_server(krb5_context context, const krb5_data *realm,
4be148
                  struct serverlist *serverlist, enum locate_service_type svc,
4be148
                  int socktype)
4be148
 {
4be148
-    krb5_error_code code;
4be148
-    struct serverlist al = SERVERLIST_INIT;
4be148
-
4be148
-    *serverlist = al;
4be148
+    krb5_error_code ret;
4be148
 
4be148
+    memset(serverlist, 0, sizeof(*serverlist));
4be148
     if (realm == NULL || realm->data == NULL || realm->data[0] == 0) {
4be148
         krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE,
4be148
                                "Cannot find KDC for invalid realm name \"\"");
4be148
         return KRB5_REALM_CANT_RESOLVE;
4be148
     }
4be148
 
4be148
-    code = module_locate_server(context, realm, &al, svc, socktype);
4be148
-    Tprintf("module_locate_server returns %d\n", code);
4be148
-    if (code == KRB5_PLUGIN_NO_HANDLE) {
4be148
-        /*
4be148
-         * We always try the local file before DNS.  Note that there
4be148
-         * is no way to indicate "service not available" via the
4be148
-         * config file.
4be148
-         */
4be148
-
4be148
-        code = prof_locate_server(context, realm, &al, svc, socktype);
4be148
-
4be148
-#ifdef KRB5_DNS_LOOKUP
4be148
-        if (code == 0 && al.nservers == 0)
4be148
-            code = dns_locate_server(context, realm, &al, svc, socktype);
4be148
-#endif /* KRB5_DNS_LOOKUP */
4be148
+    ret = locate_server(context, realm, serverlist, svc, socktype);
4be148
+    if (ret)
4be148
+        return ret;
4be148
 
4be148
-        /* We could put more heuristics here, like looking up a hostname
4be148
-           of "kerberos."+REALM, etc.  */
4be148
-    }
4be148
-    if (code == 0)
4be148
-        Tprintf ("krb5int_locate_server found %d addresses\n",
4be148
-                 al.nservers);
4be148
-    else
4be148
-        Tprintf ("krb5int_locate_server returning error code %d/%s\n",
4be148
-                 code, error_message(code));
4be148
-    if (code != 0) {
4be148
-        k5_free_serverlist(&al);
4be148
-        return code;
4be148
-    }
4be148
-    if (al.nservers == 0) {       /* No good servers */
4be148
-        k5_free_serverlist(&al);
4be148
+    if (serverlist->nservers == 0) {
4be148
+        k5_free_serverlist(serverlist);
4be148
         krb5_set_error_message(context, KRB5_REALM_UNKNOWN,
4be148
                                _("Cannot find KDC for realm \"%.*s\""),
4be148
                                realm->length, realm->data);
4be148
         return KRB5_REALM_UNKNOWN;
4be148
     }
4be148
-    *serverlist = al;
4be148
     return 0;
4be148
 }
4be148
 
4be148
@@ -598,3 +623,18 @@ k5_locate_kdc(krb5_context context, const krb5_data *realm,
4be148
     stype = get_masters ? locate_service_master_kdc : locate_service_kdc;
4be148
     return k5_locate_server(context, realm, serverlist, stype, socktype);
4be148
 }
4be148
+
4be148
+krb5_boolean
4be148
+k5_kdc_is_master(krb5_context context, const krb5_data *realm,
4be148
+                 struct server_entry *server)
4be148
+{
4be148
+    struct serverlist list;
4be148
+    krb5_boolean found;
4be148
+
4be148
+    if (locate_server(context, realm, &list, locate_service_master_kdc,
4be148
+                      server->socktype) != 0)
4be148
+        return FALSE;
4be148
+    found = server_list_contains(&list, server);
4be148
+    k5_free_serverlist(&list);
4be148
+    return found;
4be148
+}
4be148
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
4be148
index c6b730f..9125ba0 100644
4be148
--- a/src/lib/krb5/os/os-proto.h
4be148
+++ b/src/lib/krb5/os/os-proto.h
4be148
@@ -76,6 +76,9 @@ krb5_error_code k5_locate_kdc(krb5_context context, const krb5_data *realm,
4be148
                               struct serverlist *serverlist, int get_masters,
4be148
                               int socktype);
4be148
 
4be148
+krb5_boolean k5_kdc_is_master(krb5_context context, const krb5_data *realm,
4be148
+                              struct server_entry *server);
4be148
+
4be148
 void k5_free_serverlist(struct serverlist *);
4be148
 
4be148
 #ifdef HAVE_NETINET_IN_H
4be148
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
4be148
index 5f781d3..e3855a3 100644
4be148
--- a/src/lib/krb5/os/sendto_kdc.c
4be148
+++ b/src/lib/krb5/os/sendto_kdc.c
4be148
@@ -293,25 +293,6 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
4be148
 }
4be148
 
4be148
 static int
4be148
-in_addrlist(struct server_entry *entry, struct serverlist *list)
4be148
-{
4be148
-    size_t i;
4be148
-    struct server_entry *le;
4be148
-
4be148
-    for (i = 0; i < list->nservers; i++) {
4be148
-        le = &list->servers[i];
4be148
-        if (entry->hostname != NULL && le->hostname != NULL &&
4be148
-            strcmp(entry->hostname, le->hostname) == 0)
4be148
-            return 1;
4be148
-        if (entry->hostname == NULL && le->hostname == NULL &&
4be148
-            entry->addrlen == le->addrlen &&
4be148
-            memcmp(&entry->addr, &le->addr, entry->addrlen) == 0)
4be148
-            return 1;
4be148
-    }
4be148
-    return 0;
4be148
-}
4be148
-
4be148
-static int
4be148
 check_for_svc_unavailable (krb5_context context,
4be148
                            const krb5_data *reply,
4be148
                            void *msg_handler_data)
4be148
@@ -418,17 +399,9 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
4be148
     /* Set use_master to 1 if we ended up talking to a master when we didn't
4be148
      * explicitly request to. */
4be148
     if (*use_master == 0) {
4be148
-        struct serverlist mservers;
4be148
-        struct server_entry *entry = &servers.servers[server_used];
4be148
-        retval = k5_locate_kdc(context, realm, &mservers, TRUE,
4be148
-                               entry->socktype);
4be148
-        if (retval == 0) {
4be148
-            if (in_addrlist(entry, &mservers))
4be148
-                *use_master = 1;
4be148
-            k5_free_serverlist(&mservers);
4be148
-        }
4be148
+        *use_master = k5_kdc_is_master(context, realm,
4be148
+                                       &servers.servers[server_used]);
4be148
         TRACE_SENDTO_KDC_MASTER(context, *use_master);
4be148
-        retval = 0;
4be148
     }
4be148
 
4be148
 cleanup:
4be148
-- 
4be148
2.1.0
4be148