From 415b11695f2c59d7732f2b20608616b898e1f822 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Tue, 17 Jul 2012 13:25:13 -0400
Subject: [PATCH 4/4] LOCATOR: Return multiple server addresses to libkrb5
 clients

This will allow libkrb5 clients to have automatic failover to
other KDCs in the event that a KDC has become unresponsive, but
SSSD doesn't know it yet.
---
 src/krb5_plugin/sssd_krb5_locator_plugin.c |  141 ++++++++++++++++------------
 1 file changed, 80 insertions(+), 61 deletions(-)

diff --git a/src/krb5_plugin/sssd_krb5_locator_plugin.c b/src/krb5_plugin/sssd_krb5_locator_plugin.c
index c0edec037d6e7728763256d1c37986fd7b5bf5b4..93d2c69a62f2ff32496edb5a049d7972ecadd6ab 100644
--- a/src/krb5_plugin/sssd_krb5_locator_plugin.c
+++ b/src/krb5_plugin/sssd_krb5_locator_plugin.c
@@ -375,6 +375,7 @@ krb5_error_code sssd_krb5_locator_lookup(void *private_data,
     uint16_t port = 0;
     const char *addr = NULL;
     char port_str[PORT_STR_SIZE];
+    struct sssd_kserver_ctx *kserver;
 
     if (private_data == NULL) return KRB5_PLUGIN_NO_HANDLE;
     ctx = talloc_get_type_abort(private_data, struct sssd_ctx);
@@ -416,87 +417,105 @@ krb5_error_code sssd_krb5_locator_lookup(void *private_data,
 
     switch (svc) {
         case locate_service_kdc:
-            addr = ctx->kdc->addr;
-            port = ctx->kdc->port ? ctx->kdc->port : DEFAULT_KERBEROS_PORT;
+            kserver = ctx->kdc;
             break;
         case locate_service_master_kdc:
-            addr = ctx->kpasswd->addr;
-            port = DEFAULT_KERBEROS_PORT;
-            break;
         case locate_service_kadmin:
-            addr = ctx->kpasswd->addr;
-            port = DEFAULT_KADMIN_PORT;
-            break;
         case locate_service_kpasswd:
-            addr = ctx->kpasswd->addr;
-            port = ctx->kpasswd->port ? ctx->kpasswd->port : DEFAULT_KPASSWD_PORT;
+            kserver = ctx->kpasswd;
             break;
         case locate_service_krb524:
-            return KRB5_PLUGIN_NO_HANDLE;
-        default:
-            return KRB5_PLUGIN_NO_HANDLE;
-    }
-
-    switch (family) {
-        case AF_UNSPEC:
-        case AF_INET:
-        case AF_INET6:
-            break;
         default:
             return KRB5_PLUGIN_NO_HANDLE;
     }
 
-    switch (socktype) {
-        case SOCK_STREAM:
-        case SOCK_DGRAM:
-            break;
-        default:
-            return KRB5_PLUGIN_NO_HANDLE;
-    }
+    do {
+        switch (svc) {
+            case locate_service_kdc:
+                addr = kserver->addr;
+                port = kserver->port ? kserver->port : DEFAULT_KERBEROS_PORT;
+                break;
+            case locate_service_master_kdc:
+                addr = kserver->addr;
+                port = DEFAULT_KERBEROS_PORT;
+                break;
+            case locate_service_kadmin:
+                addr = kserver->addr;
+                port = DEFAULT_KADMIN_PORT;
+                break;
+            case locate_service_kpasswd:
+                addr = kserver->addr;
+                port = kserver->port ? kserver->port : DEFAULT_KPASSWD_PORT;
+                break;
+            case locate_service_krb524:
+            default:
+                return KRB5_PLUGIN_NO_HANDLE;
+        }
 
-    if (strcmp(realm, ctx->sssd_realm) != 0)
-        return KRB5_PLUGIN_NO_HANDLE;
 
-    memset(port_str, 0, PORT_STR_SIZE);
-    ret = snprintf(port_str, PORT_STR_SIZE-1, "%u", port);
-    if (ret < 0 || ret >= (PORT_STR_SIZE-1)) {
-        PLUGIN_DEBUG(("snprintf failed.\n"));
-        return KRB5_PLUGIN_NO_HANDLE;
-    }
+        switch (family) {
+            case AF_UNSPEC:
+            case AF_INET:
+            case AF_INET6:
+                break;
+            default:
+                return KRB5_PLUGIN_NO_HANDLE;
+        }
 
-    memset(&ai_hints, 0, sizeof(struct addrinfo));
-    ai_hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
-    ai_hints.ai_socktype = socktype;
-
-    ret = getaddrinfo(addr, port_str, &ai_hints, &ai);
-    if (ret != 0) {
-        PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", ret,
-                                                        gai_strerror(ret)));
-        if (ret == EAI_SYSTEM) {
-            PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", errno,
-                                                            strerror(errno)));
+        switch (socktype) {
+            case SOCK_STREAM:
+            case SOCK_DGRAM:
+                break;
+            default:
+                return KRB5_PLUGIN_NO_HANDLE;
         }
-        return KRB5_PLUGIN_NO_HANDLE;
-    }
 
