[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