From 96d01249fd5ef9b414d1cfc37633bcbcff97a920 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Thu, 23 Apr 2015 15:00:29 +0300
Subject: [PATCH] TODO: support per-forest keytabs for IPA subdomains

---
 src/providers/ad/ad_common.c       | 30 +++++++++++------
 src/providers/ad/ad_common.h       |  6 +++-
 src/providers/ad/ad_subdomains.c   |  2 +-
 src/providers/ipa/ipa_subdomains.c | 67 +++++++++++++++++++++++++++++++++++++-
 src/tests/cmocka/test_ad_common.c  |  3 +-
 5 files changed, 94 insertions(+), 14 deletions(-)

diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 5eeb8dd..4513ce2 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -110,7 +110,9 @@ fail:
 struct ad_options *
 ad_create_default_options(TALLOC_CTX *mem_ctx,
                           const char *realm,
-                          const char *hostname)
+                          const char *hostname,
+                          sdap_options_modifier_fn id_options_fn,
+                          void *id_options_fn_data)
 {
     struct ad_options *ad_options;
     errno_t ret;
@@ -134,6 +136,10 @@ ad_create_default_options(TALLOC_CTX *mem_ctx,
         return NULL;
     }
 
+    if (id_options_fn != NULL) {
+        id_options_fn(ad_options->id, id_options_fn_data);
+    }
+
     ret = dp_opt_set_string(ad_options->basic, AD_KRB5_REALM, realm);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "Cannot set AD domain\n");
@@ -865,15 +871,19 @@ ad_set_ad_id_options(struct ad_options *ad_opts,
            id_opts->basic[SDAP_KRB5_REALM].opt_name,
            krb5_realm);
 
