summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--librpc/idl/security.idl13
-rw-r--r--source4/dsdb/samdb/ldb_modules/samldb.c190
-rw-r--r--source4/dsdb/samdb/samdb.h6
-rw-r--r--source4/rpc_server/lsa/dcesrv_lsa.c15
-rw-r--r--source4/setup/schema_samba4.ldif1
5 files changed, 220 insertions, 5 deletions
diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl
index eb80a869b0..78c13c9950 100644
--- a/librpc/idl/security.idl
+++ b/librpc/idl/security.idl
@@ -674,14 +674,21 @@ interface security
const string GUID_DRS_CHANGE_RID_MASTER = "d58d5f36-0a98-11d1-adbb-00c04fd8d5cd";
const string GUID_DRS_CHANGE_SCHEMA_MASTER = "e12b56b6-0a95-11d1-adbb-00c04fd8d5cd";
const string GUID_DRS_GET_CHANGES = "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2";
+ const string GUID_DRS_REPL_SYNCRONIZE = "1131f6ab-9c07-11d1-f79f-00c04fc2dcd2";
+ const string GUID_DRS_MANAGE_TOPOLOGY = "1131f6ac-9c07-11d1-f79f-00c04fc2dcd2";
const string GUID_DRS_GET_ALL_CHANGES = "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2";
+ const string GUID_DRS_RO_REPL_SECRET_SYNC = "1131f6ae-9c07-11d1-f79f-00c04fc2dcd2";
const string GUID_DRS_GET_FILTERED_ATTRIBUTES = "89e95b76-444d-4c62-991a-0facbeda640c";
- const string GUID_DRS_MANAGE_TOPOLOGY = "1131f6ac-9c07-11d1-f79f-00c04fc2dcd2";
const string GUID_DRS_MONITOR_TOPOLOGY = "f98340fb-7c5b-4cdb-a00b-2ebdfa115a96";
- const string GUID_DRS_REPL_SYNCRONIZE = "1131f6ab-9c07-11d1-f79f-00c04fc2dcd2";
- const string GUID_DRS_RO_REPL_SECRET_SYNC = "1131f6ae-9c07-11d1-f79f-00c04fc2dcd2";
const string GUID_DRS_USER_CHANGE_PASSWORD = "ab721a53-1e2f-11d0-9819-00aa0040529b";
const string GUID_DRS_FORCE_CHANGE_PASSWORD = "00299570-246d-11d0-a768-00aa006e0529";
+ const string GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT
+ = "280f369c-67c7-438e-ae98-1d46f3c6f541";
+ const string GUID_DRS_UNEXPIRE_PASSWORD = "ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501";
+ const string GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD
+ = "05c74c5e-4deb-43b4-bd9f-86664c2a7fd5";
+ const string GUID_DRS_DS_INSTALL_REPLICA = "9923a32a-3607-11d2-b9be-0000f87a36b2";
+
/***************************************************************/
/* validated writes guids */
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index 7619bbb066..54e2e5e629 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -33,6 +33,7 @@
#include "includes.h"
#include "libcli/ldap/ldap_ndr.h"
#include "ldb_module.h"
+#include "auth/auth.h"
#include "dsdb/samdb/samdb.h"
#include "dsdb/samdb/ldb_modules/util.h"
#include "dsdb/samdb/ldb_modules/ridalloc.h"
@@ -944,6 +945,10 @@ static int samldb_schema_info_update(struct samldb_ctx *ac)
}
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);
/*
* "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
@@ -1039,7 +1044,6 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac)
el = ldb_msg_find_element(ac->msg, "userAccountControl");
if (el != NULL) {
uint32_t user_account_control, account_type;
-
/* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
"userAccountControl",
@@ -1155,6 +1159,12 @@ static int samldb_objectclass_trigger(struct samldb_ctx *ac)
return ret;
}
}
+
+ ret = samldb_check_user_account_control_acl(ac, NULL,
+ user_account_control, 0);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
break;
}
@@ -1442,6 +1452,172 @@ static int samldb_prim_group_trigger(struct samldb_ctx *ac)
return ret;
}
+/**
+ * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
+ *
+ */
+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)
+{
+ int i, ret = 0;
+ bool need_acl_check = false;
+ struct ldb_result *res;
+ const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL};
+ struct security_token *user_token;
+ struct security_descriptor *domain_sd;
+ struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
+ const struct uac_to_guid {
+ uint32_t uac;
+ const char *oid;
+ const char *guid;
+ enum sec_privilege privilege;
+ bool delete_is_privileged;
+ const char *error_string;
+ } map[] = {
+ {
+ .uac = UF_PASSWD_NOTREQD,
+ .guid = GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT,
+ .error_string = "Adding the UF_PASSWD_NOTREQD bit in userAccountControl requires the Update-Password-Not-Required-Bit right that was not given on the Domain object"
+ },
+ {
+ .uac = UF_DONT_EXPIRE_PASSWD,
+ .guid = GUID_DRS_UNEXPIRE_PASSWORD,
+ .error_string = "Adding the UF_DONT_EXPIRE_PASSWD bit in userAccountControl requires the Unexpire-Password right that was not given on the Domain object"
+ },
+ {
+ .uac = UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
+ .guid = GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD,
+ .error_string = "Adding the UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED bit in userAccountControl requires the Enable-Per-User-Reversibly-Encrypted-Password right that was not given on the Domain object"
+ },
+ {
+ .uac = UF_SERVER_TRUST_ACCOUNT,
+ .guid = GUID_DRS_DS_INSTALL_REPLICA,
+ .error_string = "Adding the UF_SERVER_TRUST_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
+ },
+ {
+ .uac = UF_PARTIAL_SECRETS_ACCOUNT,
+ .guid = GUID_DRS_DS_INSTALL_REPLICA,
+ .error_string = "Adding the UF_PARTIAL_SECRETS_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
+ },
+ {
+ .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
+ .oid = DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
+ .error_string = "Updating the UF_INTERDOMAIN_TRUST_ACCOUNT bit in userAccountControl is not permitted over LDAP. This bit is restricted to the LSA CreateTrustedDomain interface",
+ .delete_is_privileged = true
+ },
+ {
+ .uac = UF_TRUSTED_FOR_DELEGATION,
+ .privilege = SEC_PRIV_ENABLE_DELEGATION,
+ .delete_is_privileged = true,
+ .error_string = "Updating the UF_TRUSTED_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
+ },
+ {
+ .uac = UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
+ .privilege = SEC_PRIV_ENABLE_DELEGATION,
+ .delete_is_privileged = true,
+ .error_string = "Updating the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
+ }
+
+ };
+
+ if (dsdb_module_am_system(ac->module)) {
+ return LDB_SUCCESS;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(map); i++) {
+ if (user_account_control & map[i].uac) {
+ need_acl_check = true;
+ break;
+ }
+ }
+ if (need_acl_check == false) {
+ return LDB_SUCCESS;
+ }
+
+ user_token = acl_user_token(ac->module);
+ if (user_token == NULL) {
+ return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+
+ ret = dsdb_module_search_dn(ac->module, ac, &res,
+ domain_dn,
+ sd_attrs,
+ DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ if (res->count != 1) {
+ return ldb_module_operr(ac->module);
+ }
+
+ ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac->module),
+ ac, res->msgs[0], &domain_sd);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(map); i++) {
+ uint32_t this_uac_new = user_account_control & map[i].uac;
+ uint32_t this_uac_old = user_account_control_old & map[i].uac;
+ if (this_uac_new != this_uac_old) {
+ if (this_uac_old != 0) {
+ if (map[i].delete_is_privileged == false) {
+ continue;
+ }
+ }
+ if (map[i].oid) {
+ struct ldb_control *control = ldb_request_get_control(ac->req, map[i].oid);
+ if (control == NULL) {
+ ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+ } else if (map[i].privilege != SEC_PRIV_INVALID) {
+ bool have_priv = security_token_has_privilege(user_token,
+ map[i].privilege);
+ if (have_priv == false) {
+ ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+ }
+ } else {
+ ret = acl_check_extended_right(ac, domain_sd,
+ user_token,
+ map[i].guid,
+ SEC_ADS_CONTROL_ACCESS,
+ sid);
+ }
+ if (ret != LDB_SUCCESS) {
+ break;
+ }
+ }
+ }
+ if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+ 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);
+ }
+ if (map[i].guid) {
+ dsdb_acl_debug(domain_sd, acl_user_token(ac->module),
+ domain_dn,
+ true,
+ 10);
+ }
+ }
+ return ret;
+}
/**
* This function is called on LDB modify operations. It performs some additions/
@@ -1467,6 +1643,7 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
struct ldb_val *val;
struct ldb_val computer_val;
struct ldb_message *tmp_msg;
+ struct dom_sid *sid;
int ret;
struct ldb_result *res;
const char * const attrs[] = {
@@ -1475,6 +1652,7 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
"userAccountControl",
"msDS-User-Account-Control-Computed",
"lockoutTime",
+ "objectSid",
NULL
};
bool is_computer = false;
@@ -1671,6 +1849,16 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac)
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;
}
diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h
index 7f77d4e382..4f57343e05 100644
--- a/source4/dsdb/samdb/samdb.h
+++ b/source4/dsdb/samdb/samdb.h
@@ -135,6 +135,12 @@ struct dsdb_control_password_change {
*/
#define DSDB_CONTROL_SEC_DESC_PROPAGATION_OID "1.3.6.1.4.1.7165.4.3.21"
+/*
+ * passed when creating a interdomain trust account through LSA
+ * to relax constraints in the samldb ldb module.
+ */
+#define DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID "1.3.6.1.4.1.7165.4.3.23"
+
#define DSDB_EXTENDED_REPLICATED_OBJECTS_OID "1.3.6.1.4.1.7165.4.4.1"
struct dsdb_extended_replicated_object {
struct ldb_message *msg;
diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c
index cc2048da07..b7936b892e 100644
--- a/source4/rpc_server/lsa/dcesrv_lsa.c
+++ b/source4/rpc_server/lsa/dcesrv_lsa.c
@@ -800,6 +800,7 @@ static NTSTATUS add_trust_user(TALLOC_CTX *mem_ctx,
struct trustAuthInOutBlob *in,
struct ldb_dn **user_dn)
{
+ struct ldb_request *req;
struct ldb_message *msg;
struct ldb_dn *dn;
uint32_t i;
@@ -860,7 +861,19 @@ static NTSTATUS add_trust_user(TALLOC_CTX *mem_ctx,
}
/* create the trusted_domain user account */
- ret = ldb_add(sam_ldb, msg);
+ ret = ldb_build_add_req(&req, sam_ldb, mem_ctx, msg, NULL, NULL,
+ ldb_op_default_callback, NULL);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = ldb_request_add_control(req, DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
+ false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ret = dsdb_autotransaction_request(sam_ldb, req);
if (ret != LDB_SUCCESS) {
DEBUG(0,("Failed to create user record %s: %s\n",
ldb_dn_get_linearized(msg->dn),
diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif
index 94aedb099d..22f0bc13d0 100644
--- a/source4/setup/schema_samba4.ldif
+++ b/source4/setup/schema_samba4.ldif
@@ -197,6 +197,7 @@
#Allocated: DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA 1.3.6.1.4.1.7165.4.3.19.1
#Allocated: DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID 1.3.6.1.4.1.7165.4.3.20
#Allocated: DSDB_CONTROL_SEC_DESC_PROPAGATION_OID 1.3.6.1.4.1.7165.4.3.21
+#Allocated: DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID 1.3.6.1.4.1.7165.4.3.23
# Extended 1.3.6.1.4.1.7165.4.4.x
#Allocated: DSDB_EXTENDED_REPLICATED_OBJECTS_OID 1.3.6.1.4.1.7165.4.4.1