The branch, master has been updated via c8e6d8b s4-dsdb: Use data_blob_string_const and add explaination for open-coded function in samldb via 6250317 s4-dsdb: Use strcasecmp_m() to compare possibly multibyte strings in samldb via d4391f7 s4:samldb LDB module - make sure to not add identical "servicePrincipalName"s more than once from 299c13b s3:passdb fix a compiler warning
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit c8e6d8b4875e7dc67734597b6db8e81806d94faa Author: Andrew Bartlett <abart...@samba.org> Date: Fri May 4 08:47:29 2012 +1000 s4-dsdb: Use data_blob_string_const and add explaination for open-coded function in samldb Autobuild-User: Andrew Bartlett <abart...@samba.org> Autobuild-Date: Fri May 4 02:34:41 CEST 2012 on sn-devel-104 commit 62503179b5f3e8efe22abcf3b30ddb795db5d8c9 Author: Andrew Bartlett <abart...@samba.org> Date: Fri May 4 08:46:57 2012 +1000 s4-dsdb: Use strcasecmp_m() to compare possibly multibyte strings in samldb commit d4391f77bf54ae94de9715bfbefcd545c556e55c Author: Matthias Dieter Wallnöfer <m...@samba.org> Date: Thu May 3 22:55:06 2012 +0200 s4:samldb LDB module - make sure to not add identical "servicePrincipalName"s more than once The service principal names need to be case-insensitively unique, otherwise we end up in a LDB ERR_ATTRIBUTE_OR_VALUE_EXISTS error. This issue has been discovered on the technical mailing list (thread: cannot rename windows xp machine in samba4) when trying to rename a AD client workstation. ----------------------------------------------------------------------- Summary of changes: source4/dsdb/samdb/ldb_modules/samldb.c | 63 +++++++++++++++++++++++-------- source4/dsdb/tests/python/sam.py | 51 +++++++++++++++++++++++-- 2 files changed, 94 insertions(+), 20 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 168e55b..41c97bf 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -1816,7 +1816,7 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) struct ldb_result *res; const char *dns_hostname = NULL, *old_dns_hostname = NULL, *sam_accountname = NULL, *old_sam_accountname = NULL; - unsigned int i; + unsigned int i, j; int ret; el = dsdb_get_single_valued_attr(ac->msg, "dNSHostName", @@ -1895,7 +1895,7 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) dns_hostname = NULL; } if ((old_dns_hostname != NULL) && (dns_hostname != NULL) && - (strcasecmp(old_dns_hostname, dns_hostname) == 0)) { + (strcasecmp_m(old_dns_hostname, dns_hostname) == 0)) { /* The "dNSHostName" didn't change */ dns_hostname = NULL; } @@ -1905,7 +1905,7 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) sam_accountname = NULL; } if ((old_sam_accountname != NULL) && (sam_accountname != NULL) && - (strcasecmp(old_sam_accountname, sam_accountname) == 0)) { + (strcasecmp_m(old_sam_accountname, sam_accountname) == 0)) { /* The "sAMAccountName" didn't change */ sam_accountname = NULL; } @@ -1957,15 +1957,28 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) } if (res->msgs[0]->num_elements == 1) { - /* Yes, we do have "servicePrincipalName"s. First we update them + /* + * Yes, we do have "servicePrincipalName"s. First we update them * locally, that means we do always substitute the current * "dNSHostName" with the new one and/or "sAMAccountName" - * without "$" with the new one and then we append this to the - * modification request (Windows behaviour). */ + * without "$" with the new one and then we append the + * modified "servicePrincipalName"s as a message element + * replace to the modification request (Windows behaviour). We + * need also to make sure that the values remain case- + * insensitively unique. + */ + + ret = ldb_msg_add_empty(ac->msg, "servicePrincipalName", + LDB_FLAG_MOD_REPLACE, &el); + if (ret != LDB_SUCCESS) { + return ret; + } for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) { char *old_str, *new_str, *pos; const char *tok; + struct ldb_val *vals; + bool found = false; old_str = (char *) res->msgs[0]->elements[0].values[i].data; @@ -1978,11 +1991,11 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) while ((tok = strtok_r(NULL, "/", &pos)) != NULL) { if ((dns_hostname != NULL) && - (strcasecmp(tok, old_dns_hostname) == 0)) { + (strcasecmp_m(tok, old_dns_hostname) == 0)) { tok = dns_hostname; } if ((sam_accountname != NULL) && - (strcasecmp(tok, old_sam_accountname) == 0)) { + (strcasecmp_m(tok, old_sam_accountname) == 0)) { tok = sam_accountname; } @@ -1993,16 +2006,34 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) } } - ret = ldb_msg_add_string(ac->msg, - "servicePrincipalName", - new_str); - if (ret != LDB_SUCCESS) { - return ret; + /* Uniqueness check */ + for (j = 0; (!found) && (j < el->num_values); j++) { + if (strcasecmp_m((char *)el->values[j].data, + new_str) == 0) { + found = true; + } + } + if (found) { + continue; } - } - el = ldb_msg_find_element(ac->msg, "servicePrincipalName"); - el->flags = LDB_FLAG_MOD_REPLACE; + /* + * append the new "servicePrincipalName" - + * code derived from ldb_msg_add_value(). + * + * Open coded to make it clear that we must + * append to the MOD_REPLACE el created above. + */ + vals = talloc_realloc(ac->msg, el->values, + struct ldb_val, + el->num_values + 1); + if (vals == NULL) { + return ldb_module_oom(ac->module); + } + el->values = vals; + el->values[el->num_values] = data_blob_string_const(new_str); + ++(el->num_values); + } } talloc_free(res); diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py index 8417b26..c5727cd 100755 --- a/source4/dsdb/tests/python/sam.py +++ b/source4/dsdb/tests/python/sam.py @@ -2432,10 +2432,53 @@ class SamTests(samba.tests.TestCase): self.assertTrue(len(res) == 1) self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom") self.assertEquals(res[0]["sAMAccountName"][0], "testname2$") - self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2" or - res[0]["servicePrincipalName"][1] == "HOST/testname2") - self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2.testdom" or - res[0]["servicePrincipalName"][1] == "HOST/testname2.testdom") + self.assertTrue(len(res[0]["servicePrincipalName"]) == 2) + self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"]) + self.assertTrue("HOST/testname2.testdom" in res[0]["servicePrincipalName"]) + + m = Message() + m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) + m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom", + FLAG_MOD_ADD, "servicePrincipalName") + try: + ldb.modify(m) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS) + + m = Message() + m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) + m["servicePrincipalName"] = MessageElement("HOST/testname3", + FLAG_MOD_ADD, "servicePrincipalName") + ldb.modify(m) + + res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn, + scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"]) + self.assertTrue(len(res) == 1) + self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom") + self.assertEquals(res[0]["sAMAccountName"][0], "testname2$") + self.assertTrue(len(res[0]["servicePrincipalName"]) == 3) + self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"]) + self.assertTrue("HOST/testname3" in res[0]["servicePrincipalName"]) + self.assertTrue("HOST/testname2.testdom" in res[0]["servicePrincipalName"]) + + m = Message() + m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) + m["dNSHostName"] = MessageElement("testname3.testdom", + FLAG_MOD_REPLACE, "dNSHostName") + m["servicePrincipalName"] = MessageElement("HOST/testname3.testdom", + FLAG_MOD_ADD, "servicePrincipalName") + ldb.modify(m) + + res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn, + scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"]) + self.assertTrue(len(res) == 1) + self.assertEquals(res[0]["dNSHostName"][0], "testname3.testdom") + self.assertEquals(res[0]["sAMAccountName"][0], "testname2$") + self.assertTrue(len(res[0]["servicePrincipalName"]) == 3) + self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"]) + self.assertTrue("HOST/testname3" in res[0]["servicePrincipalName"]) + self.assertTrue("HOST/testname3.testdom" in res[0]["servicePrincipalName"]) delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn) -- Samba Shared Repository