From: Isaac Boukris Date: Fri, 27 Sep 2019 15:35:30 +0000 (+0300) Subject: krb5-mit: Enable S4U client support for MIT build X-Git-Tag: tevent-0.12.0~571 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea15ecfe4d5501189e78b927e4e496dd0f1a4ce0;p=thirdparty%2Fsamba.git krb5-mit: Enable S4U client support for MIT build Pair-Programmed-With: Andreas Schneider Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Reviewed-by: Stefan Metzmacher --- diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c index 99809ffea27..e9eaddac75d 100644 --- a/lib/krb5_wrap/krb5_samba.c +++ b/lib/krb5_wrap/krb5_samba.c @@ -2702,6 +2702,198 @@ krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx, return 0; } + +#else /* MIT */ + +static bool princ_compare_no_dollar(krb5_context ctx, + krb5_principal a, + krb5_principal b) +{ + krb5_principal mod = NULL; + bool cmp; + + if (a->length == 1 && b->length == 1 && + a->data[0].length != 0 && b->data[0].length != 0 && + a->data[0].data[a->data[0].length - 1] != + b->data[0].data[b->data[0].length - 1]) { + if (a->data[0].data[a->data[0].length - 1] == '$') { + mod = a; + mod->data[0].length--; + } else if (b->data[0].data[b->data[0].length - 1] == '$') { + mod = b; + mod->data[0].length--; + } + } + + cmp = krb5_principal_compare_flags(ctx, + a, + b, + KRB5_PRINCIPAL_COMPARE_CASEFOLD); + if (mod != NULL) { + mod->data[0].length++; + } + + return cmp; +} + +krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx, + krb5_ccache store_cc, + krb5_principal init_principal, + const char *init_password, + krb5_principal impersonate_principal, + const char *self_service, + const char *target_service, + krb5_get_init_creds_opt *krb_options, + time_t *expire_time, + time_t *kdc_time) +{ + krb5_error_code code; + krb5_principal self_princ = NULL; + krb5_principal target_princ = NULL; + krb5_creds *store_creds = NULL; + krb5_creds *s4u2self_creds = NULL; + krb5_creds *s4u2proxy_creds = NULL; + krb5_creds init_creds = {0}; + krb5_creds mcreds = {0}; + krb5_flags options = KRB5_GC_NO_STORE; + krb5_ccache tmp_cc; + bool s4u2proxy = false; + bool ok; + + code = krb5_cc_new_unique(ctx, "MEMORY", NULL, &tmp_cc); + if (code != 0) { + return code; + } + + code = krb5_get_init_creds_password(ctx, + &init_creds, + init_principal, + init_password, + NULL, + NULL, + 0, + NULL, + krb_options); + if (code != 0) { + goto done; + } + + code = krb5_cc_initialize(ctx, tmp_cc, init_creds.client); + if (code != 0) { + goto done; + } + + code = krb5_cc_store_cred(ctx, tmp_cc, &init_creds); + if (code != 0) { + goto done; + } + + /* + * Check if we also need S4U2Proxy or if S4U2Self is + * enough in order to get a ticket for the target. + */ + if (target_service == NULL) { + s4u2proxy = false; + } else if (strcmp(target_service, self_service) == 0) { + s4u2proxy = false; + } else { + s4u2proxy = true; + } + + code = krb5_parse_name(ctx, self_service, &self_princ); + if (code != 0) { + goto done; + } + + /* + * MIT lacks aliases support in S4U, for S4U2Self we require the tgt + * client and the request server to be the same principal name. + */ + ok = princ_compare_no_dollar(ctx, init_creds.client, self_princ); + if (!ok) { + code = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; + goto done; + } + + mcreds.client = impersonate_principal; + mcreds.server = init_creds.client; + + code = krb5_get_credentials_for_user(ctx, options, tmp_cc, &mcreds, + NULL, &s4u2self_creds); + if (code != 0) { + goto done; + } + + if (s4u2proxy) { + code = krb5_parse_name(ctx, target_service, &target_princ); + if (code != 0) { + goto done; + } + + mcreds.client = init_creds.client; + mcreds.server = target_princ; + mcreds.second_ticket = s4u2self_creds->ticket; + + code = krb5_get_credentials(ctx, options | + KRB5_GC_CONSTRAINED_DELEGATION, + tmp_cc, &mcreds, &s4u2proxy_creds); + if (code != 0) { + goto done; + } + + /* Check KDC support of S4U2Proxy extension */ + if (!krb5_principal_compare(ctx, s4u2self_creds->client, + s4u2proxy_creds->client)) { + code = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; + goto done; + } + + store_creds = s4u2proxy_creds; + } else { + store_creds = s4u2self_creds;; + + /* We need to save the ticket with the requested server name + * or the caller won't be able to find it in cache. */ + if (!krb5_principal_compare(ctx, self_princ, + store_creds->server)) { + krb5_free_principal(ctx, store_creds->server); + store_creds->server = NULL; + code = krb5_copy_principal(ctx, self_princ, + &store_creds->server); + if (code != 0) { + goto done; + } + } + } + + code = krb5_cc_initialize(ctx, store_cc, store_creds->client); + if (code != 0) { + goto done; + } + + code = krb5_cc_store_cred(ctx, store_cc, store_creds); + if (code != 0) { + goto done; + } + + if (expire_time) { + *expire_time = (time_t) store_creds->times.endtime; + } + + if (kdc_time) { + *kdc_time = (time_t) store_creds->times.starttime; + } + +done: + krb5_cc_destroy(ctx, tmp_cc); + krb5_free_cred_contents(ctx, &init_creds); + krb5_free_creds(ctx, s4u2self_creds); + krb5_free_creds(ctx, s4u2proxy_creds); + krb5_free_principal(ctx, self_princ); + krb5_free_principal(ctx, target_princ); + + return code; +} #endif #if !defined(HAVE_KRB5_MAKE_PRINCIPAL) && defined(HAVE_KRB5_BUILD_PRINCIPAL_ALLOC_VA) diff --git a/lib/krb5_wrap/krb5_samba.h b/lib/krb5_wrap/krb5_samba.h index a66b7465530..c8573f52bd9 100644 --- a/lib/krb5_wrap/krb5_samba.h +++ b/lib/krb5_wrap/krb5_samba.h @@ -252,7 +252,6 @@ krb5_error_code smb_krb5_kinit_password_ccache(krb5_context ctx, krb5_get_init_creds_opt *krb_options, time_t *expire_time, time_t *kdc_time); -#ifdef SAMBA4_USES_HEIMDAL krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx, krb5_ccache store_cc, krb5_principal init_principal, @@ -263,7 +262,6 @@ krb5_error_code smb_krb5_kinit_s4u2_ccache(krb5_context ctx, krb5_get_init_creds_opt *krb_options, time_t *expire_time, time_t *kdc_time); -#endif #if defined(HAVE_KRB5_MAKE_PRINCIPAL) #define smb_krb5_make_principal krb5_make_principal diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c index 544d9d853cc..c14d8c72d8c 100644 --- a/source4/auth/kerberos/kerberos_util.c +++ b/source4/auth/kerberos/kerberos_util.c @@ -234,9 +234,7 @@ done: { krb5_error_code ret; const char *password; -#ifdef SAMBA4_USES_HEIMDAL const char *self_service; -#endif const char *target_service; time_t kdc_time = 0; krb5_principal princ; @@ -268,9 +266,7 @@ done: return ret; } -#ifdef SAMBA4_USES_HEIMDAL self_service = cli_credentials_get_self_service(credentials); -#endif target_service = cli_credentials_get_target_service(credentials); password = cli_credentials_get_password(credentials); @@ -331,7 +327,6 @@ done: #endif if (password) { if (impersonate_principal) { -#ifdef SAMBA4_USES_HEIMDAL ret = smb_krb5_kinit_s4u2_ccache(smb_krb5_context->krb5_context, ccache, princ, @@ -342,12 +337,6 @@ done: krb_options, NULL, &kdc_time); -#else - talloc_free(mem_ctx); - (*error_string) = "INTERNAL error: s4u2 ops " - "are not supported with MIT build yet"; - return EINVAL; -#endif } else { ret = smb_krb5_kinit_password_ccache(smb_krb5_context->krb5_context, ccache,