Author: mkhl
Date: 2006-06-24 22:00:52 +0000 (Sat, 24 Jun 2006)
New Revision: 16505

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

Log:
Check incoming DN before performing mappings.
Add chunks of searching boilerplate.

Martin

Modified:
   branches/SOC/mkhl/ldb-map/modules/ldb_map.c


Changeset:
Modified: branches/SOC/mkhl/ldb-map/modules/ldb_map.c
===================================================================
--- branches/SOC/mkhl/ldb-map/modules/ldb_map.c 2006-06-24 20:38:38 UTC (rev 
16504)
+++ branches/SOC/mkhl/ldb-map/modules/ldb_map.c 2006-06-24 22:00:52 UTC (rev 
16505)
@@ -1,25 +1,25 @@
 /* 
-   ldb database library - map backend
+   Mapping ldb module
 
    Copyright (C) Jelmer Vernooij 2005
 
-     ** NOTE! The following LGPL license applies to the ldb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
+   * NOTICE: this module is NOT released under the GNU LGPL license as
+   * other ldb code. This module is release under the GNU GPL v2 or
+   * later license.
+
+   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 2 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 2 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, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307        
 USA
+   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, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
 /*
@@ -27,7 +27,7 @@
  *
  *  Component: ldb ldb_map module
  *
- *  Description: ...
+ *  Description: Map portions of data into a different format on a remote 
partition.
  *
  *  Author: Jelmer Vernooij, Martin Kuehl
  */
@@ -57,7 +57,7 @@
 #define map_oom(module) ldb_set_errstring(module->ldb, talloc_asprintf(module, 
"Out of Memory"));
 
 
-/* Private data */
+/* private data */
 struct map_private {
        struct ldb_map_context context;
 };
@@ -73,9 +73,11 @@
 }
 
 
-/* Async context data */
+/* async context data */
 struct map_async_context {
        enum map_step {
+               MAP_SEARCH_LOCAL,
+               MAP_SEARCH_REMOTE,
                MAP_DO_ADD_REMOTE,
                MAP_DO_ADD_LOCAL,
                MAP_SEARCH_SELF_MODIFY,
@@ -87,7 +89,7 @@
                MAP_SEARCH_SELF_RENAME,
                MAP_DO_RENAME_REMOTE,
                MAP_DO_RENAME_FIXUP,
-               MAP_DO_RENAME_LOCAL,
+               MAP_DO_RENAME_LOCAL
        } step;
 
        struct ldb_module *module;
@@ -104,6 +106,13 @@
        struct ldb_async_result *search_res;
 };
 
+/* async context data for searches */
+struct map_async_search_context {
+       struct map_async_context *ac;
+       struct ldb_async_result *local_res;
+       struct ldb_async_result *remote_res;
+};
+
 /* create async context and handle */
 static
 struct ldb_async_handle *
@@ -191,7 +200,7 @@
         return new;
 }
 
-#define MAP_DN_REBASE(dn) dn = ldb_dn_rebase(request, dn, map->local_base_dn, 
map->remote_base_dn)
+#define MAP_DN_REBASE(dn) dn = ldb_dn_rebase(request, dn, data->local_base_dn, 
data->remote_base_dn)
 
 /* run request in the remote partition */
 static
