krb5_error_code krb5_db_sign_authdata(krb5_context kcontext,
unsigned int flags,
krb5_const_principal client_princ,
+ krb5_const_principal server_princ,
krb5_db_entry *client,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *session_key,
krb5_timestamp authtime,
krb5_authdata **tgt_auth_data,
+ void *ad_info,
krb5_data ***auth_indicators,
krb5_authdata ***signed_auth_data);
unsigned int flags,
krb5_db_entry **entry);
+krb5_error_code krb5_db_allowed_to_delegate_from(krb5_context context,
+ krb5_const_principal client,
+ krb5_const_principal server,
+ void *server_ad_info,
+ const krb5_db_entry *proxy);
+
+krb5_error_code krb5_db_get_authdata_info(krb5_context context,
+ unsigned int flags,
+ krb5_authdata **in_authdata,
+ krb5_const_principal client_princ,
+ krb5_const_principal server_princ,
+ krb5_keyblock *server_key,
+ krb5_keyblock *krbtgt_key,
+ krb5_db_entry *krbtgt,
+ krb5_timestamp authtime,
+ void **ad_info_out,
+ krb5_principal *client_out);
+
+void krb5_db_free_authdata_info(krb5_context context, void *ad_info);
+
/**
* Sort an array of @a krb5_key_data keys in descending order by their kvno.
* Key data order within a kvno is preserved.
* principal requested by the service; for regular TGS requests, the
* possibly-canonicalized client principal.
*
- * client: The DB entry of the client. For S4U2Self, this will be the DB
- * entry for the client principal requested by the service).
+ * server_princ: The server principal in the request.
+ *
+ * client: The DB entry of the client if it is in the local realm, NULL
+ * if not. For S4U2Self and S4U2Proxy TGS requests, this is the DB
+ * entry for the client principal requested by the service.
*
* server: The DB entry of the service principal, or of a cross-realm
* krbtgt principal in case of referral.
*
- * krbtgt: For TGS requests, the DB entry of the server of the ticket in
- * the PA-TGS-REQ padata; this is usually a local or cross-realm krbtgt
- * principal, but not always. For AS requests, the DB entry of the
- * service principal; this is usually a local krbtgt principal, but not
- * always.
+ * krbtgt: For S4U2Proxy requests, the DB entry of the second ticket
+ * server. For other TGS requests, the DB entry of the header ticket
+ * server. For AS requests, the DB entry of the service principal;
+ * this is usually a local krbtgt principal.
*
* client_key: The reply key for the KDC request, before any FAST armor
* is applied. For AS requests, this may be the client's long-term key
*
* server_key: The server key used to encrypt the returned ticket.
*
- * krbtgt_key: For TGS requests, the key used to decrypt the ticket in
- * the PA-TGS-REQ padata. For AS requests, the server key used to
- * encrypt the returned ticket.
+ * krbtgt_key: For S4U2Proxy requests, the key used to decrypt the second
+ * ticket. For other TGS requests, the key used to decrypt the header
+ * ticket. For AS requests, the server key used to encrypt the
+ * returned ticket.
*
* session_key: The session key of the ticket being granted to the
* requestor.
* tgt_auth_data: For TGS requests, the authorization data present in the
* subject ticket. For AS requests, NULL.
*
+ * ad_info: For TGS requests, the parsed authorization data if obtained
+ * by get_authdata_info method from the authorization data present in
+ * the subject ticket. Otherwise NULL.
+ *
* auth_indicators: Points to NULL or a null-terminated list of krb5_data
* pointers, each containing an authentication indicator (RFC 8129).
* The method may modify this list, or free it and replace
krb5_error_code (*sign_authdata)(krb5_context kcontext,
unsigned int flags,
krb5_const_principal client_princ,
+ krb5_const_principal server_princ,
krb5_db_entry *client,
krb5_db_entry *server,
krb5_db_entry *krbtgt,
krb5_keyblock *session_key,
krb5_timestamp authtime,
krb5_authdata **tgt_auth_data,
+ void *ad_info,
krb5_data ***auth_indicators,
krb5_authdata ***signed_auth_data);
unsigned int flags,
krb5_db_entry **entry_out);
+ /*
+ * Optional: Perform a policy check on server being allowed to obtain
+ * tickets from client to proxy. This method is similar to
+ * check_allowed_to_delegate, but it operates on the target server DB entry
+ * (called "proxy" here as in Microsoft's protocol documentation) rather
+ * than the intermediate server entry. server_ad_info represents the
+ * authdata of the intermediate server, as returned by the
+ * get_authdata_info method on the header ticket. Return 0 if policy
+ * allows the delegation, or an appropriate error (such as
+ * KRB5KDC_ERR_POLICY) if not.
+ *
+ * This method is called for S4U2Proxy requests and implements the
+ * resource-based constrained delegation variant, which can support
+ * cross-realm delegation. If this method is not implemented or if it
+ * returns a policy error, the KDC will fall back to
+ * check_allowed_to_delegate if the intermediate and target servers are in
+ * the same realm and the evidence ticket is forwardable.
+ */
+ krb5_error_code (*allowed_to_delegate_from)(krb5_context context,
+ krb5_const_principal client,
+ krb5_const_principal server,
+ void *server_ad_info,
+ const krb5_db_entry *proxy);
+
+ /*
+ * Optional: Perform verification and policy checks on authorization data,
+ * such as a Windows PAC, based on the request client lookup flags. Return
+ * 0 if all checks have passed. Optionally return a representation of the
+ * authdata in *ad_info_out, to be consumed by allowed_to_delegate_from and
+ * sign_authdata. If client_out is not NULL, set *client_out to the client
+ * name in the PAC; this indicates the requested client principal for a
+ * cross-realm S4U2Proxy request.
+ *
+ * This method is called for TGS requests on the authorization data from
+ * the header ticket. For S4U2Proxy requests it is also called on the
+ * authorization data from the evidence ticket. If the
+ * KRB5_KDB_FLAG_PROTOCOL_TRANSITION bit is set in flags, the authdata is
+ * from the header ticket of an S4U2Self referral request, and the supplied
+ * client_princ is the requested client.
+ */
+ krb5_error_code (*get_authdata_info)(krb5_context context,
+ unsigned int flags,
+ krb5_authdata **in_authdata,
+ krb5_const_principal client_princ,
+ krb5_const_principal server_princ,
+ krb5_keyblock *server_key,
+ krb5_keyblock *krbtgt_key,
+ krb5_db_entry *krbtgt,
+ krb5_timestamp authtime,
+ void **ad_info_out,
+ krb5_principal *client_out);
+
+ void (*free_authdata_info)(krb5_context context,
+ void *ad_info);
+
/* End of minor version 0 for major version 8. */
} kdb_vftabl;
state->server, NULL, state->local_tgt,
&state->local_tgt_key, &state->client_keyblock,
&state->server_keyblock, NULL, state->req_pkt,
- state->request, NULL, NULL,
+ state->request, NULL, NULL, NULL,
&state->auth_indicators, &state->enc_tkt_reply);
if (errcode) {
krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
static krb5_error_code
decrypt_2ndtkt(kdc_realm_t *, krb5_kdc_req *, krb5_flags, krb5_db_entry **,
- const char **);
+ krb5_keyblock **, const char **);
static krb5_error_code
gen_session_key(kdc_realm_t *, krb5_kdc_req *, krb5_db_entry *,
{
krb5_keyblock * subkey = 0;
krb5_keyblock *header_key = NULL;
+ krb5_keyblock *stkt_server_key = NULL;
+ krb5_keyblock *subject_key;
krb5_db_entry *server = NULL;
krb5_db_entry *stkt_server = NULL;
+ krb5_db_entry *subject_server;
krb5_kdc_rep reply;
krb5_enc_kdc_rep_part reply_encpart;
krb5_ticket ticket_reply, *header_ticket = 0;
krb5_keyblock *reply_key = NULL;
krb5_key_data *server_key;
krb5_principal cprinc = NULL, sprinc = NULL, altcprinc = NULL;
+ krb5_const_principal authdata_client;
+ krb5_principal stkt_authdata_client = NULL;
krb5_last_req_entry *nolrarray[2], nolrentry;
int errcode;
const char *status = 0;
krb5_pa_data **e_data = NULL;
krb5_audit_state *au_state = NULL;
krb5_data **auth_indicators = NULL;
+ void *ad_info = NULL, *stkt_ad_info = NULL;
memset(&reply, 0, sizeof(reply));
memset(&reply_encpart, 0, sizeof(reply_encpart));
if (errcode)
goto cleanup;
+
+ if (s4u_x509_user != NULL && client == NULL) {
+ /*
+ * For an S4U2Self referral request (the requesting service is
+ * following a referral back to its own realm), the authdata in the
+ * header ticket should be for the requested client.
+ */
+ setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
+ authdata_client = s4u_x509_user->user_id.user;
+ } else {
+ /* Otherwise (including for initial S4U2Self requests), the authdata
+ * should be for the header ticket client. */
+ authdata_client = header_enc_tkt->client;
+ }
+ errcode = krb5_db_get_authdata_info(kdc_context, c_flags,
+ header_enc_tkt->authorization_data,
+ authdata_client, request->server,
+ header_key, &local_tgt_key, local_tgt,
+ header_enc_tkt->times.authtime,
+ &ad_info, NULL);
+ if (errcode && errcode != KRB5_PLUGIN_OP_NOTSUPP)
+ goto cleanup;
+
+ /* Flag all S4U2Self requests now that we have checked the authdata. */
if (s4u_x509_user != NULL)
setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
/* Deal with user-to-user and constrained delegation */
errcode = decrypt_2ndtkt(kdc_active_realm, request, c_flags,
- &stkt_server, &status);
+ &stkt_server, &stkt_server_key, &status);
if (errcode)
goto cleanup;
if (isflagset(request->kdc_options, KDC_OPT_CNAME_IN_ADDL_TKT)) {
/* Do constrained delegation protocol and authorization checks */
- errcode = kdc_process_s4u2proxy_req(kdc_active_realm,
- request,
+ setflag(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
+
+ errcode = kdc_process_s4u2proxy_req(kdc_active_realm, c_flags, request,
request->second_ticket[st_idx]->enc_part2,
- stkt_server,
+ local_tgt, &local_tgt_key,
+ stkt_server, stkt_server_key,
header_ticket->enc_part2->client,
- request->server,
+ server, request->server, ad_info,
+ &stkt_ad_info,
+ &stkt_authdata_client,
&status);
if (errcode == KDC_ERR_POLICY || errcode == KDC_ERR_BADOPTION)
au_state->violation = PROT_CONSTRAINT;
if (errcode)
goto cleanup;
- setflag(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
-
assert(krb5_is_tgs_principal(header_ticket->server));
-
- assert(client == NULL); /* assured by kdc_process_s4u2self_req() */
- client = stkt_server;
- stkt_server = NULL;
- } else if (request->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
- krb5_db_free_principal(kdc_context, stkt_server);
- stkt_server = NULL;
- } else
- assert(stkt_server == NULL);
+ }
au_state->stage = ISSUE_TKT;
* the others could be forged by a malicious server.
*/
- if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION))
+ if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
subject_tkt = request->second_ticket[st_idx]->enc_part2;
- else
+ subject_server = stkt_server;
+ subject_key = stkt_server_key;
+ } else {
subject_tkt = header_enc_tkt;
+ subject_server = header_server;
+ subject_key = header_key;
+ }
authtime = subject_tkt->times.authtime;
- /* Extract auth indicators from the subject ticket, except for S4U2Proxy
+ /* Extract auth indicators from the subject ticket, except for S4U2Self
* requests (where the client didn't authenticate). */
if (s4u_x509_user == NULL) {
errcode = get_auth_indicators(kdc_context, subject_tkt, local_tgt,
if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
altcprinc = s4u_x509_user->user_id.user;
} else if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
- altcprinc = subject_tkt->client;
+ /* kdc_process_s4u2proxy_req() only allows cross-realm requests if
+ * stkt_authdata_client is set. */
+ altcprinc = isflagset(c_flags, KRB5_KDB_FLAG_CROSS_REALM) ?
+ stkt_authdata_client : subject_tkt->client;
} else {
altcprinc = NULL;
}
clear(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED);
}
if (isflagset(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED) == 0) {
- /*
- * If we are not doing protocol transition/constrained delegation
- * try to lookup the client principal so plugins can add additional
- * authorization information.
- *
- * Always validate authorization data for constrained delegation
- * because we must validate the KDC signatures.
- */
- if (!isflagset(c_flags, KRB5_KDB_FLAGS_S4U)) {
+ /* If we are not doing protocol transition, try to look up the subject
+ * principal so that KDB modules can add additional authdata. */
+ if (!isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
/* Generate authorization data so we can include it in ticket */
setflag(c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
/* Map principals from foreign (possibly non-AD) realms */
}
}
- if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) && !is_referral)
- enc_tkt_reply.client = s4u_x509_user->user_id.user;
+ if (isflagset(c_flags, KRB5_KDB_FLAGS_S4U) && !is_referral)
+ enc_tkt_reply.client = altcprinc;
else
- enc_tkt_reply.client = subject_tkt->client;
+ enc_tkt_reply.client = header_enc_tkt->client;
enc_tkt_reply.session = &session_key;
enc_tkt_reply.transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
}
errcode = handle_authdata(kdc_context, c_flags, client, server,
- header_server, local_tgt, &local_tgt_key,
+ subject_server, local_tgt, &local_tgt_key,
subkey != NULL ? subkey :
header_ticket->enc_part2->session,
- encrypting_key, header_key, pkt, request,
- s4u_x509_user ?
- s4u_x509_user->user_id.user : NULL,
+ encrypting_key, subject_key, pkt, request,
+ altcprinc, stkt_ad_info ? stkt_ad_info : ad_info,
subject_tkt, &auth_indicators, &enc_tkt_reply);
if (errcode) {
krb5_klog_syslog(LOG_INFO, _("TGS_REQ : handle_authdata (%d)"),
krb5_free_keyblock_contents(kdc_context, &server_keyblock);
if (reply_key)
krb5_free_keyblock(kdc_context, reply_key);
+ if (stkt_server_key)
+ krb5_free_keyblock(kdc_context, stkt_server_key);
if (errcode)
emsg = krb5_get_error_message (kdc_context, errcode);
krb5_free_authdata(kdc_context, enc_tkt_reply.authorization_data);
krb5_free_pa_data(kdc_context, e_data);
k5_free_data_ptr_list(auth_indicators);
+ krb5_db_free_authdata_info(kdc_context, ad_info);
+ krb5_db_free_authdata_info(kdc_context, stkt_ad_info);
+ krb5_free_principal(kdc_context, stkt_authdata_client);
return retval;
}
static krb5_error_code
decrypt_2ndtkt(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
krb5_flags flags, krb5_db_entry **server_out,
- const char **status)
+ krb5_keyblock **key_out, const char **status)
{
krb5_error_code retval;
krb5_db_entry *server = NULL;
- krb5_keyblock *key;
krb5_kvno kvno;
krb5_ticket *stkt;
return 0;
stkt = req->second_ticket[0];
- retval = kdc_get_server_key(kdc_context, stkt,
- flags,
- TRUE, /* match_enctype */
- &server,
- &key,
- &kvno);
+ retval = kdc_get_server_key(kdc_context, stkt, flags, TRUE, &server,
+ key_out, &kvno);
if (retval != 0) {
*status = "2ND_TKT_SERVER";
goto cleanup;
}
- retval = krb5_decrypt_tkt_part(kdc_context, key,
+ retval = krb5_decrypt_tkt_part(kdc_context, *key_out,
req->second_ticket[0]);
- krb5_free_keyblock(kdc_context, key);
if (retval != 0) {
*status = "2ND_TKT_DECRYPT";
goto cleanup;
krb5_db_entry *client, krb5_db_entry *server,
krb5_db_entry *header_server, krb5_keyblock *client_key,
krb5_keyblock *server_key, krb5_keyblock *header_key,
- krb5_kdc_req *req, krb5_const_principal for_user_princ,
- krb5_enc_tkt_part *enc_tkt_req,
+ krb5_kdc_req *req, krb5_const_principal altcprinc,
+ void *ad_info, krb5_enc_tkt_part *enc_tkt_req,
krb5_enc_tkt_part *enc_tkt_reply,
krb5_data ***auth_indicators)
{
return 0;
}
- /*
- * We have this special case for protocol transition, because for
- * cross-realm protocol transition the ticket reply client will
- * not be changed until the final hop.
- */
- if (isflagset(flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION))
- actual_client = for_user_princ;
+ /* S4U referral replies should contain authdata for the requested client,
+ * even though they use the requesting service as the ticket client. */
+ if (isflagset(flags, KRB5_KDB_FLAGS_S4U))
+ actual_client = altcprinc;
else
actual_client = enc_tkt_reply->client;
krbtgt_key = (header_key != NULL) ? header_key : server_key;
tgt_authdata = tgs_req ? enc_tkt_req->authorization_data : NULL;
- ret = krb5_db_sign_authdata(context, flags, actual_client, client,
- server, krbtgt, client_key, server_key,
+ ret = krb5_db_sign_authdata(context, flags, actual_client, req->server,
+ client, server, krbtgt, client_key, server_key,
krbtgt_key, enc_tkt_reply->session,
enc_tkt_reply->times.authtime, tgt_authdata,
- auth_indicators, &db_authdata);
+ ad_info, auth_indicators, &db_authdata);
if (ret)
return (ret == KRB5_PLUGIN_OP_NOTSUPP) ? 0 : ret;
krb5_keyblock *local_tgt_key, krb5_keyblock *client_key,
krb5_keyblock *server_key, krb5_keyblock *header_key,
krb5_data *req_pkt, krb5_kdc_req *req,
- krb5_const_principal for_user_princ,
+ krb5_const_principal altcprinc, void *ad_info,
krb5_enc_tkt_part *enc_tkt_req,
krb5_data ***auth_indicators,
krb5_enc_tkt_part *enc_tkt_reply)
h = &authdata_modules[i];
ret = h->vt.handle(context, h->data, flags, client, server,
header_server, client_key, server_key,
- header_key, req_pkt, req, for_user_princ,
+ header_key, req_pkt, req, altcprinc,
enc_tkt_req, enc_tkt_reply);
if (ret)
kdc_err(context, ret, "from authdata module %s", h->vt.name);
/* Fetch authdata from the KDB if appropriate. */
ret = fetch_kdb_authdata(context, flags, client, server, header_server,
client_key, server_key, header_key, req,
- for_user_princ, enc_tkt_req, enc_tkt_reply,
- auth_indicators);
+ altcprinc, ad_info, enc_tkt_req,
+ enc_tkt_reply, auth_indicators);
if (ret)
return ret;
}
/* Validate and insert AD-SIGNTICKET authdata. This must happen last
* since it contains a signature over the other authdata. */
ret = handle_signticket(context, flags, client, server, local_tgt,
- local_tgt_key, req, for_user_princ,
- enc_tkt_req, enc_tkt_reply);
+ local_tgt_key, req, altcprinc, enc_tkt_req,
+ enc_tkt_reply);
if (ret)
return ret;
}
&reply_encpart->enc_padata);
if (code)
goto cleanup;
+
+ code = kdc_add_pa_pac_options(context, request,
+ &reply_encpart->enc_padata);
+ if (code)
+ goto cleanup;
+
/*Add potentially other enc_padata providers*/
cleanup:
return code;
const krb5_db_entry *server,
krb5_const_principal proxy)
{
- /* Can't get a TGT (otherwise it would be unconstrained delegation) */
- if (krb5_is_tgs_principal(proxy))
- return KRB5KDC_ERR_POLICY;
-
/* Must be in same realm */
if (!krb5_realm_compare(context, server->princ, proxy))
return KRB5KDC_ERR_POLICY;
return krb5_db_check_allowed_to_delegate(context, client, server, proxy);
}
+static krb5_error_code
+check_rbcd_policy(kdc_realm_t *kdc_active_realm, unsigned int flags,
+ const krb5_principal stkt_client_princ,
+ krb5_principal stkt_authdata_client,
+ const krb5_db_entry *stkt_server,
+ krb5_const_principal header_client_princ,
+ void *header_ad_info, const krb5_db_entry *proxy)
+{
+ krb5_principal client_princ = stkt_client_princ;
+
+ /* Ensure that either the evidence ticket server or the client matches the
+ * TGT client. */
+ if (isflagset(flags, KRB5_KDB_FLAG_CROSS_REALM)) {
+ /*
+ * Check that the proxy server is local, that the second ticket is a
+ * cross realm TGT, and that the second ticket client matches the
+ * header ticket client.
+ */
+ if (isflagset(flags, KRB5_KDB_FLAG_ISSUING_REFERRAL) ||
+ !is_cross_tgs_principal(stkt_server->princ) ||
+ !krb5_principal_compare(kdc_context, stkt_client_princ,
+ header_client_princ)) {
+ return KRB5KDC_ERR_BADOPTION;
+ }
+ /* The KDB module must be able to recover the reply ticket client name
+ * from the evidence ticket authorization data. */
+ if (stkt_authdata_client == NULL ||
+ stkt_authdata_client->realm.length == 0)
+ return KRB5KDC_ERR_BADOPTION;
+ client_princ = stkt_authdata_client;
+ } else if (!krb5_principal_compare(kdc_context, stkt_server->princ,
+ header_client_princ)) {
+ return KRB5KDC_ERR_BADOPTION;
+ }
+
+ /* If we are issuing a referral, the KDC in the resource realm will check
+ * if delegation is allowed. */
+ if (isflagset(flags, KRB5_KDB_FLAG_ISSUING_REFERRAL))
+ return 0;
+
+ return krb5_db_allowed_to_delegate_from(kdc_context, client_princ,
+ header_client_princ,
+ header_ad_info, proxy);
+}
+
krb5_error_code
-kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm,
+kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, unsigned int flags,
krb5_kdc_req *request,
const krb5_enc_tkt_part *t2enc,
+ krb5_db_entry *krbtgt, krb5_keyblock *krbtgt_key,
const krb5_db_entry *server,
+ krb5_keyblock *server_key,
krb5_const_principal server_princ,
+ const krb5_db_entry *proxy,
krb5_const_principal proxy_princ,
+ void *ad_info, void **stkt_ad_info,
+ krb5_principal *stkt_authdata_client,
const char **status)
{
krb5_error_code errcode;
+ krb5_boolean support_rbcd;
/*
* Constrained delegation is mutually exclusive with renew/forward/etc.
return KRB5KDC_ERR_BADOPTION;
}
+ /* Can't get a TGT (otherwise it would be unconstrained delegation). */
+ if (krb5_is_tgs_principal(proxy_princ)) {
+ *status = "NOT_ALLOWED_TO_DELEGATE";
+ return KRB5KDC_ERR_POLICY;
+ }
+
+ errcode = krb5_db_get_authdata_info(kdc_context, flags,
+ t2enc->authorization_data,
+ t2enc->client, proxy_princ, server_key,
+ krbtgt_key, krbtgt,
+ t2enc->times.authtime, stkt_ad_info,
+ stkt_authdata_client);
+ if (errcode && errcode != KRB5_PLUGIN_OP_NOTSUPP) {
+ *status = "NOT_ALLOWED_TO_DELEGATE";
+ return errcode;
+ }
+
+ errcode = kdc_get_pa_pac_rbcd(kdc_context, request->padata, &support_rbcd);
+ if (errcode)
+ return errcode;
+
+ if (support_rbcd && ad_info != NULL) {
+ errcode = check_rbcd_policy(kdc_active_realm, flags, t2enc->client,
+ *stkt_authdata_client, server,
+ server_princ, ad_info, proxy);
+ if (errcode == 0)
+ return 0;
+ if (errcode != KRB5KDC_ERR_POLICY &&
+ errcode != KRB5_PLUGIN_OP_NOTSUPP) {
+ *status = "INVALID_S4U2PROXY_XREALM_REQUEST";
+ return errcode;
+ }
+ /* Fall back to old constrained delegation. */
+ }
+
/* Ensure that evidence ticket server matches TGT client */
if (!krb5_principal_compare(kdc_context,
server->princ, /* after canon */
return ret;
}
+krb5_error_code
+kdc_get_pa_pac_rbcd(krb5_context context, krb5_pa_data **in_padata,
+ krb5_boolean *supported)
+{
+ krb5_error_code retval;
+ krb5_pa_pac_options *pac_options = NULL;
+
+ *supported = FALSE;
+
+ retval = kdc_get_pa_pac_options(context, in_padata, &pac_options);
+ if (retval || !pac_options)
+ return retval;
+
+ if (pac_options->options & KRB5_PA_PAC_OPTIONS_RBCD)
+ *supported = TRUE;
+
+ free(pac_options);
+ return 0;
+}
+
/*
* Although the KDC doesn't call this function directly,
* process_tcp_connection_read() in net-server.c does call it.
krb5_keyblock *header_key,
krb5_data *req_pkt,
krb5_kdc_req *request,
- krb5_const_principal for_user_princ,
+ krb5_const_principal altcprinc,
+ void *ad_info,
krb5_enc_tkt_part *enc_tkt_request,
krb5_data ***auth_indicators,
krb5_enc_tkt_part *enc_tkt_reply);
krb5_error_code
kdc_process_s4u2proxy_req (kdc_realm_t *kdc_active_realm,
+ unsigned int flags,
krb5_kdc_req *request,
const krb5_enc_tkt_part *t2enc,
+ krb5_db_entry *krbtgt,
+ krb5_keyblock *krbtgt_key,
const krb5_db_entry *server,
+ krb5_keyblock *server_key,
krb5_const_principal server_princ,
+ const krb5_db_entry *proxy,
krb5_const_principal proxy_princ,
+ void *ad_info,
+ void **stkt_ad_info,
+ krb5_principal *stkt_ad_client,
const char **status);
krb5_error_code
kdc_get_pa_pac_options(krb5_context context, krb5_pa_data **in_padata,
krb5_pa_pac_options **pac_options_out);
+krb5_error_code
+kdc_get_pa_pac_rbcd(krb5_context context, krb5_pa_data **in_padata,
+ krb5_boolean *supported);
+
/* Information handle for kdcpreauth callbacks. All pointers are aliases. */
struct krb5_kdcpreauth_rock_st {
krb5_kdc_req *request;
out->check_allowed_to_delegate = in->check_allowed_to_delegate;
out->free_principal_e_data = in->free_principal_e_data;
out->get_s4u_x509_principal = in->get_s4u_x509_principal;
+ out->allowed_to_delegate_from = in->allowed_to_delegate_from;
+ out->get_authdata_info = in->get_authdata_info;
+ out->free_authdata_info = in->free_authdata_info;
/* Set defaults for optional fields. */
if (out->fetch_master_key == NULL)
krb5_error_code
krb5_db_sign_authdata(krb5_context kcontext, unsigned int flags,
- krb5_const_principal client_princ, krb5_db_entry *client,
+ krb5_const_principal client_princ,
+ krb5_const_principal server_princ, 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_keyblock *session_key,
krb5_timestamp authtime, krb5_authdata **tgt_auth_data,
- krb5_data ***auth_indicators,
+ void *ad_info, krb5_data ***auth_indicators,
krb5_authdata ***signed_auth_data)
{
krb5_error_code status = 0;
return status;
if (v->sign_authdata == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->sign_authdata(kcontext, flags, client_princ, client, server,
- krbtgt, client_key, server_key, krbtgt_key,
- session_key, authtime, tgt_auth_data,
- auth_indicators, signed_auth_data);
+ return v->sign_authdata(kcontext, flags, client_princ, server_princ,
+ client, server, krbtgt, client_key, server_key,
+ krbtgt_key, session_key, authtime, tgt_auth_data,
+ ad_info, auth_indicators, signed_auth_data);
}
krb5_error_code
return 0;
}
+krb5_error_code
+krb5_db_allowed_to_delegate_from(krb5_context kcontext,
+ krb5_const_principal client,
+ krb5_const_principal server,
+ void *server_ad_info,
+ const krb5_db_entry *proxy)
+{
+ krb5_error_code ret;
+ kdb_vftabl *v;
+
+ ret = get_vftabl(kcontext, &v);
+ if (ret)
+ return ret;
+ if (v->allowed_to_delegate_from == NULL)
+ return KRB5_PLUGIN_OP_NOTSUPP;
+ return v->allowed_to_delegate_from(kcontext, client, server,
+ server_ad_info, proxy);
+}
+
+krb5_error_code
+krb5_db_get_authdata_info(krb5_context kcontext, unsigned int flags,
+ krb5_authdata **in_authdata,
+ krb5_const_principal client_princ,
+ krb5_const_principal server_princ,
+ krb5_keyblock *server_key, krb5_keyblock *krbtgt_key,
+ krb5_db_entry *krbtgt, krb5_timestamp authtime,
+ void **ad_info_out, krb5_principal *client_out)
+{
+ krb5_error_code ret;
+ kdb_vftabl *v;
+
+ *ad_info_out = NULL;
+ if (client_out != NULL)
+ *client_out = NULL;
+
+ ret = get_vftabl(kcontext, &v);
+ if (ret)
+ return ret;
+ if (v->get_authdata_info == NULL)
+ return KRB5_PLUGIN_OP_NOTSUPP;
+ return v->get_authdata_info(kcontext, flags, in_authdata, client_princ,
+ server_princ, server_key, krbtgt_key, krbtgt,
+ authtime, ad_info_out, client_out);
+}
+
+void
+krb5_db_free_authdata_info(krb5_context kcontext, void *ad_info)
+{
+ krb5_error_code ret;
+ kdb_vftabl *v;
+
+ if (ad_info == NULL)
+ return;
+ ret = get_vftabl(kcontext, &v);
+ if (ret)
+ return;
+ if (v->free_authdata_info == NULL)
+ return;
+ v->free_authdata_info(kcontext, ad_info);
+}
+
void
krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length)
{
krb5_db_inited
krb5_db_alloc
krb5_db_free
+krb5_db_allowed_to_delegate_from
krb5_db_audit_as_req
krb5_db_check_allowed_to_delegate
krb5_db_get_s4u_x509_principal
krb5_db_fetch_mkey
krb5_db_fetch_mkey_list
krb5_db_fini
+krb5_db_free_authdata_info
krb5_db_free_principal
krb5_db_get_age
+krb5_db_get_authdata_info
krb5_db_get_key_data_kvno
krb5_db_get_context
krb5_db_get_principal
static krb5_error_code
test_sign_authdata(krb5_context context, unsigned int flags,
- krb5_const_principal client_princ, krb5_db_entry *client,
+ krb5_const_principal client_princ,
+ krb5_const_principal server_princ, 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_keyblock *session_key,
krb5_timestamp authtime, krb5_authdata **tgt_auth_data,
- krb5_data ***auth_indicators,
+ void *ad_info, krb5_data ***auth_indicators,
krb5_authdata ***signed_auth_data)
{
krb5_authdata **list, *ad;