[SCM] Samba Shared Repository - branch master updated

Matthias Dieter Wallnöfer mdw at samba.org
Fri Nov 12 12:40:02 MST 2010


The branch, master has been updated
       via  37bd313 s4:objectclass LDB module - we should not simply ignore additional "objectClass" attribute changes
       via  584a2d1 s4:repl_meta_data LDB module - convert two debug messages into error messages
       via  5585591 s4:samldb/objectclass_attrs LDB modules - move "description" logic from "objectclass_attrs" into "samldb"
      from  e4eba98 waf/samba_version: Simplify git show command.

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 37bd3133049eba7ad26aeb74864e732c6efe70e5
Author: Matthias Dieter Wallnöfer <mdw at samba.org>
Date:   Fri Nov 12 19:49:47 2010 +0100

    s4:objectclass LDB module - we should not simply ignore additional "objectClass" attribute changes
    
    There first one we perform all other tentatives are terminated with
    ERR_ATTRIBUTE_OR_VALUE_EXISTS (tested against Windows).
    
    Autobuild-User: Matthias Dieter Wallnöfer <mdw at samba.org>
    Autobuild-Date: Fri Nov 12 19:39:07 UTC 2010 on sn-devel-104

commit 584a2d125ec564ffaa019aba53a2d3b29d4c09c3
Author: Matthias Dieter Wallnöfer <mdw at samba.org>
Date:   Fri Nov 12 19:28:48 2010 +0100

    s4:repl_meta_data LDB module - convert two debug messages into error messages
    
    These regarding "objectGUID".

commit 5585591b2e6959bebb005966ad72eb7af4bf1760
Author: Matthias Dieter Wallnöfer <mdw at samba.org>
Date:   Fri Nov 12 18:57:57 2010 +0100

    s4:samldb/objectclass_attrs LDB modules - move "description" logic from "objectclass_attrs" into "samldb"
    
    This according to an answer from dochelp is SAM specific behaviour.

-----------------------------------------------------------------------

Summary of changes:
 source4/dsdb/samdb/ldb_modules/objectclass.c       |   18 ++-
 source4/dsdb/samdb/ldb_modules/objectclass_attrs.c |   43 -----
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c    |    8 +-
 source4/dsdb/samdb/ldb_modules/samldb.c            |   81 +++++++++
 source4/dsdb/tests/python/ldap.py                  |  176 +++-----------------
 source4/dsdb/tests/python/sam.py                   |  156 +++++++++++++++++-
 6 files changed, 278 insertions(+), 204 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c
index 2e95eb5..d2b4f10 100644
--- a/source4/dsdb/samdb/ldb_modules/objectclass.c
+++ b/source4/dsdb/samdb/ldb_modules/objectclass.c
@@ -1082,12 +1082,26 @@ static int objectclass_do_mod(struct oc_context *ac)
 		break;
 	}
 
+	/* Only one "objectclass" attribute change element per modify request
+	 * allowed! */
+	for (i = 0; i < ac->req->op.mod.message->num_elements; i++) {
+		if (ldb_attr_cmp(ac->req->op.mod.message->elements[i].name,
+				 "objectClass") != 0) continue;
+
+		if (ldb_msg_element_compare(&ac->req->op.mod.message->elements[i],
+					    oc_el_change) != 0) {
+			ldb_set_errstring(ldb,
+					  "objectclass: only one 'objectClass' attribute change per modify request allowed!");
+			talloc_free(mem_ctx);
+			return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+		}
+	}
+
 	ret = ldb_msg_add_empty(msg, "objectClass",
 				LDB_FLAG_MOD_REPLACE, &oc_el_change);
 	if (ret != LDB_SUCCESS) {
-		ldb_oom(ldb);
 		talloc_free(mem_ctx);
-		return ret;
+		return ldb_oom(ldb);
 	}
 
 	/* Move from the linked list back into an ldb msg */
diff --git a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
index 26eaaea..67d11b3 100644
--- a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
+++ b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
@@ -158,49 +158,6 @@ static int attr_handler(struct oc_context *ac)
 			}
 		}
 