-    PLUGIN_DEBUG(("addr[%s:%s] family[%d] socktype[%d]\n", addr, port_str,
-                 ai->ai_family, ai->ai_socktype));
+        if (strcmp(realm, ctx->sssd_realm) != 0)
+            return KRB5_PLUGIN_NO_HANDLE;
+
+        memset(port_str, 0, PORT_STR_SIZE);
+        ret = snprintf(port_str, PORT_STR_SIZE-1, "%u", port);
+        if (ret < 0 || ret >= (PORT_STR_SIZE-1)) {
+            PLUGIN_DEBUG(("snprintf failed.\n"));
+            return KRB5_PLUGIN_NO_HANDLE;
+        }
 
-    if ((family == AF_UNSPEC || ai->ai_family == family) &&
-        ai->ai_socktype == socktype) {
+        memset(&ai_hints, 0, sizeof(struct addrinfo));
+        ai_hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
+        ai_hints.ai_socktype = socktype;
 
-        ret = cbfunc(cbdata, socktype, ai->ai_addr);
+        ret = getaddrinfo(addr, port_str, &ai_hints, &ai);
         if (ret != 0) {
-            PLUGIN_DEBUG(("cbfunc failed\n"));
-            freeaddrinfo(ai);
-            return ret;
+            PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", ret,
+                                                            gai_strerror(ret)));
+            if (ret == EAI_SYSTEM) {
+                PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", errno,
+                                                                strerror(errno)));
+            }
+            return KRB5_PLUGIN_NO_HANDLE;
+        }
+
+        PLUGIN_DEBUG(("addr[%s:%s] family[%d] socktype[%d]\n", addr, port_str,
+                     ai->ai_family, ai->ai_socktype));
+
+        if ((family == AF_UNSPEC || ai->ai_family == family) &&
+            ai->ai_socktype == socktype) {
+
+            ret = cbfunc(cbdata, socktype, ai->ai_addr);
+            if (ret != 0) {
+                PLUGIN_DEBUG(("cbfunc failed\n"));
+                freeaddrinfo(ai);
+                return ret;
+            } else {
+                PLUGIN_DEBUG(("[%s] used\n", addr));
+            }
         } else {
-            PLUGIN_DEBUG(("[%s] used\n", addr));
+            PLUGIN_DEBUG(("[%s] NOT used\n", addr));
         }
-    } else {
-        PLUGIN_DEBUG(("[%s] NOT used\n", addr));
-    }
-    freeaddrinfo(ai);
+        freeaddrinfo(ai);
+
+        kserver = kserver->next;
+    } while (kserver);
 
     return 0;
 }
-- 
1.7.10.4

