The branch, master has been updated via c0ebf5d s4:sam.py - add a short double swap "primaryGroupID" test via 98fefa8 s4:samldb LDB module - adapt the "samldb_prim_group_change" trigger to support multiple "primaryGroupID" modification entries via 02355fc s4:samr RPC server - the LDB error codes for adding or deleting a group member have changed via c664f01 s4:sam.py - enhance "member" tests via 4987467 s4:samldb LDB module - "member" trigger via 5a2c3ad s4:rpc_server/common.h - quiet compilation warnings from b548674 provision: fix wrong tests
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit c0ebf5d7435c3c4968eefafc6c566dc818e600a0 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 17:48:51 2010 +0200 s4:sam.py - add a short double swap "primaryGroupID" test It's not really meaningful but can happen. Autobuild-User: Matthias Dieter Wallnöfer <m...@samba.org> Autobuild-Date: Sat Oct 30 18:15:31 UTC 2010 on sn-devel-104 commit 98fefa8a017bbb67f6c33080c8a80c77c34e42b8 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 17:43:17 2010 +0200 s4:samldb LDB module - adapt the "samldb_prim_group_change" trigger to support multiple "primaryGroupID" modification entries commit 02355fc6fd176312b61198e626cfe1fbb1ed5ac5 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 18:32:43 2010 +0200 s4:samr RPC server - the LDB error codes for adding or deleting a group member have changed commit c664f010d387af483dce41816d5d222bd8d84f46 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 18:09:12 2010 +0200 s4:sam.py - enhance "member" tests commit 4987467b785a5870cb338881c8916b4268006cd6 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 17:12:48 2010 +0200 s4:samldb LDB module - "member" trigger - adapt the "samldb_member_check" trigger to support multiple "member" modification entries. There can exist special modification messages which delete and add members in one operation - support the right error codes when modifications do fail (ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM) commit 5a2c3ad2fa198b260bd8f0934fad0e3113c9f670 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sat Oct 30 17:55:56 2010 +0200 s4:rpc_server/common.h - quiet compilation warnings ----------------------------------------------------------------------- Summary of changes: source4/dsdb/samdb/ldb_modules/samldb.c | 172 ++++++++++++++++++++++--------- source4/dsdb/tests/python/sam.py | 44 ++++++++ source4/rpc_server/common/common.h | 2 + source4/rpc_server/samr/dcesrv_samr.c | 6 +- 4 files changed, 172 insertions(+), 52 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 924c05e..44c8fee 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -1002,8 +1002,41 @@ 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; + } + } + if (el == NULL) { + 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, @@ -1033,9 +1066,20 @@ static int samldb_prim_group_change(struct samldb_ctx *ac) return ldb_operr(ldb); } - /* Finds out the DN of the new primary group */ + /* Finds out the DN of the new primary group + * Notice: in order to parse the primary group ID correctly we create + * a temporary message here. */ - rid = ldb_msg_find_attr_as_uint(ac->msg, "primaryGroupID", (uint32_t) -1); + msg = ldb_msg_new(ac->msg); + if (msg == NULL) { + return ldb_module_oom(ac->module); + } + ret = ldb_msg_add(msg, el, 0); + if (ret != LDB_SUCCESS) { + return ret; + } + rid = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", (uint32_t) -1); + talloc_free(msg); if (rid == (uint32_t) -1) { /* we aren't affected of any primary group change */ return LDB_SUCCESS; @@ -1066,6 +1110,9 @@ 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); + if (msg == NULL) { + return ldb_module_oom(ac->module); + } msg->dn = new_prim_group_dn; ret = samdb_msg_add_delval(ldb, msg, msg, "member", @@ -1081,6 +1128,9 @@ static int samldb_prim_group_change(struct samldb_ctx *ac) /* Add a "member" attribute for the previous primary group */ msg = talloc_zero(ac, struct ldb_message); + if (msg == NULL) { + return ldb_module_oom(ac->module); + } msg->dn = prev_prim_group_dn; ret = samdb_msg_add_addval(ldb, msg, msg, "member", @@ -1095,6 +1145,8 @@ static int samldb_prim_group_change(struct samldb_ctx *ac) } } + talloc_free(res); + return LDB_SUCCESS; } @@ -1113,55 +1165,86 @@ static int samldb_prim_group_trigger(struct samldb_ctx *ac) static int samldb_member_check(struct samldb_ctx *ac) { - struct ldb_context *ldb; + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); struct ldb_message_element *el; struct ldb_dn *member_dn, *group_dn; uint32_t prim_group_rid; struct dom_sid *sid; - unsigned int i; - - ldb = ldb_module_get_ctx(ac->module); - - el = ldb_msg_find_element(ac->msg, "member"); - if (el == NULL) { - /* we aren't affected */ - return LDB_SUCCESS; - } + unsigned int i, j; + int cnt; - for (i = 0; i < el->num_values; i++) { - /* Denies to add "member"s to groups which are primary ones - * for them */ - member_dn = ldb_dn_from_ldb_val(ac, ldb, &el->values[i]); - if (!ldb_dn_validate(member_dn)) { - return ldb_operr(ldb); - } - - prim_group_rid = samdb_search_uint(ldb, ac, (uint32_t) -1, - member_dn, "primaryGroupID", - NULL); - if (prim_group_rid == (uint32_t) -1) { - /* the member hasn't to be a user account -> therefore - * no check needed in this case. */ + /* We've to walk over all modification entries and consider the "member" + * ones. */ + for (i = 0; i < ac->msg->num_elements; i++) { + if (ldb_attr_cmp(ac->msg->elements[i].name, "member") != 0) { continue; } - sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), - prim_group_rid); - if (sid == NULL) { - return ldb_operr(ldb); - } - - group_dn = samdb_search_dn(ldb, ac, NULL, "(objectSid=%s)", - ldap_encode_ndr_dom_sid(ac, sid)); - if (group_dn == NULL) { - return ldb_operr(ldb); - } + el = &ac->msg->elements[i]; + for (j = 0; j < el->num_values; j++) { + member_dn = ldb_dn_from_ldb_val(ac, ldb, + &el->values[j]); + if (!ldb_dn_validate(member_dn)) { + return ldb_operr(ldb); + } - if (ldb_dn_compare(group_dn, ac->msg->dn) == 0) { - if (LDB_FLAG_MOD_TYPE(el->flags) + /* The "member" attribute can be modified with the + * following restrictions (beside a valid DN): + * + * - "add" operations can only be performed when the + * member still doesn't exist - if not then return + * ERR_ENTRY_ALREADY_EXISTS (not + * ERR_ATTRIBUTE_OR_VALUE_EXISTS!) + * - "delete" operations can only be performed when the + * member does exist - if not then return + * ERR_UNWILLING_TO_PERFORM (not + * ERR_NO_SUCH_ATTRIBUTE!) + * - primary group check + */ + cnt = samdb_search_count(ldb, ac, ac->msg->dn, + "(member=%s)", + ldb_dn_get_linearized(member_dn)); + if (cnt < 0) { + return ldb_operr(ldb); + } + if ((cnt > 0) && (LDB_FLAG_MOD_TYPE(el->flags) + == LDB_FLAG_MOD_ADD)) { + return LDB_ERR_ENTRY_ALREADY_EXISTS; + } + if ((cnt == 0) && LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) { return LDB_ERR_UNWILLING_TO_PERFORM; - } else { + } + + /* Denies to add "member"s to groups which are primary + * ones for them - in this case return + * ERR_ENTRY_ALREADY_EXISTS. */ + + prim_group_rid = samdb_search_uint(ldb, ac, + (uint32_t) -1, + member_dn, + "primaryGroupID", + NULL); + if (prim_group_rid == (uint32_t) -1) { + /* the member hasn't to be a user account -> + * therefore no check needed in this case. */ + continue; + } + + sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), + prim_group_rid); + if (sid == NULL) { + return ldb_operr(ldb); + } + + group_dn = samdb_search_dn(ldb, ac, NULL, + "(objectSid=%s)", + ldap_encode_ndr_dom_sid(ac, sid)); + if (group_dn == NULL) { + return ldb_operr(ldb); + } + + if (ldb_dn_compare(group_dn, ac->msg->dn) == 0) { return LDB_ERR_ENTRY_ALREADY_EXISTS; } } @@ -1393,19 +1476,12 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) } el = ldb_msg_find_element(ac->msg, "primaryGroupID"); - if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) - && el->num_values == 1) { - modified = true; - + if (el != NULL) { ret = samldb_prim_group_change(ac); if (ret != LDB_SUCCESS) { return ret; } } - el = ldb_msg_find_element(ac->msg, "primaryGroupID"); - 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, "userAccountControl"); if (el && (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py index 43e57f9..bbcc4a8 100755 --- a/source4/dsdb/tests/python/sam.py +++ b/source4/dsdb/tests/python/sam.py @@ -402,6 +402,15 @@ class SamTests(unittest.TestCase): FLAG_MOD_REPLACE, "primaryGroupID") ldb.modify(m) + # Swap the groups (does not really make sense but does the same) + m = Message() + m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn) + m["primaryGroupID"] = MessageElement(str(group_rid_1), + FLAG_MOD_REPLACE, "primaryGroupID") + m["primaryGroupID"] = MessageElement(str(group_rid_2), + FLAG_MOD_REPLACE, "primaryGroupID") + ldb.modify(m) + # Old primary group should contain a "member" attribute for the user, # the new shouldn't contain anymore one res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn, @@ -427,6 +436,17 @@ class SamTests(unittest.TestCase): except LdbError, (num, _): self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + # Delete invalid group member + m = Message() + m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn) + m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn, + FLAG_MOD_DELETE, "member") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + # Also this should be denied try: ldb.add({ @@ -455,6 +475,17 @@ class SamTests(unittest.TestCase): FLAG_MOD_ADD, "member") ldb.modify(m) + # Already added + m = Message() + m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn) + m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn, + FLAG_MOD_ADD, "member") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS) + # Invalid member m = Message() m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn) @@ -478,6 +509,19 @@ class SamTests(unittest.TestCase): except LdbError, (num, _): self.assertEquals(num, ERR_NO_SUCH_OBJECT) + # Invalid member + m = Message() + m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn) + m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn, + FLAG_MOD_REPLACE, "member") + m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn, + FLAG_MOD_ADD, "member") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_NO_SUCH_OBJECT) + m = Message() m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn) m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn, diff --git a/source4/rpc_server/common/common.h b/source4/rpc_server/common/common.h index 3f3275b..240ef29 100644 --- a/source4/rpc_server/common/common.h +++ b/source4/rpc_server/common/common.h @@ -24,10 +24,12 @@ #define _DCERPC_SERVER_COMMON_H_ struct share_config; +struct dcesrv_connection; struct dcesrv_context; struct dcesrv_context; struct dcesrv_call_state; struct ndr_interface_table; +struct ncacn_packet; struct dcerpc_server_info { const char *domain_name; diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index 3c08851..dbc9c1e 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -1994,7 +1994,6 @@ static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, T switch (ret) { case LDB_SUCCESS: return NT_STATUS_OK; - case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS: case LDB_ERR_ENTRY_ALREADY_EXISTS: return NT_STATUS_MEMBER_IN_GROUP; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: @@ -2099,7 +2098,7 @@ static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call switch (ret) { case LDB_SUCCESS: return NT_STATUS_OK; - case LDB_ERR_NO_SUCH_ATTRIBUTE: + case LDB_ERR_UNWILLING_TO_PERFORM: return NT_STATUS_MEMBER_NOT_IN_GROUP; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: return NT_STATUS_ACCESS_DENIED; @@ -2468,7 +2467,6 @@ static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, T switch (ret) { case LDB_SUCCESS: return NT_STATUS_OK; - case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS: case LDB_ERR_ENTRY_ALREADY_EXISTS: return NT_STATUS_MEMBER_IN_GROUP; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: @@ -2521,7 +2519,7 @@ static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call switch (ret) { case LDB_SUCCESS: return NT_STATUS_OK; - case LDB_ERR_NO_SUCH_ATTRIBUTE: + case LDB_ERR_UNWILLING_TO_PERFORM: return NT_STATUS_MEMBER_NOT_IN_GROUP; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: return NT_STATUS_ACCESS_DENIED; -- Samba Shared Repository