-		/* "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_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);
-			}
-		}
-
 		/* "dSHeuristics" syntax check */
 		if (ldb_attr_cmp(attr->lDAPDisplayName, "dSHeuristics") == 0) {
 			ret = oc_validate_dsheuristics(&(msg->elements[i]));
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index b2d5292..957ca3c 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -770,8 +770,8 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
 	if ( guid_blob != NULL ) {
 		if( !allow_add_guid ) {
-			ldb_debug_set(ldb, LDB_DEBUG_ERROR,
-			      "replmd_add: it's not allowed to add an object with objectGUID\n");
+			ldb_set_errstring(ldb,
+					  "replmd_add: it's not allowed to add an object with objectGUID!");
 			talloc_free(ac);
 			return LDB_ERR_UNWILLING_TO_PERFORM;
 		} else {
@@ -2169,8 +2169,8 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
 
 	guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
 	if ( guid_blob != NULL ) {
-		ldb_debug_set(ldb, LDB_DEBUG_ERROR,
-			      "replmd_modify: it's not allowed to change the objectGUID\n");
+		ldb_set_errstring(ldb,
+				  "replmd_modify: it's not allowed to change the objectGUID!");
 		talloc_free(ac);
 		return LDB_ERR_CONSTRAINT_VIOLATION;
 	}
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index 0cd8bc9..4b8a303 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -1496,6 +1496,79 @@ static int samldb_member_check(struct samldb_ctx *ac)
 		}
 	}
 
+	talloc_free(res);
+
+	return LDB_SUCCESS;
+}
+
+/* SAM objects have special rules regarding the "description" attribute on
+ * modify operations. */
+static int samldb_description_check(struct samldb_ctx *ac)
+{
+	struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+	const char * const attrs[] = { "objectClass", "description", NULL };
+	struct ldb_message_element *el;
+	struct ldb_result *res;
+	unsigned int i;
+	int ret;
+
+	/* Fetch informations from the existing object */
+
+	ret = ldb_search(ldb, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
+			 NULL);
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+	if (res->count != 1) {
+		return ldb_operr(ldb);
+	}
+
+	/* if it's not a SAM object then please skip the constraints */
+	if ((samdb_find_attribute(ldb, res->msgs[0], "objectClass",
+				  "group") == NULL) &&
+	    (samdb_find_attribute(ldb, res->msgs[0], "objectClass",
+				  "samDomain") == NULL) &&
+	    (samdb_find_attribute(ldb, res->msgs[0], "objectClass",
+				  "samServer") == NULL) &&
+	    (samdb_find_attribute(ldb, res->msgs[0], "objectClass",
+				  "user") == NULL)) {
+		talloc_free(res);
+		return LDB_SUCCESS;
+	}
+
+	/* We've to walk over all modification entries and consider the
+	 * "description" ones. */
+	for (i = 0; i < ac->msg->num_elements; i++) {
+		if (ldb_attr_cmp(ac->msg->elements[i].name,
+				 "description") != 0) {
+			continue;
+		}
+
+		el = &ac->msg->elements[i];
+
+		/* Multi-valued add or replace operations are always denied */
+		if ((LDB_FLAG_MOD_TYPE(el->flags) != LDB_FLAG_MOD_DELETE) &&
+		    (el->num_values > 1)) {
+			ldb_asprintf_errstring(ldb,
+					       "samldb: Description on SAM entry '%s' is changed using a multi-valued add or replace operation!",
+					       ldb_dn_get_linearized(ac->msg->dn));
+			return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+		}
+
+		/* Add operations are only allowed if no value exists */
+		if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) {
+			if (ldb_msg_find_element(res->msgs[0], "description")
+								!= NULL) {
+				ldb_asprintf_errstring(ldb,
+						       "samldb: Description on SAM entry '%s' is changed using an add operation while a value already exists!",
+						       ldb_dn_get_linearized(ac->msg->dn));
+				return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+			}
+		}
+	}
+
+	talloc_free(res);
+
 	return LDB_SUCCESS;
 }
 
@@ -1894,6 +1967,14 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
 		}
 	}
 
+	el = ldb_msg_find_element(ac->msg, "description");
+	if (el != NULL) {
+		ret = samldb_description_check(ac);
+		if (ret != LDB_SUCCESS) {
+			return ret;
+		}
+	}
+
 	el = ldb_msg_find_element(ac->msg, "dNSHostName");
 	el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
 	if ((el != NULL) || (el2 != NULL)) {
diff --git a/source4/dsdb/tests/python/ldap.py b/source4/dsdb/tests/python/ldap.py
index 833e141..0ac57d5 100755
--- a/source4/dsdb/tests/python/ldap.py
+++ b/source4/dsdb/tests/python/ldap.py
@@ -310,6 +310,19 @@ class BasicTests(unittest.TestCase):
         except LdbError, (num, _):
             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
 
+        # More than one change operation is not allowed
+        m = Message()
+        m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
+        m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_DELETE,
+          "objectClass")
+        m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_ADD,
+          "objectClass")
+        try:
+            ldb.modify(m)
+            self.fail()
+        except LdbError, (num, _):
+            self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+
         # We cannot remove all object classes by an empty replace
         m = Message()
         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
@@ -618,160 +631,6 @@ class BasicTests(unittest.TestCase):
 
         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
 
-    def test_description_attribute(self):
-        """Test description attribute"""
-        print "Test description attribute"""
-
-        self.ldb.add({
-            "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
-            "description": "desc2",
-            "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({
-            "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
-            "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,
-          "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","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)
-
-        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)
-        m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
-          "description")
-        try:
-            ldb.modify(m)
-            self.fail()
-        except LdbError, (num, _):
-            self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
-
-        m = Message()
-        m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
-        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)
-        m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
-          "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(["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"""
@@ -1943,6 +1802,15 @@ servicePrincipalName: host/ldaptest2computer29
                  "objectClass": "user",
                  "cn": "LDAPtestUSER4"})
 
+        # Here we don't enforce these hard "description" constraints
+        ldb.modify_ldif("""
+dn: cn=ldaptestcontainer,""" + self.base_dn + """
+changetype: modify
+replace: description
+description: desc1
+description: desc2
+""")
+
         ldb.modify_ldif("""
 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
 changetype: modify
diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py
index 245d051..b64cce1 100755
--- a/source4/dsdb/tests/python/sam.py
+++ b/source4/dsdb/tests/python/sam.py
@@ -17,7 +17,7 @@ from samba.auth import system_session
 from ldb import 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_OTHER
+from ldb import ERR_OTHER, ERR_NO_SUCH_ATTRIBUTE
 from ldb import ERR_OBJECT_CLASS_VIOLATION
 from ldb import ERR_CONSTRAINT_VIOLATION
 from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
@@ -2251,6 +2251,160 @@ class SamTests(unittest.TestCase):
 
         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
 
+    def test_sam_description_attribute(self):
+        """Test SAM description attribute"""
+        print "Test SAM description attribute"""
+
+        self.ldb.add({
+            "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+            "description": "desc2",
+            "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({
+            "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
+            "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,
+          "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","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)
+
+        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)


-- 
Samba Shared Repository


More information about the samba-cvs mailing list