[SCM] Samba Shared Repository - branch master updated
Matthias Dieter Wallnöfer
mdw at samba.org
Tue Oct 26 12:54:01 MDT 2010
The branch, master has been updated
via 1b68910 s4:ldap.py - add a test for attribute ranges - still very basic
via dd25f4b s4:sam.py - enhance users and groups test
via 802e3b4 s4:samldb LDB module - enhance the "member"-check trigger
via a839422 s4:ldap.py - enhance and activate the "description" attribute test
via 4f25eec s4:objectclass_attrs.c - rework to support these special "description" constraints
from c251cb6 wafsamba: Fix soname for standalone private libraries.
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 1b68910d65eb7becf968fbe5a3c16104ccf19906
Author: Matthias Dieter Wallnöfer <mdw at samba.org>
Date: Tue Oct 26 19:09:44 2010 +0200
s4:ldap.py - add a test for attribute ranges - still very basic
And partially outcommented.
Autobuild-User: Matthias Dieter Wallnöfer <mdw at samba.org>
Autobuild-Date: Tue Oct 26 18:53:12 UTC 2010 on sn-devel-104
commit dd25f4b83b0ccc24512ae9ba7636a587ec43c9ec
Author: Matthias Dieter Wallnöfer <mdw at samba.org>
Date: Tue Oct 26 12:37:21 2010 +0200
s4:sam.py - enhance users and groups test
commit 802e3b4e1f2e0fdc7fc11ed7881dade261bfa34a
Author: Matthias Dieter Wallnöfer <mdw at samba.org>
Date: Tue Oct 26 12:08:02 2010 +0200
s4:samldb LDB module - enhance the "member"-check trigger
- Also multi-valued "member" attributes are allowed
- When you try to delete a member from a group which has it primary group set
exactly to this group you get "UNWILLING_TO_PERFORM"
commit a839422fc57762ea3366afbe58b018cf11bfffd7
Author: Matthias Dieter Wallnöfer <mdw at samba.org>
Date: Sun Oct 24 21:25:52 2010 +0200
s4:ldap.py - enhance and activate the "description" attribute test
It tests only the "description" attribute in particular since it behaves
differently from all others.
commit 4f25eec5a5d9e57f0a63591535fe3f581ce23f45
Author: Matthias Dieter Wallnöfer <mdw at samba.org>
Date: Mon Oct 25 13:56:14 2010 +0200
s4:objectclass_attrs.c - rework to support these special "description" constraints
Only the "description" attribute has this special restrictions.
-----------------------------------------------------------------------
Summary of changes:
source4/dsdb/samdb/ldb_modules/objectclass_attrs.c | 50 +++++--
source4/dsdb/samdb/ldb_modules/samldb.c | 10 +-
source4/dsdb/tests/python/ldap.py | 169 +++++++++++++++++---
source4/dsdb/tests/python/sam.py | 65 ++++++++-
4 files changed, 253 insertions(+), 41 deletions(-)
Changeset truncated at 500 lines:
diff --git a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
index b3f7048..5d3f51f 100644
--- a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
+++ b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
@@ -139,17 +139,47 @@ static int attr_handler(struct oc_context *ac)
}
}
- /* Multi-valued replace operations are generally denied but
- * there do exist exceptions where attributes have the flag
- * "FLAG_ATTR_REQ_PARTIAL_SET_MEMBER" set. */
+ /* "description" on AD is very special: it's nearly single-
+ * valued (only on add operations it isn't). */
if ((ac->req->operation == LDB_MODIFY) &&
- (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE) &&
- (msg->elements[i].num_values > 1) &&
- ((attr->systemFlags & DS_FLAG_ATTR_REQ_PARTIAL_SET_MEMBER) == 0)) {
- ldb_asprintf_errstring(ldb, "objectclass_attrs: attribute '%s' on entry '%s' is replaced multi-valued!",
- msg->elements[i].name,
- ldb_dn_get_linearized(msg->dn));
- return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ (ldb_attr_cmp(attr->lDAPDisplayName, "description") == 0)) {
+ /* Multi-valued add or replace operations are always
+ * denied */
+ if ((LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
+ != LDB_FLAG_MOD_DELETE) &&
+ (msg->elements[i].num_values > 1)) {
+ ldb_asprintf_errstring(ldb,
+ "objectclass_attrs: attribute '%s' on entry '%s' is changed using a multi-valued add or replace operation!",
+ msg->elements[i].name,
+ ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+
+ /* Add operations are only allowed if no value exists */
+ if (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
+ == LDB_FLAG_MOD_ADD) {
+ const char *attrs[] = { attr->lDAPDisplayName,
+ NULL };
+ struct ldb_result *res;
+ struct ldb_message_element *el;
+
+ ret = ldb_search(ldb, ac, &res, msg->dn,
+ LDB_SCOPE_BASE, attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ el = ldb_msg_find_element(res->msgs[0],
+ attr->lDAPDisplayName);
+ if (el != NULL) {
+ ldb_asprintf_errstring(ldb,
+ "objectclass_attrs: attribute '%s' on entry '%s' is changed using an add operation, but there a value already exists!",
+ msg->elements[i].name,
+ ldb_dn_get_linearized(msg->dn));
+ return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+ }
+ talloc_free(res);
+ }
}
/* Substitute the attribute name to match in case */
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index 26022b7..924c05e 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -1158,7 +1158,12 @@ static int samldb_member_check(struct samldb_ctx *ac)
}
if (ldb_dn_compare(group_dn, ac->msg->dn) == 0) {
- return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ if (LDB_FLAG_MOD_TYPE(el->flags)
+ == LDB_FLAG_MOD_DELETE) {
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ } else {
+ return LDB_ERR_ENTRY_ALREADY_EXISTS;
+ }
}
}
@@ -1463,8 +1468,7 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
}
el = ldb_msg_find_element(ac->msg, "member");
- if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE)
- && el->num_values == 1) {
+ if (el != NULL) {
ret = samldb_member_check(ac);
if (ret != LDB_SUCCESS) {
return ret;
diff --git a/source4/dsdb/tests/python/ldap.py b/source4/dsdb/tests/python/ldap.py
index a7e718e..d713056 100755
--- a/source4/dsdb/tests/python/ldap.py
+++ b/source4/dsdb/tests/python/ldap.py
@@ -20,7 +20,7 @@ from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
from ldb import ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_OTHER, ERR_INVALID_DN_SYNTAX
-from ldb import ERR_NO_SUCH_ATTRIBUTE
+from ldb import ERR_NO_SUCH_ATTRIBUTE, ERR_INVALID_ATTRIBUTE_SYNTAX
from ldb import ERR_OBJECT_CLASS_VIOLATION, ERR_NOT_ALLOWED_ON_RDN
from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION
from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
@@ -591,14 +591,9 @@ class BasicTests(unittest.TestCase):
self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- def test_multi_valued_attributes(self):
- """Test multi-valued attributes"""
- print "Test multi-valued attributes"""
-
-# TODO: In this test I added some special tests where I got very unusual
-# results back from a real AD. s4 doesn't match them and I've no idea how to
-# implement those error cases (maybe there exists a special trigger for
-# "description" attributes which handle them)
+ def test_description_attribute(self):
+ """Test description attribute"""
+ print "Test description attribute"""
self.ldb.add({
"dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
@@ -606,6 +601,13 @@ class BasicTests(unittest.TestCase):
"objectclass": "group",
"description": "desc1"})
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 1)
+ self.assertEquals(res[0]["description"][0], "desc1")
+
self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
self.ldb.add({
@@ -613,6 +615,16 @@ class BasicTests(unittest.TestCase):
"objectclass": "group",
"description": ["desc1", "desc2"]})
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 2)
+ self.assertTrue(res[0]["description"][0] == "desc1" or
+ res[0]["description"][1] == "desc1")
+ self.assertTrue(res[0]["description"][0] == "desc2" or
+ res[0]["description"][1] == "desc2")
+
m = Message()
m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
@@ -625,19 +637,58 @@ class BasicTests(unittest.TestCase):
m = Message()
m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
+ "description")
+ ldb.modify(m)
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
+ self.ldb.add({
+ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+ "objectclass": "group" })
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
"description")
ldb.modify(m)
-# m = Message()
-# m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
-# m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
-# "description")
-# try:
-# ldb.modify(m)
-# self.fail()
-# except LdbError, (num, _):
-# self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 1)
+ self.assertEquals(res[0]["description"][0], "desc1")
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
+ self.ldb.add({
+ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+ "objectclass": "group",
+ "description": ["desc1", "desc2"]})
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
+ "description")
+ ldb.modify(m)
+
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 1)
+ self.assertEquals(res[0]["description"][0], "desc1")
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
+ "description")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
m = Message()
m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
@@ -654,6 +705,10 @@ class BasicTests(unittest.TestCase):
m["description"] = MessageElement("desc1", FLAG_MOD_DELETE,
"description")
ldb.modify(m)
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertFalse("description" in res[0])
m = Message()
m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
@@ -665,23 +720,85 @@ class BasicTests(unittest.TestCase):
except LdbError, (num, _):
self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
+ "description")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ m["description"] = MessageElement("desc1", FLAG_MOD_ADD,
+ "description")
+ ldb.modify(m)
+
+ res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
+ scope=SCOPE_BASE, attrs=["description"])
+ self.assertTrue(len(res) == 1)
+ self.assertTrue("description" in res[0])
+ self.assertTrue(len(res[0]["description"]) == 1)
+ self.assertEquals(res[0]["description"][0], "desc1")
+
+ self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+
+ def test_attribute_ranges(self):
+ """Test attribute ranges"""
+ print "Test attribute ranges"""
+
+ # Too short (min. 1)
+ try:
+ ldb.add({
+ "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+ "objectClass": "person",
+ "sn": "" })
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
+
+ # Too long (max. 64)
+# try:
+# ldb.add({
+# "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+# "objectClass": "person",
+# "sn": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" })
+# self.fail()
+# except LdbError, (num, _):
+# self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
+
+ ldb.add({
+ "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+ "objectClass": "person" })
+
+ # Too short (min. 1)
+ m = Message()
+ m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ m["sn"] = MessageElement("", FLAG_MOD_REPLACE, "sn")
+ try:
+ ldb.modify(m)
+ self.fail()
+ except LdbError, (num, _):
+ self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
+
+ # Too long (max. 64)
# m = Message()
-# m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
-# m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
-# "description")
+# m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+# m["sn"] = MessageElement("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", FLAG_MOD_REPLACE, "sn")
# try:
# ldb.modify(m)
# self.fail()
# except LdbError, (num, _):
-# self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+# self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
m = Message()
- m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
- "description")
+ m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ m["sn"] = MessageElement("x", FLAG_MOD_REPLACE, "sn")
ldb.modify(m)
- self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
+ self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
def test_empty_messages(self):
"""Test empty messages"""
diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py
index 1970673..43e57f9 100755
--- a/source4/dsdb/tests/python/sam.py
+++ b/source4/dsdb/tests/python/sam.py
@@ -96,9 +96,10 @@ class SamTests(unittest.TestCase):
print "baseDN: %s\n" % self.base_dn
self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=users," + self.base_dn)
self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
- self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
+ self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
def test_users_groups(self):
"""This tests the SAM users and groups behaviour"""
@@ -415,17 +416,77 @@ class SamTests(unittest.TestCase):
self.assertTrue(len(res1) == 1)
self.assertFalse("member" in res1[0])
+ # Primary group 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_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({
- "dn": "cn=ldaptestuser1,cn=users," + self.base_dn,
+ "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
"objectclass": ["user", "person"],
"primaryGroupID": "0"})
self.fail()
except LdbError, (num, _):
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
+ # Recreate user accounts
+
+ self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+
+ ldb.add({
+ "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
+ "objectclass": ["user", "person"]})
+
+ ldb.add({
+ "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
+ "objectclass": ["user", "person"]})
+
+ 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")
+ ldb.modify(m)
+
+ # Invalid 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_REPLACE, "member")
+ try:
+ ldb.modify(m)
+ self.fail()
+ 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,
+ "cn=ldaptestuser1,cn=users," + self.base_dn],
+ FLAG_MOD_REPLACE, "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,
+ "cn=ldaptestuser2,cn=users," + self.base_dn],
+ FLAG_MOD_REPLACE, "member")
+ ldb.modify(m)
+
self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+ self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
--
Samba Shared Repository
More information about the samba-cvs
mailing list