summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/auth/kerberos/kerberos.c134
-rw-r--r--source4/auth/kerberos/kerberos.h4
-rw-r--r--source4/auth/kerberos/kerberos_util.c1
3 files changed, 134 insertions, 5 deletions
diff --git a/source4/auth/kerberos/kerberos.c b/source4/auth/kerberos/kerberos.c
index fa8c64b93e..d32559ed81 100644
--- a/source4/auth/kerberos/kerberos.c
+++ b/source4/auth/kerberos/kerberos.c
@@ -81,13 +81,16 @@
The impersonate_principal is the principal if NULL, or the principal to impersonate
- The target_service defaults to the krbtgt if NULL, but could be kpasswd/realm or the local service (if we are doing s4u2self)
+ The self_service, should be the local service (for S4U2Self if impersonate_principal is given).
+
+ The target_service defaults to the krbtgt if NULL, but could be kpasswd/realm or a remote service (for S4U2Proxy)
*/
krb5_error_code kerberos_kinit_password_cc(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)
@@ -96,13 +99,21 @@
krb5_get_creds_opt options;
krb5_principal store_principal;
krb5_creds store_creds;
- const char *self_service = target_service;
krb5_creds *s4u2self_creds;
+ Ticket s4u2self_ticket;
+ size_t s4u2self_ticketlen;
+ krb5_creds *s4u2proxy_creds;
krb5_principal self_princ;
+ bool s4u2proxy;
+ krb5_principal target_princ;
krb5_ccache tmp_cc;
const char *self_realm;
krb5_principal blacklist_principal = NULL;
+ if (impersonate_principal && self_service == NULL) {
+ return EINVAL;
+ }
+
/*
* If we are not impersonating, then get this ticket for the
* target service, otherwise a krbtgt, and get the next ticket
@@ -168,6 +179,18 @@
krb5_free_cred_contents(ctx, &store_creds);
/*
+ * 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;
+ }
+
+ /*
* For S4U2Self we need our own service principal,
* which belongs to our own realm (available on
* our client principal).
@@ -197,6 +220,14 @@
return code;
}
+ if (s4u2proxy) {
+ /*
+ * If we want S4U2Proxy, we need the forwardable flag
+ * on the S4U2Self ticket.
+ */
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
+ }
+
code = krb5_get_creds_opt_set_impersonate(ctx, options,
impersonate_principal);
if (code != 0) {
@@ -211,6 +242,101 @@
self_princ, &s4u2self_creds);
krb5_get_creds_opt_free(ctx, options);
krb5_free_principal(ctx, self_princ);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ if (!s4u2proxy) {
+ krb5_cc_destroy(ctx, tmp_cc);
+
+ /*
+ * Now make sure we store the impersonated principal
+ * and creds instead of the TGT related stuff
+ * in the krb5_ccache of the caller.
+ */
+ code = krb5_copy_creds_contents(ctx, s4u2self_creds,
+ &store_creds);
+ krb5_free_creds(ctx, s4u2self_creds);
+ if (code != 0) {
+ return code;
+ }
+
+ /*
+ * It's important to store the principal the KDC
+ * returned, as otherwise the caller would not find
+ * the S4U2Self ticket in the krb5_ccache lookup.
+ */
+ store_principal = store_creds.client;
+ goto store;
+ }
+
+ /*
+ * We are trying S4U2Proxy:
+ *
+ * We need the ticket from the S4U2Self step
+ * and our TGT in order to get the delegated ticket.
+ */
+ code = decode_Ticket((const uint8_t *)s4u2self_creds->ticket.data,
+ s4u2self_creds->ticket.length,
+ &s4u2self_ticket,
+ &s4u2self_ticketlen);
+ krb5_free_creds(ctx, s4u2self_creds);
+ if (code != 0) {
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ /*
+ * For S4U2Proxy we also got a target service principal,
+ * which also belongs to our own realm (available on
+ * our client principal).
+ */
+ code = krb5_parse_name(ctx, target_service, &target_princ);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_principal_set_realm(ctx, target_princ, self_realm);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds_opt_alloc(ctx, &options);
+ if (code != 0) {
+ free_Ticket(&s4u2self_ticket);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_FORWARDABLE);
+ krb5_get_creds_opt_set_options(ctx, options, KRB5_GC_CONSTRAINED_DELEGATION);
+
+ code = krb5_get_creds_opt_set_ticket(ctx, options, &s4u2self_ticket);
+ free_Ticket(&s4u2self_ticket);
+ if (code != 0) {
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, target_princ);
+ krb5_free_principal(ctx, blacklist_principal);
+ krb5_cc_destroy(ctx, tmp_cc);
+ return code;
+ }
+
+ code = krb5_get_creds(ctx, options, tmp_cc,
+ target_princ, &s4u2proxy_creds);
+ krb5_get_creds_opt_free(ctx, options);
+ krb5_free_principal(ctx, target_princ);
krb5_cc_destroy(ctx, tmp_cc);
if (code != 0) {
krb5_free_principal(ctx, blacklist_principal);
@@ -222,9 +348,9 @@
* and creds instead of the TGT related stuff
* in the krb5_ccache of the caller.
*/
- code = krb5_copy_creds_contents(ctx, s4u2self_creds,
+ code = krb5_copy_creds_contents(ctx, s4u2proxy_creds,
&store_creds);
- krb5_free_creds(ctx, s4u2self_creds);
+ krb5_free_creds(ctx, s4u2proxy_creds);
if (code != 0) {
krb5_free_principal(ctx, blacklist_principal);
return code;
diff --git a/source4/auth/kerberos/kerberos.h b/source4/auth/kerberos/kerberos.h
index c712569e5d..31794b8e03 100644
--- a/source4/auth/kerberos/kerberos.h
+++ b/source4/auth/kerberos/kerberos.h
@@ -97,7 +97,9 @@ krb5_error_code ads_krb5_mk_req(krb5_context context,
bool get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt);
krb5_error_code kerberos_kinit_password_cc(krb5_context ctx, krb5_ccache cc,
krb5_principal principal, const char *password,
- krb5_principal impersonate_principal, const char *target_service,
+ 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 kerberos_kinit_keyblock_cc(krb5_context ctx, krb5_ccache cc,
diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c
index 9cef977306..9a48e95c6d 100644
--- a/source4/auth/kerberos/kerberos_util.c
+++ b/source4/auth/kerberos/kerberos_util.c
@@ -408,6 +408,7 @@ krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx,
princ, password,
impersonate_principal,
self_service,
+ target_service,
krb_options,
NULL, &kdc_time);
} else if (impersonate_principal) {