Blame SOURCES/0022-krb5-Write-multiple-dnsnames-into-kdc-info-file.patch

841ac7
From f61c92c399531a5530dbb57a36b4e0db46c72b5b Mon Sep 17 00:00:00 2001
841ac7
From: Tomas Halman <thalman@redhat.com>
841ac7
Date: Wed, 13 Mar 2019 08:37:36 +0100
841ac7
Subject: [PATCH 22/23] krb5: Write multiple dnsnames into kdc info file
841ac7
841ac7
Multiple servers should be written to kdc info file. In
841ac7
this PR we iterate trough server list and we write
841ac7
list of primary servers followed by backup servers.
841ac7
841ac7
Resolves:
841ac7
https://pagure.io/SSSD/sssd/issue/3974
841ac7
841ac7
Reviewed-by: Sumit Bose <sbose@redhat.com>
841ac7
(cherry picked from commit 208a79a83c76b6693bdf927c3d7d6267e3218b0b)
841ac7
---
841ac7
 src/providers/ad/ad_common.c       |  39 +++++----
841ac7
 src/providers/fail_over.c          |  27 ++++++
841ac7
 src/providers/fail_over.h          |   9 ++
841ac7
 src/providers/ipa/ipa_common.c     |  25 +-----
841ac7
 src/providers/ipa/ipa_subdomains.c |   4 +-
841ac7
 src/providers/krb5/krb5_common.c   | 131 ++++++++++++++++++++---------
841ac7
 src/providers/krb5/krb5_common.h   |   7 +-
841ac7
 7 files changed, 158 insertions(+), 84 deletions(-)
841ac7
841ac7
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
841ac7
index 0d154ca57..b7f34daa9 100644
841ac7
--- a/src/providers/ad/ad_common.c
841ac7
+++ b/src/providers/ad/ad_common.c
841ac7
@@ -24,6 +24,7 @@
841ac7
 #include "providers/ad/ad_common.h"
841ac7
 #include "providers/ad/ad_opts.h"
841ac7
 #include "providers/be_dyndns.h"
841ac7
+#include "providers/fail_over.h"
841ac7
 
841ac7
 struct ad_server_data {
841ac7
     bool gc;
841ac7
@@ -839,6 +840,20 @@ done:
841ac7
     return ret;
841ac7
 }
841ac7
 
841ac7
+static bool
841ac7
+ad_krb5info_file_filter(struct fo_server *server)
841ac7
+{
841ac7
+    struct ad_server_data *sdata = NULL;
841ac7
+    if (server == NULL) return true;
841ac7
+
841ac7
+    sdata = fo_get_server_user_data(server);
841ac7
+    if (sdata && sdata->gc) {
841ac7
+        /* Only write kdcinfo files for local servers */
841ac7
+        return true;
841ac7
+    }
841ac7
+    return false;
841ac7
+}
841ac7
+
841ac7
 static void
841ac7
 ad_resolve_callback(void *private_data, struct fo_server *server)
841ac7
 {
841ac7
@@ -848,7 +863,6 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
841ac7
     struct resolv_hostent *srvaddr;
841ac7
     struct sockaddr_storage *sockaddr;
841ac7
     char *address;
841ac7
-    char *safe_addr_list[2] = { NULL, NULL };
841ac7
     char *new_uri;
841ac7
     int new_port;
841ac7
     const char *srv_name;
841ac7
@@ -953,25 +967,14 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
841ac7
         goto done;
841ac7
     }
841ac7
 
