krb5_context context,
struct ldb_context *samdb,
const enum auth_group_inclusion group_inclusion,
- const krb5_pac pac, DATA_BLOB *pac_blob,
+ const krb5_const_pac pac, DATA_BLOB *pac_blob,
struct PAC_SIGNATURE_DATA *pac_srv_sig,
struct PAC_SIGNATURE_DATA *pac_kdc_sig)
{
return werr;
}
+/**
+ * @brief Verify a PAC
+ *
+ * @param mem_ctx A talloc memory context
+ *
+ * @param context A krb5 context
+ *
+ * @param flags Bitwise OR'ed flags
+ *
+ * @param client The client samba kdc entry.
+
+ * @param server_principal The server principal
+
+ * @param krbtgt The krbtgt samba kdc entry.
+ *
+ * @param device The computer's samba kdc entry; used for compound
+ * authentication.
+
+ * @param device_pac The PAC from the computer's TGT; used
+ * for compound authentication.
+
+ * @param pac The PAC
+
+ * @return A Kerberos error code.
+ */
+krb5_error_code samba_kdc_verify_pac(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ uint32_t flags,
+ struct samba_kdc_entry *client,
+ const krb5_principal server_principal,
+ const struct samba_kdc_entry *krbtgt,
+ const struct samba_kdc_entry *device,
+ const krb5_const_pac *device_pac,
+ const krb5_const_pac pac)
+{
+ krb5_error_code code = EINVAL;
+ NTSTATUS nt_status;
+ bool is_trusted = flags & SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED;
+
+ struct pac_blobs pac_blobs;
+ pac_blobs_init(&pac_blobs);
+
+ if (client != NULL) {
+ /*
+ * Check the objectSID of the client and pac data are the same.
+ * Does a parse and SID check, but no crypto.
+ */
+ code = samba_kdc_validate_pac_blob(context,
+ client,
+ pac);
+ if (code != 0) {
+ goto done;
+ }
+ }
+
+ if (device != NULL) {
+ SMB_ASSERT(*device_pac != NULL);
+
+ /*
+ * Check the objectSID of the device and pac data are the same.
+ * Does a parse and SID check, but no crypto.
+ */
+ code = samba_kdc_validate_pac_blob(context,
+ device,
+ *device_pac);
+ if (code != 0) {
+ goto done;
+ }
+
+ /*
+ * TODO: When we support compound authentication, we will use
+ * the device PAC to generate PAC buffers for Device Info
+ * (containing the computer account's groups) and Device Claims
+ * (containing claims for the computer account), and insert them
+ * into the emitted PAC.
+ *
+ * See [MS-KILE 1.3.4], [MS-KILE 3.3.5.7.4].
+ */
+ }
+
+ if (!is_trusted) {
+ const struct auth_user_info_dc *user_info_dc = NULL;
+ WERROR werr;
+
+ struct dom_sid *object_sids = NULL;
+ uint32_t j;
+
+ if (client == NULL) {
+ code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ goto done;
+ }
+
+ nt_status = samba_kdc_get_user_info_from_db(mem_ctx, client, client->msg, &user_info_dc);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DBG_ERR("Getting user info for PAC failed: %s\n",
+ nt_errstr(nt_status));
+ code = KRB5KDC_ERR_TGT_REVOKED;
+ goto done;
+ }
+
+ /*
+ * Check if the SID list in the user_info_dc intersects
+ * correctly with the RODC allow/deny lists.
+ */
+ object_sids = talloc_array(mem_ctx, struct dom_sid, user_info_dc->num_sids);
+ if (object_sids == NULL) {
+ code = ENOMEM;
+ goto done;
+ }
+
+ for (j = 0; j < user_info_dc->num_sids; ++j) {
+ object_sids[j] = user_info_dc->sids[j].sid;
+ }
+
+ werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
+ object_sids,
+ krbtgt,
+ client);
+ TALLOC_FREE(object_sids);
+ if (!W_ERROR_IS_OK(werr)) {
+ code = KRB5KDC_ERR_TGT_REVOKED;
+ if (W_ERROR_EQUAL(werr,
+ WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
+ code = KRB5KDC_ERR_POLICY;
+ }
+ goto done;
+ }
+
+ /*
+ * The RODC PAC data isn't trusted for authorization as it may
+ * be stale. The only thing meaningful we can do with an RODC
+ * account on a full DC is exchange the RODC TGT for a 'real'
+ * TGT.
+ *
+ * So we match Windows (at least server 2022) and
+ * don't allow S4U2Self.
+ *
+ * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
+ */
+ if (flags & SAMBA_KDC_FLAG_PROTOCOL_TRANSITION) {
+ code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ goto done;
+ }
+ }
+
+ /* Check the types of the given PAC */
+
+ code = pac_blobs_from_krb5_pac(&pac_blobs,
+ mem_ctx,
+ context,
+ pac);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = pac_blobs_ensure_exists(&pac_blobs,
+ PAC_TYPE_LOGON_INFO);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = pac_blobs_ensure_exists(&pac_blobs,
+ PAC_TYPE_LOGON_NAME);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = pac_blobs_ensure_exists(&pac_blobs,
+ PAC_TYPE_SRV_CHECKSUM);
+ if (code != 0) {
+ goto done;
+ }
+
+ code = pac_blobs_ensure_exists(&pac_blobs,
+ PAC_TYPE_KDC_CHECKSUM);
+ if (code != 0) {
+ goto done;
+ }
+
+ if (!(flags & SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION)) {
+ code = pac_blobs_ensure_exists(&pac_blobs,
+ PAC_TYPE_REQUESTER_SID);
+ if (code != 0) {
+ code = KRB5KDC_ERR_TGT_REVOKED;
+ goto done;
+ }
+ }
+
+ code = 0;
+
+done:
+ pac_blobs_destroy(&pac_blobs);
+
+ return code;
+}
+
/**
* @brief Update a PAC
*
* @param server The server samba kdc entry.
- * @param krbtgt The krbtgt samba kdc entry.
- *
* @param delegated_proxy_principal The delegated proxy principal used for
* updating the constrained delegation PAC
* buffer.
struct samba_kdc_entry *client,
const krb5_principal server_principal,
const struct samba_kdc_entry *server,
- const struct samba_kdc_entry *krbtgt,
const krb5_principal delegated_proxy_principal,
- const struct samba_kdc_entry *device,
- const krb5_const_pac *device_pac,
- const krb5_pac old_pac,
- const krb5_pac new_pac)
+ struct samba_kdc_entry *device,
+ const krb5_const_pac device_pac,
+ const krb5_const_pac old_pac,
+ krb5_pac new_pac)
{
krb5_error_code code = EINVAL;
NTSTATUS nt_status;
group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
}
- if (client != NULL) {
- /*
- * Check the objectSID of the client and pac data are the same.
- * Does a parse and SID check, but no crypto.
- */
- code = samba_kdc_validate_pac_blob(context,
- client,
- old_pac);
- if (code != 0) {
- goto done;
- }
- }
-
if (delegated_proxy_principal != NULL) {
deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
if (deleg_blob == NULL) {
}
}
- if (device != NULL) {
- SMB_ASSERT(*device_pac != NULL);
-
- /*
- * Check the objectSID of the device and pac data are the same.
- * Does a parse and SID check, but no crypto.
- */
- code = samba_kdc_validate_pac_blob(context,
- device,
- *device_pac);
- if (code != 0) {
- goto done;
- }
-
- /*
- * TODO: When we support compound authentication, we will use
- * the device PAC to generate PAC buffers for Device Info
- * (containing the computer account's groups) and Device Claims
- * (containing claims for the computer account), and insert them
- * into the emitted PAC.
- *
- * See [MS-KILE 1.3.4], [MS-KILE 3.3.5.7.4].
- */
- }
-
if (!is_trusted) {
struct auth_user_info_dc user_info_dc = {};
- WERROR werr;
-
- struct dom_sid *object_sids = NULL;
- uint32_t j;
/*
* In this case the RWDC discards the PAC an RODC generated.
code = EINVAL;
goto done;
}
-
- /*
- * Check if the SID list in the user_info_dc intersects
- * correctly with the RODC allow/deny lists.
- */
- object_sids = talloc_array(mem_ctx, struct dom_sid, user_info_dc.num_sids);
- if (object_sids == NULL) {
- code = ENOMEM;
- goto done;
- }
-
- for (j = 0; j < user_info_dc.num_sids; ++j) {
- object_sids[j] = user_info_dc.sids[j].sid;
- }
-
- werr = samba_rodc_confirm_user_is_allowed(user_info_dc.num_sids,
- object_sids,
- krbtgt,
- client);
- TALLOC_FREE(object_sids);
- if (!W_ERROR_IS_OK(werr)) {
- code = KRB5KDC_ERR_TGT_REVOKED;
- if (W_ERROR_EQUAL(werr,
- WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
- code = KRB5KDC_ERR_POLICY;
- }
- goto done;
- }
-
- /*
- * The RODC PAC data isn't trusted for authorization as it may
- * be stale. The only thing meaningful we can do with an RODC
- * account on a full DC is exchange the RODC TGT for a 'real'
- * TGT.
- *
- * So we match Windows (at least server 2022) and
- * don't allow S4U2Self.
- *
- * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
- */
- if (flags & SAMBA_KDC_FLAG_PROTOCOL_TRANSITION) {
- code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
- goto done;
- }
} else {
pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
if (pac_blob == NULL) {
}
#endif
- if (!(flags & SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION)) {
- code = pac_blobs_ensure_exists(&pac_blobs,
- PAC_TYPE_REQUESTER_SID);
- if (code != 0) {
- code = KRB5KDC_ERR_TGT_REVOKED;
- goto done;
- }
- }
-
code = pac_blobs_add_blob(&pac_blobs,
mem_ctx,
PAC_TYPE_CONSTRAINED_DELEGATION,
krb5_context context,
struct ldb_context *samdb,
enum auth_group_inclusion group_inclusion,
- const krb5_pac pac, DATA_BLOB *pac_blob,
+ const krb5_const_pac pac, DATA_BLOB *pac_blob,
struct PAC_SIGNATURE_DATA *pac_srv_sig,
struct PAC_SIGNATURE_DATA *pac_kdc_sig);
const struct samba_kdc_entry *rodc,
const struct samba_kdc_entry *object);
+krb5_error_code samba_kdc_verify_pac(TALLOC_CTX *mem_ctx,
+ krb5_context context,
+ uint32_t flags,
+ struct samba_kdc_entry *client,
+ krb5_principal server_principal,
+ const struct samba_kdc_entry *krbtgt,
+ const struct samba_kdc_entry *device,
+ const krb5_const_pac *device_pac,
+ krb5_const_pac pac);
+
krb5_error_code samba_kdc_update_pac(TALLOC_CTX *mem_ctx,
krb5_context context,
struct ldb_context *samdb,
struct samba_kdc_entry *client,
krb5_principal server_principal,
const struct samba_kdc_entry *server,
- const struct samba_kdc_entry *krbtgt,
krb5_principal delegated_proxy_principal,
- const struct samba_kdc_entry *device,
- const krb5_const_pac *device_pac,
- krb5_pac old_pac,
+ struct samba_kdc_entry *device,
+ krb5_const_pac device_pac,
+ krb5_const_pac old_pac,
krb5_pac new_pac);
NTSTATUS samba_kdc_get_logon_info_blob(TALLOC_CTX *mem_ctx,
return ret;
}
-static krb5_error_code samba_wdc_reget_pac2(astgs_request_t r,
- const krb5_principal delegated_proxy_principal,
- const hdb_entry *client,
- const hdb_entry *server,
- hdb_entry *krbtgt,
- krb5_pac *pac,
- krb5_cksumtype ctype,
- const hdb_entry *device,
- krb5_const_pac *device_pac)
+static krb5_error_code samba_wdc_verify_pac2(astgs_request_t r,
+ const krb5_principal delegated_proxy_principal,
+ const hdb_entry *client,
+ const hdb_entry *server,
+ const hdb_entry *krbtgt,
+ const krb5_pac pac,
+ krb5_cksumtype ctype,
+ const hdb_entry *device,
+ krb5_const_pac *device_pac,
+ krb5_boolean *is_trusted_out)
{
krb5_context context = kdc_request_get_context((kdc_request_t)r);
struct samba_kdc_entry *client_skdc_entry = NULL;
- struct samba_kdc_entry *server_skdc_entry =
- talloc_get_type_abort(server->context, struct samba_kdc_entry);
struct samba_kdc_entry *device_skdc_entry = NULL;
struct samba_kdc_entry *krbtgt_skdc_entry =
talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry);
TALLOC_CTX *mem_ctx = NULL;
- krb5_pac new_pac = NULL;
krb5_error_code ret;
bool is_s4u2self = samba_wdc_is_s4u2self_req(r);
bool is_in_db = false;
bool is_trusted = false;
uint32_t flags = 0;
- mem_ctx = talloc_named(NULL, 0, "samba_wdc_reget_pac2 context");
+ mem_ctx = talloc_named(NULL, 0, "samba_wdc_verify_pac2 context");
if (mem_ctx == NULL) {
return ENOMEM;
}
/* Check the KDC, whole-PAC and ticket signatures. */
ret = krb5_pac_verify(context,
- *pac,
+ pac,
0,
NULL,
NULL,
flags |= SAMBA_KDC_FLAG_KRBTGT_IN_DB;
}
+ ret = samba_kdc_verify_pac(mem_ctx,
+ context,
+ flags,
+ client_skdc_entry,
+ server->principal,
+ krbtgt_skdc_entry,
+ device_skdc_entry,
+ device_pac,
+ pac);
+ if (ret != 0) {
+ goto out;
+ }
+
+ if (is_trusted_out != NULL) {
+ *is_trusted_out = is_trusted;
+ }
+
+out:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+/* Resign (and reform, including possibly new groups) a PAC */
+
+static krb5_error_code samba_wdc_reget_pac(void *priv, 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)
+{
+ krb5_context context = kdc_request_get_context((kdc_request_t)r);
+ const hdb_entry *device = kdc_request_get_explicit_armor_client(r);
+ const krb5_const_pac device_pac = kdc_request_get_explicit_armor_pac(r);
+ struct samba_kdc_entry *client_skdc_entry = NULL;
+ struct samba_kdc_entry *device_skdc_entry = NULL;
+ const struct samba_kdc_entry *server_skdc_entry =
+ talloc_get_type_abort(server->context, struct samba_kdc_entry);
+ const struct samba_kdc_entry *krbtgt_skdc_entry =
+ talloc_get_type_abort(krbtgt->context, struct samba_kdc_entry);
+ TALLOC_CTX *mem_ctx = NULL;
+ krb5_pac new_pac = NULL;
+ krb5_error_code ret;
+ bool is_trusted = false;
+ uint32_t flags = 0;
+
+ mem_ctx = talloc_named(NULL, 0, "samba_wdc_reget_pac context");
+ if (mem_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ if (client != NULL) {
+ client_skdc_entry = talloc_get_type_abort(client->context,
+ struct samba_kdc_entry);
+ }
+
+ if (device != NULL) {
+ device_skdc_entry = talloc_get_type_abort(device->context,
+ struct samba_kdc_entry);
+ }
+
ret = krb5_pac_init(context, &new_pac);
if (ret != 0) {
new_pac = NULL;
goto out;
}
+ is_trusted = krb5_pac_is_trusted(*pac);
+ if (is_trusted) {
+ flags |= SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED;
+ }
+
ret = samba_kdc_update_pac(mem_ctx,
context,
krbtgt_skdc_entry->kdc_db_ctx->samdb,
client_skdc_entry,
server->principal,
server_skdc_entry,
- krbtgt_skdc_entry,
delegated_proxy_principal,
device_skdc_entry,
device_pac,
return ret;
}
-/* Resign (and reform, including possibly new groups) a PAC */
+/* Verify a PAC's SID and signatures */
-static krb5_error_code samba_wdc_reget_pac(void *priv, 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)
+static krb5_error_code samba_wdc_verify_pac(void *priv, 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,
+ krb5_boolean *is_trusted)
{
krb5_context context = kdc_request_get_context((kdc_request_t)r);
krb5_kdc_configuration *config = kdc_request_get_config((kdc_request_t)r);
* the PAC, and this will need to be updated.
*/
ret = krb5_pac_get_kdc_checksum_info(context,
- *pac,
+ pac,
&ctype,
&rodc_id);
if (ret != 0) {
}
}
- ret = samba_wdc_reget_pac2(r,
- delegated_proxy_principal,
- client,
- server,
- krbtgt,
- pac,
- ctype,
- explicit_armor_client,
- &explicit_armor_pac);
+ ret = samba_wdc_verify_pac2(r,
+ delegated_proxy_principal,
+ client,
+ server,
+ krbtgt,
+ pac,
+ ctype,
+ explicit_armor_client,
+ &explicit_armor_pac,
+ is_trusted);
if (krbtgt == &signing_krbtgt_hdb) {
hdb_free_entry(context, config->db[0], &signing_krbtgt_hdb);
}
struct krb5plugin_kdc_ftable kdc_plugin_table = {
- .minor_version = KRB5_PLUGIN_KDC_VERSION_10,
+ .minor_version = KRB5_PLUGIN_KDC_VERSION_11,
.init = samba_wdc_plugin_init,
.fini = samba_wdc_plugin_fini,
- .pac_verify = samba_wdc_reget_pac,
+ .pac_verify = samba_wdc_verify_pac,
+ .pac_update = samba_wdc_reget_pac,
.client_access = samba_wdc_check_client_access,
.finalize_reply = samba_wdc_finalize_reply,
.pac_generate = samba_wdc_get_pac,