The branch, master has been updated via 9401189 s4:samldb LDB module - make the "userAccountControl" and "groupType" modify handlers separate functions via 098ea71 s4:samldb LDB module - add a new function which handles special cases for single-valued attribute on SAM modifications via 095c8b2 s4:samldb LDB module - primary group change - free temporary messages to save memory from c0ebf5d s4:sam.py - add a short double swap "primaryGroupID" test
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 9401189d5435632bcc6a177845ce03beaa804113 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 19:56:54 2010 +0200 s4:samldb LDB module - make the "userAccountControl" and "groupType" modify handlers separate functions It's easier to maintain afterwards Autobuild-User: Matthias Dieter Wallnöfer <m...@samba.org> Autobuild-Date: Sat Oct 30 19:07:20 UTC 2010 on sn-devel-104 commit 098ea71728eb6389ff4c5314d17df533f79a07a8 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 19:37:30 2010 +0200 s4:samldb LDB module - add a new function which handles special cases for single-valued attribute on SAM modifications This saves quiet some work. commit 095c8b2078128838f6b830613e80cbdcf49e10cf Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 19:56:24 2010 +0200 s4:samldb LDB module - primary group change - free temporary messages to save memory ----------------------------------------------------------------------- Summary of changes: source4/dsdb/samdb/ldb_modules/samldb.c | 380 ++++++++++++++++++------------ 1 files changed, 228 insertions(+), 152 deletions(-) Changeset truncated at 500 lines: diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 44c8fee..9b6d6e0 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -751,6 +751,53 @@ static int samldb_schema_info_update(struct samldb_ctx *ac) } /* + * Gets back a single-valued attribute by the rules of the SAM triggers when + * performing a modify operation + */ +static int samldb_get_single_valued_attr(struct samldb_ctx *ac, + const char *attr_name, + struct ldb_message_element **attr) +{ + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + struct ldb_message_element *el = NULL; + unsigned int i; + + /* We've to walk over all modification entries and consider the + * "attr_name" ones. + * + * 1.) Add operations aren't allowed and there is returned + * "ATTRIBUTE_OR_VALUE_EXISTS". + * 2.) Replace operations are allowed but the last one is taken + * 3.) Delete operations are also not allowed and there is returned + * "UNWILLING_TO_PERFORM". + * + * If "el" is afterwards NULL then that means we've nothing to do here. + */ + for (i = 0; i < ac->msg->num_elements; i++) { + if (ldb_attr_cmp(ac->msg->elements[i].name, attr_name) != 0) { + continue; + } + + el = &ac->msg->elements[i]; + if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) { + ldb_asprintf_errstring(ldb, + "samldb: attribute '%s' already exists!", + attr_name); + return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + } + if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) { + ldb_asprintf_errstring(ldb, + "samldb: attribute '%s' cannot be deleted!", + attr_name); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + } + + *attr = el; + return LDB_SUCCESS; +} + +/* * "Objectclass" trigger (MS-SAMR 3.1.1.8.1) * * Has to be invoked on "add" and "modify" operations on "user", "computer" and @@ -1002,41 +1049,17 @@ static int samldb_prim_group_change(struct samldb_ctx *ac) uint32_t rid; struct dom_sid *sid; struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn; - unsigned int i; int ret; - /* We've to walk over all modification entries and consider the - * "primaryGroupID" ones. - * - * 1.) Add operations aren't allowed and there is returned - * "ATTRIBUTE_OR_VALUE_EXISTS". - * 2.) Replace operations are allowed but the last one is taken - * 3.) Delete operations are also not allowed and there is returned - * "UNWILLING_TO_PERFORM". - * - * If "el" is afterwards NULL then that means we've nothing to do here. - */ - el = NULL; - for (i = 0; i < ac->msg->num_elements; i++) { - if (ldb_attr_cmp(ac->msg->elements[i].name, - "primaryGroupID") != 0) { - continue; - } - - el = &ac->msg->elements[i]; - if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) { - return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; - } - if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) { - return LDB_ERR_UNWILLING_TO_PERFORM; - } + ret = samldb_get_single_valued_attr(ac, "primaryGroupID", &el); + if (ret != LDB_SUCCESS) { + return ret; } if (el == NULL) { + /* we are not affected */ return LDB_SUCCESS; } - /* Okay, now for sure we are performing a "primaryGroupID" replace */ - /* Fetch informations from the existing object */ ret = ldb_search(ldb, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs, @@ -1109,7 +1132,7 @@ static int samldb_prim_group_change(struct samldb_ctx *ac) } /* Remove the "member" attribute on the new primary group */ - msg = talloc_zero(ac, struct ldb_message); + msg = ldb_msg_new(ac->msg); if (msg == NULL) { return ldb_module_oom(ac->module); } @@ -1125,9 +1148,10 @@ static int samldb_prim_group_change(struct samldb_ctx *ac) if (ret != LDB_SUCCESS) { return ret; } + talloc_free(msg); /* Add a "member" attribute for the previous primary group */ - msg = talloc_zero(ac, struct ldb_message); + msg = ldb_msg_new(ac->msg); if (msg == NULL) { return ldb_module_oom(ac->module); } @@ -1143,6 +1167,7 @@ static int samldb_prim_group_change(struct samldb_ctx *ac) if (ret != LDB_SUCCESS) { return ret; } + talloc_free(msg); } talloc_free(res); @@ -1163,6 +1188,169 @@ static int samldb_prim_group_trigger(struct samldb_ctx *ac) return ret; } +static int samldb_user_account_control_change(struct samldb_ctx *ac) +{ + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + uint32_t user_account_control, account_type; + struct ldb_message_element *el; + struct ldb_message *tmp_msg; + int ret; + + ret = samldb_get_single_valued_attr(ac, "userAccountControl", &el); + if (ret != LDB_SUCCESS) { + return ret; + } + if (el == NULL) { + /* we are not affected */ + return LDB_SUCCESS; + } + + /* Create a temporary message for fetching the "userAccountControl" */ + tmp_msg = ldb_msg_new(ac->msg); + if (tmp_msg == NULL) { + return ldb_module_oom(ac->module); + } + ret = ldb_msg_add(tmp_msg, el, 0); + if (ret != LDB_SUCCESS) { + return ret; + } + user_account_control = ldb_msg_find_attr_as_uint(tmp_msg, + "userAccountControl", + 0); + talloc_free(tmp_msg); + + /* Temporary duplicate accounts aren't allowed */ + if ((user_account_control & UF_TEMP_DUPLICATE_ACCOUNT) != 0) { + return LDB_ERR_OTHER; + } + + account_type = ds_uf2atype(user_account_control); + if (account_type == 0) { + ldb_set_errstring(ldb, "samldb: Unrecognized account type!"); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType", + account_type); + if (ret != LDB_SUCCESS) { + return ret; + } + el = ldb_msg_find_element(ac->msg, "sAMAccountType"); + el->flags = LDB_FLAG_MOD_REPLACE; + + if (user_account_control + & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) { + ret = samdb_msg_add_string(ldb, ac->msg, ac->msg, + "isCriticalSystemObject", "TRUE"); + if (ret != LDB_SUCCESS) { + return ret; + } + el = ldb_msg_find_element(ac->msg, + "isCriticalSystemObject"); + el->flags = LDB_FLAG_MOD_REPLACE; + } + + if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) { + uint32_t rid = ds_uf2prim_group_rid(user_account_control); + ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, + "primaryGroupID", rid); + if (ret != LDB_SUCCESS) { + return ret; + } + el = ldb_msg_find_element(ac->msg, + "primaryGroupID"); + el->flags = LDB_FLAG_MOD_REPLACE; + } + + return LDB_SUCCESS; +} + +static int samldb_group_type_change(struct samldb_ctx *ac) +{ + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + uint32_t group_type, old_group_type, account_type; + struct ldb_message_element *el; + struct ldb_message *tmp_msg; + int ret; + + ret = samldb_get_single_valued_attr(ac, "groupType", &el); + if (ret != LDB_SUCCESS) { + return ret; + } + if (el == NULL) { + /* we are not affected */ + return LDB_SUCCESS; + } + + /* Create a temporary message for fetching the "groupType" */ + tmp_msg = ldb_msg_new(ac->msg); + if (tmp_msg == NULL) { + return ldb_module_oom(ac->module); + } + ret = ldb_msg_add(tmp_msg, el, 0); + if (ret != LDB_SUCCESS) { + return ret; + } + group_type = ldb_msg_find_attr_as_uint(tmp_msg, "groupType", 0); + talloc_free(tmp_msg); + + old_group_type = samdb_search_uint(ldb, ac, 0, ac->msg->dn, + "groupType", NULL); + if (old_group_type == 0) { + return ldb_operr(ldb); + } + + /* Group type switching isn't so easy as it seems: We can only + * change in this directions: global <-> universal <-> local + * On each step also the group type itself + * (security/distribution) is variable. */ + + switch (group_type) { + case GTYPE_SECURITY_GLOBAL_GROUP: + case GTYPE_DISTRIBUTION_GLOBAL_GROUP: + /* change to "universal" allowed */ + if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) || + (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) { + return LDB_ERR_UNWILLING_TO_PERFORM; + } + break; + + case GTYPE_SECURITY_UNIVERSAL_GROUP: + case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP: + /* each change allowed */ + break; + + case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP: + case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP: + /* change to "universal" allowed */ + if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) || + (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) { + return LDB_ERR_UNWILLING_TO_PERFORM; + } + break; + + case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP: + default: + /* we don't allow this "groupType" values */ + return LDB_ERR_UNWILLING_TO_PERFORM; + break; + } + + account_type = ds_gtype2atype(group_type); + if (account_type == 0) { + ldb_set_errstring(ldb, "samldb: Unrecognized account type!"); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "sAMAccountType", + account_type); + if (ret != LDB_SUCCESS) { + return ret; + } + el = ldb_msg_find_element(ac->msg, "sAMAccountType"); + el->flags = LDB_FLAG_MOD_REPLACE; + + return LDB_SUCCESS; +} + static int samldb_member_check(struct samldb_ctx *ac) { struct ldb_context *ldb = ldb_module_get_ctx(ac->module); @@ -1354,10 +1542,9 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct samldb_ctx *ac; - struct ldb_message_element *el, *el2; + struct ldb_message_element *el; bool modified = false; int ret; - uint32_t account_type; if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */ @@ -1406,75 +1593,6 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) return ldb_operr(ldb); } - el = ldb_msg_find_element(ac->msg, "groupType"); - if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) - && el->num_values == 1) { - uint32_t group_type, old_group_type; - - modified = true; - - group_type = ldb_msg_find_attr_as_uint(ac->msg, "groupType", 0); - old_group_type = samdb_search_uint(ldb, ac, 0, ac->msg->dn, - "groupType", NULL); - if (old_group_type == 0) { - return ldb_operr(ldb); - } - - /* Group type switching isn't so easy as it seems: We can only - * change in this directions: global <-> universal <-> local - * On each step also the group type itself - * (security/distribution) is variable. */ - - switch (group_type) { - case GTYPE_SECURITY_GLOBAL_GROUP: - case GTYPE_DISTRIBUTION_GLOBAL_GROUP: - /* change to "universal" allowed */ - if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) || - (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) { - return LDB_ERR_UNWILLING_TO_PERFORM; - } - break; - - case GTYPE_SECURITY_UNIVERSAL_GROUP: - case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP: - /* each change allowed */ - break; - - case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP: - case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP: - /* change to "universal" allowed */ - if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) || - (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) { - return LDB_ERR_UNWILLING_TO_PERFORM; - } - break; - - case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP: - default: - /* we don't allow this "groupType" values */ - return LDB_ERR_UNWILLING_TO_PERFORM; - break; - } - - account_type = ds_gtype2atype(group_type); - if (account_type == 0) { - ldb_set_errstring(ldb, "samldb: Unrecognized account type!"); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, - "sAMAccountType", - account_type); - if (ret != LDB_SUCCESS) { - return ret; - } - el2 = ldb_msg_find_element(ac->msg, "sAMAccountType"); - el2->flags = LDB_FLAG_MOD_REPLACE; - } - el = ldb_msg_find_element(ac->msg, "groupType"); - if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) { - return LDB_ERR_UNWILLING_TO_PERFORM; - } - el = ldb_msg_find_element(ac->msg, "primaryGroupID"); if (el != NULL) { ret = samldb_prim_group_change(ac); @@ -1484,64 +1602,22 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) } el = ldb_msg_find_element(ac->msg, "userAccountControl"); - if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) - && el->num_values == 1) { - uint32_t user_account_control; - + if (el != NULL) { modified = true; - - user_account_control = ldb_msg_find_attr_as_uint(ac->msg, - "userAccountControl", - 0); - - /* Temporary duplicate accounts aren't allowed */ - if ((user_account_control & UF_TEMP_DUPLICATE_ACCOUNT) != 0) { - return LDB_ERR_OTHER; - } - - account_type = ds_uf2atype(user_account_control); - if (account_type == 0) { - ldb_set_errstring(ldb, "samldb: Unrecognized account type!"); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, - "sAMAccountType", - account_type); + ret = samldb_user_account_control_change(ac); if (ret != LDB_SUCCESS) { return ret; } - el2 = ldb_msg_find_element(ac->msg, "sAMAccountType"); - el2->flags = LDB_FLAG_MOD_REPLACE; - - if (user_account_control & (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) { - ret = samdb_msg_add_string(ldb, ac->msg, ac->msg, - "isCriticalSystemObject", - "TRUE"); - if (ret != LDB_SUCCESS) { - return ret; - } - el2 = ldb_msg_find_element(ac->msg, - "isCriticalSystemObject"); - el2->flags = LDB_FLAG_MOD_REPLACE; - } - - if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) { - uint32_t rid = ds_uf2prim_group_rid(user_account_control); + } - ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, - "primaryGroupID", rid); - if (ret != LDB_SUCCESS) { - return ret; - } - el2 = ldb_msg_find_element(ac->msg, - "primaryGroupID"); - el2->flags = LDB_FLAG_MOD_REPLACE; + el = ldb_msg_find_element(ac->msg, "groupType"); + if (el != NULL) { + modified = true; + ret = samldb_group_type_change(ac); + if (ret != LDB_SUCCESS) { + return ret; } } - el = ldb_msg_find_element(ac->msg, "userAccountControl"); - if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) { - return LDB_ERR_UNWILLING_TO_PERFORM; - } el = ldb_msg_find_element(ac->msg, "member"); if (el != NULL) { -- Samba Shared Repository