841ac7
-    /* Only write kdcinfo files for local servers */
841ac7
-    if ((sdata == NULL || sdata->gc == false) &&
841ac7
-        service->krb5_service->write_kdcinfo) {
841ac7
-        /* Write krb5 info files */
841ac7
-        safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
841ac7
-                                                  srvaddr->family,
841ac7
-                                                  address);
841ac7
-        if (safe_addr_list[0] == NULL) {
841ac7
-            DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
841ac7
-            ret = ENOMEM;
841ac7
-            goto done;
841ac7
-        }
841ac7
-
841ac7
-        ret = write_krb5info_file(service->krb5_service,
841ac7
-                                  safe_addr_list,
841ac7
-                                  SSS_KRB5KDC_FO_SRV);
841ac7
+    if (service->krb5_service->write_kdcinfo) {
841ac7
+        ret = write_krb5info_file_from_fo_server(service->krb5_service,
841ac7
+                                                 server,
841ac7
+                                                 SSS_KRB5KDC_FO_SRV,
841ac7
+                                                 ad_krb5info_file_filter);
841ac7
         if (ret != EOK) {
841ac7
             DEBUG(SSSDBG_MINOR_FAILURE,
841ac7
-                "write_krb5info_file failed, authentication might fail.\n");
841ac7
+                  "write_krb5info_file failed, authentication might fail.\n");
841ac7
         }
841ac7
     }
841ac7
 
841ac7
diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c
841ac7
index 168e59d6f..dc5c7c7d8 100644
841ac7
--- a/src/providers/fail_over.c
841ac7
+++ b/src/providers/fail_over.c
841ac7
@@ -1637,6 +1637,33 @@ fo_get_server_hostname_last_change(struct fo_server *server)
841ac7
     return server->common->last_status_change.tv_sec;
841ac7
 }
841ac7
 
841ac7
+struct fo_server *fo_server_first(struct fo_server *server)
841ac7
+{
841ac7
+    if (!server) return NULL;
841ac7
+
841ac7
+    while (server->prev) { server = server->prev; }
841ac7
+    return server;
841ac7
+}
841ac7
+
841ac7
+struct fo_server *fo_server_next(struct fo_server *server)
841ac7
+{
841ac7
+    if (!server) return NULL;
841ac7
+
841ac7
+    return server->next;
841ac7
+}
841ac7
+
841ac7
+size_t fo_server_count(struct fo_server *server)
841ac7
+{
841ac7
+    struct fo_server *item = fo_server_first(server);
841ac7
+    size_t size = 0;
841ac7
+
841ac7
+    while (item) {
841ac7
+        ++size;
841ac7
+        item = item->next;
841ac7
+    }
841ac7
+    return size;
841ac7
+}
841ac7
+
841ac7
 time_t fo_get_service_retry_timeout(struct fo_service *svc)
