Cosmetic corrections for the DSDB module
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / proxy.c
index 643ff5f3d0e0008d28995ee2625348af84ca98ef..932fd3bcb6b284dbb2711de37225b89b32320d1c 100644 (file)
@@ -10,7 +10,7 @@
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 2 of the License, or (at your option) any later version.
+   version 3 of the License, or (at your option) any later version.
 
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -18,8 +18,7 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 
 /*
@@ -41,7 +40,7 @@
 #include "ldb/include/ldb.h"
 #include "ldb/include/ldb_errors.h"
 #include "ldb/include/ldb_private.h"
-#include "lib/cmdline/popt_common.h"
+#include "auth/credentials/credentials.h"
 
 struct proxy_data {
        struct ldb_context *upstream;
@@ -51,6 +50,14 @@ struct proxy_data {
        const char **newstr;
 };
 
+struct proxy_ctx {
+       struct ldb_module *module;
+       struct ldb_request *req;
+
+#ifdef DEBUG_PROXY
+       int count;
+#endif
+};
 
 /*
   load the @PROXYINFO record
@@ -59,54 +66,53 @@ static int load_proxy_info(struct ldb_module *module)
 {
        struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
        struct ldb_dn *dn;
-       struct ldb_result *res;
+       struct ldb_result *res = NULL;
        int ret;
        const char *olddn, *newdn, *url, *username, *password, *oldstr, *newstr;
        struct cli_credentials *creds;
-       
 
        /* see if we have already loaded it */
        if (proxy->upstream != NULL) {
-               return 0;
+               return LDB_SUCCESS;
        }
 
-       dn = ldb_dn_explode(proxy, "@PROXYINFO");
+       dn = ldb_dn_new(proxy, module->ldb, "@PROXYINFO");
        if (dn == NULL) {
                goto failed;
        }
-       ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
+       ret = ldb_search(module->ldb, proxy, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
        talloc_free(dn);
        if (ret != LDB_SUCCESS || res->count != 1) {
                ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find @PROXYINFO\n");
                goto failed;
        }
 
-       url      = ldb_msg_find_string(res->msgs[0], "url", NULL);
-       olddn    = ldb_msg_find_string(res->msgs[0], "olddn", NULL);
-       newdn    = ldb_msg_find_string(res->msgs[0], "newdn", NULL);
-       username = ldb_msg_find_string(res->msgs[0], "username", NULL);
-       password = ldb_msg_find_string(res->msgs[0], "password", NULL);
-       oldstr   = ldb_msg_find_string(res->msgs[0], "oldstr", NULL);
-       newstr   = ldb_msg_find_string(res->msgs[0], "newstr", NULL);
+       url      = ldb_msg_find_attr_as_string(res->msgs[0], "url", NULL);
+       olddn    = ldb_msg_find_attr_as_string(res->msgs[0], "olddn", NULL);
+       newdn    = ldb_msg_find_attr_as_string(res->msgs[0], "newdn", NULL);
+       username = ldb_msg_find_attr_as_string(res->msgs[0], "username", NULL);
+       password = ldb_msg_find_attr_as_string(res->msgs[0], "password", NULL);
+       oldstr   = ldb_msg_find_attr_as_string(res->msgs[0], "oldstr", NULL);
+       newstr   = ldb_msg_find_attr_as_string(res->msgs[0], "newstr", NULL);
 
        if (url == NULL || olddn == NULL || newdn == NULL || username == NULL || password == NULL) {
                ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Need url, olddn, newdn, oldstr, newstr, username and password in @PROXYINFO\n");
                goto failed;
        }
 
-       proxy->olddn = ldb_dn_explode(proxy, olddn);
+       proxy->olddn = ldb_dn_new(proxy, module->ldb, olddn);
        if (proxy->olddn == NULL) {
                ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode olddn '%s'\n", olddn);
                goto failed;
        }
        
-       proxy->newdn = ldb_dn_explode(proxy, newdn);
+       proxy->newdn = ldb_dn_new(proxy, module->ldb, newdn);
        if (proxy->newdn == NULL) {
                ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode newdn '%s'\n", newdn);
                goto failed;
        }
 
-       proxy->upstream = ldb_init(proxy);
+       proxy->upstream = ldb_init(proxy, ldb_get_event_context(ldb));
        if (proxy->upstream == NULL) {
                ldb_oom(module->ldb);
                goto failed;
@@ -130,7 +136,7 @@ static int load_proxy_info(struct ldb_module *module)
                ldb_oom(module->ldb);
                goto failed;
        }
-       cli_credentials_guess(creds);
+       cli_credentials_guess(creds, ldb_get_opaque(module->ldb, "loadparm"));
        cli_credentials_set_username(creds, username, CRED_SPECIFIED);
        cli_credentials_set_password(creds, password, CRED_SPECIFIED);
 
@@ -146,7 +152,7 @@ static int load_proxy_info(struct ldb_module *module)
 
        talloc_free(res);
 
-       return 0;
+       return LDB_SUCCESS;
 
 failed:
        talloc_free(res);
@@ -154,7 +160,7 @@ failed:
        talloc_free(proxy->newdn);
        talloc_free(proxy->upstream);
        proxy->upstream = NULL;
-       return -1;
+       return LDB_ERR_OPERATIONS_ERROR;
 }
 
 
