The branch, master has been updated via 58cfa5a s4:passwords.py - test empty password attributes behaviour via 0bfbf6d s4:password_hash LDB module - deleting password attributes is a little more complicated via 9154d4d s4:samdb_msg_find_old_and_new_ldb_val - rework via 6041ef7 s4:password_hash LDB module - clear the fact that a delete of password attributes isn't possible via d4c9a34 s4:acl LDB module - define the delete passwords special case a bit better via acffe25 s4:passwords.py - add another two failure cases from 9aa0ed2 ldb:pyldb.c - "py_ldb_msg_element_get" - here we can safely use "unsigned int" for the element reference
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 58cfa5a82519e2850cb400bb9f1e76d3dbfd3ff2 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Mon Nov 1 19:54:07 2010 +0100 s4:passwords.py - test empty password attributes behaviour Autobuild-User: Matthias Dieter Wallnöfer <m...@samba.org> Autobuild-Date: Mon Nov 8 12:09:56 UTC 2010 on sn-devel-104 commit 0bfbf6d5264fb45d9b788a9dabad18826db1a875 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Mon Nov 8 11:33:53 2010 +0100 s4:password_hash LDB module - deleting password attributes is a little more complicated commit 9154d4dcfc142c0a549993f2e1083eb52a759213 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sun Nov 7 22:08:19 2010 +0100 s4:samdb_msg_find_old_and_new_ldb_val - rework - don't crash when no values where specified - return ERR_CONSTRAINT_VIOLATION on malformed messages - only check for flags when we are involved in a LDB modify operation commit 6041ef7442fda2f96c416d333f1dfc6dabd0d252 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Mon Nov 8 11:31:16 2010 +0100 s4:password_hash LDB module - clear the fact that a delete of password attributes isn't possible commit d4c9a34cf82abea5497dc2a8072ed2a67894e0ea Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sun Nov 7 22:37:39 2010 +0100 s4:acl LDB module - define the delete passwords special case a bit better commit acffe258960c261903eefce630bbf02acbef1348 Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Sun Nov 7 22:35:29 2010 +0100 s4:passwords.py - add another two failure cases ----------------------------------------------------------------------- Summary of changes: source4/dsdb/common/util.c | 33 ++++- source4/dsdb/samdb/ldb_modules/acl.c | 7 +- source4/dsdb/samdb/ldb_modules/password_hash.c | 29 +++-- source4/dsdb/tests/python/passwords.py | 176 +++++++++++++++++++++++- 4 files changed, 224 insertions(+), 21 deletions(-) Changeset truncated at 500 lines: diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 3fa6774..79a4c14 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -709,12 +709,13 @@ struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, * for entries). The latter (old value) has always specified * LDB_FLAG_MOD_DELETE. * - * Returns LDB_ERR_NO_SUCH_ATTRIBUTE if the attribute which should be deleted - * doesn't contain only one value (this is the Windows Server behaviour) - * otherwise LDB_SUCCESS. + * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if + * matching message elements are malformed in respect to the set/change rules. + * Otherwise it returns LDB_SUCCESS. */ int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg, const char *name, + enum ldb_request_type operation, const struct ldb_val **new_val, const struct ldb_val **old_val) { @@ -728,11 +729,31 @@ int samdb_msg_find_old_and_new_ldb_val(const struct ldb_message *msg, } for (i = 0; i < msg->num_elements; i++) { - if (ldb_attr_cmp(msg->elements[i].name, name) == 0) { - if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE) { + if (ldb_attr_cmp(msg->elements[i].name, name) != 0) { + continue; + } + + if ((operation == LDB_MODIFY) && + (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) { + /* 0 values are allowed */ + if (msg->elements[i].num_values == 1) { *old_val = &msg->elements[i].values[0]; + } else if (msg->elements[i].num_values > 1) { + return LDB_ERR_CONSTRAINT_VIOLATION; + } + } else if ((operation == LDB_MODIFY) && + (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) { + if (msg->elements[i].num_values > 0) { + *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1]; + } else { + return LDB_ERR_UNWILLING_TO_PERFORM; + } + } else { + /* Add operations and LDB_FLAG_MOD_ADD */ + if (msg->elements[i].num_values > 0) { + *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1]; } else { - *new_val = &msg->elements[i].values[0]; + return LDB_ERR_CONSTRAINT_VIOLATION; } } } diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c index 0a7f431..3cf768e 100644 --- a/source4/dsdb/samdb/ldb_modules/acl.c +++ b/source4/dsdb/samdb/ldb_modules/acl.c @@ -570,9 +570,10 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx, ldb_msg_remove_element(msg, el); } } - /* a single delete will be handled by password hash - later in the stack, so we let it though here */ - if (del_attr_cnt > 0 && add_attr_cnt == 0) { + + /* single deletes will be handled by the "password_hash" LDB module + * later in the stack, so we let it though here */ + if ((del_attr_cnt > 0) && (add_attr_cnt == 0) && (rep_attr_cnt == 0)) { talloc_free(tmp_ctx); return LDB_SUCCESS; } diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index 7b02479..731b8e9 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -1687,7 +1687,9 @@ static int setup_io(struct ph_context *ac, } ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "userPassword", - &io->n.cleartext_utf8, &io->og.cleartext_utf8); + ac->req->operation, + &io->n.cleartext_utf8, + &io->og.cleartext_utf8); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "setup_io: " @@ -1696,7 +1698,9 @@ static int setup_io(struct ph_context *ac, } ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "clearTextPassword", - &io->n.cleartext_utf16, &io->og.cleartext_utf16); + ac->req->operation, + &io->n.cleartext_utf16, + &io->og.cleartext_utf16); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "setup_io: " @@ -1718,7 +1722,9 @@ static int setup_io(struct ph_context *ac, a nthash */ ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "unicodePwd", - "ed_utf16, &old_quoted_utf16); + ac->req->operation, + "ed_utf16, + &old_quoted_utf16); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "setup_io: " @@ -1833,7 +1839,8 @@ static int setup_io(struct ph_context *ac, /* Handles the "dBCSPwd" attribute (LM hash) */ io->n.lm_hash = NULL; io->og.lm_hash = NULL; ret = samdb_msg_find_old_and_new_ldb_val(orig_msg, "dBCSPwd", - &lm_hash, &old_lm_hash); + ac->req->operation, + &lm_hash, &old_lm_hash); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "setup_io: " @@ -1908,7 +1915,13 @@ static int setup_io(struct ph_context *ac, && (!io->n.nt_hash) && (!io->n.lm_hash)) { ldb_asprintf_errstring(ldb, "setup_io: " - "The password change/set operations performed using the LAN Manager hash alone are deactivated!"); + "It' not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!"); + /* on "userPassword" and "clearTextPassword" we've to return + * something different, since these are virtual attributes */ + if ((ldb_msg_find_element(orig_msg, "userPassword") != NULL) || + (ldb_msg_find_element(orig_msg, "clearTextPassword") != NULL)) { + return LDB_ERR_CONSTRAINT_VIOLATION; + } return LDB_ERR_UNWILLING_TO_PERFORM; } @@ -2507,12 +2520,6 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r ldb_msg_remove_element(msg, passwordAttr); } } - if ((del_attr_cnt > 0) && (add_attr_cnt == 0)) { - talloc_free(ac); - ldb_set_errstring(ldb, - "Only the delete action for a password change specified!"); - return LDB_ERR_CONSTRAINT_VIOLATION; - } if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) { talloc_free(ac); ldb_set_errstring(ldb, diff --git a/source4/dsdb/tests/python/passwords.py b/source4/dsdb/tests/python/passwords.py index 66a6cf9..bb2fbd5 100755 --- a/source4/dsdb/tests/python/passwords.py +++ b/source4/dsdb/tests/python/passwords.py @@ -28,7 +28,7 @@ from ldb import ERR_UNWILLING_TO_PERFORM, ERR_INSUFFICIENT_ACCESS_RIGHTS from ldb import ERR_NO_SUCH_ATTRIBUTE from ldb import ERR_CONSTRAINT_VIOLATION from ldb import Message, MessageElement, Dn -from ldb import FLAG_MOD_REPLACE, FLAG_MOD_DELETE +from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE from samba import gensec from samba.samdb import SamDB import samba.tests @@ -402,6 +402,27 @@ userPassword: thatsAcomplPASS1 dn: cn=testuser,cn=users,""" + self.base_dn + """ changetype: modify delete: userPassword +userPassword: thatsAcomplPASS1 +""") + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + try: + ldb.modify_ldif(""" +dn: cn=testuser,cn=users,""" + self.base_dn + """ +changetype: modify +delete: userPassword +""") + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + try: + self.ldb2.modify_ldif(""" +dn: cn=testuser,cn=users,""" + self.base_dn + """ +changetype: modify +delete: userPassword """) self.fail() except LdbError, (num, _): @@ -647,6 +668,159 @@ userPassword: thatsAcomplPASS4 "objectclass": "user", "userPassword": ["thatsAcomplPASS1", "thatsAcomplPASS1"] }) + def test_empty_passwords(self): + print "Performs some empty passwords testing" + + try: + self.ldb.add({ + "dn": "cn=testuser2,cn=users," + self.base_dn, + "objectclass": "user", + "unicodePwd": [] }) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + try: + self.ldb.add({ + "dn": "cn=testuser2,cn=users," + self.base_dn, + "objectclass": "user", + "dBCSPwd": [] }) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + try: + self.ldb.add({ + "dn": "cn=testuser2,cn=users," + self.base_dn, + "objectclass": "user", + "userPassword": [] }) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + try: + self.ldb.add({ + "dn": "cn=testuser2,cn=users," + self.base_dn, + "objectclass": "user", + "clearTextPassword": [] }) + self.fail() + except LdbError, (num, _): + self.assertTrue(num == ERR_CONSTRAINT_VIOLATION or + num == ERR_NO_SUCH_ATTRIBUTE) # for Windows + + self.delete_force(self.ldb, "cn=testuser2,cn=users," + self.base_dn) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["unicodePwd"] = MessageElement([], FLAG_MOD_ADD, "unicodePwd") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["dBCSPwd"] = MessageElement([], FLAG_MOD_ADD, "dBCSPwd") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["userPassword"] = MessageElement([], FLAG_MOD_ADD, "userPassword") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["clearTextPassword"] = MessageElement([], FLAG_MOD_ADD, "clearTextPassword") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertTrue(num == ERR_CONSTRAINT_VIOLATION or + num == ERR_NO_SUCH_ATTRIBUTE) # for Windows + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["unicodePwd"] = MessageElement([], FLAG_MOD_REPLACE, "unicodePwd") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["dBCSPwd"] = MessageElement([], FLAG_MOD_REPLACE, "dBCSPwd") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["userPassword"] = MessageElement([], FLAG_MOD_REPLACE, "userPassword") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["clearTextPassword"] = MessageElement([], FLAG_MOD_REPLACE, "clearTextPassword") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertTrue(num == ERR_UNWILLING_TO_PERFORM or + num == ERR_NO_SUCH_ATTRIBUTE) # for Windows + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["unicodePwd"] = MessageElement([], FLAG_MOD_DELETE, "unicodePwd") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["dBCSPwd"] = MessageElement([], FLAG_MOD_DELETE, "dBCSPwd") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["userPassword"] = MessageElement([], FLAG_MOD_DELETE, "userPassword") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + + m = Message() + m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn) + m["clearTextPassword"] = MessageElement([], FLAG_MOD_DELETE, "clearTextPassword") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertTrue(num == ERR_CONSTRAINT_VIOLATION or + num == ERR_NO_SUCH_ATTRIBUTE) # for Windows + def tearDown(self): super(PasswordTests, self).tearDown() self.delete_force(self.ldb, "cn=testuser,cn=users," + self.base_dn) -- Samba Shared Repository