# KDC TGT tests
#
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_allowed_denied
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_krbtgt_link
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_no_partial_secrets
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_allowed
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_renew_rodc_not_revealed
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_allowed_denied
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_krbtgt_link
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_no_partial_secrets
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_allowed
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_s4u2self_rodc_not_revealed
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_allowed_denied
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_krbtgt_link
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_no_partial_secrets
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_allowed
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_tgs_rodc_not_revealed
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_mac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_upn_dns_info_ex_upn_mac
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_sname_krbtgt
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_user2user_wrong_srealm
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_authdata_no_pac
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_allowed_denied
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_denied
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_krbtgt_link
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_no_partial_secrets
-^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_allowed
^samba.tests.krb5.kdc_tgs_tests.samba.tests.krb5.kdc_tgs_tests.KdcTgsTests.test_validate_rodc_not_revealed
#
# PAC request tests
\
"pwdLastSet", \
"msDS-UserPasswordExpiryTimeComputed", \
- "accountExpires"
+ "accountExpires", \
+ \
+ /* Needed for RODC rule processing */ \
+ "msDS-KrbTgtLinkBL"
const char *krbtgt_attrs[] = {
KRBTGT_ATTRS, NULL
/*
* Return an array of SIDs from a ldb_message given an attribute name assumes
- * the SIDs are in NDR form (with additional sids applied on the end).
+ * the SIDs are in NDR form (with primary_sid applied on the start).
*/
-WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
- struct ldb_message *msg,
- TALLOC_CTX *mem_ctx,
- const char *attr,
- uint32_t *num_sids,
- struct dom_sid **sids,
- const struct dom_sid *additional_sids,
- unsigned int num_additional)
+static WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
+ struct ldb_message *msg,
+ TALLOC_CTX *mem_ctx,
+ const char *attr,
+ uint32_t *num_sids,
+ struct dom_sid **sids,
+ const struct dom_sid *primary_sid)
{
struct ldb_message_element *el;
- unsigned int i, j;
+ unsigned int i;
el = ldb_msg_find_element(msg, attr);
if (!el) {
/* Make array long enough for NULL and additional SID */
(*sids) = talloc_array(mem_ctx, struct dom_sid,
- el->num_values + num_additional);
+ el->num_values + 1);
W_ERROR_HAVE_NO_MEMORY(*sids);
- for (i=0; i<el->num_values; i++) {
+ (*sids)[0] = *primary_sid;
+
+ for (i = 0; i<el->num_values; i++) {
enum ndr_err_code ndr_err;
+ struct dom_sid sid = { 0, };
- ndr_err = ndr_pull_struct_blob_all_noalloc(&el->values[i], &(*sids)[i],
+ ndr_err = ndr_pull_struct_blob_all_noalloc(&el->values[i], &sid,
(ndr_pull_flags_fn_t)ndr_pull_dom_sid);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
return WERR_INTERNAL_DB_CORRUPTION;
}
+ /* Primary SID is already in position zero. */
+ (*sids)[i+1] = sid;
}
- for (j = 0; j < num_additional; j++) {
- (*sids)[i++] = additional_sids[j];
- }
-
- *num_sids = i;
+ *num_sids = i+1;
return WERR_OK;
}
}
WERROR samdb_confirm_rodc_allowed_to_repl_to_sid_list(struct ldb_context *sam_ctx,
+ const struct dom_sid *rodc_machine_account_sid,
struct ldb_message *rodc_msg,
struct ldb_message *obj_msg,
uint32_t num_token_sids,
return WERR_DS_DRA_SECRETS_DENIED;
}
+ /* The RODC can replicate and print tickets for itself. */
+ if (dom_sid_equal(&token_sids[0], rodc_machine_account_sid)) {
+ TALLOC_FREE(frame);
+ return WERR_OK;
+ }
+
if (never_reveal_sids &&
sid_list_match(num_token_sids,
token_sids,
* rather than relying on the caller providing those
*/
WERROR samdb_confirm_rodc_allowed_to_repl_to(struct ldb_context *sam_ctx,
+ struct dom_sid *rodc_machine_account_sid,
struct ldb_message *rodc_msg,
struct ldb_message *obj_msg)
{
frame, "tokenGroups",
&num_token_sids,
&token_sids,
- object_sid, 1);
+ object_sid);
if (!W_ERROR_IS_OK(werr) || token_sids==NULL) {
DBG_ERR("Failed to get tokenGroups on %s to confirm access via RODC %s: %s\n",
ldb_dn_get_linearized(obj_msg->dn),
}
werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(sam_ctx,
+ rodc_machine_account_sid,
rodc_msg,
obj_msg,
num_token_sids,
&logon_info_blob,
cred_ndr_ptr,
&upn_dns_info_blob,
- NULL, NULL);
+ NULL, NULL,
+ NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(tmp_ctx);
if (NT_STATUS_EQUAL(nt_status,
&pac_blob,
NULL,
&upn_blob,
- NULL, NULL);
+ NULL, NULL,
+ NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
code = EINVAL;
goto done;
#include "libcli/security/security.h"
#include "dsdb/samdb/samdb.h"
#include "auth/kerberos/pac_utils.h"
+#include "source4/dsdb/common/util.h"
static
NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
return 0;
}
+/*
+ * We return not just the blobs, but also the user_info_dc because we
+ * will need, in the RODC case, to confirm that the returned user is
+ * permitted to be replicated to the KDC
+ */
NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
struct samba_kdc_entry *p,
DATA_BLOB **_logon_info_blob,
DATA_BLOB **_cred_ndr_blob,
DATA_BLOB **_upn_info_blob,
DATA_BLOB **_pac_attrs_blob,
- const krb5_boolean *pac_request)
+ const krb5_boolean *pac_request,
+ struct auth_user_info_dc **_user_info_dc)
{
struct auth_user_info_dc *user_info_dc;
DATA_BLOB *logon_blob = NULL;
}
}
- TALLOC_FREE(user_info_dc);
+ /*
+ * Return to the caller to allow a check on the allowed/denied
+ * RODC replication groups
+ */
+ if (_user_info_dc == NULL) {
+ TALLOC_FREE(user_info_dc);
+ } else {
+ *_user_info_dc = user_info_dc;
+ }
*_logon_info_blob = logon_blob;
if (_cred_ndr_blob != NULL) {
*_cred_ndr_blob = cred_blob;
TALLOC_FREE(frame);
return code;
}
+
+
+/*
+ * In the RODC case, to confirm that the returned user is permitted to
+ * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
+ */
+WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids,
+ struct dom_sid *object_sids,
+ struct samba_kdc_entry *rodc,
+ struct samba_kdc_entry *object)
+{
+ int ret;
+ WERROR werr;
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *rodc_attrs[] = { "msDS-KrbTgtLink",
+ "msDS-NeverRevealGroup",
+ "msDS-RevealOnDemandGroup",
+ "userAccountControl",
+ "objectSid",
+ NULL };
+ struct ldb_result *rodc_machine_account = NULL;
+ struct ldb_dn *rodc_machine_account_dn = samdb_result_dn(rodc->kdc_db_ctx->samdb,
+ frame,
+ rodc->msg,
+ "msDS-KrbTgtLinkBL",
+ NULL);
+ const struct dom_sid *rodc_machine_account_sid = NULL;
+
+ if (rodc_machine_account_dn == NULL) {
+ DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
+ ldb_dn_get_linearized(rodc->msg->dn));
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_BAD_DN;
+ }
+
+ /*
+ * Follow the link and get the RODC account (the krbtgt
+ * account is the krbtgt_XXX account, but the
+ * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
+ * the RODC$ account)
+ *
+ * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
+ * out of the extended DNs
+ */
+
+ ret = dsdb_search_dn(rodc->kdc_db_ctx->samdb,
+ frame,
+ &rodc_machine_account,
+ rodc_machine_account_dn,
+ rodc_attrs,
+ DSDB_SEARCH_SHOW_EXTENDED_DN);
+ if (ret != LDB_SUCCESS) {
+ DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
+ ldb_dn_get_linearized(rodc_machine_account_dn),
+ ldb_dn_get_linearized(rodc->msg->dn),
+ ldb_errstring(rodc->kdc_db_ctx->samdb));
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_BAD_DN;
+ }
+
+ if (rodc_machine_account->count != 1) {
+ DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
+ ldb_dn_get_linearized(rodc_machine_account_dn),
+ ldb_dn_get_linearized(rodc->msg->dn),
+ rodc_machine_account->count);
+ TALLOC_FREE(frame);
+ return WERR_DS_DRA_BAD_DN;
+ }
+
+ /* if the object SID is equal to the user_sid, allow */
+ rodc_machine_account_sid = samdb_result_dom_sid(frame,
+ rodc_machine_account->msgs[0],
+ "objectSid");
+ if (rodc_machine_account_sid == NULL) {
+ return WERR_DS_DRA_BAD_DN;
+ }
+
+ werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc->kdc_db_ctx->samdb,
+ rodc_machine_account_sid,
+ rodc_machine_account->msgs[0],
+ object->msg,
+ num_object_sids,
+ object_sids);
+
+ TALLOC_FREE(frame);
+ return werr;
+}
DATA_BLOB **_cred_ndr_blob,
DATA_BLOB **_upn_info_blob,
DATA_BLOB **_pac_attrs_blob,
- const krb5_boolean *pac_request);
-
+ const krb5_boolean *pac_request,
+ struct auth_user_info_dc **_user_info_dc);
NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
krb5_context context,
struct ldb_context *samdb,
krb5_context context,
struct samba_kdc_entry *client_skdc_entry,
const krb5_pac pac);
+
+/*
+ * In the RODC case, to confirm that the returned user is permitted to
+ * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
+ */
+WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_sids,
+ struct dom_sid *sids,
+ struct samba_kdc_entry *rodc,
+ struct samba_kdc_entry *object);
#include "kdc/pac-glue.h"
#include "sdb.h"
#include "sdb_hdb.h"
+#include "librpc/gen_ndr/auth.h"
/*
* Given the right private pointer from hdb_samba4,
cred_ndr_ptr,
&upn_blob,
&pac_attrs_blob,
- pac_request);
+ pac_request,
+ NULL);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
return EINVAL;
}
}
- /* If the krbtgt was generated by an RODC, and we are not that
+ /*
+ * If the krbtgt was generated by an RODC, and we are not that
* RODC, then we need to regenerate the PAC - we can't trust
- * it */
+ * it, and confirm that the RODC was permitted to print this ticket
+ *
+ * Becasue of the samba_kdc_validate_pac_blob() step we can be
+ * sure that the record in 'client' matches the SID in the
+ * original PAC.
+ */
ret = samba_krbtgt_is_in_db(krbtgt_skdc_entry, &is_in_db, &is_untrusted);
if (ret != 0) {
talloc_free(mem_ctx);
if (is_untrusted) {
struct samba_kdc_entry *client_skdc_entry = NULL;
+ struct auth_user_info_dc *user_info_dc = NULL;
+ WERROR werr;
if (client == NULL) {
return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry,
&pac_blob, NULL, &upn_blob,
- NULL, NULL);
+ NULL, NULL,
+ &user_info_dc);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(mem_ctx);
- return EINVAL;
+ return KRB5KDC_ERR_TGT_REVOKED;
+ }
+
+ /*
+ * Now check if the SID list in the user_info_dc
+ * intersects correctly with the RODC allow/deny
+ * lists
+ */
+
+ werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
+ user_info_dc->sids,
+ krbtgt_skdc_entry,
+ client_skdc_entry);
+ if (!W_ERROR_IS_OK(werr)) {
+ talloc_free(mem_ctx);
+ return KRB5KDC_ERR_TGT_REVOKED;
}
- } else {
+ }
+
+ if (!is_untrusted) {
pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
if (!pac_blob) {
talloc_free(mem_ctx);
NULL };
const char *obj_attrs[] = { "tokenGroups", "objectSid", "UserAccountControl", "msDS-KrbTgtLinkBL", NULL };
struct ldb_result *rodc_res = NULL, *obj_res = NULL;
- const struct dom_sid *object_sid = NULL;
WERROR werr;
DEBUG(3,(__location__ ": DRSUAPI_EXOP_REPL_SECRET extended op on %s\n",
ret = dsdb_search_dn(b_state->sam_ctx_system, mem_ctx, &obj_res, obj_dn, obj_attrs, 0);
if (ret != LDB_SUCCESS || obj_res->count != 1) goto failed;
- /* if the object SID is equal to the user_sid, allow */
- object_sid = samdb_result_dom_sid(mem_ctx, obj_res->msgs[0], "objectSid");
- if (object_sid == NULL) {
- goto failed;
- }
- if (dom_sid_equal(user_sid, object_sid)) {
- goto allowed;
- }
-
/*
* Must be an RODC account at this point, verify machine DN matches the
* SID account
}
werr = samdb_confirm_rodc_allowed_to_repl_to(b_state->sam_ctx_system,
+ user_sid,
rodc_res->msgs[0],
obj_res->msgs[0]);
if (ret != LDB_SUCCESS || obj_res->count != 1) goto denied;
werr = samdb_confirm_rodc_allowed_to_repl_to(sam_ctx,
+ user_sid,
rodc_res->msgs[0],
obj_res->msgs[0]);