@@ -181,10 +187,10 @@ static void proxy_convert_blob(TALLOC_CTX *mem_ctx, struct ldb_val *v,
 /*
   convert a returned value
 */
-static void proxy_convert_value(struct ldb_module *module, struct ldb_message *msg, struct ldb_val *v)
+static void proxy_convert_value(struct proxy_data *proxy, struct ldb_message *msg, struct ldb_val *v)
 {
-       struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
        int i;
+
        for (i=0;proxy->oldstr[i];i++) {
                char *p = strcasestr((char *)v->data, proxy->oldstr[i]);
                if (p == NULL) continue;
@@ -196,20 +202,21 @@ static void proxy_convert_value(struct ldb_module *module, struct ldb_message *m
 /*
   convert a returned value
 */
-static struct ldb_parse_tree *proxy_convert_tree(struct ldb_module *module, 
+static struct ldb_parse_tree *proxy_convert_tree(TALLOC_CTX *mem_ctx,
+                                                struct proxy_data *proxy,
                                                 struct ldb_parse_tree *tree)
 {
-       struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
        int i;
-       char *expression = ldb_filter_from_tree(module, tree);
+       char *expression = ldb_filter_from_tree(mem_ctx, tree);
+
        for (i=0;proxy->newstr[i];i++) {
                struct ldb_val v;
                char *p = strcasestr(expression, proxy->newstr[i]);
                if (p == NULL) continue;
                v.data = (uint8_t *)expression;
                v.length = strlen(expression)+1;
-               proxy_convert_blob(module, &v, proxy->newstr[i], proxy->oldstr[i]);
-               return ldb_parse_tree(module, (const char *)v.data);
+               proxy_convert_blob(mem_ctx, &v, proxy->newstr[i], proxy->oldstr[i]);
+               return ldb_parse_tree(mem_ctx, (const char *)v.data);
        }
        return tree;
 }
@@ -219,38 +226,88 @@ static struct ldb_parse_tree *proxy_convert_tree(struct ldb_module *module,
 /*
   convert a returned record
 */
-static void proxy_convert_record(struct ldb_module *module, struct ldb_message *msg)
+static void proxy_convert_record(struct ldb_context *ldb,
+                                struct proxy_data *proxy,
+                                struct ldb_message *msg)
 {
-       struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
        int attr, v;
-       
+
        /* fix the message DN */
-       if (ldb_dn_compare_base(module->ldb, proxy->olddn, msg->dn) == 0) {
-               struct ldb_dn *newdn = ldb_dn_copy(msg, msg->dn);
-               newdn->comp_num -= proxy->olddn->comp_num;
-               msg->dn = ldb_dn_compose(msg, newdn, proxy->newdn);
+       if (ldb_dn_compare_base(proxy->olddn, msg->dn) == 0) {
+               ldb_dn_remove_base_components(msg->dn, ldb_dn_get_comp_num(proxy->olddn));
+               ldb_dn_add_base(msg->dn, proxy->newdn);
        }
 
        /* fix any attributes */
        for (attr=0;attr<msg->num_elements;attr++) {
                for (v=0;v<msg->elements[attr].num_values;v++) {
-                       proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
+                       proxy_convert_value(proxy, msg, &msg->elements[attr].values[v]);
                }
        }
 
        /* fix any DN components */
        for (attr=0;attr<msg->num_elements;attr++) {
                for (v=0;v<msg->elements[attr].num_values;v++) {
-                       proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
+                       proxy_convert_value(proxy, msg, &msg->elements[attr].values[v]);
                }
        }
 }
 
+static int proxy_search_callback(struct ldb_request *req,
+                                 struct ldb_reply *ares)
+{
+       struct proxy_data *proxy;
+       struct proxy_ctx *ac;
+       int ret;
+
+       ac = talloc_get_type(req->context, struct proxy_ctx);
+       proxy = talloc_get_type(ac->module->private_data, struct proxy_data);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
+
+       /* Only entries are interesting, and we only want the olddn */
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
+
+#ifdef DEBUG_PROXY
+               ac->count++;
+#endif
+               proxy_convert_record(ac->module->ldb, proxy, ares->message);
+               ret = ldb_module_send_entry(ac->req, ares->message);
+               break;
+
+       case LDB_REPLY_REFERRAL:
+
+               /* ignore remote referrals */
+               break;
+
+       case LDB_REPLY_DONE:
+
+#ifdef DEBUG_PROXY
+               printf("# record %d\n", ac->count+1);
+#endif
+
+               return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
+       }
+
+       talloc_free(ares);
+       return ret;
+}
+
 /* search */
 static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *req)
 {
+       struct proxy_ctx *ac;
+       struct ldb_parse_tree *newtree;
        struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
-       struct ldb_request newreq;
+       struct ldb_request *newreq;
        struct ldb_dn *base;
        int ret, i;
 
@@ -261,55 +318,63 @@ static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *re
        }
 
        if (load_proxy_info(module) != 0) {
-               return -1;
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
        /* see if the dn is within olddn */
-       if (ldb_dn_compare_base(module->ldb, proxy->newdn, req->op.search.base) != 0) {
+       if (ldb_dn_compare_base(proxy->newdn, req->op.search.base) != 0) {
                goto passthru;
        }
 
-       newreq.op.search.tree = proxy_convert_tree(module, req->op.search.tree);
+       ac = talloc(req, struct proxy_ctx);
+       if (ac == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ac->module = module;
+       ac->req = req;
+#ifdef DEBUG_PROXY
+       ac->count = 0;
+#endif
+
+       newtree = proxy_convert_tree(ac, proxy, req->op.search.tree);
 
        /* convert the basedn of this search */
-       base = ldb_dn_copy(proxy, req->op.search.base);
+       base = ldb_dn_copy(ac, req->op.search.base);
        if (base == NULL) {
                goto failed;
        }
-       base->comp_num -= proxy->newdn->comp_num;
-       base = ldb_dn_compose(proxy, newreq.op.search.base, proxy->olddn);
+       ldb_dn_remove_base_components(base, ldb_dn_get_comp_num(proxy->newdn));
+       ldb_dn_add_base(base, proxy->olddn);
 
        ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n", 
-                 ldb_filter_from_tree(proxy, newreq.op.search.tree), ldb_dn_linearize(proxy, newreq.op.search.base));
+                 ldb_filter_from_tree(ac, newreq->op.search.tree), ldb_dn_get_linearized(newreq->op.search.base));
        for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
                ldb_debug(module->ldb, LDB_DEBUG_FATAL, "attr: '%s'\n", req->op.search.attrs[i]);
        }
 
-       newreq.op.search.base = base;
-       newreq.op.search.scope = req->op.search.scope;
-       newreq.op.search.attrs = req->op.search.attrs;
-       newreq.op.search.res = req->op.search.res;
-       ret = ldb_request(proxy->upstream, &newreq);
+       ret = ldb_build_search_req_ex(&newreq, module->ldb, ac,
+                                     base, req->op.search.scope,
+                                     newtree, req->op.search.attrs,
+                                     req->controls,
+                                     ac, proxy_search_callback,
+                                     req);
+
+       /* FIXME: warning, need a real event system hooked up for this to work properly,
+        *        for now this makes the module *not* ASYNC */
+       ret = ldb_request(proxy->upstream, newreq);
        if (ret != LDB_SUCCESS) {
-               ldb_set_errstring(module, talloc_strdup(module, ldb_errstring(proxy->upstream)));
-               return -1;
+               ldb_set_errstring(module->ldb, ldb_errstring(proxy->upstream));
        }
-
-       for (i = 0; i < (*newreq.op.search.res)->count; i++) {
-               struct ldb_ldif ldif;
-               printf("# record %d\n", i+1);
-               
-               proxy_convert_record(module, (*newreq.op.search.res)->msgs[i]);
-
-               ldif.changetype = LDB_CHANGETYPE_NONE;
-               ldif.msg = (*newreq.op.search.res)->msgs[i];
+       ret = ldb_wait(newreq->handle, LDB_WAIT_ALL);
+       if (ret != LDB_SUCCESS) {
+               ldb_set_errstring(module->ldb, ldb_errstring(proxy->upstream));
        }
-
        return ret;
 
 failed:
        ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n", 
-                 ldb_dn_linearize(proxy, req->op.search.base));
+                 ldb_dn_get_linearized(req->op.search.base));
 
 passthru:
        return ldb_next_request(module, req); 
@@ -328,31 +393,7 @@ static int proxy_request(struct ldb_module *module, struct ldb_request *req)
        }
 }
 
-static const struct ldb_module_ops proxy_ops = {
+_PUBLIC_ const struct ldb_module_ops ldb_proxy_module_ops = {
        .name           = "proxy",
        .request        = proxy_request
 };
-
-#ifdef HAVE_DLOPEN_DISABLED
-struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
-#else
-struct ldb_module *proxy_module_init(struct ldb_context *ldb, const char *options[])
-#endif
-{
-       struct ldb_module *ctx;
-
-       ctx = talloc(ldb, struct ldb_module);
-       if (!ctx)
-               return NULL;
-
-       ctx->ldb = ldb;
-       ctx->prev = ctx->next = NULL;
-       ctx->ops = &proxy_ops;
-
-       ctx->private_data = talloc_zero(ctx, struct proxy_data);
-       if (ctx->private_data == NULL) {
-               return NULL;
-       }
-
-       return ctx;
-}