svn commit: samba r25781 - in branches/SAMBA_4_0: source/dsdb/samdb/ldb_modules testprogs/ejs

abartlet at samba.org abartlet at samba.org
Thu Nov 1 12:34:06 GMT 2007


Author: abartlet
Date: 2007-11-01 12:34:06 +0000 (Thu, 01 Nov 2007)
New Revision: 25781

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=25781

Log:
Handle and test linked attribute renames.  

Andrew Bartlett

Modified:
   branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/linked_attributes.c
   branches/SAMBA_4_0/testprogs/ejs/ldap.js


Changeset:
Modified: branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/linked_attributes.c
===================================================================
--- branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/linked_attributes.c	2007-11-01 11:43:00 UTC (rev 25780)
+++ branches/SAMBA_4_0/source/dsdb/samdb/ldb_modules/linked_attributes.c	2007-11-01 12:34:06 UTC (rev 25781)
@@ -41,6 +41,8 @@
 	struct ldb_request **down_req;
 	int num_requests;
 	int finished_requests;
+
+	const char **linked_attrs;
 };
 
 static struct linked_attributes_context *linked_attributes_init_handle(struct ldb_request *req, 
@@ -369,22 +371,323 @@
 	return ret;
 }
 
-/* delete */
-static int linked_attributes_delete(struct ldb_module *module, struct ldb_request *req)
+static int setup_modifies(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
+			  struct linked_attributes_context *ac,
+			  struct ldb_message *msg, 
+			  struct ldb_dn *olddn, struct ldb_dn *newdn) 
 {
-	/* Look up list of linked attributes */
-	/* Search to see if any linked attributes are in this entry */
-	return ldb_next_request(module, req);
+	int i, j, ret = LDB_SUCCESS;
+	const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+	/* Look up each of the returned attributes */
+	/* Find their schema */
+	/* And it is an actual entry: now create a series of modify requests */
+	for (i=0; i < msg->num_elements; i++) {
+		int otherid;
+		const struct dsdb_attribute *target_attr;
+		const struct ldb_message_element *el = &msg->elements[i];
+		const struct dsdb_attribute *schema_attr
+			= dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+		if (!schema_attr) {
+			ldb_asprintf_errstring(ldb, 
+					       "attribute %s is not a valid attribute in schema", el->name);
+			return LDB_ERR_OBJECT_CLASS_VIOLATION;			
+		}
+		/* We have a valid attribute, but if it's not linked they maybe we just got an extra return on our search... */
+		if (schema_attr->linkID == 0) {
+			continue;
+		}
+		
+		/* Depending on which direction this link is in, we need to find it's partner */
+		if ((schema_attr->linkID & 1) == 1) {
+			otherid = schema_attr->linkID - 1;
+		} else {
+			otherid = schema_attr->linkID + 1;
+		}
+		
+		/* Now find the target attribute */
+		target_attr = dsdb_attribute_by_linkID(schema, otherid);
+		if (!target_attr) {
+			ldb_asprintf_errstring(ldb, 
+					       "attribute %s does not have valid link target", el->name);
+			return LDB_ERR_OBJECT_CLASS_VIOLATION;			
+		}
+		
+		/* For each value being moded, we need to setup the modify */
+		for (j=0; j < el->num_values; j++) {
+			struct ldb_message_element *ret_el;
+			struct ldb_request *new_req;
+			/* Create the modify request */
+			struct ldb_message *new_msg = ldb_msg_new(ac->down_req);
+			if (!new_msg) {
+				ldb_oom(ldb);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+			new_msg->dn = ldb_dn_new(new_msg, ldb, (char *)el->values[j].data);
+			if (!new_msg->dn) {
+				ldb_asprintf_errstring(ldb, 
+						       "attribute %s value %s was not a valid DN", msg->elements[i].name,
+						       el->values[j].data);
+				return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+			}
+			
+			if (olddn) {
+				ret = ldb_msg_add_empty(new_msg, target_attr->lDAPDisplayName, 
+							LDB_FLAG_MOD_DELETE, &ret_el);
+				if (ret != LDB_SUCCESS) {
+					return ret;
+				}	
+				ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
+				if (!ret_el->values) {
+					ldb_oom(ldb);
+					return LDB_ERR_OPERATIONS_ERROR;
+				}
+				ret_el->values[0] = data_blob_string_const(ldb_dn_get_linearized(olddn));
+				ret_el->num_values = 1;
+			}
+			
+			if (newdn) {
+				ret = ldb_msg_add_empty(new_msg, target_attr->lDAPDisplayName, 
+							LDB_FLAG_MOD_ADD, &ret_el);
+				if (ret != LDB_SUCCESS) {
+					return ret;
+				}	
+				ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
+				if (!ret_el->values) {
+					ldb_oom(ldb);
+					return LDB_ERR_OPERATIONS_ERROR;
+				}
+				ret_el->values[0] = data_blob_string_const(ldb_dn_get_linearized(newdn));
+				ret_el->num_values = 1;
+			}
+
+			ret = ldb_build_mod_req(&new_req, ldb, ac->down_req,
+						new_msg,
+						NULL,
+						NULL,
+						NULL);
+			if (ret != LDB_SUCCESS) {
+				return ret;
+			}
+			
+			talloc_steal(new_req, new_msg);
+			
+			ldb_set_timeout_from_prev_req(ldb, ac->orig_req, new_req);
+			
+			/* Now add it to the list */
+			ac->down_req = talloc_realloc(ac, ac->down_req, 
+						      struct ldb_request *, ac->num_requests + 1);
+			if (!ac->down_req) {
+				ldb_oom(ldb);
+				return LDB_ERR_OPERATIONS_ERROR;
+			}
+			ac->down_req[ac->num_requests] = new_req;
+			ac->num_requests++;
+			
+			/* Run the new request */
+			ret = ldb_next_request(ac->module, new_req);
+			if (ret != LDB_SUCCESS) {
+				return ret;
+			}
+		}
+	}
+	return ret;
 }
 
+static int linked_attributes_rename_del_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) 
+{
+	struct ldb_request *req;
+	struct linked_attributes_context *ac = talloc_get_type(context, struct linked_attributes_context);
+	struct ldb_dn *olddn, *newdn;
+	TALLOC_CTX *mem_ctx = talloc_new(ac);
+    
+	if (!mem_ctx) {
+		ldb_oom(ldb);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	
+	switch (ac->orig_req->operation) {
+	case LDB_DELETE:
+	{
+		olddn = ac->orig_req->op.del.dn;
+		newdn = NULL;
+		break;
+	} 
+	case LDB_RENAME:
+	{
+		olddn = ac->orig_req->op.rename.olddn;
+		newdn = ac->orig_req->op.rename.newdn;
+		break;
+	}	
+	default:
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	
+
+	/* OK, we have one search result here: */
+
+	/* Only entries are interesting, and we only want the olddn */
+	if (ares->type == LDB_REPLY_ENTRY
+	    && ldb_dn_compare(ares->message->dn, olddn) == 0) {
+		/* only bother at all if there were some linked attributes found */
+		if (ares->message->num_elements > 0) {
+			return setup_modifies(ldb, mem_ctx, ac,
+					      ares->message, olddn, newdn);
+		}
+		talloc_free(ares);
+		return LDB_SUCCESS;
+	} else if (ares->type == LDB_REPLY_ENTRY) {
+		/* Guh?  We only asked for this DN */
+		return LDB_ERR_OPERATIONS_ERROR;
+	} else if (ares->type == LDB_REPLY_DONE) {
+		req = talloc(mem_ctx, struct ldb_request);
+		*req = *ac->orig_req;
+		talloc_free(ares);
+
+		ac->down_req = talloc_realloc(ac, ac->down_req, 
+					      struct ldb_request *, ac->num_requests + 1);
+		if (!ac->down_req) {
+			ldb_oom(ldb);
+			return LDB_ERR_OPERATIONS_ERROR;
+		}
+		ac->down_req[ac->num_requests] = req;
+		ac->num_requests++;
+		
+		return ldb_next_request(ac->module, req);
+
+	} else {
+		talloc_free(ares);
+		return LDB_SUCCESS;
+	}
+	
+	
+}
 /* rename */
 static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
 {
 	/* Look up list of linked attributes */
-	/* Search to see if any linked attributes are in this entry */
-	return ldb_next_request(module, req);
+	const char **attrs;
+	WERROR werr;
+	int ret;
+	struct linked_attributes_context *ac;
+	struct ldb_request *new_req;
+	const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
+	if (!schema) {
+		/* without schema, this doesn't make any sense */
+		return ldb_next_request(module, req);
+	}
+
+	/* This gets complex:  We need to:
+	   - Do a search for the entry 
+	   - Wait for these result to appear
+	   - In the callback for the result, issue a modify request based on the linked attributes found
+	   - Wait for each modify result
+	   - Regain our sainity 
+	*/
+
+	ac = linked_attributes_init_handle(req, module);
+	if (!ac) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	
+	werr = dsdb_linked_attribute_lDAPDisplayName_list(schema, ac, &attrs);
+	if (!W_ERROR_IS_OK(werr)) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	
+	ret = ldb_build_search_req(&new_req, module->ldb, req,
+				   req->op.rename.olddn, 
+				   LDB_SCOPE_BASE,
+				   "(objectClass=*)",
+				   attrs,
+				   NULL, 
+				   ac, 
+				   linked_attributes_rename_del_search_callback);
+
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+
+	talloc_steal(new_req, attrs);
+
+	ac->down_req = talloc_realloc(ac, ac->down_req, 
+					struct ldb_request *, ac->num_requests + 1);
+	if (!ac->down_req) {
+		ldb_oom(ac->module->ldb);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	ac->down_req[ac->num_requests] = new_req;
+	if (req == NULL) {
+		ldb_oom(ac->module->ldb);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	ac->num_requests++;
+	return ldb_next_request(module, new_req);
 }
 
+/* delete */
+static int linked_attributes_delete(struct ldb_module *module, struct ldb_request *req)
+{
+	/* Look up list of linked attributes */
+	const char **attrs;
+	WERROR werr;
+	int ret;
+	struct ldb_request *new_req;
+	struct linked_attributes_context *ac;
+	const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
+	if (!schema) {
+		/* without schema, this doesn't make any sense */
+		return ldb_next_request(module, req);
+	}
+
+	/* This gets complex:  We need to:
+	   - Do a search for the entry 
+	   - Wait for these result to appear
+	   - In the callback for the result, issue a modify request based on the linked attributes found
+	   - Wait for each modify result
+	   - Regain our sainity 
+	*/
+
+	ac = linked_attributes_init_handle(req, module);
+	if (!ac) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	
+	werr = dsdb_linked_attribute_lDAPDisplayName_list(schema, ac, &attrs);
+	if (!W_ERROR_IS_OK(werr)) {
+		return LDB_ERR_OPERATIONS_ERROR;
+	};
+	
+	ret = ldb_build_search_req(&new_req, module->ldb, req,
+				   req->op.del.dn, 
+				   LDB_SCOPE_BASE,
+				   "(objectClass=*)",
+				   attrs,
+				   NULL, 
+				   ac, 
+				   linked_attributes_rename_del_search_callback);
+
+	if (ret != LDB_SUCCESS) {
+		return ret;
+	}
+
+	talloc_steal(new_req, attrs);
+
+	ac->down_req = talloc_realloc(ac, ac->down_req, 
+					struct ldb_request *, ac->num_requests + 1);
+	if (!ac->down_req) {
+		ldb_oom(ac->module->ldb);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	ac->down_req[ac->num_requests] = new_req;
+	if (req == NULL) {
+		ldb_oom(ac->module->ldb);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+	ac->num_requests++;
+	return ldb_next_request(module, new_req);
+}
+
+
 static int linked_attributes_wait_none(struct ldb_handle *handle) {
 	struct linked_attributes_context *ac;
 	int i, ret = LDB_ERR_OPERATIONS_ERROR;

Modified: branches/SAMBA_4_0/testprogs/ejs/ldap.js
===================================================================
--- branches/SAMBA_4_0/testprogs/ejs/ldap.js	2007-11-01 11:43:00 UTC (rev 25780)
+++ branches/SAMBA_4_0/testprogs/ejs/ldap.js	2007-11-01 12:34:06 UTC (rev 25781)
@@ -55,7 +55,31 @@
 		}
 	}
 
+	ldb.del("cn=ldaptestgroup,cn=users," + base_dn);
+
 	var ok = ldb.add("
+dn: cn=ldaptestgroup,cn=uSers," + base_dn + "
+objectclass: group
+member: cn=ldaptestuser,cn=useRs," + base_dn + "
+");
+	if (ok.error != 0) {
+		ok = ldb.del("cn=ldaptestgroup,cn=users," + base_dn);
+		if (ok.error != 0) {
+			println(ok.errstr);
+			assert(ok.error == 0);
+		}
+		ok = ldb.add("
+dn: cn=ldaptestgroup,cn=uSers," + base_dn + "
+objectclass: group
+member: cn=ldaptestuser,cn=useRs," + base_dn + "
+");
+		if (ok.error != 0) {
+			println(ok.errstr);
+			assert(ok.error == 0);
+		}
+	}
+
+	var ok = ldb.add("
 dn: cn=ldaptestcomputer,cn=computers," + base_dn + "
 objectclass: computer
 cN: LDAPtestCOMPUTER
@@ -77,6 +101,11 @@
 		}
 	}
 
+	if (ok.error != 0) {
+		println(ok.errstr);
+		assert(ok.error == 0);
+	}
+
 	var ok = ldb.add("
 dn: cn=ldaptest2computer,cn=computers," + base_dn + "
 objectClass: computer
@@ -140,6 +169,20 @@
 		}
 	}
 
+	println("Testing Group Modifies");
+	ok = ldb.modify("
+dn: cn=ldaptestgroup,cn=users," + base_dn + "
+changetype: modify
+add: member
+member: cn=ldaptestuser2,cn=users," + base_dn + "
+member: cn=ldaptestcomputer,cn=computers," + base_dn + "
+");
+
+	if (ok.error != 0) {
+		println(ok.errstr);
+		assert(ok.error == 0);
+	}
+
 	ok = ldb.del("cn=ldaptestuser3,cn=users," + base_dn);
 
 	println("Testing Renames");
@@ -230,6 +273,14 @@
 
 	ok = ldb.del("cn=ldaptestuser5,cn=users," + base_dn);
 
+	ok = ldb.del("cn=ldaptestgroup2,cn=users," + base_dn);
+
+	ok = ldb.rename("cn=ldaptestgroup,cn=users," + base_dn, "cn=ldaptestgroup2,cn=users," + base_dn);
+	if (ok.error != 0) {
+		println(ok.errstr);
+		assert(ok.error == 0);
+	}
+
 	println("Testing subtree Renames");
 
 	ok = ldb.add("
@@ -562,7 +613,13 @@
 //	assert(res.msgs[0].userAccountControl == 4098);
 
 
-        var attrs = new Array("cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor");
+   	ok = ldb.del(res.msgs[0].dn);
+	if (ok.error != 0) {
+		println(ok.errstr);
+		assert(ok.error == 0);
+	}
+
+        var attrs = new Array("cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "memberOf");
 	println("Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))");
 	var res = ldb.search("(&(cn=ldaptestUSer2)(objectClass=user))", base_dn, ldb.SCOPE_SUBTREE, attrs);
 	if (res.error != 0 || res.msgs.length != 1) {
@@ -581,8 +638,8 @@
 	assert(res.msgs[0].objectGUID != undefined);
 	assert(res.msgs[0].whenCreated != undefined);
 	assert(res.msgs[0].nTSecurityDescriptor != undefined);
+	assert(res.msgs[0].memberOf[0] == ("CN=ldaptestgroup2,CN=Users," + base_dn));
 
-
 	ok = ldb.del(res.msgs[0].dn);
 	if (ok.error != 0) {
 		println(ok.errstr);
@@ -614,6 +671,12 @@
 		assert(ok.error == 0);
 	}
 
+	ok = ldb.del(("CN=ldaptestgroup2,CN=Users," + base_dn))
+	if (ok.error != 0) {
+		println(ok.errstr);
+		assert(ok.error == 0);
+	}
+
 	println("Testing ldb.search for (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))");
 	var res = ldb.search("(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
 



More information about the samba-cvs mailing list