841ac7
 {
841ac7
     if (svc == NULL || svc->ctx == NULL || svc->ctx->opts == NULL) {
841ac7
diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h
841ac7
index d70212fb7..bc8142710 100644
841ac7
--- a/src/providers/fail_over.h
841ac7
+++ b/src/providers/fail_over.h
841ac7
@@ -216,6 +216,15 @@ const char **fo_svc_server_list(TALLOC_CTX *mem_ctx,
841ac7
                                 struct fo_service *service,
841ac7
                                 size_t *_count);
841ac7
 
841ac7
+/*
841ac7
+ * Folowing functions allow to iterate trough list of servers.
841ac7
+ */
841ac7
+struct fo_server *fo_server_first(struct fo_server *server);
841ac7
+
841ac7
+struct fo_server *fo_server_next(struct fo_server *server);
841ac7
+
841ac7
+size_t fo_server_count(struct fo_server *server);
841ac7
+
841ac7
 /*
841ac7
  * pvt will be talloc_stealed to ctx
841ac7
  */
841ac7
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
841ac7
index 17d14e6b0..1ed2e2203 100644
841ac7
--- a/src/providers/ipa/ipa_common.c
841ac7
+++ b/src/providers/ipa/ipa_common.c
841ac7
@@ -819,8 +819,6 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
841ac7
     struct ipa_service *service;
841ac7
     struct resolv_hostent *srvaddr;
841ac7
     struct sockaddr_storage *sockaddr;
841ac7
-    char *address;
841ac7
-    char *safe_addr_list[2] = { NULL, NULL };
841ac7
     char *new_uri;
841ac7
     const char *srv_name;
841ac7
     int ret;
841ac7
@@ -854,13 +852,6 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
841ac7
         return;
841ac7
     }
841ac7
 
841ac7
-    address = resolv_get_string_address(tmp_ctx, srvaddr);
841ac7
-    if (address == NULL) {
841ac7
-        DEBUG(SSSDBG_CRIT_FAILURE, "resolv_get_string_address failed.\n");
841ac7
-        talloc_free(tmp_ctx);
841ac7
-        return;
841ac7
-    }
841ac7
-
841ac7
     srv_name = fo_get_server_name(server);
841ac7
     if (srv_name == NULL) {
841ac7
         DEBUG(SSSDBG_CRIT_FAILURE, "Could not get server host name\n");
841ac7
@@ -883,18 +874,10 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
841ac7
     service->sdap->sockaddr = talloc_steal(service, sockaddr);
841ac7
 
841ac7
     if (service->krb5_service->write_kdcinfo) {
841ac7
-        safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
841ac7
-                                             srvaddr->family,
841ac7
-                                             address);
841ac7
-        if (safe_addr_list[0] == NULL) {
841ac7
-            DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
841ac7
-            talloc_free(tmp_ctx);
841ac7
-            return;
841ac7
-        }
841ac7
-
841ac7
-        ret = write_krb5info_file(service->krb5_service,
841ac7
-                                  safe_addr_list,
841ac7
-                                  SSS_KRB5KDC_FO_SRV);
841ac7
+        ret = write_krb5info_file_from_fo_server(service->krb5_service,
841ac7
+                                                 server,
841ac7
+                                                 SSS_KRB5KDC_FO_SRV,
841ac7
+                                                 NULL);
841ac7
         if (ret != EOK) {
841ac7
             DEBUG(SSSDBG_OP_FAILURE,
841ac7
                   "write_krb5info_file failed, authentication might fail.\n");
841ac7
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
841ac7
index d86ca4cc5..da1279e3e 100644
841ac7
--- a/src/providers/ipa/ipa_subdomains.c
841ac7
+++ b/src/providers/ipa/ipa_subdomains.c
841ac7
@@ -2545,7 +2545,7 @@ static errno_t ipa_subdomains_write_kdcinfo_write_step(struct sss_domain_info *d
841ac7
     errno_t ret;
841ac7
     char *address = NULL;
841ac7
     char *safe_address = NULL;
841ac7
-    char **safe_addr_list;
841ac7
+    const char **safe_addr_list;
841ac7
     int addr_index = 0;
841ac7
     TALLOC_CTX *tmp_ctx = NULL;
841ac7
 
841ac7
@@ -2554,7 +2554,7 @@ static errno_t ipa_subdomains_write_kdcinfo_write_step(struct sss_domain_info *d
841ac7
         return ENOMEM;
841ac7
     }
841ac7
 
841ac7
-    safe_addr_list = talloc_zero_array(tmp_ctx, char *, rhp_len+1);
841ac7
+    safe_addr_list = talloc_zero_array(tmp_ctx, const char *, rhp_len+1);
841ac7
     if (safe_addr_list == NULL) {
841ac7
         ret = ENOMEM;
841ac7
         goto done;
841ac7
diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
841ac7
index 2b003e164..1e33fc0f5 100644
841ac7
--- a/src/providers/krb5/krb5_common.c
841ac7
+++ b/src/providers/krb5/krb5_common.c
841ac7
@@ -33,6 +33,7 @@
841ac7
 #include "providers/krb5/krb5_common.h"
841ac7
 #include "providers/krb5/krb5_opts.h"
841ac7
 #include "providers/krb5/krb5_utils.h"
841ac7
+#include "providers/fail_over.h"
841ac7
 
841ac7
 #ifdef HAVE_KRB5_CC_COLLECTION
841ac7
 /* krb5 profile functions */
841ac7
@@ -592,7 +593,7 @@ done:
841ac7
 }
841ac7
 
841ac7
 errno_t write_krb5info_file(struct krb5_service *krb5_service,
841ac7
-                            char **server_list,
841ac7
+                            const char **server_list,
841ac7
                             const char *service)
841ac7
 {
841ac7
     int i;
841ac7
@@ -635,73 +636,119 @@ done:
841ac7
     return ret;
841ac7
 }
841ac7
 
841ac7
-static void krb5_resolve_callback(void *private_data, struct fo_server *server)
841ac7
+static const char* fo_server_address_or_name(TALLOC_CTX *tmp_ctx, struct fo_server *server)
841ac7
 {
841ac7
-    struct krb5_service *krb5_service;
841ac7
     struct resolv_hostent *srvaddr;
841ac7
     char *address;
841ac7
-    char *safe_addr_list[2] = { NULL, NULL };
841ac7
-    int ret;
841ac7
+
841ac7
+    if (!server) return NULL;
841ac7
+
841ac7
+    srvaddr = fo_get_server_hostent(server);
841ac7
+    if (srvaddr) {
841ac7
+        address = resolv_get_string_address(tmp_ctx, srvaddr);
841ac7
+        if (address) {
841ac7
+            return sss_escape_ip_address(tmp_ctx,
841ac7
+                                         srvaddr->family,
841ac7
+                                         address);
841ac7
+        }
841ac7
+    }
841ac7
+
841ac7
+    return fo_get_server_name(server);
841ac7
+}
841ac7
+
841ac7
+errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
841ac7
+                                           struct fo_server *server,
841ac7
+                                           const char *service,
841ac7
+                                           bool (*filter)(struct fo_server *))
841ac7
+{
841ac7
     TALLOC_CTX *tmp_ctx = NULL;
841ac7
+    const char **server_list;
841ac7
+    size_t server_idx;
841ac7
+    struct fo_server *item;
841ac7
+    int primary;
841ac7
+    const char *address;
841ac7
+    errno_t ret;
841ac7
 
841ac7
     tmp_ctx = talloc_new(NULL);
841ac7
     if (tmp_ctx == NULL) {
841ac7
         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed\n");
841ac7
-        return;
841ac7
+        return ENOMEM;
841ac7
     }
841ac7
 
841ac7
-    krb5_service = talloc_get_type(private_data, struct krb5_service);
841ac7
-    if (!krb5_service) {
841ac7
-        DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Bad private_data\n");
841ac7
+    server_idx = 0;
841ac7
+    server_list = talloc_zero_array(tmp_ctx,
841ac7
+                                    const char *,
841ac7
+                                    fo_server_count(server) + 1);
841ac7
+    if (server_list == NULL) {
841ac7
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array failed\n");
841ac7
         talloc_free(tmp_ctx);
841ac7
-        return;
841ac7
+        return ENOMEM;
841ac7
     }
841ac7
 
841ac7
-    srvaddr = fo_get_server_hostent(server);
841ac7
-    if (!srvaddr) {
841ac7
-        DEBUG(SSSDBG_CRIT_FAILURE,
841ac7
-              "FATAL: No hostent available for server (%s)\n",
841ac7
-                  fo_get_server_str_name(server));
841ac7
-        talloc_free(tmp_ctx);
841ac7
-        return;
841ac7
+    if (filter == NULL || filter(server) == false) {
841ac7
+        address = fo_server_address_or_name(tmp_ctx, server);
841ac7
+        if (address) {
841ac7
+            server_list[server_idx++] = address;
841ac7
+        } else {
841ac7
+            DEBUG(SSSDBG_CRIT_FAILURE,
841ac7
+                  "Server without name and address found in list.\n");
841ac7
+        }
841ac7
     }
841ac7
 
841ac7
-    address = resolv_get_string_address(tmp_ctx, srvaddr);
841ac7
-    if (address == NULL) {
841ac7
-        DEBUG(SSSDBG_CRIT_FAILURE, "resolv_get_string_address failed.\n");
841ac7
-        talloc_free(tmp_ctx);
841ac7
-        return;
841ac7
+    for (primary = 1; primary >= 0; --primary) {
841ac7
+        for (item = fo_server_next(server) ? fo_server_next(server) : fo_server_first(server);
841ac7
+             item != server;
841ac7
+             item = fo_server_next(item) ? fo_server_next(item) : fo_server_first(item)) {
841ac7
+
841ac7
+            if (primary && !fo_is_server_primary(item)) continue;
841ac7
+            if (!primary && fo_is_server_primary(item)) continue;
841ac7
+            if (filter != NULL && filter(item)) continue;
841ac7
+
841ac7
+            address = fo_server_address_or_name(tmp_ctx, item);
841ac7
+            if (address == NULL) {
841ac7
+                DEBUG(SSSDBG_CRIT_FAILURE,
841ac7
+                      "Server without name and address found in list.\n");
841ac7
+                continue;
841ac7
+            }
841ac7
+
841ac7
+            server_list[server_idx++] = address;
841ac7
+        }
841ac7
     }
841ac7
+    if (server_list[0] == NULL) {
841ac7
+        DEBUG(SSSDBG_CRIT_FAILURE,
841ac7
+              "There is no server that can be written into kdc info file.\n");
841ac7
+        ret = EINVAL;
841ac7
+    } else {
841ac7
+        ret = write_krb5info_file(krb5_service,
841ac7
+                                  server_list,
841ac7
+                                  service);
841ac7
+    }
841ac7
+    talloc_free(tmp_ctx);
841ac7
+    return ret;
841ac7
+}
841ac7
 
841ac7
-    safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
841ac7
-                                              srvaddr->family,
841ac7
-                                              address);
841ac7
-    if (safe_addr_list[0] == NULL) {
841ac7
-        DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
841ac7
-        talloc_free(tmp_ctx);
841ac7
+
841ac7
+static void krb5_resolve_callback(void *private_data, struct fo_server *server)
841ac7
+{
841ac7
+    struct krb5_service *krb5_service;
841ac7
+    int ret;
841ac7
+
841ac7
+    krb5_service = talloc_get_type(private_data, struct krb5_service);
841ac7
+    if (!krb5_service) {
841ac7
+        DEBUG(SSSDBG_CRIT_FAILURE, "FATAL: Bad private_data\n");
841ac7
         return;
841ac7
     }
841ac7
 
841ac7
     if (krb5_service->write_kdcinfo) {
841ac7
-        safe_addr_list[0] = talloc_asprintf_append(safe_addr_list[0], ":%d",
841ac7
-                                                   fo_get_server_port(server));
841ac7
-        if (safe_addr_list[0] == NULL) {
841ac7
-            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf_append failed.\n");
841ac7
-            talloc_free(tmp_ctx);
841ac7
-            return;
841ac7
-        }
841ac7
-
841ac7
-        ret = write_krb5info_file(krb5_service,
841ac7
-                                  safe_addr_list,
841ac7
-                                  krb5_service->name);
841ac7
+        ret = write_krb5info_file_from_fo_server(krb5_service,
841ac7
+                                                 server,
841ac7
+                                                 krb5_service->name,
841ac7
+                                                 NULL);
841ac7
         if (ret != EOK) {
841ac7
             DEBUG(SSSDBG_OP_FAILURE,
841ac7
                   "write_krb5info_file failed, authentication might fail.\n");
841ac7
         }
841ac7
     }
841ac7
-
841ac7
-    talloc_free(tmp_ctx);
841ac7
-    return;
841ac7
 }
841ac7
 
841ac7
 static errno_t _krb5_servers_init(struct be_ctx *ctx,
841ac7
diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
841ac7
index bf36a551a..be541626b 100644
841ac7
--- a/src/providers/krb5/krb5_common.h
841ac7
+++ b/src/providers/krb5/krb5_common.h
841ac7
@@ -161,9 +161,14 @@ errno_t sss_krb5_get_options(TALLOC_CTX *memctx, struct confdb_ctx *cdb,
841ac7
                              const char *conf_path, struct dp_option **_opts);
841ac7
 
841ac7
 errno_t write_krb5info_file(struct krb5_service *krb5_service,
841ac7
-                            char **server_list,
841ac7
+                            const char **server_list,
841ac7
                             const char *service);
841ac7
 
841ac7
+errno_t write_krb5info_file_from_fo_server(struct krb5_service *krb5_service,
841ac7
+                                           struct fo_server *server,
841ac7
+                                           const char *service,
841ac7
+                                           bool (*filter)(struct fo_server *));
841ac7
+
841ac7
 struct krb5_service *krb5_service_new(TALLOC_CTX *mem_ctx,
841ac7
                                       struct be_ctx *be_ctx,
841ac7
                                       const char *service_name,
841ac7
-- 
841ac7
2.19.1
841ac7