static struct heim_plugin_data kdc_plugin_data = {
"krb5",
"kdc",
- KRB5_PLUGIN_KDC_VERSION_10,
+ KRB5_PLUGIN_KDC_VERSION_11,
kdc_plugin_deps,
kdc_get_instance
};
hdb_entry *client;
hdb_entry *server;
hdb_entry *krbtgt;
- krb5_pac *pac;
+ krb5_pac pac;
+ krb5_boolean *is_trusted;
};
static krb5_error_code KRB5_LIB_CALL
uc->r,
uc->client_principal,
uc->delegated_proxy_principal,
- uc->client, uc->server, uc->krbtgt, uc->pac);
+ uc->client, uc->server, uc->krbtgt, uc->pac,
+ uc->is_trusted);
return ret;
}
hdb_entry *client,
hdb_entry *server,
hdb_entry *krbtgt,
- krb5_pac *pac)
+ krb5_pac pac,
+ krb5_boolean *is_trusted)
{
struct verify_uc uc;
uc.server = server;
uc.krbtgt = krbtgt;
uc.pac = pac;
+ uc.is_trusted = is_trusted;
return _krb5_plugin_run_f(r->context, &kdc_plugin_data,
0, &uc, verify);
}
+struct update_uc {
+ astgs_request_t r;
+ krb5_principal client_principal;
+ krb5_principal delegated_proxy_principal;
+ hdb_entry *client;
+ hdb_entry *server;
+ hdb_entry *krbtgt;
+ krb5_pac *pac;
+};
+
+static krb5_error_code KRB5_LIB_CALL
+update(krb5_context context, const void *plug, void *plugctx, void *userctx)
+{
+ const krb5plugin_kdc_ftable *ft = (const krb5plugin_kdc_ftable *)plug;
+ struct update_uc *uc = (struct update_uc *)userctx;
+ krb5_error_code ret;
+
+ if (ft->pac_update == NULL)
+ return KRB5_PLUGIN_NO_HANDLE;
+
+ ret = ft->pac_update((void *)plug,
+ uc->r,
+ uc->client_principal,
+ uc->delegated_proxy_principal,
+ uc->client, uc->server, uc->krbtgt, uc->pac);
+ return ret;
+}
+
+krb5_error_code
+_kdc_pac_update(astgs_request_t r,
+ const krb5_principal client_principal,
+ const krb5_principal delegated_proxy_principal,
+ hdb_entry *client,
+ hdb_entry *server,
+ hdb_entry *krbtgt,
+ krb5_pac *pac)
+{
+ struct update_uc uc;
+
+ if (!have_plugin)
+ return KRB5_PLUGIN_NO_HANDLE;
+
+ uc.r = r;
+ uc.client_principal = client_principal;
+ uc.delegated_proxy_principal = delegated_proxy_principal;
+ uc.client = client;
+ uc.server = server;
+ uc.krbtgt = krbtgt;
+ uc.pac = pac;
+
+ return _krb5_plugin_run_f(r->context, &kdc_plugin_data,
+ 0, &uc, update);
+}
+
static krb5_error_code KRB5_LIB_CALL
check(krb5_context context, const void *plug, void *plugctx, void *userctx)
{
/*
* Verify the PAC KDC signatures by fetching the appropriate TGS key
- * and calling krb5_pac_verify() with that key. Optionally update the
- * PAC buffers on success.
+ * and calling krb5_pac_verify() with that key. The possibly-NULL
+ * is_trusted may be set by the plugin to indicate that the PAC was
+ * issued by a trusted server, and not, for example, by an RODC.
*/
typedef krb5_error_code
hdb_entry *,/* client */
hdb_entry *,/* server */
hdb_entry *,/* krbtgt */
- krb5_pac *);
+ krb5_pac, /* pac */
+ krb5_boolean *); /* is_trusted */
+
+/*
+ * Update the KDC PAC buffers. This function may be used after verifying the PAC
+ * with a call to krb5plugin_kdc_pac_verify(), and it resembles the latter
+ * function in the parameters it takes. The 'pac' parameter always points to a
+ * non-NULL PAC.
+ */
+
+typedef krb5_error_code
+(KRB5_CALLCONV *krb5plugin_kdc_pac_update)(void *,
+ astgs_request_t,
+ const krb5_principal, /* new ticket client */
+ const krb5_principal, /* delegation proxy */
+ hdb_entry *,/* client */
+ hdb_entry *,/* server */
+ hdb_entry *,/* krbtgt */
+ krb5_pac *); /* pac */
/*
* Authorize the client principal's access to the Authentication Service (AS).
* Plugins should carefully check API contract notes for changes
* between plugin API versions.
*/
-#define KRB5_PLUGIN_KDC_VERSION_10 10
+#define KRB5_PLUGIN_KDC_VERSION_11 11
typedef struct krb5plugin_kdc_ftable {
HEIM_PLUGIN_FTABLE_COMMON_ELEMENTS(krb5_context);
krb5plugin_kdc_pac_generate pac_generate;
krb5plugin_kdc_pac_verify pac_verify;
+ krb5plugin_kdc_pac_update pac_update;
krb5plugin_kdc_client_access client_access;
krb5plugin_kdc_referral_policy referral_policy;
krb5plugin_kdc_finalize_reply finalize_reply;
krb5_pac pac = NULL;
krb5_error_code ret;
krb5_boolean signedticket;
+ krb5_boolean is_trusted = FALSE;
*kdc_issued = FALSE;
*ppac = NULL;
/* Verify the KDC signatures. */
ret = _kdc_pac_verify(r,
client_principal, delegated_proxy_principal,
- client, server, krbtgt, &pac);
+ client, server, krbtgt, pac, &is_trusted);
if (ret == 0) {
if (pac_canon_name) {
ret = _krb5_pac_get_canon_principal(context, pac, pac_canon_name);
goto out;
}
+ if (priv->pac != NULL) {
+ ret = _kdc_pac_update(priv, priv->client_princ, NULL,
+ priv->client, priv->server, priv->krbtgt,
+ &priv->pac);
+ if (ret == KRB5_PLUGIN_NO_HANDLE) {
+ ret = 0;
+ }
+ if (ret) {
+ const char *msg = krb5_get_error_message(context, ret);
+ kdc_audit_addreason((kdc_request_t)priv, "PAC update failed");
+ kdc_log(context, config, 4,
+ "Update PAC failed for %s (%s) from %s with %s",
+ spn, cpn, from, msg);
+ krb5_free_error_message(context, msg);
+ goto out;
+ }
+
+ if (priv->pac == NULL) {
+ /* the plugin may indicate no PAC should be generated */
+ priv->pac_attributes = 0;
+ }
+ }
+
/*
* Process request
*/
goto out;
}
+ heim_assert(s4u_pac != NULL, "ad_kdc_issued implies the PAC is non-NULL");
+
+ ret = _kdc_pac_update(r, s4u_client_name, s4u_server_name,
+ s4u_client, r->server, r->krbtgt,
+ &s4u_pac);
+ if (ret == KRB5_PLUGIN_NO_HANDLE) {
+ ret = 0;
+ }
+ if (ret) {
+ const char *msg = krb5_get_error_message(r->context, ret);
+ kdc_audit_addreason((kdc_request_t)r,
+ "Constrained delegation ticket PAC update failed");
+ kdc_log(r->context, r->config, 4,
+ "Update delegated PAC failed to %s for client"
+ "%s (%s) as %s from %s with %s",
+ r->sname, r->cname, s4usname, s4ucname, r->from, msg);
+ krb5_free_error_message(r->context, msg);
+ goto out;
+ }
+
/*
* If the evidence ticket PAC didn't include PAC_UPN_DNS_INFO with
* the canonical client name, but the user is local to our KDC, we
hdb_entry * client,
hdb_entry * server,
hdb_entry * krbtgt,
- krb5_pac *pac)
+ krb5_pac pac,
+ krb5_boolean *is_trusted)
{
krb5_context context = kdc_request_get_context((kdc_request_t)r);
krb5_error_code ret;
krb5_warnx(context, "pac_verify");
- ret = krb5_pac_get_buffer(context, *pac, 1, &data);
+ ret = krb5_pac_get_buffer(context, pac, 1, &data);
if (ret)
return ret;
krb5_data_free(&data);
- ret = krb5_pac_get_kdc_checksum_info(context, *pac, &cstype, &rodc_id);
+ ret = krb5_pac_get_kdc_checksum_info(context, pac, &cstype, &rodc_id);
if (ret)
return ret;
if (ret)
return ret;
- return krb5_pac_verify(context, *pac, 0, NULL, NULL, &key->key);
+ return krb5_pac_verify(context, pac, 0, NULL, NULL, &key->key);
}
static void logit(const char *what, astgs_request_t r)
}
static krb5plugin_kdc_ftable kdc_plugin = {
- KRB5_PLUGIN_KDC_VERSION_10,
+ KRB5_PLUGIN_KDC_VERSION_11,
init,
fini,
pac_generate,
pac_verify,
+ NULL, /* pac_update */
client_access,
NULL, /* referral_policy */
finalize_reply,