svn commit: samba r17310 - in branches/SOC/mkhl: ldb-map/modules testprogs-map/ejs

mkhl at samba.org mkhl at samba.org
Sat Jul 29 14:11:49 GMT 2006


Author: mkhl
Date: 2006-07-29 14:11:48 +0000 (Sat, 29 Jul 2006)
New Revision: 17310

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

Log:

Let search requests target the remote database first and the local
database afterwards.
Local searching isn't actually enabled yet, as the callback is never
called in absence of local search results.

Because of unreliable splitting of parse-trees, the merged result is
checked against the original parse-tree and attribute list before
passing it to the original callback.

Add a few kludges related to split attrs and parse-trees that let more
tests pass.

Enable tests that now pass.  Add one more (disabled) test that
requires merging the remote with the local search result.

Martin
Modified:
   branches/SOC/mkhl/ldb-map/modules/ldb_map.c
   branches/SOC/mkhl/testprogs-map/ejs/samba3sam


Changeset:
Modified: branches/SOC/mkhl/ldb-map/modules/ldb_map.c
===================================================================
--- branches/SOC/mkhl/ldb-map/modules/ldb_map.c	2006-07-29 14:01:34 UTC (rev 17309)
+++ branches/SOC/mkhl/ldb-map/modules/ldb_map.c	2006-07-29 14:11:48 UTC (rev 17310)
@@ -104,7 +104,7 @@
 /* async context data */
 struct map_async_context {
 	enum map_step {
-		MAP_SEARCH_LOCAL,
+		MAP_SEARCH_REMOTE,
 		MAP_ADD_REMOTE,
 		MAP_ADD_LOCAL,
 		MAP_SEARCH_SELF_MODIFY,
@@ -1862,7 +1862,50 @@
 
  */
 
+/* remote reply -> local reply */
+static
+int
+map_remote_reply(struct ldb_module *module,
+		 struct ldb_reply *ares)
+{
+	struct ldb_message *msg;
+	struct ldb_dn *dn;
+	int ret;
 
+	/* there is no remote message, skip */
+	if (ares->type != LDB_REPLY_ENTRY)
+		return LDB_SUCCESS;
+
+	/* create a new result message */
+	msg = ldb_msg_new(ares);
+	if (msg == NULL) {
+		map_oom(module);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	/* merge remote message into new message */
+	ret = merge_msg(module, msg, ares->message);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(msg);
+		return ret;
+	}
+
+	/* create corresponding local DN */
+	dn = map_unrebase_remote_dn(module, msg, ares->message->dn);
+	if (dn == NULL) {
+		talloc_free(msg);
+		return LDB_ERR_OPERATIONS_ERROR;
+	}
+
+	/* store new message with new DN as the result */
+	talloc_free(ares->message);
+	msg->dn = dn;
+	ares->message = msg;
+
+	return LDB_SUCCESS;
+}
+
+
 typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_reply *);
 
 /* store single search result in async context */
@@ -1969,6 +2012,51 @@
 	return search_base_req(ac, dn, attrs, tree, search_self_callback);
 }
 
+static
+int
+up_callback(struct ldb_context *ldb,
+		const struct ldb_request *req,
+		struct ldb_reply *ares)
+{
+	int i;
+
+	if (ares->type != LDB_REPLY_ENTRY)
+		goto callback;
+
+	/* the merged result doesn't match the original tree, skip it */
+	/* TODO: silence warning about tree being `const' */
+	if (!ldb_match_msg(ldb, ares->message, req->op.search.tree,
+			   req->op.search.base, req->op.search.scope)) {
+		ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
+			  "Skipping record '%s': "
+			  "doesn't match original search\n",
+			  ldb_dn_linearize(ldb, ares->message->dn));
+		return LDB_SUCCESS;
+	}
+
+	/* XXX: ugly kludge: pass only requested attrs */
+	if (req->op.search.attrs) {
+		struct ldb_message *msg = ldb_msg_new(ares);
+		if (msg == NULL)
+			goto error;
+
+		for (i = 0; req->op.search.attrs[i]; i++) {
+			struct ldb_message_element *el = ldb_msg_find_element(ares->message, req->op.search.attrs[i]);
+			if (el)
+				ldb_msg_add(msg, el, 0);
+		}
+
+		talloc_free(ares->message);
+		ares->message = msg;
+	}
+
+callback:
+	return req->callback(ldb, req->context, ares);
+
+error:
+	return LDB_ERR_OPERATIONS_ERROR;
+}
+
 /* merge remote record with associated local record */
 static
 int
