From f2db754e329c478857ec2a807edf8915cad21875 Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Mon, 28 Mar 2011 06:45:35 -0400
Subject: [PATCH] Allow new option to specify principal for FAST

https://fedorahosted.org/sssd/ticket/700
---
 src/man/sssd-krb5.5.xml          |    9 +++++++
 src/providers/ipa/ipa_common.c   |    3 +-
 src/providers/ipa/ipa_common.h   |    2 +-
 src/providers/krb5/krb5_child.c  |   44 +++++++++++++++++++++++++++++++++++--
 src/providers/krb5/krb5_common.c |   12 +++++++++-
 src/providers/krb5/krb5_common.h |    2 +
 6 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml
index 491e0442bc3098a87f8b9de945164972f6bc02bd..04523c06e539886036b2acf4c667d82936d4114d 100644
--- a/src/man/sssd-krb5.5.xml
+++ b/src/man/sssd-krb5.5.xml
@@ -393,6 +393,15 @@
                     </listitem>
                 </varlistentry>
 
+                <varlistentry>
+                    <term>krb5_fast_principal (string)</term>
+                    <listitem>
+                        <para>
+                            Specifies the server principal to use for FAST.
+                        </para>
+                    </listitem>
+                </varlistentry>
+
             </variablelist>
         </para>
     </refsect1>
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 067f2ee85c625a2a6e5dec77b07f9b2359a2dad0..61859a981799f4881533e524823fe24752e21f1c 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -164,7 +164,8 @@ struct dp_option ipa_def_krb5_opts[] = {
     { "krb5_renewable_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "krb5_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "krb5_renew_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
-    { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }
+    { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "krb5_fast_principal", DP_OPT_STRING, NULL_STRING, NULL_STRING }
 };
 
 int ipa_get_options(TALLOC_CTX *memctx,
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 588aa63e412dc2ba006714729bb4710a4075ff25..5ff0ba4ff40a3894b931c553719a05b3cc3a533d 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -40,7 +40,7 @@ struct ipa_service {
 /* the following define is used to keep track of the options in the krb5
  * module, so that if they change and ipa is not updated correspondingly
  * this will trigger a runtime abort error */
-#define IPA_KRB5_OPTS_TEST 13
+#define IPA_KRB5_OPTS_TEST 14
 
 enum ipa_basic_opt {
     IPA_DOMAIN = 0,
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 1ed63f6b2583c2fad267ad04ab0e32bd7f6d327b..010d2e8f38c73887234e4d1d23feb03bd025aef8 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -1221,7 +1221,8 @@ done:
     return krberr;
 }
 
-static krb5_error_code check_fast_ccache(krb5_context ctx, const char *realm,
+static krb5_error_code check_fast_ccache(krb5_context ctx, const char *primary,
+                                         const char *realm,
                                          const char *keytab_name,
                                          TALLOC_CTX *mem_ctx,
                                          char **fast_ccname)
@@ -1260,7 +1261,7 @@ static krb5_error_code check_fast_ccache(krb5_context ctx, const char *realm,
         goto done;
     }
 
-    kerr = find_principal_in_keytab(ctx, keytab, NULL, realm, &client_princ);
+    kerr = find_principal_in_keytab(ctx, keytab, primary, realm, &client_princ);
     if (kerr != 0) {
         DEBUG(1, ("find_principal_in_keytab failed.\n"));
         goto done;
@@ -1322,6 +1323,11 @@ static int krb5_child_setup(struct krb5_req *kr, uint32_t offline)
     krb5_error_code kerr = 0;
     char *lifetime_str;
     char *use_fast_str;
+    char *tmp_str;
+    krb5_data *realm_data;
+    krb5_principal fast_princ_struct;
+    char *fast_principal = NULL;
+    const char *fast_principal_realm = NULL;
     krb5_deltat lifetime;
 
     kr->krb5_ctx = talloc_zero(kr, struct krb5_child_ctx);
@@ -1443,7 +1449,40 @@ static int krb5_child_setup(struct krb5_req *kr, uint32_t offline)
             DEBUG(9, ("Not using FAST.\n"));
         } else if (strcasecmp(use_fast_str, "try") == 0 ||
                    strcasecmp(use_fast_str, "demand") == 0) {
-            kerr = check_fast_ccache(kr->ctx, kr->krb5_ctx->realm, kr->keytab,
+
+            tmp_str = getenv(SSSD_KRB5_FAST_PRINCIPAL);
+            if (!tmp_str) {
+                fast_principal = NULL;
+                fast_principal_realm = kr->krb5_ctx->realm;
+            } else {
+                kerr = krb5_parse_name(kr->ctx, tmp_str, &fast_princ_struct);
+                if (kerr) {
+                    DEBUG(1, ("krb5_parse_name failed.\n"));
+                    goto failed;
+                }
+                kerr = krb5_unparse_name_flags(kr->ctx, fast_princ_struct,
+                                               KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+                                               &tmp_str);
+                if (kerr) {
+                    DEBUG(1, ("krb5_unparse_name_flags failed.\n"));
+                    goto failed;
+                }
+                fast_principal = talloc_strdup(kr, tmp_str);
+                if (!fast_principal) {
+                    DEBUG(1, ("talloc_strdup failed.\n"));
+                    kerr = KRB5KRB_ERR_GENERIC;
+                    goto failed;
+                }
+                free(tmp_str);
+                realm_data = krb5_princ_realm(kr->ctx, fast_princ_struct);
+                fast_principal_realm = talloc_asprintf(kr, "%.*s", realm_data->length, realm_data->data);
+                if (!fast_principal_realm) {
+                    DEBUG(1, ("talloc_asprintf failed.\n"));
+                    goto failed;
+                }
+            }
+
+            kerr = check_fast_ccache(kr->ctx, fast_principal, fast_principal_realm, kr->keytab,
                                      kr, &kr->fast_ccname);
             if (kerr != 0) {
                 DEBUG(1, ("check_fast_ccache failed.\n"));
diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
index 434fc7fbc85e23af1f766790cee4d862a3a2641c..ca37ba7d8c90ce4f94752dcef2ec6684d7fbf378 100644
--- a/src/providers/krb5/krb5_common.c
+++ b/src/providers/krb5/krb5_common.c
@@ -44,7 +44,8 @@ struct dp_option default_krb5_opts[] = {
     { "krb5_renewable_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "krb5_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "krb5_renew_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
-    { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }
+    { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "krb5_fast_principal", DP_OPT_STRING, NULL_STRING, NULL_STRING }
 };
 
 errno_t check_and_export_lifetime(struct dp_option *opts, const int opt_id,
@@ -109,6 +110,7 @@ errno_t check_and_export_options(struct dp_option *opts,
     const char *realm;
     const char *dummy;
     char *use_fast_str;
+    char *fast_principal;
 
     realm = dp_opt_get_cstring(opts, KRB5_REALM);
     if (realm == NULL) {
@@ -155,6 +157,14 @@ errno_t check_and_export_options(struct dp_option *opts,
             ret = setenv(SSSD_KRB5_USE_FAST, use_fast_str, 1);
             if (ret != EOK) {
                 DEBUG(2, ("setenv [%s] failed.\n", SSSD_KRB5_USE_FAST));
+            } else {
+                fast_principal = dp_opt_get_string(opts, KRB5_FAST_PRINCIPAL);
+                if (fast_principal != NULL) {
+                    ret = setenv(SSSD_KRB5_FAST_PRINCIPAL, fast_principal, 1);
+                    if (ret != EOK) {
+                        DEBUG(2, ("setenv [%s] failed.\n", SSSD_KRB5_FAST_PRINCIPAL));
+                    }
+                }
             }
         }
     }
diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
index c65ff74bbe9cd853f48ff83ad2a462837de9f9f0..d1a90c857f91122f058754c3f8ff116b0e44b642 100644
--- a/src/providers/krb5/krb5_common.h
+++ b/src/providers/krb5/krb5_common.h
@@ -38,6 +38,7 @@
 #define SSSD_KRB5_RENEWABLE_LIFETIME "SSSD_KRB5_RENEWABLE_LIFETIME"
 #define SSSD_KRB5_LIFETIME "SSSD_KRB5_LIFETIME"
 #define SSSD_KRB5_USE_FAST "SSSD_KRB5_USE_FAST"
+#define SSSD_KRB5_FAST_PRINCIPAL "SSSD_KRB5_FAST_PRINCIPAL"
 
 #define KDCINFO_TMPL PUBCONF_PATH"/kdcinfo.%s"
 #define KPASSWDINFO_TMPL PUBCONF_PATH"/kpasswdinfo.%s"
@@ -59,6 +60,7 @@ enum krb5_opts {
     KRB5_LIFETIME,
     KRB5_RENEW_INTERVAL,
     KRB5_USE_FAST,
+    KRB5_FAST_PRINCIPAL,
 
     KRB5_OPTS
 };
-- 
1.7.4.1

