From c3dda55a499f5a5dbf25c8d9da0750595d3b286f Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 27 Jun 2012 21:38:13 -0400
Subject: [PATCH 7/8] AD: Add AD auth and chpass providers

These new providers take advantage of existing code for the KRB5
provider, providing sensible defaults for operating against an
Active Directory 2008 R2 or later server.
---
 src/providers/ad/ad_common.c     |   60 +++++++++++++++++++++++++++
 src/providers/ad/ad_common.h     |    7 +++-
 src/providers/ad/ad_init.c       |   85 ++++++++++++++++++++++++++++++++++++++
 src/providers/krb5/krb5_common.h |    4 ++
 4 files changed, 155 insertions(+), 1 deletion(-)

diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 8c80faac69702ede96c13d008abe317dbe80f8f1..00ff4cb56d88df022433531425873f5167237d95 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -605,3 +605,63 @@ ad_set_search_bases(struct sdap_options *id_opts)
 done:
     return ret;
 }
+
+errno_t
+ad_get_auth_options(TALLOC_CTX *mem_ctx,
+                    struct ad_options *ad_opts,
+                    struct be_ctx *bectx,
+                    struct dp_option **_opts)
+{
+    errno_t ret;
+    struct dp_option *krb5_options;
+    const char *krb5_realm;
+
+    TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    /* Get krb5 options */
+    ret = dp_get_options(tmp_ctx, bectx->cdb, bectx->conf_path,
+                         ad_def_krb5_opts, KRB5_OPTS,
+                         &krb5_options);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Could not read Kerberos options from the configuration\n"));
+        goto done;
+    }
+
+    /* If there is no KDC, try the deprecated krb5_kdcip option, too */
+    /* FIXME - this can be removed in a future version */
+    ret = krb5_try_kdcip(bectx->cdb, bectx->conf_path,
+                         krb5_options, KRB5_KDC);
+    if (ret != EOK) {
+        DEBUG(1, ("sss_krb5_try_kdcip failed.\n"));
+        goto done;
+    }
+
+    /* Set krb5 realm */
+    /* Set the Kerberos Realm for GSSAPI */
+    krb5_realm = dp_opt_get_string(ad_opts->basic, AD_KRB5_REALM);
+    if (!krb5_realm) {
+        /* Should be impossible, this is set in ad_get_common_options() */
+        DEBUG(SSSDBG_FATAL_FAILURE, ("No Kerberos realm\n"));
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (NULL == dp_opt_get_string(krb5_options, KRB5_REALM)) {
+        ret = dp_opt_set_string(krb5_options, KRB5_REALM, krb5_realm);
+        if (ret != EOK) goto done;
+        DEBUG(SSSDBG_CONF_SETTINGS,
+              ("Option %s set to %s\n",
+                      krb5_options[KRB5_REALM].opt_name,
+               krb5_realm));
+    }
+
+    *_opts = talloc_steal(mem_ctx, krb5_options);
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index fefb67b60b1c70f67210fe3d192c94e9961029f5..d34f498a04d515935170136655dca11209379e0f 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -60,7 +60,7 @@ struct ad_options {
 
     /* Auth and chpass Provider */
     struct dp_option *auth;
-    struct ad_auth_ctx *auth_ctx;
+    struct krb5_ctx *auth_ctx;
 };
 
 errno_t
@@ -81,5 +81,10 @@ ad_get_id_options(struct ad_options *ad_opts,
                    struct confdb_ctx *cdb,
                    const char *conf_path,
                    struct sdap_options **_opts);
+errno_t
+ad_get_auth_options(TALLOC_CTX *mem_ctx,
+                    struct ad_options *ad_opts,
+                    struct be_ctx *bectx,
+                    struct dp_option **_opts);
 
 #endif /* AD_COMMON_H_ */
diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
index da659da254289b44b5d54f98ed79aa0b40e8fa7d..89101a5b16ffb254d19f0bcc2082a9e0cb20d712 100644
--- a/src/providers/ad/ad_init.c
+++ b/src/providers/ad/ad_init.c
@@ -31,6 +31,7 @@
 #include "providers/ldap/ldap_common.h"
 #include "providers/ldap/sdap_idmap.h"
 #include "providers/krb5/krb5_auth.h"
+#include "providers/krb5/krb5_init_shared.h"
 #include "providers/ad/ad_id.h"
 
 struct ad_options *ad_options = NULL;
@@ -176,6 +177,90 @@ done:
     return ret;
 }
 
+int
+sssm_ad_auth_init(struct be_ctx *bectx,
+                  struct bet_ops **ops,
+                  void **pvt_data)
+{
+    errno_t ret;
+    struct krb5_ctx *krb5_auth_ctx = NULL;
+
+    if (!ad_options) {
+        ret = common_ad_init(bectx);
+        if (ret != EOK) {
+            return ret;
+        }
+    }
+
+    if (ad_options->auth_ctx) {
+        /* Already initialized */
+        *ops = &ad_auth_ops;
+        *pvt_data = ad_options->auth_ctx;
+        return EOK;
+    }
+
+    krb5_auth_ctx = talloc_zero(NULL, struct krb5_ctx);
+    if (!krb5_auth_ctx) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    krb5_auth_ctx->service = ad_options->service->krb5_service;
+
+    ret = ad_get_auth_options(krb5_auth_ctx, ad_options, bectx,
+                              &krb5_auth_ctx->opts);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              ("Could not determine Kerberos options\n"));
+        goto done;
+    }
+
+    ret = krb5_child_init(krb5_auth_ctx, bectx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              ("Could not initialize krb5_child settings: [%s]\n",
+               strerror(ret)));
+        goto done;
+    }
+
+    ad_options->auth_ctx = talloc_steal(ad_options, krb5_auth_ctx);
+    *ops = &ad_auth_ops;
+    *pvt_data = ad_options->auth_ctx;
+
+done:
+    if (ret != EOK) {
+        talloc_free(krb5_auth_ctx);
+    }
+    return ret;
+}
+
+int
+sssm_ad_chpass_init(struct be_ctx *bectx,
+                    struct bet_ops **ops,
+                    void **pvt_data)
+{
+    errno_t ret;
+
+    if (!ad_options) {
+        ret = common_ad_init(bectx);
+        if (ret != EOK) {
+            return ret;
+        }
+    }
+
+    if (ad_options->auth_ctx) {
+        /* Already initialized */
+        *ops = &ad_chpass_ops;
+        *pvt_data = ad_options->auth_ctx;
+        return EOK;
+    }
+
+    ret = sssm_ad_auth_init(bectx, ops, pvt_data);
+    *ops = &ad_chpass_ops;
+    ad_options->auth_ctx = *pvt_data;
+    return ret;
+}
+
 static void
 ad_shutdown(struct be_req *req)
 {
diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
index ec4fc0509d97f32036a041ae2e8c26edb30363e3..589b866b45400d18cb3279badd8937deddf38d16 100644
--- a/src/providers/krb5/krb5_common.h
+++ b/src/providers/krb5/krb5_common.h
@@ -173,4 +173,8 @@ errno_t remove_krb5_info_files(TALLOC_CTX *mem_ctx, const char *realm);
 errno_t krb5_get_simple_upn(TALLOC_CTX *mem_ctx, struct krb5_ctx *krb5_ctx,
                             const char *username, const char **_upn);
 
+int sssm_krb5_auth_init(struct be_ctx *bectx,
+                        struct bet_ops **ops,
+                        void **pvt_auth_data);
+
 #endif /* __KRB5_COMMON_H__ */
-- 
1.7.10.2