@@ -199,7 +208,7 @@
 ldb_next_remote_request(struct ldb_module *module,
                        struct ldb_request *request)
 {
-       struct ldb_map_context *map = map_get_privdat(module);
+       struct ldb_map_context *data = map_get_privdat(module);
         struct ldb_message *msg;
 
         switch (request->operation) {
@@ -315,24 +324,71 @@
 }
 
 
-/* Checking ldb_messages */
+/* Checking ... stuff  */
 
+/* True if dn is below the local baseDN */
 static
-int
-check_msg_is_mapped(struct ldb_module *module,
-                   const struct ldb_message *msg)
+BOOL
+check_dn_local(struct ldb_module *module,
+              const struct ldb_dn *dn)
 {
        struct ldb_map_context *data = map_get_privdat(module);
+
+       return ldb_dn_compare_base(module->ldb, data->local_base_dn, dn) == 0;
+}
+
+/* True if attr has an associated mapping that does not ignore it */
+static
+BOOL
+check_attr_mapped(struct ldb_map_context *data,
+                 const char* attr)
+{
        struct ldb_map_attribute *map;
+
+       map = find_attr_local(data, attr);
+       if (map == NULL)
+               return False;
+       if (map->type == MAP_IGNORE)
+               return False;
+       return True;
+}
+
+/* True if any of attrs is mapped */
+static
+BOOL
+check_attrs_mapped(struct ldb_module *module,
+                  const char * const *attrs)
+{
+       struct ldb_map_context *data = map_get_privdat(module);
+       BOOL ret;
        int i;
 
+       for (i = 0; attrs[i]; i++) {
+               ret = check_attr_mapped(data, attrs[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return False;
+}
+
+/* True if any of the message elements is mapped */
+static
+BOOL
+check_msg_mapped(struct ldb_module *module,
+                const struct ldb_message *msg)
+{
+       struct ldb_map_context *data = map_get_privdat(module);
+       BOOL ret;
+       int i;
+
        for (i = 0; i < msg->num_elements; i++) {
-               map = find_attr_local(data, msg->elements[i].name);
-               if (map && map->type != MAP_IGNORE)
-                       return 1;
+               ret = check_attr_mapped(data, msg->elements[i].name);
+               if (ret)
+                       return ret;
        }
 
-       return 0;
+       return False;
 }
 
 /* Check whether the given objectClass is contained in the specified
@@ -1340,11 +1396,12 @@
 }
 
 
+/* store single search result in async context */
 static
 int
-get_self_callback(struct ldb_context *ldb,
-                 void *context,
-                 struct ldb_async_result *ares)
+search_self_callback(struct ldb_context *ldb,
+                    void *context,
+                    struct ldb_async_result *ares)
 {
        struct map_async_context *ac;
 
@@ -1361,7 +1418,8 @@
                return LDB_SUCCESS;
        }
 
-       if (ac->remote_dn != NULL) {
+       /* we already have a remote DN */
+       if (ac->remote_dn) {
                ldb_set_errstring(ldb,
                                  talloc_asprintf(ldb, "Too many results"));
                talloc_free(ares);
@@ -1369,17 +1427,18 @@
        }
 
        ac->search_res = talloc_steal(ac, ares);
-       ac->remote_dn
-               = ldb_dn_explode(ac, ldb_msg_find_string(ares->message,
-                                                        IS_MAPPED, NULL));
+       ac->remote_dn = ldb_dn_explode(ac,
+                                      ldb_msg_find_string(ares->message,
+                                                          IS_MAPPED, NULL));
 
        return LDB_SUCCESS;
 }
 
+/* create request that searches for DN */
 static
 struct ldb_request *
-build_self_req(struct map_async_context *ac,
-              const struct ldb_dn *dn)
+search_self_req(struct map_async_context *ac,
+               const struct ldb_dn *dn)
 {
        /* attrs[] is returned from this function in
           ac->search_req->op.search.attrs, so it must be static, as
@@ -1406,13 +1465,53 @@
 
        req->controls = NULL;
        req->async.context = ac;
-       req->async.callback = get_self_callback;
+       req->async.callback = search_self_callback;
        ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req);
 
        return req;
 }
 
+static
+int
+local_search_callback(struct ldb_context *ldb,
+                     void *context,
+                     struct ldb_async_result *ares)
+{
+       struct map_async_search_context *sc;
 
+       if (context == NULL || ares == NULL) {
+               ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or 
Result in callback"));
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       sc = talloc_get_type(context, struct map_async_search_context);
+
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
+               /* we already have a local result */
+               if (sc->local_res != NULL) {
+                       ldb_set_errstring(ldb,
+                                         talloc_asprintf(ldb,
+                                                         "Too many results"));
+                       talloc_free(ares);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               sc->local_res = talloc_steal(sc, ares);
+
+               /* don't return the 'IS_MAPPED' attribute */
+               ldb_msg_remove_attr(ares->message, IS_MAPPED);
+
+               /* XXX: ... */
+               
+       default:
+               talloc_free(ares);
+               ldb_set_errstring(ldb, talloc_asprintf(ldb, "Unexpected result 
type in search for local record"));
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+}
+
+
 /* Handling LDB requests */
 
 /* /\* Search fallback database *\/ */
@@ -1612,6 +1711,73 @@
 /* } */
 
 
+/* Search a record */
+static
+int
+map_search(struct ldb_module *module,
+          struct ldb_request *req)
+{
+       struct ldb_async_handle *h;
+       struct map_async_context *ac;
+       const char * const *local_attrs;
+       int ret;
+
+       /* do not manipulate our control entries */
+       if (ldb_dn_is_special(req->op.search.base))
+               return ldb_next_request(module, req);
+
+       /* no mapping requested, skip to next module */
+       if (!check_dn_local(module, req->op.search.base))
+               return ldb_next_request(module, req);
+
+       /* no mapping needed, skip to next module */
+       if (req->op.search.attrs
+           && (!ldb_attr_in_list(req->op.search.attrs, "*"))
+           && (!check_attrs_mapped(module, req->op.search.attrs)))
+               return ldb_next_request(module, req);
+
+       /* prepare async context and handle */
+       h = map_init_handle(req, module);
+       if (h == NULL)
+               return LDB_ERR_OPERATIONS_ERROR;
+       ac = talloc_get_type(h->private_data, struct map_async_context);
+
+       /* return or own handle to deal with this call */
+       /* req->async.handle = h; */
+
+       /* prepare the local operation */
+       ac->local_req = talloc_zero(ac, struct ldb_request);
+       if (ac->local_req == NULL) {
+               map_oom(module);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       *(ac->local_req) = *req; /* copy the request */
+
+       /* return or own handle to deal with this call */
+       ac->local_req->async.handle = h;
+
+       ac->local_req->async.context = ac;
+       ac->local_req->async.callback = local_search_callback;
+
+       /* XXX: ... */
+
+       ac->local_req->op.search.attrs = local_attrs;
+
+       ldb_set_timeout_from_prev_req(module->ldb, req, ac->local_req);
+
+       h->state = LDB_ASYNC_INIT;
+       h->status = LDB_SUCCESS;
+
+       ac->step = MAP_SEARCH_LOCAL;
+
+       ret = ldb_next_request(module, ac->local_req);
+       if (ret == LDB_SUCCESS)
+               req->async.handle = ac->local_req->async.handle;
+       return ret;
+}
+
+
 /* Add the local record */
 static
 int
@@ -1644,8 +1810,12 @@
        if (ldb_dn_is_special(msg->dn))
                return ldb_next_request(module, req);
 
+       /* no mapping requested, skip to next module */
+       if (!check_dn_local(module, msg->dn))
+               return ldb_next_request(module, req);
+
        /* no mapping needed, skip to next module */
-       if (!check_msg_is_mapped(module, msg))
+       if (!check_msg_mapped(module, msg))
                return ldb_next_request(module, req);
 
        /* prepare async context and handle */
@@ -1797,8 +1967,12 @@
        if (ldb_dn_is_special(msg->dn))
                return ldb_next_request(module, req);
 
+       /* no mapping requested, skip to next module */
+       if (!check_dn_local(module, msg->dn))
+               return ldb_next_request(module, req);
+
        /* no mapping needed, skip to next module */
-       if (!check_msg_is_mapped(module, msg))
+       if (!check_msg_mapped(module, msg))
                return ldb_next_request(module, req);
 
        /* prepare async context and handle */
@@ -1860,7 +2034,7 @@
                return map_modify_do_local(h);
 
        /* prepare the search operation */
-       ac->search_req = build_self_req(ac, msg->dn);
+       ac->search_req = search_self_req(ac, msg->dn);
        if (ac->search_req == NULL)
                return LDB_ERR_OPERATIONS_ERROR;
 
@@ -1951,8 +2125,11 @@
        if (ldb_dn_is_special(req->op.del.dn))
                return ldb_next_request(module, req);
 
-       /* TODO: check that DN is under the local baseDN */
 
+       /* no mapping requested, skip to next module */
+       if (!check_dn_local(module, req->op.del.dn))
+               return ldb_next_request(module, req);
+
        /* prepare async context and handle */
        h = map_init_handle(req, module);
        if (h == NULL)
@@ -1963,7 +2140,7 @@
        req->async.handle = h;
 
        /* prepare the search operation */
-       ac->search_req = build_self_req(ac, req->op.del.dn);
+       ac->search_req = search_self_req(ac, req->op.del.dn);
        if (ac->search_req == NULL)
                return LDB_ERR_OPERATIONS_ERROR;
 
@@ -2104,7 +2281,11 @@
        if (ldb_dn_is_special(req->op.rename.olddn))
                return ldb_next_request(module, req);
 
-       /* TODO: check that DN is under the local baseDN */
+       /* no mapping requested, skip to next module */
+       /* TODO: both? either? neither? what to doin each case? */
+       if (!check_dn_local(module, req->op.rename.olddn) ||
+           !check_dn_local(module, req->op.rename.newdn))
+               return ldb_next_request(module, req);
 
        /* prepare async context and handle */
        h = map_init_handle(req, module);
@@ -2116,7 +2297,7 @@
        req->async.handle = h;
 
        /* prepare the search operation */
-       ac->search_req = build_self_req(ac, req->op.rename.olddn);
+       ac->search_req = search_self_req(ac, req->op.rename.olddn);
        if (ac->search_req == NULL)
                return LDB_ERR_OPERATIONS_ERROR;
 
@@ -2291,7 +2472,7 @@
        .modify            = map_modify,
        .del               = map_delete,
        .rename            = map_rename,
-/*     .search            = map_search_bytree, */
+       .search            = map_search,
        .async_wait        = map_async_wait,
 };
 

Reply via email to