@@ -1977,7 +2065,6 @@
 		     struct ldb_reply *ares)
 {
 	struct map_async_search_context *sc;
-	const struct ldb_request *req;
 	int ret;
 
 	if (context == NULL || ares == NULL) {
@@ -1989,47 +2076,45 @@
 
 	switch (ares->type) {
 	case LDB_REPLY_ENTRY:
-		/* we have already found a remote record */
-		if (sc->remote_res) {
-			ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search for mapped entry"));
-			talloc_free(ares);
-			return LDB_ERR_OPERATIONS_ERROR;
+		/* we have already found a local record */
+		if (sc->local_res) {
+			ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search for local entry"));
+			goto error;
 		}
 
-		/* store remote result */
-		sc->remote_res = ares;
+		/* store local result */
+		sc->local_res = ares;
 
-		/* merge remote into local record */
-		ret = merge_msg(sc->ac->module, sc->local_res->message,
-				sc->remote_res->message);
+		/* merge remote into local message */
+		ret = merge_msg(sc->ac->module,
+				ares->message, sc->remote_res->message);
 		if (ret != LDB_SUCCESS) {
 			talloc_free(ares);
 			return ret;
 		}
 
-		req = sc->ac->orig_req;
-		return req->callback(ldb, req->context,
-				     sc->local_res);
+		return up_callback(ldb, sc->ac->orig_req, ares);
 
 	case LDB_REPLY_DONE:
-		/* no mapped record found, continue with local record */
-		if (sc->remote_res == NULL) {
-			req = sc->ac->orig_req;
-			return req->callback(ldb, req->context,
-					     sc->local_res);
-		}
+		/* no local record found, continue with remote record */
+		if (sc->local_res == NULL)
+			return up_callback(ldb, sc->ac->orig_req,
+					   sc->remote_res);
 		break;
 
 	default:
-		talloc_free(ares);
 		ldb_set_errstring(ldb, talloc_asprintf(ldb, "Unexpected result type in base search for mapped entry"));
-		return LDB_ERR_OPERATIONS_ERROR;
+		goto error;
 	}
 
 	return LDB_SUCCESS;
+
+error:
+	talloc_free(ares);
+	return LDB_ERR_OPERATIONS_ERROR;
 }
 
-/* for each result, search associated local record */
+/* for each result, search the associated local record */
 static
 int
 remote_search_callback(struct ldb_context *ldb,
@@ -2039,8 +2124,6 @@
 	struct map_async_context *ac;
 	struct map_async_search_context *sc;
 	struct ldb_request *req;
-	struct ldb_dn *dn;
-	struct ldb_message *msg;
 	int ret;
 
 	if (context == NULL || ares == NULL) {
@@ -2052,69 +2135,48 @@
 
 	/* stop searching if it's not a record */
 	if (ares->type != LDB_REPLY_ENTRY)
-		goto callback;
+		return up_callback(ldb, ac->orig_req, ares);
 
-	/* stop searching if it's not mapped */
-	/* XXX: Doesn't apply when searching remote first.
-	   Still, make sure callback runs when no local record is found!
-	if (!ldb_msg_find_element(ares->message, IS_MAPPED))
-		goto callback;
-	*/
+	/* map result record into a local message */
+	ret = map_remote_reply(ac->module, ares);
+	if (ret != LDB_SUCCESS) {
+		talloc_free(ares);
+		return ret;
+	}
 
-	/* XXX: This kludge "maps" the search result into the local schema
-	   and throws the result at the next callback. */
-	msg = ldb_msg_new(ares);
-	dn = map_unrebase_remote_dn(ac->module, msg, ares->message->dn);
-	msg->dn = dn;
+	/* XXX: don't run local search request yet! */
+	return up_callback(ldb, ac->orig_req, ares);
 
-	ret = merge_msg(ac->module, msg, ares->message);
-	if (ret != LDB_SUCCESS)
+	/* prepare local search context */
+	sc = talloc_zero(ac, struct map_async_search_context);
+	if (sc == NULL) {
+		map_oom(ac->module);
 		goto error;
-	ares->message = msg;
+	}
 
-	goto callback;
-	/* XXX: End of Ugly Kludge */
-
-	/* extract remote DN */
-	/* XXX: Next steps should be:
-		- generate remote DN (in the local partition)
-		- generate local DN
-		- search local DN with (&(IS_MAPPED=remote_dn)(local_tree))
-		- make sure the remote message is unmapped and passed to
-		  the next callback when no local record can be found!
-	   GUIDs would make this part a lot simpler. */
-	dn = ldb_dn_explode(ac, ldb_msg_find_string(ares->message,
-						    IS_MAPPED, NULL));
-	if (dn == NULL)
-		goto error;
-	ldb_msg_remove_attr(ares->message, IS_MAPPED);
-	ac->local_dn = dn;
-
-	/* prepare remote operation */
-	sc = talloc(ac, struct map_async_search_context);
-	if (sc == NULL)
-		goto error;
-
-	/* store local result */
+	/* store remote result */
 	sc->ac = ac;
-	sc->local_res = ares;
-	sc->remote_res = NULL;
+	sc->local_res = NULL;
+	sc->remote_res = ares;
 
-	/* prepare remote search request */
-	req = search_base_req(ac, dn, ac->local_attrs, ac->local_tree,
+	/* TODO: use GUIDs here instead? */
+	/* TODO: really use the local tree? */
+	/* prepare local search request */
+	/* XXX: ugly kludge!
+	req = search_base_req(ac, ares->message->dn,
+			      ac->local_attrs, ac->local_tree,
 			      local_merge_callback);
-	if (req == NULL)
+	*/
+	req = search_base_req(ac, ares->message->dn, NULL, NULL,
+			      local_merge_callback);
+	if (req == NULL) {
+		talloc_free(sc);
 		goto error;
-
-	/* use search context to merge results */
+	}
 	req->context = sc;
 
 	return ldb_next_request(ac->module, req);
 
-callback:
-	req = ac->orig_req;
-	return req->callback(ldb, req->context, ares);
-
 error:
 	talloc_free(ares);
 	return LDB_ERR_OPERATIONS_ERROR;
@@ -2178,8 +2240,11 @@
 	if (ret != LDB_SUCCESS)
 		goto failed;
 
+	/* XXX: ugly kludge
 	ac->local_attrs = local_attrs;
 	ac->remote_req->op.search.attrs = remote_attrs;
+	*/
+	ac->remote_req->op.search.attrs = NULL;
 
 	/* split local from remote tree */
 	ret = partition_tree(module, ac->remote_req, ac,
@@ -2200,6 +2265,12 @@
 			= talloc_strdup(local_tree, IS_MAPPED);
 	}
 	*/
+	/* XXX: Yet Another try&error */
+	if (remote_tree == NULL) {
+		remote_tree = ldb_parse_tree(ac->remote_req, NULL);
+		if (remote_tree == NULL)
+			goto failed;
+	}
 
 	ac->local_tree = local_tree;
 	ac->remote_req->op.search.tree = remote_tree;
@@ -2209,7 +2280,7 @@
 	h->state = LDB_ASYNC_INIT;
 	h->status = LDB_SUCCESS;
 
-	ac->step = MAP_SEARCH_LOCAL;
+	ac->step = MAP_SEARCH_REMOTE;
 
 	ret = ldb_next_remote_request(module, ac->remote_req);
 	if (ret == LDB_SUCCESS)
@@ -2816,7 +2887,7 @@
 	case MAP_RENAME_FIXUP:
 		return ac->down_req;
 
-	case MAP_SEARCH_LOCAL:
+	case MAP_SEARCH_REMOTE:
 	case MAP_ADD_LOCAL:
 	case MAP_MODIFY_LOCAL:
 	case MAP_DELETE_LOCAL:
@@ -2835,7 +2906,7 @@
 map_get_next(struct map_async_context *ac)
 {
 	switch (ac->step) {
-	case MAP_SEARCH_LOCAL:
+	case MAP_SEARCH_REMOTE:
 		return NULL;
 
 	case MAP_ADD_LOCAL:

Modified: branches/SOC/mkhl/testprogs-map/ejs/samba3sam
===================================================================
--- branches/SOC/mkhl/testprogs-map/ejs/samba3sam	2006-07-29 14:01:34 UTC (rev 17309)
+++ branches/SOC/mkhl/testprogs-map/ejs/samba3sam	2006-07-29 14:11:48 UTC (rev 17310)
@@ -98,7 +98,7 @@
 
 println("Looking up by old name of renamed attribute");
 msg = s4.search("(displayName=Backup Operators)");
-// XXX assert(msg.length == 0);
+assert(msg.length == 0);
 
 println("Looking up mapped entry containing SID");
 msg = s4.search("(cn=Replicator)");
@@ -120,14 +120,19 @@
 cn: Foo
 showInAdvancedViewOnly: TRUE
 ");
-// XXX assert(ok);
+assert(ok);
 
 println("Checking for existance of record");
+/* TODO: This record must be searched in the local database, which is currently only supported for base searches
 msg = s4.search("(cn=Foo)", new Array('foo','blah','cn','showInAdvancedViewOnly'));
-// XXX assert(msg.length == 1);
-// XXX assert(msg[0].showInAdvancedViewOnly == "TRUE");
-// XXX assert(msg[0].foo == "bar");
-// XXX assert(msg[0].blah == "Blie");
+TODO: Actually, this version should work as well but doesn't...
+msg = s4.search("(cn=Foo)", "dc=idealx,dc=org", s4.LDB_SCOPE_SUBTREE new Array('foo','blah','cn','showInAdvancedViewOnly'));
+*/
+msg = s4.search("", "cn=Foo,dc=idealx,dc=org", s4.LDB_SCOPE_BASE new Array('foo','blah','cn','showInAdvancedViewOnly'));
+assert(msg.length == 1);
+assert(msg[0].showInAdvancedViewOnly == "TRUE");
+assert(msg[0].foo == "bar");
+assert(msg[0].blah == "Blie");
 
 println("Adding record that will be mapped");
 ok = s4.add("
@@ -140,14 +145,17 @@
 assert(ok);
 
 println("Checking for existance of record (mapped)");
-msg = s4.search("(unixName=bin)", new Array('unixName','cn','dn'));
+msg = s4.search("(unixName=bin)", new Array('unixName','cn','dn', 'unicodePwd'));
 assert(msg.length == 1);
-assert(msg[0].cn == "Niemand");
+assert(msg[0].cn == "Niemand"); 
+/* TODO: Local data isn't merged back into the search result yet
+assert(msg[0].unicodePwd == "geheim");
+*/
 
 println("Checking for data in destination database");
 msg = s3.search("(cn=Niemand)");
 assert(msg.length >= 1);
-// XXX assert(msg[0].sambaSID == "S-1-5-21-4231626423-2410014848-2360679739-2001");
+assert(msg[0].sambaSID == "S-1-5-21-4231626423-2410014848-2360679739-2001");
 assert(msg[0].displayName == "Niemand");
 
 println("Adding attribute...");



More information about the samba-cvs mailing list