From b24a7f6ed6868bd76a52c74ac302d094eb8f070e Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 25 Mar 2013 17:41:19 +0100 Subject: [PATCH] Allow usage of enterprise principals Enterprise principals are currently most useful for the AD provider and hence enabled here by default while for the other Kerberos based authentication providers they are disabled by default. If additional UPN suffixes are configured for the AD domain the user principal stored in the AD LDAP server might not contain the real Kerberos realm of the AD domain but one of the additional suffixes which might be completely randomly chooses, e.g. are not related to any existing DNS domain. This make it hard for a client to figure out the right KDC to send requests to. To get around this enterprise principals (see http://tools.ietf.org/html/rfc6806 for details) were introduced. Basically a default realm is added to the principal so that the Kerberos client libraries at least know where to send the request to. It is not in the responsibility of the KDC to either handle the request itself, return a client referral if he thinks a different KDC can handle the request or return and error. This feature is also use to allow authentication in AD environments with cross forest trusts. Fixes https://fedorahosted.org/sssd/ticket/1842 --- src/config/SSSDConfig/__init__.py.in | 1 + src/config/SSSDConfigTest.py | 9 ++++++--- src/config/etc/sssd.api.d/sssd-ad.conf | 1 + src/config/etc/sssd.api.d/sssd-ipa.conf | 1 + src/config/etc/sssd.api.d/sssd-krb5.conf | 1 + src/external/krb5.m4 | 1 + src/man/sssd-ad.5.xml | 19 +++++++++++++++++++ src/man/sssd-krb5.5.xml | 15 +++++++++++++++ src/providers/ad/ad_opts.h | 1 + src/providers/ipa/ipa_opts.h | 1 + src/providers/krb5/krb5_child.c | 14 +++++++++++--- src/providers/krb5/krb5_child_handler.c | 6 +++++- src/providers/krb5/krb5_common.h | 1 + src/providers/krb5/krb5_opts.h | 1 + src/util/sss_krb5.c | 19 +++++++++++++++++++ src/util/sss_krb5.h | 9 +++++++++ 16 files changed, 93 insertions(+), 7 deletions(-) diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index 1f997f2..f603a21 100644 --- a/src/config/SSSDConfig/__init__.py.in +++ b/src/config/SSSDConfig/__init__.py.in @@ -169,6 +169,7 @@ option_strings = { 'krb5_use_fast' : _("Enables FAST"), 'krb5_fast_principal' : _("Selects the principal to use for FAST"), 'krb5_canonicalize' : _("Enables principal canonicalization"), + 'krb5_use_enterprise_principal' : _("Enables enterprise principals"), # [provider/krb5/chpass] 'krb5_kpasswd' : _('Server where the change password service is running if not on the KDC'), diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py index 8f003f5..6ae458b 100755 --- a/src/config/SSSDConfigTest.py +++ b/src/config/SSSDConfigTest.py @@ -603,7 +603,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'krb5_renew_interval', 'krb5_use_fast', 'krb5_fast_principal', - 'krb5_canonicalize']) + 'krb5_canonicalize', + 'krb5_use_enterprise_principal']) options = domain.list_options() @@ -761,7 +762,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'krb5_renew_interval', 'krb5_use_fast', 'krb5_fast_principal', - 'krb5_canonicalize'] + 'krb5_canonicalize', + 'krb5_use_enterprise_principal'] self.assertTrue(type(options) == dict, "Options should be a dictionary") @@ -945,7 +947,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): 'krb5_renew_interval', 'krb5_use_fast', 'krb5_fast_principal', - 'krb5_canonicalize']) + 'krb5_canonicalize', + 'krb5_use_enterprise_principal']) options = domain.list_options() diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf index dbee270..4c25717 100644 --- a/src/config/etc/sssd.api.d/sssd-ad.conf +++ b/src/config/etc/sssd.api.d/sssd-ad.conf @@ -118,6 +118,7 @@ krb5_lifetime = str, None, false krb5_renew_interval = str, None, false krb5_use_fast = str, None, false krb5_fast_principal = str, None, false +krb5_use_enterprise_principal = bool, None, false [provider/ad/access] diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf index 04855d6..e88e32b 100644 --- a/src/config/etc/sssd.api.d/sssd-ipa.conf +++ b/src/config/etc/sssd.api.d/sssd-ipa.conf @@ -140,6 +140,7 @@ krb5_lifetime = str, None, false krb5_renew_interval = str, None, false krb5_use_fast = str, None, false krb5_fast_principal = str, None, false +krb5_use_enterprise_principal = bool, None, false [provider/ipa/access] ipa_hbac_refresh = int, None, false diff --git a/src/config/etc/sssd.api.d/sssd-krb5.conf b/src/config/etc/sssd.api.d/sssd-krb5.conf index 6534282..89d16d7 100644 --- a/src/config/etc/sssd.api.d/sssd-krb5.conf +++ b/src/config/etc/sssd.api.d/sssd-krb5.conf @@ -19,6 +19,7 @@ krb5_renew_interval = str, None, false krb5_use_fast = str, None, false krb5_fast_principal = str, None, false krb5_canonicalize = bool, None, false +krb5_use_enterprise_principal = bool, None, false [provider/krb5/access] diff --git a/src/external/krb5.m4 b/src/external/krb5.m4 index 56c6484..bdbd71b 100644 --- a/src/external/krb5.m4 +++ b/src/external/krb5.m4 @@ -51,6 +51,7 @@ AC_CHECK_FUNCS([krb5_get_init_creds_opt_alloc krb5_get_error_message \ krb5_get_init_creds_opt_set_fast_flags \ krb5_get_init_creds_opt_set_canonicalize \ krb5_get_init_creds_opt_set_responder \ + krb5_parse_name_flags \ krb5_unparse_name_flags \ krb5_get_init_creds_opt_set_change_password_prompt \ krb5_free_keytab_entry_contents \ diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml index 6ab133d..3b2b0bc 100644 --- a/src/man/sssd-ad.5.xml +++ b/src/man/sssd-ad.5.xml @@ -129,6 +129,25 @@ ldap_id_mapping = False + + + krb5_use_enterprise_principal (boolean) + + + Specifies if the user principal should be treated + as enterprise principal. See section 5 of RFC 6806 + for more details about enterprise principals. + + + + Default: true + + + Note that this default differs from the + traditional Kerberos provider back end. + + + diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml index 00881b8..731d772 100644 --- a/src/man/sssd-krb5.5.xml +++ b/src/man/sssd-krb5.5.xml @@ -451,6 +451,21 @@ + + krb5_use_enterprise_principal (boolean) + + + Specifies if the user principal should be treated + as enterprise principal. See section 5 of RFC 6806 + for more details about enterprise principals. + + + + Default: false (AD provide: true) + + + + diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h index 09aee7e..4b87e0c 100644 --- a/src/providers/ad/ad_opts.h +++ b/src/providers/ad/ad_opts.h @@ -142,6 +142,7 @@ struct dp_option ad_def_krb5_opts[] = { { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "krb5_fast_principal", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "krb5_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "krb5_use_enterprise_principal", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, DP_OPTION_TERMINATOR }; diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h index a3d0210..6adbdd9 100644 --- a/src/providers/ipa/ipa_opts.h +++ b/src/providers/ipa/ipa_opts.h @@ -264,6 +264,7 @@ struct dp_option ipa_def_krb5_opts[] = { { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "krb5_fast_principal", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "krb5_canonicalize", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + { "krb5_use_enterprise_principal", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, DP_OPTION_TERMINATOR }; diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index a747758..1fc25a0 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -54,6 +54,7 @@ struct krb5_req { char *keytab; bool validate; bool upn_from_different_realm; + bool use_enterprise_princ; char *fast_ccname; const char *upn; @@ -1537,6 +1538,7 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, uint32_t len; uint32_t validate; uint32_t different_realm; + uint32_t use_enterprise_princ; struct pam_data *pd; errno_t ret; @@ -1559,6 +1561,8 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, SAFEALIGN_COPY_UINT32_CHECK(offline, buf + p, size, &p); SAFEALIGN_COPY_UINT32_CHECK(&different_realm, buf + p, size, &p); kr->upn_from_different_realm = (different_realm == 0) ? false : true; + SAFEALIGN_COPY_UINT32_CHECK(&use_enterprise_princ, buf + p, size, &p); + kr->use_enterprise_princ = (use_enterprise_princ == 0) ? false : true; SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); if ((p + len ) > size) return EINVAL; kr->upn = talloc_strndup(pd, (char *)(buf + p), len); @@ -1566,9 +1570,11 @@ static errno_t unpack_buffer(uint8_t *buf, size_t size, p += len; DEBUG(SSSDBG_CONF_SETTINGS, - ("cmd [%d] uid [%llu] gid [%llu] validate [%s] offline [%s] " - "UPN [%s]\n", pd->cmd, (unsigned long long) kr->uid, + ("cmd [%d] uid [%llu] gid [%llu] validate [%s] " + "enterprise principal [%s] offline [%s] UPN [%s]\n", + pd->cmd, (unsigned long long) kr->uid, (unsigned long long) kr->gid, kr->validate ? "true" : "false", + kr->use_enterprise_princ ? "true" : "false", *offline ? "true" : "false", kr->upn ? kr->upn : "none")); if (pd->cmd == SSS_PAM_AUTHENTICATE || @@ -1900,6 +1906,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) char *lifetime_str; char *use_fast_str; krb5_deltat lifetime; + int parse_flags; kr->realm = getenv(SSSD_KRB5_REALM); if (kr->realm == NULL) { @@ -1924,7 +1931,8 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) } } - kerr = krb5_parse_name(kr->ctx, kr->upn, &kr->princ); + parse_flags = kr->use_enterprise_princ ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0; + kerr = sss_krb5_parse_name_flags(kr->ctx, kr->upn, parse_flags, &kr->princ); if (kerr != 0) { KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); return kerr; diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c index 8ff6513..0b8cd6b 100644 --- a/src/providers/krb5/krb5_child_handler.c +++ b/src/providers/krb5/krb5_child_handler.c @@ -130,6 +130,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, const char *keytab; uint32_t validate; uint32_t different_realm; + uint32_t use_enterprise_principal; size_t username_len = 0; errno_t ret; @@ -141,6 +142,8 @@ static errno_t create_send_buffer(struct krb5child_req *kr, validate = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ? 1 : 0; different_realm = kr->upn_from_different_realm ? 1 : 0; + use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts, + KRB5_USE_ENTERPRISE_PRINCIPAL) ? 1 : 0; buf = talloc(kr, struct io_buffer); if (buf == NULL) { @@ -148,7 +151,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, return ENOMEM; } - buf->size = 7*sizeof(uint32_t) + strlen(kr->upn); + buf->size = 8*sizeof(uint32_t) + strlen(kr->upn); if (kr->pd->cmd == SSS_PAM_AUTHENTICATE || kr->pd->cmd == SSS_CMD_RENEW || @@ -182,6 +185,7 @@ static errno_t create_send_buffer(struct krb5child_req *kr, SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp); SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp); SAFEALIGN_COPY_UINT32(&buf->data[rp], &different_realm, &rp); + SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp); SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->upn), &rp); safealign_memcpy(&buf->data[rp], kr->upn, strlen(kr->upn), &rp); diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h index 1303529..8504936 100644 --- a/src/providers/krb5/krb5_common.h +++ b/src/providers/krb5/krb5_common.h @@ -65,6 +65,7 @@ enum krb5_opts { KRB5_USE_FAST, KRB5_FAST_PRINCIPAL, KRB5_CANONICALIZE, + KRB5_USE_ENTERPRISE_PRINCIPAL, KRB5_OPTS }; diff --git a/src/providers/krb5/krb5_opts.h b/src/providers/krb5/krb5_opts.h index 8ac2953..c8e6478 100644 --- a/src/providers/krb5/krb5_opts.h +++ b/src/providers/krb5/krb5_opts.h @@ -43,6 +43,7 @@ struct dp_option default_krb5_opts[] = { { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "krb5_fast_principal", DP_OPT_STRING, NULL_STRING, NULL_STRING }, { "krb5_canonicalize", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, + { "krb5_use_enterprise_principal", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, DP_OPTION_TERMINATOR }; diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c index 789b37d..b42000e 100644 --- a/src/util/sss_krb5.c +++ b/src/util/sss_krb5.c @@ -766,6 +766,25 @@ sss_krb5_component_length_quoted(const krb5_data *src, int flags) krb5_error_code +sss_krb5_parse_name_flags(krb5_context context, const char *name, int flags, + krb5_principal *principal) +{ +#ifdef HAVE_KRB5_PARSE_NAME_FLAGS + return krb5_parse_name_flags(context, name, flags, principal); +#else + if (flags != 0) { + DEBUG(SSSDBG_MINOR_FAILURE, ("krb5_parse_name_flags not available on " \ + "this plattform, names are parsed " \ + "without flags. Some features like " \ + "enterprise principals might not work " \ + "as expected.\n")); + } + + return krb5_parse_name(context, name, principal); +#endif +} + +krb5_error_code sss_krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal, int flags, char **name) { diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h index aaba940..3b98f3d 100644 --- a/src/util/sss_krb5.h +++ b/src/util/sss_krb5.h @@ -122,6 +122,15 @@ krb5_error_code KRB5_CALLCONV sss_krb5_get_init_creds_opt_set_fast_flags( #endif +#ifndef HAVE_KRB5_PARSE_NAME_FLAGS +#define KRB5_PRINCIPAL_PARSE_NO_REALM 0x1 +#define KRB5_PRINCIPAL_PARSE_REQUIRE_REALM 0x2 +#define KRB5_PRINCIPAL_PARSE_ENTERPRISE 0x4 +#endif +krb5_error_code +sss_krb5_parse_name_flags(krb5_context context, const char *name, int flags, + krb5_principal *principal); + #ifndef HAVE_KRB5_UNPARSE_NAME_FLAGS #define KRB5_PRINCIPAL_UNPARSE_SHORT 0x1 #define KRB5_PRINCIPAL_UNPARSE_NO_REALM 0x2 -- 1.7.7.6