diff options
author | Greg Hudson <ghudson@mit.edu> | 2009-11-14 04:46:30 +0000 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2009-11-14 04:46:30 +0000 |
commit | 0524889196c42d81dcc4c74277522b46f987cabb (patch) | |
tree | 9f906eb1a4a32346ae94837c4fe199410e2dd10f /src/kdc/kdc_authdata.c | |
parent | 26044e2a3c3104b9c3f32a6ae58145e7e6394672 (diff) | |
download | krb5-0524889196c42d81dcc4c74277522b46f987cabb.tar.gz krb5-0524889196c42d81dcc4c74277522b46f987cabb.tar.xz krb5-0524889196c42d81dcc4c74277522b46f987cabb.zip |
Constrained delegation without PAC support
Merge Luke's users/lhoward/s4u2proxy branch to trunk. Implements a
Heimdal-compatible mechanism for allowing constrained delegation
without back-end support for PACs. Back-end support exists in LDAP
only (via a new krbAllowedToDelegateTo attribute), not DB2.
ticket: 6580
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23160 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kdc/kdc_authdata.c')
-rw-r--r-- | src/kdc/kdc_authdata.c | 684 |
1 files changed, 625 insertions, 59 deletions
diff --git a/src/kdc/kdc_authdata.c b/src/kdc/kdc_authdata.c index 3cef2d714..aa55ef455 100644 --- a/src/kdc/kdc_authdata.c +++ b/src/kdc/kdc_authdata.c @@ -3,7 +3,7 @@ * kdc/kdc_authdata.c * * Copyright (C) 2007 Apple Inc. All Rights Reserved. - * Copyright (C) 2008 by the Massachusetts Institute of Technology. + * Copyright (C) 2008, 2009 by the Massachusetts Institute of Technology. * * Export of this software from the United States of America may * require a specific license from the United States Government. @@ -36,7 +36,7 @@ #include <syslog.h> #include <assert.h> -#include "../include/krb5/authdata_plugin.h" +#include <krb5/authdata_plugin.h> #if TARGET_OS_MAC static const char *objdirs[] = { KRB5_AUTHDATA_PLUGIN_BUNDLE_DIR, @@ -70,7 +70,6 @@ typedef krb5_error_code (*init_proc) typedef void (*fini_proc) (krb5_context, void *); -/* Internal authdata system for copying TGS-REQ authdata to ticket */ static krb5_error_code handle_request_authdata (krb5_context context, unsigned int flags, @@ -86,7 +85,6 @@ static krb5_error_code handle_request_authdata krb5_enc_tkt_part *enc_tkt_request, krb5_enc_tkt_part *enc_tkt_reply); -/* Internal authdata system for handling KDC-issued authdata */ static krb5_error_code handle_tgt_authdata (krb5_context context, unsigned int flags, @@ -102,6 +100,27 @@ static krb5_error_code handle_tgt_authdata krb5_enc_tkt_part *enc_tkt_request, krb5_enc_tkt_part *enc_tkt_reply); +static krb5_error_code +handle_kdb_authdata(krb5_context context, unsigned int flags, + krb5_db_entry *client, krb5_db_entry *server, + krb5_db_entry *krbtgt, krb5_keyblock *client_key, + krb5_keyblock *server_key, krb5_keyblock *krbtgt_key, + krb5_data *req_pkt, krb5_kdc_req *request, + krb5_const_principal for_user_princ, + krb5_enc_tkt_part *enc_tkt_request, + krb5_enc_tkt_part *enc_tkt_reply); + +static krb5_error_code +handle_signedpath_authdata(krb5_context context, unsigned int flags, + krb5_db_entry *client, krb5_db_entry *server, + krb5_db_entry *krbtgt, krb5_keyblock *client_key, + krb5_keyblock *server_key, + krb5_keyblock *krbtgt_key, + krb5_data *req_pkt, krb5_kdc_req *request, + krb5_const_principal for_user_princ, + krb5_enc_tkt_part *enc_tkt_request, + krb5_enc_tkt_part *enc_tkt_reply); + typedef struct _krb5_authdata_systems { const char *name; #define AUTHDATA_SYSTEM_UNKNOWN -1 @@ -109,6 +128,7 @@ typedef struct _krb5_authdata_systems { #define AUTHDATA_SYSTEM_V2 2 int type; #define AUTHDATA_FLAG_CRITICAL 0x1 +#define AUTHDATA_FLAG_PRE_PLUGIN 0x2 int flags; void *plugin_context; init_proc init; @@ -120,10 +140,46 @@ typedef struct _krb5_authdata_systems { } krb5_authdata_systems; static krb5_authdata_systems static_authdata_systems[] = { - { "tgs_req", AUTHDATA_SYSTEM_V2, AUTHDATA_FLAG_CRITICAL, - NULL, NULL, NULL, { handle_request_authdata } }, - { "tgt", AUTHDATA_SYSTEM_V2, AUTHDATA_FLAG_CRITICAL, - NULL, NULL, NULL, { handle_tgt_authdata } }, + { + /* Propagate client-submitted authdata */ + "tgs_req", + AUTHDATA_SYSTEM_V2, + AUTHDATA_FLAG_CRITICAL | AUTHDATA_FLAG_PRE_PLUGIN, + NULL, + NULL, + NULL, + { handle_request_authdata } + }, + { + /* Propagate TGT authdata */ + "tgt", + AUTHDATA_SYSTEM_V2, + AUTHDATA_FLAG_CRITICAL, + NULL, + NULL, + NULL, + { handle_tgt_authdata } + }, + { + /* Verify and issue KDB issued authdata */ + "kdb", + AUTHDATA_SYSTEM_V2, + AUTHDATA_FLAG_CRITICAL, + NULL, + NULL, + NULL, + { handle_kdb_authdata } + }, + { + /* Verify and issue signed delegation path */ + "signedpath", + AUTHDATA_SYSTEM_V2, + AUTHDATA_FLAG_CRITICAL, + NULL, + NULL, + NULL, + { handle_signedpath_authdata } + } }; static krb5_authdata_systems *authdata_systems; @@ -204,6 +260,19 @@ load_authdata_plugins(krb5_context context) k = 0; + /* + * Special case to ensure that handle_request_authdata is + * first in the list, to make unenc_authdata available to + * plugins. + */ + for (i = 0; i < (sizeof(static_authdata_systems) / + sizeof(static_authdata_systems[0])); i++) { + if ((static_authdata_systems[i].flags & AUTHDATA_FLAG_PRE_PLUGIN) == 0) + continue; + assert(static_authdata_systems[i].init == NULL); + authdata_systems[k++] = static_authdata_systems[i]; + } + /* Add dynamically loaded V2 plugins */ if (authdata_plugins_ftables_v2 != NULL) { struct krb5plugin_authdata_server_ftable_v2 *ftable; @@ -280,20 +349,13 @@ load_authdata_plugins(krb5_context context) } } - /* Add the locally-supplied mechanisms to the dynamic list first. */ for (i = 0; i < sizeof(static_authdata_systems) / sizeof(static_authdata_systems[0]); i++) { - authdata_systems[k] = static_authdata_systems[i]; - /* Try to initialize the authdata system. If it fails, we'll remove it - * from the list of systems we'll be using. */ - server_init_proc = static_authdata_systems[i].init; - if ((server_init_proc != NULL) && - ((*server_init_proc)(context, &authdata_systems[k].plugin_context) != 0)) { - memset(&authdata_systems[k], 0, sizeof(authdata_systems[k])); + if (static_authdata_systems[i].flags & AUTHDATA_FLAG_PRE_PLUGIN) continue; - } - k++; + assert(static_authdata_systems[i].init == NULL); + authdata_systems[k++] = static_authdata_systems[i]; } n_authdata_systems = k; @@ -331,12 +393,106 @@ unload_authdata_plugins(krb5_context context) return 0; } -/* Merge authdata. If copy == 0, in_authdata is invalid on return */ +/* + * Returns TRUE if authdata should be filtered when copying from + * untrusted authdata. + */ +static krb5_boolean +is_kdc_issued_authdatum (krb5_context context, + krb5_authdata *authdata, + krb5_authdatatype desired_type) +{ + krb5_boolean ret = FALSE; + krb5_authdatatype ad_type; + unsigned int i, count = 0; + krb5_authdatatype *ad_types = NULL; + + if (authdata->ad_type == KRB5_AUTHDATA_IF_RELEVANT) { + if (krb5int_get_authdata_containee_types(context, + authdata, + &count, + &ad_types) != 0) + goto cleanup; + } else { + ad_type = authdata->ad_type; + count = 1; + ad_types = &ad_type; + } + + for (i = 0; i < count; i++) { + switch (ad_types[i]) { + case KRB5_AUTHDATA_SIGNTICKET: + case KRB5_AUTHDATA_KDC_ISSUED: + case KRB5_AUTHDATA_WIN2K_PAC: + ret = desired_type ? (desired_type == ad_types[i]) : TRUE; + break; + default: + ret = FALSE; + break; + } + if (ret) + break; + } + +cleanup: + if (authdata->ad_type == KRB5_AUTHDATA_IF_RELEVANT && + ad_types != NULL) + free(ad_types); + + return ret; +} + +static krb5_boolean +has_kdc_issued_authdata (krb5_context context, + krb5_authdata **authdata, + krb5_authdatatype desired_type) +{ + int i; + krb5_boolean ret = FALSE; + + if (authdata != NULL) { + for (i = 0; authdata[i] != NULL; i++) { + if (is_kdc_issued_authdatum(context, authdata[i], desired_type)) { + ret = TRUE; + break; + } + } + } + + return ret; +} + +static krb5_boolean +has_mandatory_for_kdc_authdata (krb5_context context, + krb5_authdata **authdata) +{ + int i; + krb5_boolean ret = FALSE; + + if (authdata != NULL) { + for (i = 0; authdata[i] != NULL; i++) { + if (authdata[0]->ad_type == KRB5_AUTHDATA_MANDATORY_FOR_KDC) { + ret = TRUE; + break; + } + } + } + + return ret; +} + +/* + * Merge authdata. + * + * If copy is FALSE, in_authdata is invalid on successful return. + * If ignore_kdc_issued is TRUE, KDC-issued authdata is not copied. + */ static krb5_error_code merge_authdata (krb5_context context, krb5_authdata **in_authdata, krb5_authdata ***out_authdata, - krb5_boolean copy) + krb5_boolean copy, + krb5_boolean ignore_kdc_issued) { size_t i, nadata = 0; krb5_authdata **authdata = *out_authdata; @@ -356,7 +512,7 @@ merge_authdata (krb5_context context, authdata = (krb5_authdata **)calloc(i + 1, sizeof(krb5_authdata *)); } else { authdata = (krb5_authdata **)realloc(authdata, - ((nadata + i + 1) * sizeof(krb5_authdata *))); + ((nadata + i + 1) * sizeof(krb5_authdata *))); } if (authdata == NULL) return ENOMEM; @@ -372,13 +528,24 @@ merge_authdata (krb5_context context, in_authdata = tmp; } - for (i = 0; in_authdata[i] != NULL; i++) - authdata[nadata + i] = in_authdata[i]; + for (i = 0; in_authdata[i] != NULL; i++) { + if (ignore_kdc_issued && + is_kdc_issued_authdatum(context, in_authdata[i], 0)) { + free(in_authdata[i]->contents); + free(in_authdata[i]); + } else + authdata[nadata + i] = in_authdata[i]; + } authdata[nadata + i] = NULL; free(in_authdata); + if (authdata[0] == NULL) { + free(authdata); + authdata = NULL; + } + *out_authdata = authdata; return 0; @@ -453,13 +620,19 @@ handle_request_authdata (krb5_context context, free(scratch.data); - code = merge_authdata(context, request->unenc_authdata, - &enc_tkt_reply->authorization_data, TRUE /* copy */); + if (has_mandatory_for_kdc_authdata(context, request->unenc_authdata)) + return KRB5KDC_ERR_POLICY; + + code = merge_authdata(context, + request->unenc_authdata, + &enc_tkt_reply->authorization_data, + TRUE, /* copy */ + TRUE); /* ignore_kdc_issued */ return code; } -/* Handle backend-managed authorization data */ +/* Handle copying TGT authorization data into reply */ static krb5_error_code handle_tgt_authdata (krb5_context context, unsigned int flags, @@ -475,6 +648,36 @@ handle_tgt_authdata (krb5_context context, krb5_enc_tkt_part *enc_tkt_request, krb5_enc_tkt_part *enc_tkt_reply) { + if (request->msg_type != KRB5_TGS_REQ) + return 0; + + if (has_mandatory_for_kdc_authdata(context, + enc_tkt_request->authorization_data)) + return KRB5KDC_ERR_POLICY; + + return merge_authdata(context, + enc_tkt_request->authorization_data, + &enc_tkt_reply->authorization_data, + TRUE, /* copy */ + TRUE); /* ignore_kdc_issued */ +} + +/* Handle backend-managed authorization data */ +static krb5_error_code +handle_kdb_authdata (krb5_context context, + unsigned int flags, + krb5_db_entry *client, + krb5_db_entry *server, + krb5_db_entry *krbtgt, + krb5_keyblock *client_key, + krb5_keyblock *server_key, + krb5_keyblock *krbtgt_key, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_const_principal for_user_princ, + krb5_enc_tkt_part *enc_tkt_request, + krb5_enc_tkt_part *enc_tkt_reply) +{ krb5_error_code code; krb5_authdata **db_authdata = NULL; krb5_boolean tgs_req = (request->msg_type == KRB5_TGS_REQ); @@ -489,12 +692,6 @@ handle_tgt_authdata (krb5_context context, * or protocol transition/constrained delegation was used, or, in * the AS-REQ case, if the pre-auth data indicated the PAC should * be present. - * - * We permit sign_authorization_data() to return a krb5_db_entry - * representing the principal associated with the authorization - * data, in case that principal is not local to our realm and we - * need to perform additional checks (such as disabling delegation - * for cross-realm protocol transition below). */ if (tgs_req) { assert(enc_tkt_request != NULL); @@ -522,16 +719,6 @@ handle_tgt_authdata (krb5_context context, else actual_client = enc_tkt_reply->client; - /* - * If the backend does not implement the sign authdata method, then - * just copy the TGT authorization data into the reply, except for - * the constrained delegation case (which requires special handling - * because it will promote untrusted auth data to KDC issued auth - * data; this requires backend-specific code) - * - * Presently this interface does not support using request auth data - * to influence (eg. possibly restrict) the reply auth data. - */ code = sign_db_authdata(context, flags, actual_client, @@ -545,26 +732,16 @@ handle_tgt_authdata (krb5_context context, tgs_req ? enc_tkt_request->authorization_data : NULL, enc_tkt_reply->session, &db_authdata); - if (code == KRB5_KDB_DBTYPE_NOSUP) { - assert(db_authdata == NULL); - - if (isflagset(flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) - return KRB5KDC_ERR_POLICY; - - if (tgs_req) - return merge_authdata(context, enc_tkt_request->authorization_data, - &enc_tkt_reply->authorization_data, TRUE); - else - return 0; - } - - if (db_authdata != NULL) { - code = merge_authdata(context, db_authdata, + if (code == 0) { + code = merge_authdata(context, + db_authdata, &enc_tkt_reply->authorization_data, - FALSE); + FALSE, /* !copy */ + FALSE); /* !ignore_kdc_issued */ if (code != 0) krb5_free_authdata(context, db_authdata); - } + } else if (code == KRB5_KDB_DBTYPE_NOSUP) + code = 0; return code; } @@ -627,3 +804,392 @@ handle_authdata (krb5_context context, return code; } + +static krb5_error_code +make_ad_signedpath_data(krb5_context context, + krb5_const_principal client, + krb5_timestamp authtime, + krb5_principal *deleg_path, + krb5_pa_data **method_data, + krb5_authdata **authdata, + krb5_data **data) +{ + krb5_ad_signedpath_data sp_data; + krb5_authdata **sign_authdata = NULL; + int i, j; + krb5_error_code code; + + memset(&sp_data, 0, sizeof(sp_data)); + + if (authdata != NULL) { + for (i = 0; authdata[i] != NULL; i++) + ; + } else + i = 0; + + if (i != 0) { + sign_authdata = k5alloc((i + 1) * sizeof(krb5_authdata *), &code); + if (code != 0) + return code; + + for (i = 0, j = 0; authdata[i] != NULL; i++) { + if (is_kdc_issued_authdatum(context, authdata[i], + KRB5_AUTHDATA_SIGNTICKET)) + continue; + + sign_authdata[j++] = authdata[i]; + } + + sign_authdata[j] = NULL; + } + + sp_data.client = (krb5_principal)client; + sp_data.authtime = authtime; + sp_data.delegated = deleg_path; + sp_data.method_data = method_data; + sp_data.authorization_data = sign_authdata; + + code = encode_krb5_ad_signedpath_data(&sp_data, data); + + if (sign_authdata != NULL) + free(sign_authdata); + + return code; +} + +static krb5_error_code +verify_ad_signedpath_checksum(krb5_context context, + const krb5_db_entry *krbtgt, + krb5_keyblock *krbtgt_key, + krb5_enc_tkt_part *enc_tkt_part, + krb5_principal *deleg_path, + krb5_pa_data **method_data, + krb5_checksum *cksum, + krb5_boolean *valid) +{ + krb5_error_code code; + krb5_data *data; + + *valid = FALSE; + + if (!krb5_c_is_keyed_cksum(cksum->checksum_type)) + return KRB5KRB_AP_ERR_INAPP_CKSUM; + + code = make_ad_signedpath_data(context, + enc_tkt_part->client, + enc_tkt_part->times.authtime, + deleg_path, + method_data, + enc_tkt_part->authorization_data, + &data); + if (code != 0) + return code; + + code = krb5_c_verify_checksum(context, + krbtgt_key, + KRB5_KEYUSAGE_AD_SIGNEDPATH, + data, + cksum, + valid); + + krb5_free_data(context, data); + + if (code == 0 && *valid == FALSE) + code = KRB5KRB_AP_ERR_MODIFIED; + + return code; +} + + +static krb5_error_code +verify_ad_signedpath(krb5_context context, + krb5_db_entry *krbtgt, + krb5_keyblock *krbtgt_key, + krb5_enc_tkt_part *enc_tkt_part, + krb5_principal **pdelegated, + krb5_boolean *path_is_signed) +{ + krb5_error_code code; + krb5_ad_signedpath *sp = NULL; + krb5_authdata **sp_authdata = NULL; + krb5_data enc_sp; + + *pdelegated = NULL; + *path_is_signed = FALSE; + + code = krb5int_find_authdata(context, + enc_tkt_part->authorization_data, + NULL, + KRB5_AUTHDATA_SIGNTICKET, + &sp_authdata); + if (code != 0) + goto cleanup; + + if (sp_authdata == NULL || + sp_authdata[0]->ad_type != KRB5_AUTHDATA_SIGNTICKET || + sp_authdata[1] != NULL) + goto cleanup; + + enc_sp.data = (char *)sp_authdata[0]->contents; + enc_sp.length = sp_authdata[0]->length; + + code = decode_krb5_ad_signedpath(&enc_sp, &sp); + if (code != 0) + goto cleanup; + + code = verify_ad_signedpath_checksum(context, + krbtgt, + krbtgt_key, + enc_tkt_part, + sp->delegated, + sp->method_data, + &sp->checksum, + path_is_signed); + if (code != 0) + goto cleanup; + + *pdelegated = sp->delegated; + sp->delegated = NULL; + +cleanup: + krb5_free_ad_signedpath(context, sp); + krb5_free_authdata(context, sp_authdata); + + return code; +} + +static krb5_error_code +make_ad_signedpath_checksum(krb5_context context, + krb5_const_principal for_user_princ, + const krb5_db_entry *krbtgt, + krb5_keyblock *krbtgt_key, + krb5_enc_tkt_part *enc_tkt_part, + krb5_principal *deleg_path, + krb5_pa_data **method_data, + krb5_checksum *cksum) +{ + krb5_error_code code; + krb5_data *data; + krb5_cksumtype cksumtype; + krb5_const_principal client; + + if (for_user_princ != NULL) + client = for_user_princ; + else + client = enc_tkt_part->client; + + code = make_ad_signedpath_data(context, + client, + enc_tkt_part->times.authtime, + deleg_path, + method_data, + enc_tkt_part->authorization_data, + &data); + if (code != 0) + return code; + + code = krb5int_c_mandatory_cksumtype(context, + krbtgt_key->enctype, + &cksumtype); + if (code != 0) { + krb5_free_data(context, data); + return code; + } + + if (!krb5_c_is_keyed_cksum(cksumtype)) { + krb5_free_data(context, data); + return KRB5KRB_AP_ERR_INAPP_CKSUM; + } + + code = krb5_c_make_checksum(context, cksumtype, krbtgt_key, + KRB5_KEYUSAGE_AD_SIGNEDPATH, data, + cksum); + + krb5_free_data(context, data); + + return code; +} + +static krb5_error_code +make_ad_signedpath(krb5_context context, + krb5_const_principal for_user_princ, + krb5_principal server, + const krb5_db_entry *krbtgt, + krb5_keyblock *krbtgt_key, + krb5_principal *deleg_path, + krb5_enc_tkt_part *enc_tkt_reply) +{ + krb5_error_code code; + krb5_ad_signedpath sp; + int i; + krb5_data *data = NULL; + krb5_authdata ad_datum, *ad_data[2]; + krb5_authdata **if_relevant = NULL; + + memset(&sp, 0, sizeof(sp)); + + sp.enctype = krbtgt_key->enctype; + + if (deleg_path != NULL) { + for (i = 0; deleg_path[i] != NULL; i++) + ; + } else + i = 0; + + sp.delegated = k5alloc((i + (server ? 1 : 0) + 1) * + sizeof(krb5_principal), &code); + if (code != 0) + goto cleanup; + + /* Combine existing and new transited services, if any */ + if (deleg_path != NULL) + memcpy(sp.delegated, deleg_path, i * sizeof(krb5_principal)); + if (server != NULL) + sp.delegated[i++] = server; + sp.delegated[i] = NULL; + sp.method_data = NULL; + + code = make_ad_signedpath_checksum(context, + for_user_princ, + krbtgt, + krbtgt_key, + enc_tkt_reply, + sp.delegated, + sp.method_data, + &sp.checksum); + if (code != 0) { + if (code == KRB5KRB_AP_ERR_INAPP_CKSUM) { + /* + * In the hopefully unlikely case the TGS key enctype + * has an unkeyed mandatory checksum type, do not fail + * so we do not prevent the KDC from servicing requests. + */ + code = 0; + } + goto cleanup; + } + + code = encode_krb5_ad_signedpath(&sp, &data); + if (code != 0) + goto cleanup; + + ad_datum.ad_type = KRB5_AUTHDATA_SIGNTICKET; + ad_datum.contents = (krb5_octet *)data->data; + ad_datum.length = data->length; + + ad_data[0] = &ad_datum; + ad_data[1] = NULL; + + code = krb5_encode_authdata_container(context, + KRB5_AUTHDATA_IF_RELEVANT, + ad_data, + &if_relevant); + if (code != 0) + goto cleanup; + + code = merge_authdata(context, + if_relevant, + &enc_tkt_reply->authorization_data, + FALSE, /* !copy */ + FALSE); /* !ignore_kdc_issued */ + if (code != 0) + goto cleanup; + + if_relevant = NULL; /* merge_authdata() freed */ + +cleanup: + if (sp.delegated != NULL) + free(sp.delegated); + krb5_free_authdata(context, if_relevant); + krb5_free_data(context, data); + krb5_free_checksum_contents(context, &sp.checksum); + krb5_free_pa_data(context, sp.method_data); + + return code; +} + +static void +free_deleg_path(krb5_context context, krb5_principal *deleg_path) +{ + if (deleg_path != NULL) { + int i; + + for (i = 0; deleg_path[i] != NULL; i++) + krb5_free_principal(context, deleg_path[i]); + free(deleg_path); + } +} + +/* + * Returns TRUE if the Windows 2000 PAC is the only element in the + * supplied authorization data. + */ +static krb5_boolean +only_pac_p(krb5_context context, krb5_authdata **authdata) +{ + return has_kdc_issued_authdata(context, + authdata, KRB5_AUTHDATA_WIN2K_PAC) && + (authdata[1] == NULL); +} + +static krb5_error_code +handle_signedpath_authdata (krb5_context context, + unsigned int flags, + krb5_db_entry *client, + krb5_db_entry *server, + krb5_db_entry *krbtgt, + krb5_keyblock *client_key, + krb5_keyblock *server_key, + krb5_keyblock *krbtgt_key, + krb5_data *req_pkt, + krb5_kdc_req *request, + krb5_const_principal for_user_princ, + krb5_enc_tkt_part *enc_tkt_request, + krb5_enc_tkt_part *enc_tkt_reply) +{ + krb5_error_code code = 0; + krb5_principal *deleg_path = NULL; + krb5_boolean signed_path = FALSE; + krb5_boolean s4u2proxy; + + s4u2proxy = isflagset(flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION); + + /* + * The Windows PAC fulfils the same role as the signed path + * if it is the only authorization data element. + */ + if (request->msg_type == KRB5_TGS_REQ && + !only_pac_p(context, enc_tkt_request->authorization_data)) { + code = verify_ad_signedpath(context, + krbtgt, + krbtgt_key, + enc_tkt_request, + &deleg_path, + &signed_path); + if (code != 0) + goto cleanup; + + if (s4u2proxy && signed_path == FALSE) { + code = KRB5KDC_ERR_BADOPTION; + goto cleanup; + } + } + + if (!isflagset(flags, KRB5_KDB_FLAG_CROSS_REALM) && + !only_pac_p(context, enc_tkt_reply->authorization_data)) { + code = make_ad_signedpath(context, + for_user_princ, + s4u2proxy ? client->princ : NULL, + krbtgt, + krbtgt_key, + deleg_path, + enc_tkt_reply); + if (code != 0) + goto cleanup; + } + +cleanup: + free_deleg_path(context, deleg_path); + + return code; +} |