From: Greg Hudson Date: Wed, 11 Feb 2015 18:40:44 +0000 (-0500) Subject: Load local TGT in KDC requests X-Git-Tag: krb5-1.14-alpha1~103 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=39548a5b17bbda9eeb63625a201cfd19b9de1c5b;p=thirdparty%2Fkrb5.git Load local TGT in KDC requests Ensure that we have the server realm TGT principal entry at hand for AS and TGS requests. In the common case, this is the same as the AS server or TGS header server principal, but in less common cases (direct AS requests for service tickets, cross-realm TGS requests) we will need to explicitly load it. The local TGT entry is not used in this commit. In the short term, it will be used to verify and sign CAMMACs and to shore up some edge cases in AD-SIGNTICKET. In the longer term, we might allow realm configuration variables to be stored in local TGT tl-data. --- diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c index 66531268d9..24231bb4db 100644 --- a/src/kdc/do_as_req.c +++ b/src/kdc/do_as_req.c @@ -102,6 +102,8 @@ struct as_req_state { krb5_keyblock client_keyblock; krb5_db_entry *client; krb5_db_entry *server; + krb5_db_entry *local_tgt; + krb5_db_entry *local_tgt_storage; krb5_kdc_req *request; struct krb5_kdcpreauth_rock_st rock; const char *status; @@ -404,6 +406,7 @@ egress: free(state->sname); krb5_db_free_principal(kdc_context, state->client); krb5_db_free_principal(kdc_context, state->server); + krb5_db_free_principal(kdc_context, state->local_tgt_storage); if (state->session_key.contents != NULL) krb5_free_keyblock_contents(kdc_context, &state->session_key); if (state->ticket_reply.enc_part.ciphertext.data != NULL) { @@ -635,6 +638,14 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt, goto errout; } + errcode = get_local_tgt(kdc_context, &state->request->server->realm, + state->server, &state->local_tgt, + &state->local_tgt_storage); + if (errcode) { + state->status = "GET_LOCAL_TGT"; + goto errout; + } + au_state->stage = VALIDATE_POL; if ((errcode = krb5_timeofday(kdc_context, &state->kdc_time))) { diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c index c8cd80df5c..73b39e0da0 100644 --- a/src/kdc/do_tgs_req.c +++ b/src/kdc/do_tgs_req.c @@ -125,6 +125,7 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, krb5_enc_tkt_part *header_enc_tkt = NULL; /* TGT */ krb5_enc_tkt_part *subject_tkt = NULL; /* TGT or evidence ticket */ krb5_db_entry *client = NULL, *header_server = NULL; + krb5_db_entry *local_tgt, *local_tgt_storage = NULL; krb5_pa_s4u_x509_user *s4u_x509_user = NULL; /* protocol transition request */ krb5_authdata **kdc_issued_auth_data = NULL; /* auth data issued by KDC */ unsigned int c_flags = 0, s_flags = 0; /* client/server KDB flags */ @@ -214,6 +215,13 @@ process_tgs_req(struct server_handle *handle, krb5_data *pkt, goto cleanup; } + errcode = get_local_tgt(kdc_context, &sprinc->realm, header_server, + &local_tgt, &local_tgt_storage); + if (errcode) { + status = "GET_LOCAL_TGT"; + goto cleanup; + } + /* Ignore (for now) the request modification due to FAST processing. */ au_state->request = request; @@ -844,6 +852,7 @@ cleanup: krb5_db_free_principal(kdc_context, server); krb5_db_free_principal(kdc_context, header_server); krb5_db_free_principal(kdc_context, client); + krb5_db_free_principal(kdc_context, local_tgt_storage); if (session_key.contents != NULL) krb5_free_keyblock_contents(kdc_context, &session_key); if (newtransited) diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index bf6f17b0ac..ec36510dae 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -540,6 +540,45 @@ errout: return retval; } +/* + * If candidate is the local TGT for realm, set *alias_out to candidate and + * *storage_out to NULL. Otherwise, load the local TGT into *storage_out and + * set *alias_out to *storage_out. + * + * In the future we might generalize this to a small per-request principal + * cache. For now, it saves a load operation in the common case where the AS + * server or TGS header ticket server is the local TGT. + */ +krb5_error_code +get_local_tgt(krb5_context context, const krb5_data *realm, + krb5_db_entry *candidate, krb5_db_entry **alias_out, + krb5_db_entry **storage_out) +{ + krb5_error_code ret; + krb5_principal princ; + krb5_db_entry *tgt; + + *alias_out = NULL; + *storage_out = NULL; + + ret = krb5_build_principal_ext(context, &princ, realm->length, realm->data, + KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, + realm->length, realm->data, 0); + if (ret) + return ret; + + if (!krb5_principal_compare(context, candidate->princ, princ)) { + ret = krb5_db_get_principal(context, princ, 0, &tgt); + if (!ret) + *storage_out = *alias_out = tgt; + } else { + *alias_out = candidate; + } + + krb5_free_principal(context, princ); + return ret; +} + /* This probably wants to be updated if you support last_req stuff */ static krb5_last_req_entry nolrentry = { KV5M_LAST_REQ_ENTRY, KRB5_LRQ_NONE, 0 }; diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index c522f0bd2e..ac868065d1 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -75,6 +75,11 @@ kdc_get_server_key (krb5_context, krb5_ticket *, unsigned int, krb5_boolean match_enctype, krb5_db_entry **, krb5_keyblock **, krb5_kvno *); +krb5_error_code +get_local_tgt(krb5_context context, const krb5_data *realm, + krb5_db_entry *candidate, krb5_db_entry **alias_out, + krb5_db_entry **storage_out); + int validate_as_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry, krb5_db_entry, krb5_timestamp,