-    keytab_path = dp_opt_get_string(ad_opts->basic, AD_KEYTAB);
-    if (keytab_path) {
-        ret = dp_opt_set_string(id_opts->basic, SDAP_KRB5_KEYTAB,
-                                keytab_path);
-        if (ret != EOK) goto done;
-        DEBUG(SSSDBG_CONF_SETTINGS,
-              "Option %s set to %s\n",
-               id_opts->basic[SDAP_KRB5_KEYTAB].opt_name,
-               keytab_path);
+    /* Allow subdomain providers to override keytab path */
+    keytab_path = dp_opt_get_string(id_opts->basic, SDAP_KRB5_KEYTAB);
+    if (keytab_path == NULL) {
+        keytab_path = dp_opt_get_string(ad_opts->basic, AD_KEYTAB);
+        if (keytab_path) {
+            ret = dp_opt_set_string(id_opts->basic, SDAP_KRB5_KEYTAB,
+                                    keytab_path);
+            if (ret != EOK) goto done;
+            DEBUG(SSSDBG_CONF_SETTINGS,
+                  "Option %s set to %s\n",
+                  id_opts->basic[SDAP_KRB5_KEYTAB].opt_name,
+                  keytab_path);
+        }
     }
 
     ret = sdap_set_sasl_options(id_opts,
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index dcd70bf..5e91c4b 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -96,6 +96,8 @@ struct ad_options {
     struct be_nsupdate_ctx *dyndns_ctx;
 };
 
+typedef void (*sdap_options_modifier_fn)(struct sdap_options *, void *);
+
 errno_t
 ad_get_common_options(TALLOC_CTX *mem_ctx,
                       struct confdb_ctx *cdb,
@@ -105,7 +107,9 @@ ad_get_common_options(TALLOC_CTX *mem_ctx,
 
 struct ad_options *ad_create_default_options(TALLOC_CTX *mem_ctx,
                                              const char *realm,
-                                             const char *hostname);
+                                             const char *hostname,
+                                             sdap_options_modifier_fn id_options_fn,
+                                             void *id_options_fn_data);
 
 errno_t
 ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index 5a6e933..bb18daf 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -115,7 +115,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
         return EINVAL;
     }
 
-    ad_options = ad_create_default_options(id_ctx, realm, hostname);
+    ad_options = ad_create_default_options(id_ctx, realm, hostname, NULL, NULL);
     if (ad_options == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
         talloc_free(ad_options);
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 20657eb..f1444fa 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -105,6 +105,69 @@ struct be_ctx *ipa_get_subdomains_be_ctx(struct be_ctx *be_ctx)
     return subdom_ctx->be_ctx;
 }
 
+static void
+ipa_ad_ctx_new_modify_id_options_callback(struct sdap_options *id_options,
+                                          void *data)
+{
+    struct sss_domain_info *subdom = (struct sss_domain_info*) data;
+    char *sasl_authid = NULL;
+    char *keytab = NULL;
+    errno_t ret;
+
+    if (subdom == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "AD provider passed back empty subdomain to "
+                                 "IPA subdomains provider. No way to detect "
+                                 "whether we need to use forest-wide principal "
+                                 "to talk to AD.\n");
+        return;
+    }
+
+    if (subdom->forest != NULL && subdom->parent != NULL) {
+        sasl_authid = talloc_asprintf(id_options, "%s$@%s",
+                                      subdom->parent->flat_name,
+                                      subdom->forest);
+        if (sasl_authid == NULL) {
+            DEBUG(SSSDBG_MINOR_FAILURE, "talloc_asprintf() failed.\n");
+            return;
+        }
+
+        ret = dp_opt_set_string(id_options->basic, SDAP_SASL_AUTHID, sasl_authid);
+        if (ret == EOK) {
+            DEBUG(SSSDBG_TRACE_FUNC, "IPA subdomains provider: redefined SASL auth ID "
+                                     "for subdomain [%s] to [%s]\n",
+                                     subdom->name, sasl_authid);
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE, "Failed to redefine SASL auth ID for subdomain "
+                                     "[%s] to [%s]\n",
+                                     subdom->name, sasl_authid);
+            talloc_free(sasl_authid);
+            return;
+        }
+
+        keytab = talloc_asprintf(id_options, "FILE:%s/trust_%s_%s.keytab", DB_PATH,
+                                 subdom->parent->flat_name, subdom->forest);
+        if (keytab == NULL) {
+            DEBUG(SSSDBG_MINOR_FAILURE, "talloc_asprintf() failed. IPA subdomain [%s] "
+                                        "will not use proper keytab to lookup its "
+                                        "keys\n", subdom->name);
+            return;
+        }
+        dp_opt_set_string(id_options->basic, SDAP_KRB5_KEYTAB, keytab);
+        if (ret == EOK) {
+            DEBUG(SSSDBG_TRACE_FUNC, "IPA subdomains provider: redefined keytab path "
+                                     "for subdomain [%s] to [%s]\n",
+                                     subdom->name, keytab);
+        } else {
+            DEBUG(SSSDBG_MINOR_FAILURE, "Failed to redefine keytab path for subdomain "
+                                        "[%s] to [%s]. IPA subdomain will not use "
+                                        "proper keytab to lookup its keys\n",
+                                        subdom->name, keytab);
+            talloc_free(keytab);
+            return;
+        }
+    }
+}
+
 static errno_t
 ipa_ad_ctx_new(struct be_ctx *be_ctx,
                struct ipa_id_ctx *id_ctx,
@@ -122,7 +185,9 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
     const char *extra_attrs;
 
     ad_options = ad_create_default_options(id_ctx, id_ctx->server_mode->realm,
-                                           id_ctx->server_mode->hostname);
+                                           id_ctx->server_mode->hostname,
+                                           ipa_ad_ctx_new_modify_id_options_callback,
+                                           subdom);
     if (ad_options == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD options\n");
         talloc_free(ad_options);
diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
index 1c44bc3..ac78f0d 100644
--- a/src/tests/cmocka/test_ad_common.c
+++ b/src/tests/cmocka/test_ad_common.c
@@ -76,7 +76,8 @@ ad_common_test_setup(void **state)
     assert_non_null(ad_ctx);
 
     ad_ctx->ad_options = ad_create_default_options(ad_ctx,
-                                                   REALMNAME, HOST_NAME);
+                                                   REALMNAME, HOST_NAME,
+                                                   NULL, NULL);
     assert_non_null(ad_ctx->ad_options);
 
     ad_ctx->gc_ctx = talloc_zero(ad_ctx, struct sdap_id_conn_ctx);
-- 
2.1.0

