}
static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid);
-static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
- struct dom_sid *sid,
- uint32_t user_account_control,
- uint32_t user_account_control_old);
+static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
+ struct dom_sid *sid,
+ uint32_t user_account_control,
+ uint32_t user_account_control_old);
/*
* "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
uac_generated = true;
}
- /* Temporary duplicate accounts aren't allowed */
- if ((user_account_control & UF_TEMP_DUPLICATE_ACCOUNT) != 0) {
- return LDB_ERR_OTHER;
+ ret = samldb_check_user_account_control_rules(ac, NULL,
+ user_account_control, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
/* Workstation and (read-only) DC objects do need objectclass "computer" */
}
}
- ret = samldb_check_user_account_control_acl(ac, NULL,
- user_account_control, 0);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
}
break;
}
return ret;
}
+static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac,
+ uint32_t user_account_control)
+{
+ int i, ret = 0;
+ bool need_check = false;
+ const struct uac_to_guid {
+ uint32_t uac;
+ bool never;
+ uint32_t needs;
+ uint32_t not_with;
+ const char *error_string;
+ } map[] = {
+ {
+ .uac = UF_TEMP_DUPLICATE_ACCOUNT,
+ .never = true,
+ .error_string = "Updating the UF_TEMP_DUPLICATE_ACCOUNT flag is never allowed"
+ },
+ {
+ .uac = UF_PARTIAL_SECRETS_ACCOUNT,
+ .needs = UF_WORKSTATION_TRUST_ACCOUNT,
+ .error_string = "Setting UF_PARTIAL_SECRETS_ACCOUNT only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
+ },
+ {
+ .uac = UF_TRUSTED_FOR_DELEGATION,
+ .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
+ .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
+ },
+ {
+ .uac = UF_NORMAL_ACCOUNT,
+ .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_NORMAL_ACCOUNT,
+ .error_string = "Setting more than one account type not permitted"
+ },
+ {
+ .uac = UF_WORKSTATION_TRUST_ACCOUNT,
+ .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_WORKSTATION_TRUST_ACCOUNT,
+ .error_string = "Setting more than one account type not permitted"
+ },
+ {
+ .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
+ .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_INTERDOMAIN_TRUST_ACCOUNT,
+ .error_string = "Setting more than one account type not permitted"
+ },
+ {
+ .uac = UF_SERVER_TRUST_ACCOUNT,
+ .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_SERVER_TRUST_ACCOUNT,
+ .error_string = "Setting more than one account type not permitted"
+ },
+ {
+ .uac = UF_TRUSTED_FOR_DELEGATION,
+ .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
+ .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
+ }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(map); i++) {
+ if (user_account_control & map[i].uac) {
+ need_check = true;
+ break;
+ }
+ }
+ if (need_check == false) {
+ return LDB_SUCCESS;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(map); i++) {
+ uint32_t this_uac = user_account_control & map[i].uac;
+ if (this_uac != 0) {
+ if (map[i].never) {
+ ret = LDB_ERR_OTHER;
+ break;
+ } else if (map[i].needs != 0) {
+ if ((map[i].needs & user_account_control) == 0) {
+ ret = LDB_ERR_OTHER;
+ break;
+ }
+ } else if (map[i].not_with != 0) {
+ if ((map[i].not_with & user_account_control) != 0) {
+ ret = LDB_ERR_OTHER;
+ break;
+ }
+ }
+ }
+ }
+ if (ret != LDB_SUCCESS) {
+ switch (ac->req->operation) {
+ case LDB_ADD:
+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
+ "Failed to add %s: %s",
+ ldb_dn_get_linearized(ac->msg->dn),
+ map[i].error_string);
+ break;
+ case LDB_MODIFY:
+ ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
+ "Failed to modify %s: %s",
+ ldb_dn_get_linearized(ac->msg->dn),
+ map[i].error_string);
+ break;
+ default:
+ return ldb_module_operr(ac->module);
+ }
+ }
+ return ret;
+}
+
/**
* Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
*
return ret;
}
+static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
+ struct dom_sid *sid,
+ uint32_t user_account_control,
+ uint32_t user_account_control_old)
+{
+ int ret;
+ ret = samldb_check_user_account_control_invariants(ac, user_account_control);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ return ret;
+}
+
+
/**
* This function is called on LDB modify operations. It performs some additions/
* replaces on the current LDB message when "userAccountControl" changes.
if (new_ufa == 0) {
/*
* When there is no account type embedded in "userAccountControl"
- * fall back to the old.
+ * fall back to UF_NORMAL_ACCOUNT.
*/
- new_ufa = old_ufa;
+ new_ufa = UF_NORMAL_ACCOUNT;
new_uac |= new_ufa;
}
+ sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
+ if (sid == NULL) {
+ return ldb_module_operr(ac->module);
+ }
+
+ ret = samldb_check_user_account_control_rules(ac, sid, new_uac, old_uac);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
new_atype = ds_uf2atype(new_ufa);
new_pgrid = ds_uf2prim_group_rid(new_uac);
ldb_msg_remove_attr(ac->msg, "userAccountControl");
}
- sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
- if (sid == NULL) {
- return ldb_module_operr(ac->module);
- }
-
- ret = samldb_check_user_account_control_acl(ac, sid, new_uac, old_uac);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
return LDB_SUCCESS;
}
self.assertEqual(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT|UF_ACCOUNTDISABLE|UF_PASSWD_NOTREQD)
+ m = ldb.Message()
+ m.dn = res[0].dn
+ m["userAccountControl"] = ldb.MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT|UF_PARTIAL_SECRETS_ACCOUNT|UF_TRUSTED_FOR_DELEGATION),
+ ldb.FLAG_MOD_REPLACE, "userAccountControl")
+ try:
+ self.admin_samdb.modify(m)
+ self.fail("Unexpectedly able to set userAccountControl to UF_WORKSTATION_TRUST_ACCOUNT|UF_PARTIAL_SECRETS_ACCOUNT|UF_TRUSTED_FOR_DELEGATION on %s" % m.dn)
+ except LdbError, (enum, estr):
+ self.assertEqual(ldb.ERR_OTHER, enum)
+
m = ldb.Message()
m.dn = res[0].dn
m["userAccountControl"] = ldb.MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT|UF_PARTIAL_SECRETS_ACCOUNT),
scope=SCOPE_SUBTREE,
attrs=["userAccountControl"])
- self.assertEqual(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT| UF_ACCOUNTDISABLE)
+ self.assertEqual(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT| UF_ACCOUNTDISABLE)
def test_uac_bits_set(self):
# These bits really are privileged
priv_bits = set([UF_INTERDOMAIN_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT,
- UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
- UF_PARTIAL_SECRETS_ACCOUNT])
+ UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION])
- invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT])
+ invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT, UF_PARTIAL_SECRETS_ACCOUNT])
for bit in bits:
m = ldb.Message()
"description")
self.samdb.modify(m)
- invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT])
+ invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT, UF_PARTIAL_SECRETS_ACCOUNT])
super_priv_bits = set([UF_INTERDOMAIN_TRUST_ACCOUNT])
self.sd_utils.dacl_add_ace("OU=test_computer_ou1," + self.base_dn, mod)
- invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT])
+ invalid_bits = set([UF_TEMP_DUPLICATE_ACCOUNT, UF_PARTIAL_SECRETS_ACCOUNT])
# These bits are privileged, but authenticated users have that CAR by default, so this is a pain to test
priv_to_auth_users_bits = set([UF_PASSWD_NOTREQD, UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
# These bits really are privileged
priv_bits = set([UF_INTERDOMAIN_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT,
- UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
- UF_PARTIAL_SECRETS_ACCOUNT])
+ UF_TRUSTED_FOR_DELEGATION, UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION])
for bit in bits:
try: