s4:dsdb - always fail if a search filter could not be parsed
[mdw/samba.git] / source4 / dsdb / samdb / ldb_modules / proxy.c
index a7704ef41378bcee6485ffcc242689174d27c926..c3f12bae3a16dd2d07ee1d19588fcb10121e4331 100644 (file)
@@ -3,22 +3,18 @@
 
    Copyright (C) Andrew Tridgell 2005
 
-     ** NOTE! The following LGPL license applies to the ldb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
    
-   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 3 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
+   This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   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, see <http://www.gnu.org/licenses/>.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /*
@@ -37,9 +33,7 @@
  */
 
 #include "includes.h"
-#include "ldb/include/ldb.h"
-#include "ldb/include/ldb_errors.h"
-#include "ldb/include/ldb_private.h"
+#include "ldb_module.h"
 #include "auth/credentials/credentials.h"
 
 struct proxy_data {
@@ -50,33 +44,41 @@ 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
 */
 static int load_proxy_info(struct ldb_module *module)
 {
-       struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct proxy_data *proxy = talloc_get_type(ldb_module_get_private(module), struct proxy_data);
        struct ldb_dn *dn;
        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_new(proxy, module->ldb, "@PROXYINFO");
+       dn = ldb_dn_new(proxy, ldb, "@PROXYINFO");
        if (dn == NULL) {
                goto failed;
        }
-       ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
+       ret = ldb_search(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");
+               ldb_debug(ldb, LDB_DEBUG_FATAL, "Can't find @PROXYINFO\n");
                goto failed;
        }
 
@@ -89,63 +91,63 @@ static int load_proxy_info(struct ldb_module *module)
        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");
+               ldb_debug(ldb, LDB_DEBUG_FATAL, "Need url, olddn, newdn, oldstr, newstr, username and password in @PROXYINFO\n");
                goto failed;
        }
 
-       proxy->olddn = ldb_dn_new(proxy, module->ldb, olddn);
+       proxy->olddn = ldb_dn_new(proxy, ldb, olddn);
        if (proxy->olddn == NULL) {
-               ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode olddn '%s'\n", olddn);
+               ldb_debug(ldb, LDB_DEBUG_FATAL, "Failed to explode olddn '%s'\n", olddn);
                goto failed;
        }
        
-       proxy->newdn = ldb_dn_new(proxy, module->ldb, newdn);
+       proxy->newdn = ldb_dn_new(proxy, ldb, newdn);
        if (proxy->newdn == NULL) {
-               ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to explode newdn '%s'\n", newdn);
+               ldb_debug(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);
+               ldb_oom(ldb);
                goto failed;
        }
 
        proxy->oldstr = str_list_make(proxy, oldstr, ", ");
        if (proxy->oldstr == NULL) {
-               ldb_oom(module->ldb);
+               ldb_oom(ldb);
                goto failed;
        }
 
        proxy->newstr = str_list_make(proxy, newstr, ", ");
        if (proxy->newstr == NULL) {
-               ldb_oom(module->ldb);
+               ldb_oom(ldb);
                goto failed;
        }
 
        /* setup credentials for connection */
        creds = cli_credentials_init(proxy->upstream);
        if (creds == NULL) {
-               ldb_oom(module->ldb);
+               ldb_oom(ldb);
                goto failed;
        }
-       cli_credentials_guess(creds, ldb_get_opaque(module->ldb, "loadparm"));
+       cli_credentials_guess(creds, ldb_get_opaque(ldb, "loadparm"));
        cli_credentials_set_username(creds, username, CRED_SPECIFIED);
        cli_credentials_set_password(creds, password, CRED_SPECIFIED);
 
        ldb_set_opaque(proxy->upstream, "credentials", creds);
 
        ret = ldb_connect(proxy->upstream, url, 0, NULL);
-       if (ret != 0) {
-               ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxy failed to connect to %s\n", url);
+       if (ret != LDB_SUCCESS) {
+               ldb_debug(ldb, LDB_DEBUG_FATAL, "proxy failed to connect to %s\n", url);
                goto failed;
        }
 
-       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy connected to %s\n", url);
+       ldb_debug(ldb, LDB_DEBUG_TRACE, "proxy connected to %s\n", url);
 
        talloc_free(res);
 
-       return 0;
+       return LDB_SUCCESS;
 
 failed:
        talloc_free(res);
@@ -153,7 +155,7 @@ failed:
        talloc_free(proxy->newdn);
        talloc_free(proxy->upstream);
        proxy->upstream = NULL;
-       return -1;
+       return ldb_operr(ldb);
 }
 
 
@@ -163,7 +165,7 @@ failed:
 static void proxy_convert_blob(TALLOC_CTX *mem_ctx, struct ldb_val *v,
                               const char *oldstr, const char *newstr)
 {
-       int len1, len2, len3;
+       size_t len1, len2, len3;
        uint8_t *olddata = v->data;
        char *p = strcasestr((char *)v->data, oldstr);
 
@@ -180,10 +182,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;
+       size_t i;
+
        for (i=0;proxy->oldstr[i];i++) {
                char *p = strcasestr((char *)v->data, proxy->oldstr[i]);
                if (p == NULL) continue;
@@ -195,20 +197,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);
+       size_t i;
+       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;
 }
@@ -218,13 +221,14 @@ 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;
-       
+       unsigned int attr, v;
+
        /* fix the message DN */
-       if (ldb_dn_compare_base(module->ldb, proxy->olddn, msg->dn) == 0) {
+       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);
        }
@@ -232,25 +236,81 @@ static void proxy_convert_record(struct ldb_module *module, struct ldb_message *
        /* 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 ldb_context *ldb;
+       struct proxy_data *proxy;
+       struct proxy_ctx *ac;
+       int ret;
+
+       ac = talloc_get_type(req->context, struct proxy_ctx);
+       ldb = ldb_module_get_ctx(ac->module);
+       proxy = talloc_get_type(ldb_module_get_private(module), 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(ldb, proxy, ares->message);
+               ret = ldb_module_send_entry(ac->req, ares->message, ares->controls);
+               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_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
+       struct ldb_context *ldb;
+       struct proxy_ctx *ac;
+       struct ldb_parse_tree *newtree;
+       struct proxy_data *proxy = talloc_get_type(ldb_module_get_private(module), struct proxy_data);
        struct ldb_request *newreq;
        struct ldb_dn *base;
-       int ret, i;
+       unsigned int i;
+       int ret;
+
+       ldb = ldb_module_get_ctx(module);
 
        if (req->op.search.base == NULL ||
                (req->op.search.base->comp_num == 1 &&
@@ -258,60 +318,66 @@ static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *re
                goto passthru;
        }
 
-       if (load_proxy_info(module) != 0) {
-               return -1;
+       if (load_proxy_info(module) != LDB_SUCCESS) {
+               return ldb_operr(ldb);
        }
 
        /* 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 = talloc(module, struct ldb_request);
-       if (newreq == NULL) {
-               return -1;
+       ac = talloc(req, struct proxy_ctx);
+       if (ac == NULL) {
+               return ldb_oom(ldb);
        }
 
-       newreq->op.search.tree = proxy_convert_tree(module, req->op.search.tree);
+       ac->module = module;
+       ac->req = req;
+#ifdef DEBUG_PROXY
+       ac->count = 0;
+#endif
+
+       newtree = proxy_convert_tree(ac, proxy, req->op.search.tree);
+       if (newtree == NULL) {
+               goto failed;
+       }
 
        /* 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) {
-               talloc_free(newreq);
                goto failed;
        }
        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_get_linearized(newreq->op.search.base));
+       ldb_debug(ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n", 
+                 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]);
+               ldb_debug(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;
-       newreq->controls = req->controls;
+       ret = ldb_build_search_req_ex(&newreq, ldb, ac,
+                                     base, req->op.search.scope,
+                                     newtree, req->op.search.attrs,
+                                     req->controls,
+                                     ac, proxy_search_callback,
+                                     req);
+       LDB_REQ_SET_LOCATION(newreq);
+       /* 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->ldb, ldb_errstring(proxy->upstream));
-               talloc_free(newreq);
-               return -1;
+               ldb_set_errstring(ldb, ldb_errstring(proxy->upstream));
        }
-
-       for (i = 0; i < newreq->op.search.res->count; i++) {
-               printf("# record %d\n", i+1);
-               
-               proxy_convert_record(module, newreq->op.search.res->msgs[i]);
+       ret = ldb_wait(newreq->handle, LDB_WAIT_ALL);
+       if (ret != LDB_SUCCESS) {
+               ldb_set_errstring(ldb, ldb_errstring(proxy->upstream));
        }
-
-       talloc_free(newreq);
        return ret;
 
 failed:
-       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n", 
+       ldb_debug(ldb, LDB_DEBUG_TRACE, "proxy failed for %s\n", 
                  ldb_dn_get_linearized(req->op.search.base));
 
 passthru:
@@ -331,7 +397,13 @@ static int proxy_request(struct ldb_module *module, struct ldb_request *req)
        }
 }
 
-const struct ldb_module_ops ldb_proxy_module_ops = {
+static const struct ldb_module_ops ldb_proxy_module_ops = {
        .name           = "proxy",
        .request        = proxy_request
 };
+
+int ldb_proxy_module_init(const char *version)
+{
+       LDB_MODULE_CHECK_VERSION(version);
+       return ldb_register_module(&ldb_proxy_module_ops);
+}