Merge branch 'master' of ssh://git.samba.org/data/git/samba into extended-dn
authorAndrew Bartlett <abartlet@samba.org>
Mon, 8 Dec 2008 20:27:02 +0000 (07:27 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 8 Dec 2008 20:27:02 +0000 (07:27 +1100)
35 files changed:
source4/dsdb/samdb/ldb_modules/config.mk
source4/dsdb/samdb/ldb_modules/extended_dn.c [deleted file]
source4/dsdb/samdb/ldb_modules/extended_dn_in.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/extended_dn_out.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/extended_dn_out_dereference.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/extended_dn_out_ldb.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/extended_dn_store.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/linked_attributes.c
source4/dsdb/samdb/ldb_modules/local_password.c
source4/dsdb/samdb/ldb_modules/normalise.c
source4/dsdb/samdb/ldb_modules/rootdse.c
source4/dsdb/samdb/ldb_modules/simple_ldap_map.c
source4/dsdb/samdb/samdb.h
source4/ldap_server/ldap_backend.c
source4/lib/ldb-samba/ldif_handlers.c
source4/lib/ldb/common/ldb_attributes.c
source4/lib/ldb/common/ldb_controls.c
source4/lib/ldb/common/ldb_dn.c
source4/lib/ldb/common/ldb_ldif.c
source4/lib/ldb/include/ldb.h
source4/lib/ldb/include/ldb_private.h
source4/lib/ldb/ldb.i
source4/lib/ldb/ldb.py
source4/lib/ldb/ldb_ildap/ldb_ildap.c
source4/lib/ldb/ldb_wrap.c
source4/lib/ldb/tests/python/ldap.py
source4/libcli/ldap/ldap.c
source4/libcli/ldap/ldap_controls.c
source4/scripting/python/samba/provision.py
source4/setup/provision_basedn_modify.ldif
source4/setup/schema_samba4.ldif
source4/torture/config.mk
source4/torture/ldb/ldb.c [new file with mode: 0644]
source4/torture/torture.c
testprogs/blackbox/test_ldb.sh

index 138706625625766d3184568882b09d780d8f2ec4..19375bb923f8df82d15c340e5aed2f3c53661b5b 100644 (file)
@@ -171,15 +171,39 @@ INIT_FUNCTION = LDB_MODULE(kludge_acl)
 ldb_kludge_acl_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/kludge_acl.o
 
 ################################################
-# Start MODULE ldb_extended_dn
-[MODULE::ldb_extended_dn]
+# Start MODULE ldb_extended_dn_in
+[MODULE::ldb_extended_dn_in]
 SUBSYSTEM = LIBLDB
-PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBNDR LIBSECURITY SAMDB
-INIT_FUNCTION = LDB_MODULE(extended_dn)
-# End MODULE ldb_extended_dn
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS
+INIT_FUNCTION = LDB_MODULE(extended_dn_in)
+# End MODULE ldb_extended_dn_in
+################################################
+
+ldb_extended_dn_in_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/extended_dn_in.o
+
+################################################
+# Start MODULE ldb_extended_dn_out
+[MODULE::ldb_extended_dn_out]
+SUBSYSTEM = LIBLDB
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS
+INIT_FUNCTION = LDB_MODULE(extended_dn_out_ldb),LDB_MODULE(extended_dn_out_dereference)
+ENABLE = YES
+ALIASES = extended_dn_out_ldb extended_dn_out_dereference
+# End MODULE ldb_extended_dn_out
+################################################
+
+ldb_extended_dn_out_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/extended_dn_out.o
+
+################################################
+# Start MODULE ldb_extended_dn_store
+[MODULE::ldb_extended_dn_store]
+SUBSYSTEM = LIBLDB
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS
+INIT_FUNCTION = LDB_MODULE(extended_dn_store)
+# End MODULE ldb_extended_dn_store
 ################################################
 
-ldb_extended_dn_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/extended_dn.o
+ldb_extended_dn_store_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/extended_dn_store.o
 
 ################################################
 # Start MODULE ldb_show_deleted
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn.c b/source4/dsdb/samdb/ldb_modules/extended_dn.c
deleted file mode 100644 (file)
index a0602d9..0000000
+++ /dev/null
@@ -1,666 +0,0 @@
-/* 
-   ldb database library
-
-   Copyright (C) Simo Sorce 2005-2008
-
-     ** NOTE! The following LGPL license applies to the ldb
-     ** library. This does NOT imply that all of Samba is released
-     ** under the LGPL
-   
-   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,
-   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/>.
-*/
-
-/*
- *  Name: ldb
- *
- *  Component: ldb extended dn control module
- *
- *  Description: this module builds a special dn
- *
- *  Author: Simo Sorce
- */
-
-#include "includes.h"
-#include "ldb/include/ldb.h"
-#include "ldb/include/ldb_errors.h"
-#include "ldb/include/ldb_private.h"
-#include "librpc/gen_ndr/ndr_misc.h"
-#include "dsdb/samdb/samdb.h"
-#include "libcli/security/security.h"
-
-#include <time.h>
-
-static bool is_attr_in_list(const char * const * attrs, const char *attr)
-{
-       int i;
-
-       for (i = 0; attrs[i]; i++) {
-               if (strcasecmp(attrs[i], attr) == 0)
-                       return true;
-       }
-
-       return false;
-}
-
-static char **copy_attrs(void *mem_ctx, const char * const * attrs)
-{
-       char **new;
-       int i, num;
-
-       for (num = 0; attrs[num]; num++);
-
-       new = talloc_array(mem_ctx, char *, num + 1);
-       if (!new) return NULL;
-
-       for(i = 0; i < num; i++) {
-               new[i] = talloc_strdup(new, attrs[i]);
-               if (!new[i]) {
-                       talloc_free(new);
-                       return NULL;
-               }
-       }
-       new[i] = NULL;
-
-       return new;
-}
-
-static bool add_attrs(void *mem_ctx, char ***attrs, const char *attr)
-{
-       char **new;
-       int num;
-
-       for (num = 0; (*attrs)[num]; num++);
-
-       new = talloc_realloc(mem_ctx, *attrs, char *, num + 2);
-       if (!new) return false;
-
-       *attrs = new;
-
-       new[num] = talloc_strdup(new, attr);
-       if (!new[num]) return false;
-
-       new[num + 1] = NULL;
-
-       return true;
-}
-
-static int inject_extended_dn(struct ldb_message *msg,
-                               struct ldb_context *ldb,
-                               int type,
-                               bool remove_guid,
-                               bool remove_sid)
-{
-       const struct ldb_val *val;
-       struct GUID guid;
-       struct dom_sid *sid;
-       const DATA_BLOB *guid_blob;
-       const DATA_BLOB *sid_blob;
-       char *object_guid;
-       char *object_sid;
-       char *new_dn;
-
-       guid_blob = ldb_msg_find_ldb_val(msg, "objectGUID");
-       sid_blob = ldb_msg_find_ldb_val(msg, "objectSID");
-
-       if (!guid_blob) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       switch (type) {
-               case 0:
-                       /* return things in hexadecimal format */
-                       if (sid_blob) {
-                               const char *lower_guid_hex = strlower_talloc(msg, data_blob_hex_string(msg, guid_blob));
-                               const char *lower_sid_hex = strlower_talloc(msg, data_blob_hex_string(msg, sid_blob));
-                               if (!lower_guid_hex || !lower_sid_hex) {
-                                       return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                               new_dn = talloc_asprintf(msg, "<GUID=%s>;<SID=%s>;%s",
-                                                        lower_guid_hex, 
-                                                        lower_sid_hex,
-                                                        ldb_dn_get_linearized(msg->dn));
-                       } else {
-                               const char *lower_guid_hex = strlower_talloc(msg, data_blob_hex_string(msg, guid_blob));
-                               if (!lower_guid_hex) {
-                                       return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                               new_dn = talloc_asprintf(msg, "<GUID=%s>;%s",
-                                                        lower_guid_hex, 
-                                                        ldb_dn_get_linearized(msg->dn));
-                       }
-
-                       break;
-               case 1:
-                       /* retrieve object_guid */
-                       guid = samdb_result_guid(msg, "objectGUID");
-                       object_guid = GUID_string(msg, &guid);
-                       
-                       /* retrieve object_sid */
-                       object_sid = NULL;
-                       sid = samdb_result_dom_sid(msg, msg, "objectSID");
-                       if (sid) {
-                               object_sid = dom_sid_string(msg, sid);
-                               if (!object_sid)
-                                       return LDB_ERR_OPERATIONS_ERROR;
-
-                       }
-                       
-                       /* Normal, sane format */
-                       if (object_sid) {
-                               new_dn = talloc_asprintf(msg, "<GUID=%s>;<SID=%s>;%s",
-                                                        object_guid, object_sid,
-                                                        ldb_dn_get_linearized(msg->dn));
-                       } else {
-                               new_dn = talloc_asprintf(msg, "<GUID=%s>;%s",
-                                                        object_guid,
-                                                        ldb_dn_get_linearized(msg->dn));
-                       }
-                       break;
-               default:
-                       return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (!new_dn) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (remove_guid) {
-               ldb_msg_remove_attr(msg, "objectGUID");
-       }
-
-       if (sid_blob && remove_sid) {
-               ldb_msg_remove_attr(msg, "objectSID");
-       }
-
-       msg->dn = ldb_dn_new(msg, ldb, new_dn);
-       if (! ldb_dn_validate(msg->dn))
-               return LDB_ERR_OPERATIONS_ERROR;
-
-       val = ldb_msg_find_ldb_val(msg, "distinguishedName");
-       if (val) {
-               ldb_msg_remove_attr(msg, "distinguishedName");
-               if (ldb_msg_add_steal_string(msg, "distinguishedName", new_dn))
-                       return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       return LDB_SUCCESS;
-}
-
-/* search */
-struct extended_context {
-
-       struct ldb_module *module;
-       struct ldb_request *req;
-       struct ldb_control *control;
-       struct ldb_dn *basedn;
-       char *wellknown_object;
-       bool inject;
-       bool remove_guid;
-       bool remove_sid;
-       int extended_type;
-       const char * const *cast_attrs;
-};
-
-static int extended_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
-       struct extended_context *ac;
-       int ret;
-
-       ac = talloc_get_type(req->context, struct extended_context);
-
-       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);
-       }
-
-       switch (ares->type) {
-       case LDB_REPLY_ENTRY:
-               if (ac->inject) {
-                       /* for each record returned post-process to add any derived
-                          attributes that have been asked for */
-                       ret = inject_extended_dn(ares->message, ac->module->ldb,
-                                                ac->extended_type, ac->remove_guid,
-                                                ac->remove_sid);
-                       if (ret != LDB_SUCCESS) {
-                               return ldb_module_done(ac->req, NULL, NULL, ret);
-                       }
-               }
-
-               return ldb_module_send_entry(ac->req, ares->message);
-
-       case LDB_REPLY_REFERRAL:
-               return ldb_module_send_referral(ac->req, ares->referral);
-
-       case LDB_REPLY_DONE:
-               return ldb_module_done(ac->req, ares->controls,
-                                       ares->response, LDB_SUCCESS);
-
-       }
-       return LDB_SUCCESS;
-}
-
-static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
-       struct extended_context *ac;
-       struct ldb_request *down_req;
-       struct ldb_control **saved_controls;
-       struct ldb_message_element *el;
-       int ret;
-       size_t i;
-       size_t wkn_len = 0;
-       char *valstr = NULL;
-       const char *found = NULL;
-
-       ac = talloc_get_type(req->context, struct extended_context);
-
-       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);
-       }
-
-       switch (ares->type) {
-       case LDB_REPLY_ENTRY:
-               if (!ac->wellknown_object) {
-                       ac->basedn = ares->message->dn;
-                       break;
-               }
-
-               wkn_len = strlen(ac->wellknown_object);
-
-               el = ldb_msg_find_element(ares->message, "wellKnownObjects");
-               if (!el) {
-                       ac->basedn = NULL;
-                       break;
-               }
-
-               for (i=0; i < el->num_values; i++) {
-                       valstr = talloc_strndup(ac,
-                                               (const char *)el->values[i].data,
-                                               el->values[i].length);
-                       if (!valstr) {
-                               ldb_oom(ac->module->ldb);
-                               return ldb_module_done(ac->req, NULL, NULL,
-                                                      LDB_ERR_OPERATIONS_ERROR);
-                       }
-
-                       if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
-                               talloc_free(valstr);
-                               continue;
-                       }
-
-                       found = &valstr[wkn_len];
-                       break;
-               }
-
-               if (!found) {
-                       break;
-               }
-
-               ac->basedn = ldb_dn_new(ac, ac->module->ldb, found);
-               talloc_free(valstr);
-               if (!ac->basedn) {
-                       ldb_oom(ac->module->ldb);
-                       return ldb_module_done(ac->req, NULL, NULL,
-                                              LDB_ERR_OPERATIONS_ERROR);
-               }
-
-               break;
-
-       case LDB_REPLY_REFERRAL:
-               break;
-
-       case LDB_REPLY_DONE:
-
-               if (!ac->basedn) {
-                       const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
-                                                         ldb_dn_get_linearized(ac->req->op.search.base));
-                       ldb_set_errstring(ac->module->ldb, str);
-                       return ldb_module_done(ac->req, NULL, NULL,
-                                              LDB_ERR_NO_SUCH_OBJECT);
-               }
-
-               ret = ldb_build_search_req_ex(&down_req,
-                                               ac->module->ldb, ac,
-                                               ac->basedn,
-                                               ac->req->op.search.scope,
-                                               ac->req->op.search.tree,
-                                               ac->cast_attrs,
-                                               ac->req->controls,
-                                               ac, extended_callback,
-                                               ac->req);
-               if (ret != LDB_SUCCESS) {
-                       return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
-               }
-
-               if (ac->control) {
-                       /* save it locally and remove it from the list */
-                       /* we do not need to replace them later as we
-                        * are keeping the original req intact */
-                       if (!save_controls(ac->control, down_req, &saved_controls)) {
-                               return ldb_module_done(ac->req, NULL, NULL,
-                                                       LDB_ERR_OPERATIONS_ERROR);
-                       }
-               }
-
-               /* perform the search */
-               return ldb_next_request(ac->module, down_req);
-       }
-       return LDB_SUCCESS;
-}
-
-static int extended_search(struct ldb_module *module, struct ldb_request *req)
-{
-       struct ldb_control *control;
-       struct ldb_extended_dn_control *extended_ctrl = NULL;
-       struct ldb_control **saved_controls;
-       struct extended_context *ac;
-       struct ldb_request *down_req;
-       char **new_attrs;
-       int ret;
-       struct ldb_dn *base_dn = NULL;
-       enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
-       const char *base_dn_filter = NULL;
-       const char * const *base_dn_attrs = NULL;
-       char *wellknown_object = NULL;
-       static const char *dnattr[] = {
-               "distinguishedName",
-               NULL
-       };
-       static const char *wkattr[] = {
-               "wellKnownObjects",
-               NULL
-       };
-
-       if (ldb_dn_is_special(req->op.search.base)) {
-               char *dn;
-
-               dn = ldb_dn_alloc_linearized(req, req->op.search.base);
-               if (!dn) {
-                       ldb_oom(module->ldb);
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-
-               if (strncasecmp(dn, "<SID=", 5) == 0) {
-                       char *str;
-                       char *valstr;
-                       char *p;
-
-                       p = strchr(dn, '=');
-                       if (!p) {
-                               return LDB_ERR_INVALID_DN_SYNTAX;
-                       }
-
-                       p[0] = '\0';
-                       p++;
-
-                       str = p;
-
-                       p = strchr(str, '>');
-                       if (!p) {
-                               return LDB_ERR_INVALID_DN_SYNTAX;
-                       }
-                       p[0] = '\0';
-
-                       if (strncasecmp(str, "S-", 2) == 0) {
-                               valstr = str;
-                       } else {
-                               DATA_BLOB binary;
-                               binary = strhex_to_data_blob(NULL, str);
-                               if (!binary.data) {
-                                       ldb_oom(module->ldb);
-                                       return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                               valstr = ldb_binary_encode(req, binary);
-                               data_blob_free(&binary);
-                               if (!valstr) {
-                                       ldb_oom(module->ldb);
-                                       return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                       }
-
-                       /* TODO: do a search over all partitions */
-                       base_dn = ldb_get_default_basedn(module->ldb);
-                       base_dn_filter = talloc_asprintf(req, "(objectSid=%s)", valstr);
-                       if (!base_dn_filter) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
-                       }
-                       base_dn_scope = LDB_SCOPE_SUBTREE;
-                       base_dn_attrs = dnattr;
-               } else if (strncasecmp(dn, "<GUID=", 6) == 0) {
-                       char *str;
-                       char *valstr;
-                       char *p;
-
-                       p = strchr(dn, '=');
-                       if (!p) {
-                               return LDB_ERR_INVALID_DN_SYNTAX;
-                       }
-
-                       p[0] = '\0';
-                       p++;
-
-                       str = p;
-
-                       p = strchr(str, '>');
-                       if (!p) {
-                               return LDB_ERR_INVALID_DN_SYNTAX;
-                       }
-                       p[0] = '\0';
-
-                       if (strchr(str, '-')) {
-                               valstr = str;
-                       } else {
-                               DATA_BLOB binary;
-                               binary = strhex_to_data_blob(NULL, str);
-                               if (!binary.data) {
-                                       ldb_oom(module->ldb);
-                                       return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                               valstr = ldb_binary_encode(req, binary);
-                               data_blob_free(&binary);
-                               if (!valstr) {
-                                       ldb_oom(module->ldb);
-                                       return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                       }
-
-                       /* TODO: do a search over all partitions */
-                       base_dn = ldb_get_default_basedn(module->ldb);
-                       base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)", valstr);
-                       if (!base_dn_filter) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
-                       }
-                       base_dn_scope = LDB_SCOPE_SUBTREE;
-                       base_dn_attrs = dnattr;
-               } else if (strncasecmp(dn, "<WKGUID=", 8) == 0) {
-                       char *tail_str;
-                       char *p;
-
-                       p = strchr(dn, ',');
-                       if (!p) {
-                               return LDB_ERR_INVALID_DN_SYNTAX;
-                       }
-
-                       p[0] = '\0';
-                       p++;
-
-                       wellknown_object = talloc_asprintf(req, "B:32:%s:", &dn[8]);
-                       if (!wellknown_object) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
-                       }
-
-                       tail_str = p;
-                       p = strchr(tail_str, '>');
-                       if (!p) {
-                               return LDB_ERR_INVALID_DN_SYNTAX;
-                       }
-                       p[0] = '\0';
-
-                       base_dn = ldb_dn_new(req, module->ldb, tail_str);
-                       if (!base_dn) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
-                       }
-                       base_dn_filter = talloc_strdup(req, "(objectClass=*)");
-                       if (!base_dn_filter) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
-                       }
-                       base_dn_scope = LDB_SCOPE_BASE;
-                       base_dn_attrs = wkattr;
-               }
-               talloc_free(dn);
-       }
-
-       /* check if there's an extended dn control */
-       control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID);
-       if (control == NULL && base_dn_filter == NULL) {
-               /* not found go on */
-               return ldb_next_request(module, req);
-       }
-
-       if (control && control->data) {
-               extended_ctrl = talloc_get_type(control->data, struct ldb_extended_dn_control);
-               if (!extended_ctrl) {
-                       return LDB_ERR_PROTOCOL_ERROR;
-               }
-       }
-
-       ac = talloc_zero(req, struct extended_context);
-       if (ac == NULL) {
-               ldb_oom(module->ldb);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ac->module = module;
-       ac->req = req;
-       ac->control = control;
-       ac->basedn = NULL;
-       ac->wellknown_object = wellknown_object;
-       ac->inject = false;
-       ac->remove_guid = false;
-       ac->remove_sid = false;
-
-       if (control) {
-               ac->inject = true;
-               if (extended_ctrl) {
-                       ac->extended_type = extended_ctrl->type;
-               } else {
-                       ac->extended_type = 0;
-               }
-
-               /* check if attrs only is specified, in that case check wether we need to modify them */
-               if (req->op.search.attrs) {
-                       if (! is_attr_in_list(req->op.search.attrs, "objectGUID")) {
-                               ac->remove_guid = true;
-                       }
-                       if (! is_attr_in_list(req->op.search.attrs, "objectSID")) {
-                               ac->remove_sid = true;
-                       }
-                       if (ac->remove_guid || ac->remove_sid) {
-                               new_attrs = copy_attrs(ac, req->op.search.attrs);
-                               if (new_attrs == NULL) {
-                                       ldb_oom(module->ldb);
-                                       return LDB_ERR_OPERATIONS_ERROR;
-                               }
-
-                               if (ac->remove_guid) {
-                                       if (!add_attrs(ac, &new_attrs, "objectGUID"))
-                                               return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                               if (ac->remove_sid) {
-                                       if (!add_attrs(ac, &new_attrs, "objectSID"))
-                                               return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                               ac->cast_attrs = (const char * const *)new_attrs;
-                       } else {
-                               ac->cast_attrs = req->op.search.attrs;
-                       }
-               }
-       }
-
-       if (base_dn) {
-               ret = ldb_build_search_req(&down_req,
-                                          module->ldb, ac,
-                                          base_dn,
-                                          base_dn_scope,
-                                          base_dn_filter,
-                                          base_dn_attrs,
-                                          NULL,
-                                          ac, extended_base_callback,
-                                          req);
-               if (ret != LDB_SUCCESS) {
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-
-               /* perform the search */
-               return ldb_next_request(module, down_req);
-       }
-
-       ret = ldb_build_search_req_ex(&down_req,
-                                       module->ldb, ac,
-                                       req->op.search.base,
-                                       req->op.search.scope,
-                                       req->op.search.tree,
-                                       ac->cast_attrs,
-                                       req->controls,
-                                       ac, extended_callback,
-                                       req);
-       if (ret != LDB_SUCCESS) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (ac->control) {
-               /* save it locally and remove it from the list */
-               /* we do not need to replace them later as we
-                * are keeping the original req intact */
-               if (!save_controls(control, down_req, &saved_controls)) {
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-       }
-
-       /* perform the search */
-       return ldb_next_request(module, down_req);
-}
-
-static int extended_init(struct ldb_module *module)
-{
-       int ret;
-
-       ret = ldb_mod_register_control(module, LDB_CONTROL_EXTENDED_DN_OID);
-       if (ret != LDB_SUCCESS) {
-               ldb_debug(module->ldb, LDB_DEBUG_ERROR,
-                       "extended_dn: Unable to register control with rootdse!\n");
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       return ldb_next_init(module);
-}
-
-_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_module_ops = {
-       .name              = "extended_dn",
-       .search            = extended_search,
-       .init_context      = extended_init
-};
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c
new file mode 100644 (file)
index 0000000..f21c171
--- /dev/null
@@ -0,0 +1,394 @@
+/* 
+   ldb database library
+
+   Copyright (C) Simo Sorce 2005-2008
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
+
+   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 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 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/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb extended dn control module
+ *
+ *  Description: this module interprets DNs of the form <SID=S-1-2-4456> into normal DNs.
+ *
+ *  Authors: Simo Sorce
+ *           Andrew Bartlett
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+
+/* search */
+struct extended_search_context {
+       struct ldb_module *module;
+       struct ldb_request *req;
+       struct ldb_dn *basedn;
+       char *wellknown_object;
+       int extended_type;
+};
+
+/* An extra layer of indirection because LDB does not allow the original request to be altered */
+
+static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       int ret = LDB_ERR_OPERATIONS_ERROR;
+       struct extended_search_context *ac;
+       ac = talloc_get_type(req->context, struct extended_search_context);
+
+       if (ares->error != LDB_SUCCESS) {
+               ret = ldb_module_done(ac->req, ares->controls,
+                                     ares->response, ares->error);
+       } else {
+               switch (ares->type) {
+               case LDB_REPLY_ENTRY:
+                       
+                       ret = ldb_module_send_entry(ac->req, ares->message);
+                       break;
+               case LDB_REPLY_REFERRAL:
+                       
+                       ret = ldb_module_send_referral(ac->req, ares->referral);
+                       break;
+               case LDB_REPLY_DONE:
+                       
+                       ret = ldb_module_done(ac->req, ares->controls,
+                                             ares->response, ares->error);
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       struct extended_search_context *ac;
+       struct ldb_request *down_req;
+       struct ldb_message_element *el;
+       int ret;
+       size_t i;
+       size_t wkn_len = 0;
+       char *valstr = NULL;
+       const char *found = NULL;
+
+       ac = talloc_get_type(req->context, struct extended_search_context);
+
+       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);
+       }
+
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
+               if (!ac->wellknown_object) {
+                       ac->basedn = talloc_steal(ac, ares->message->dn);
+                       break;
+               }
+
+               wkn_len = strlen(ac->wellknown_object);
+
+               el = ldb_msg_find_element(ares->message, "wellKnownObjects");
+               if (!el) {
+                       ac->basedn = NULL;
+                       break;
+               }
+
+               for (i=0; i < el->num_values; i++) {
+                       valstr = talloc_strndup(ac,
+                                               (const char *)el->values[i].data,
+                                               el->values[i].length);
+                       if (!valstr) {
+                               ldb_oom(ac->module->ldb);
+                               return ldb_module_done(ac->req, NULL, NULL,
+                                                      LDB_ERR_OPERATIONS_ERROR);
+                       }
+
+                       if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
+                               talloc_free(valstr);
+                               continue;
+                       }
+
+                       found = &valstr[wkn_len];
+                       break;
+               }
+
+               if (!found) {
+                       break;
+               }
+
+               ac->basedn = ldb_dn_new(ac, ac->module->ldb, found);
+               talloc_free(valstr);
+               if (!ac->basedn) {
+                       ldb_oom(ac->module->ldb);
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                              LDB_ERR_OPERATIONS_ERROR);
+               }
+
+               break;
+
+       case LDB_REPLY_REFERRAL:
+               break;
+
+       case LDB_REPLY_DONE:
+
+               if (!ac->basedn) {
+                       const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
+                                                         ldb_dn_get_linearized(ac->req->op.search.base));
+                       ldb_set_errstring(ac->module->ldb, str);
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                              LDB_ERR_NO_SUCH_OBJECT);
+               }
+
+               switch (ac->req->operation) {
+               case LDB_SEARCH:
+                       ret = ldb_build_search_req_ex(&down_req,
+                                                     ac->module->ldb, ac->req,
+                                                     ac->basedn,
+                                                     ac->req->op.search.scope,
+                                                     ac->req->op.search.tree,
+                                                     ac->req->op.search.attrs,
+                                                     ac->req->controls,
+                                                     ac, extended_final_callback, 
+                                                     ac->req);
+                       break;
+               case LDB_ADD:
+               {
+                       struct ldb_message *add_msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
+                       if (!add_msg) {
+                               ldb_oom(ac->module->ldb);
+                               return ldb_module_done(ac->req, NULL, NULL,
+                                                      LDB_ERR_OPERATIONS_ERROR);
+                       }
+                       
+                       add_msg->dn = ac->basedn;
+
+                       ret = ldb_build_add_req(&down_req,
+                                               ac->module->ldb, ac->req,
+                                               add_msg, 
+                                               ac->req->controls,
+                                               ac, extended_final_callback, 
+                                               ac->req);
+                       break;
+               }
+               case LDB_MODIFY:
+               {
+                       struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
+                       if (!mod_msg) {
+                               ldb_oom(ac->module->ldb);
+                               return ldb_module_done(ac->req, NULL, NULL,
+                                                      LDB_ERR_OPERATIONS_ERROR);
+                       }
+                       
+                       mod_msg->dn = ac->basedn;
+
+                       ret = ldb_build_mod_req(&down_req,
+                                               ac->module->ldb, ac->req,
+                                               mod_msg, 
+                                               ac->req->controls,
+                                               ac, extended_final_callback, 
+                                               ac->req);
+                       break;
+               }
+               case LDB_DELETE:
+                       ret = ldb_build_del_req(&down_req,
+                                               ac->module->ldb, ac->req,
+                                               ac->basedn, 
+                                               ac->req->controls,
+                                               ac, extended_final_callback, 
+                                               ac->req);
+                       break;
+               case LDB_RENAME:
+                       ret = ldb_build_rename_req(&down_req,
+                                                  ac->module->ldb, ac->req,
+                                                  ac->basedn, 
+                                                  ac->req->op.rename.newdn,
+                                                  ac->req->controls,
+                                                  ac, extended_final_callback, 
+                                                  ac->req);
+                       break;
+               default:
+                       return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+               }
+               
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
+               }
+
+               return ldb_next_request(ac->module, down_req);
+       }
+       talloc_free(ares);
+       return LDB_SUCCESS;
+}
+
+static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
+{
+       struct extended_search_context *ac;
+       struct ldb_request *down_req;
+       int ret;
+       struct ldb_dn *base_dn = NULL;
+       enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
+       const char *base_dn_filter = NULL;
+       const char * const *base_dn_attrs = NULL;
+       char *wellknown_object = NULL;
+       static const char *no_attr[] = {
+               NULL
+       };
+       static const char *wkattr[] = {
+               "wellKnownObjects",
+               NULL
+       };
+
+       if (!ldb_dn_has_extended(dn)) {
+               /* Move along there isn't anything to see here */
+               return ldb_next_request(module, req);
+       } else {
+               /* It looks like we need to map the DN */
+               const struct ldb_val *sid_val, *guid_val, *wkguid_val;
+
+               sid_val = ldb_dn_get_extended_component(dn, "SID");
+               guid_val = ldb_dn_get_extended_component(dn, "GUID");
+               wkguid_val = ldb_dn_get_extended_component(dn, "WKGUID");
+
+               if (sid_val) {
+                       /* TODO: do a search over all partitions */
+                       base_dn = ldb_get_default_basedn(module->ldb);
+                       base_dn_filter = talloc_asprintf(req, "(objectSid=%s)", 
+                                                        ldb_binary_encode(req, *sid_val));
+                       if (!base_dn_filter) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                       base_dn_scope = LDB_SCOPE_SUBTREE;
+                       base_dn_attrs = no_attr;
+
+               } else if (guid_val) {
+
+                       /* TODO: do a search over all partitions */
+                       base_dn = ldb_get_default_basedn(module->ldb);
+                       base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)", 
+                                                        ldb_binary_encode(req, *guid_val));
+                       if (!base_dn_filter) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                       base_dn_scope = LDB_SCOPE_SUBTREE;
+                       base_dn_attrs = no_attr;
+
+
+               } else if (wkguid_val) {
+                       char *wkguid_dup;
+                       char *tail_str;
+                       char *p;
+
+                       wkguid_dup = talloc_strndup(req, (char *)wkguid_val->data, wkguid_val->length);
+
+                       p = strchr(wkguid_dup, ',');
+                       if (!p) {
+                               return LDB_ERR_INVALID_DN_SYNTAX;
+                       }
+
+                       p[0] = '\0';
+                       p++;
+
+                       wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
+                       if (!wellknown_object) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+
+                       tail_str = p;
+
+                       base_dn = ldb_dn_new(req, module->ldb, tail_str);
+                       talloc_free(wkguid_dup);
+                       if (!base_dn) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                       base_dn_filter = talloc_strdup(req, "(objectClass=*)");
+                       if (!base_dn_filter) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                       base_dn_scope = LDB_SCOPE_BASE;
+                       base_dn_attrs = wkattr;
+               } else {
+                       return LDB_ERR_INVALID_DN_SYNTAX;
+               }
+
+               ac = talloc_zero(req, struct extended_search_context);
+               if (ac == NULL) {
+                       ldb_oom(module->ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               
+               ac->module = module;
+               ac->req = req;
+               ac->basedn = NULL;  /* Filled in if the search finds the DN by SID/GUID etc */
+               ac->wellknown_object = wellknown_object;
+               
+               /* If the base DN was an extended DN (perhaps a well known
+                * GUID) then search for that, so we can proceed with the original operation */
+
+               ret = ldb_build_search_req(&down_req,
+                                          module->ldb, ac,
+                                          base_dn,
+                                          base_dn_scope,
+                                          base_dn_filter,
+                                          base_dn_attrs,
+                                          NULL,
+                                          ac, extended_base_callback,
+                                          req);
+               if (ret != LDB_SUCCESS) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               /* perform the search */
+               return ldb_next_request(module, down_req);
+       }
+}
+
+static int extended_dn_in_search(struct ldb_module *module, struct ldb_request *req)
+{
+       return extended_dn_in_fix(module, req, req->op.search.base);
+}
+
+static int extended_dn_in_modify(struct ldb_module *module, struct ldb_request *req)
+{
+       return extended_dn_in_fix(module, req, req->op.mod.message->dn);
+}
+
+static int extended_dn_in_del(struct ldb_module *module, struct ldb_request *req)
+{
+       return extended_dn_in_fix(module, req, req->op.del.dn);
+}
+
+static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *req)
+{
+       return extended_dn_in_fix(module, req, req->op.rename.olddn);
+}
+
+_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
+       .name              = "extended_dn_in",
+       .search            = extended_dn_in_search,
+       .modify            = extended_dn_in_modify,
+       .del               = extended_dn_in_del,
+       .rename            = extended_dn_in_rename,
+};
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_out.c b/source4/dsdb/samdb/ldb_modules/extended_dn_out.c
new file mode 100644 (file)
index 0000000..0333b82
--- /dev/null
@@ -0,0 +1,582 @@
+/* 
+   ldb database library
+
+   Copyright (C) Simo Sorce 2005-2008
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
+
+   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 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 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/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb extended dn control module
+ *
+ *  Description: this module builds a special dn for returned search
+ *  results 
+ *  values.
+ *
+ *  Authors: Simo Sorce
+ *           Andrew Bartlett
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/ndr/libndr.h"
+#include "dsdb/samdb/samdb.h"
+
+struct extended_dn_out_private {
+       bool dereference;
+       struct dsdb_openldap_dereference_control *dereference_control;
+};
+
+static bool is_attr_in_list(const char * const * attrs, const char *attr)
+{
+       int i;
+
+       for (i = 0; attrs[i]; i++) {
+               if (strcasecmp(attrs[i], attr) == 0)
+                       return true;
+       }
+
+       return false;
+}
+
+static char **copy_attrs(void *mem_ctx, const char * const * attrs)
+{
+       char **new;
+       int i, num;
+
+       for (num = 0; attrs[num]; num++);
+
+       new = talloc_array(mem_ctx, char *, num + 1);
+       if (!new) return NULL;
+
+       for(i = 0; i < num; i++) {
+               new[i] = talloc_strdup(new, attrs[i]);
+               if (!new[i]) {
+                       talloc_free(new);
+                       return NULL;
+               }
+       }
+       new[i] = NULL;
+
+       return new;
+}
+
+static bool add_attrs(void *mem_ctx, char ***attrs, const char *attr)
+{
+       char **new;
+       int num;
+
+       for (num = 0; (*attrs)[num]; num++);
+
+       new = talloc_realloc(mem_ctx, *attrs, char *, num + 2);
+       if (!new) return false;
+
+       *attrs = new;
+
+       new[num] = talloc_strdup(new, attr);
+       if (!new[num]) return false;
+
+       new[num + 1] = NULL;
+
+       return true;
+}
+
+static int inject_extended_dn_out(struct ldb_reply *ares,
+                             struct ldb_context *ldb,
+                             int type,
+                             bool remove_guid,
+                             bool remove_sid)
+{
+       int ret;
+       const struct ldb_val *val;
+       const DATA_BLOB *guid_blob;
+       const DATA_BLOB *sid_blob;
+
+       guid_blob = ldb_msg_find_ldb_val(ares->message, "objectGUID");
+       sid_blob = ldb_msg_find_ldb_val(ares->message, "objectSID");
+
+       if (!guid_blob) {
+               ldb_set_errstring(ldb, "Did not find objectGUID to inject into extended DN");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = ldb_dn_set_extended_component(ares->message->dn, "GUID", guid_blob);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       if (sid_blob) {
+               ret = ldb_dn_set_extended_component(ares->message->dn, "SID", sid_blob);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       if (remove_guid) {
+               ldb_msg_remove_attr(ares->message, "objectGUID");
+       }
+
+       if (sid_blob && remove_sid) {
+               ldb_msg_remove_attr(ares->message, "objectSID");
+       }
+
+       val = ldb_msg_find_ldb_val(ares->message, "distinguishedName");
+       if (val) {
+               ldb_msg_remove_attr(ares->message, "distinguishedName");
+               ret = ldb_msg_add_steal_string(ares->message, "distinguishedName", 
+                                              ldb_dn_extended_linearized(ares->message, ares->message->dn, type));
+               if (ret != LDB_SUCCESS) {
+                       ldb_oom(ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+       }
+       return LDB_SUCCESS;
+}
+
+static int handle_dereference(struct ldb_dn *dn,
+                             struct dsdb_openldap_dereference_result **dereference_attrs, 
+                             const char *attr, DATA_BLOB *val)
+{
+       const struct ldb_val *entryUUIDblob, *sid_blob;
+       struct ldb_message fake_msg; /* easier to use routines that expect an ldb_message */
+       int j;
+       
+       fake_msg.num_elements = 0;
+                       
+       /* Look for this attribute in the returned control */
+       for (j = 0; dereference_attrs && dereference_attrs[j]; j++) {
+               DATA_BLOB source_dn = data_blob_string_const(dereference_attrs[j]->dereferenced_dn);
+               if (ldb_attr_cmp(dereference_attrs[j]->source_attribute, attr)
+                   && data_blob_cmp(&source_dn, val) == 0) {
+                       
+                       fake_msg.num_elements = dereference_attrs[j]->num_attributes;
+                       fake_msg.elements = dereference_attrs[j]->attributes;
+                       break;
+               }
+       }
+       if (!fake_msg.num_elements) {
+               return LDB_SUCCESS;
+       }
+       /* Look for an OpenLDAP entryUUID */
+       
+       entryUUIDblob = ldb_msg_find_ldb_val(&fake_msg, "entryUUID");
+       if (entryUUIDblob) {
+               NTSTATUS status;
+               enum ndr_err_code ndr_err;
+               
+               struct ldb_val guid_blob;
+               struct GUID guid;
+               
+               status = GUID_from_data_blob(entryUUIDblob, &guid);
+               
+               if (!NT_STATUS_IS_OK(status)) {
+                       return LDB_ERR_INVALID_DN_SYNTAX;
+               }
+               ndr_err = ndr_push_struct_blob(&guid_blob, NULL, NULL, &guid,
+                                              (ndr_push_flags_fn_t)ndr_push_GUID);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return LDB_ERR_INVALID_DN_SYNTAX;
+               }
+               
+               ldb_dn_set_extended_component(dn, "GUID", &guid_blob);
+       }
+       
+       sid_blob = ldb_msg_find_ldb_val(&fake_msg, "objectSID");
+       
+       /* Look for the objectSID */
+       if (sid_blob) {
+               ldb_dn_set_extended_component(dn, "SID", sid_blob);
+       }
+       return LDB_SUCCESS;
+}
+
+/* search */
+struct extended_search_context {
+       struct ldb_module *module;
+       const struct dsdb_schema *schema;
+       struct ldb_request *req;
+       struct ldb_control *control;
+       bool inject;
+       bool remove_guid;
+       bool remove_sid;
+       int extended_type;
+};
+
+static int extended_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       struct extended_search_context *ac;
+       struct ldb_control *control;
+       struct dsdb_openldap_dereference_result_control *dereference_control = NULL;
+       int ret, i, j;
+       struct ldb_message *msg = ares->message;
+       struct extended_dn_out_private *private;
+
+       ac = talloc_get_type(req->context, struct extended_search_context);
+       private = talloc_get_type(ac->module->private_data, struct extended_dn_out_private);
+
+       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);
+       }
+
+       switch (ares->type) {
+       case LDB_REPLY_REFERRAL:
+               return ldb_module_send_referral(ac->req, ares->referral);
+
+       case LDB_REPLY_DONE:
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, LDB_SUCCESS);
+       case LDB_REPLY_ENTRY:
+               break;
+       }
+
+       if (ac->inject) {
+               /* for each record returned post-process to add any derived
+                  attributes that have been asked for */
+               ret = inject_extended_dn_out(ares, ac->module->ldb,
+                                            ac->extended_type, ac->remove_guid,
+                                            ac->remove_sid);
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
+               }
+       }
+
+       control = ldb_reply_get_control(ares, DSDB_OPENLDAP_DEREFERENCE_CONTROL);
+
+       if (private->dereference && control && control->data) {
+              dereference_control = talloc_get_type(control->data, struct dsdb_openldap_dereference_result_control);
+       }
+       for (i = 0; i < msg->num_elements; i++) {
+               const struct dsdb_attribute *attribute;
+               if (ldb_attr_cmp(msg->elements[i].name, "distinguishedName") == 0) {
+                       continue;
+               }
+               attribute = dsdb_attribute_by_lDAPDisplayName(ac->schema, msg->elements[i].name);
+               if (!attribute) {
+                       continue;
+               }
+               /* Look to see if this attributeSyntax is a DN */
+               if (strcmp(attribute->attributeSyntax_oid, "2.5.5.1") != 0) {
+                       continue;
+               }
+
+               for (j = 0; j < msg->elements[i].num_values; j++) {
+                       const char *dn_str;
+                       struct ldb_dn *dn = ldb_dn_from_ldb_val(ac, ac->module->ldb, &msg->elements[i].values[j]);
+                       if (!dn || !ldb_dn_validate(dn)) {
+                               return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_INVALID_DN_SYNTAX);
+                       }
+
+                       /* If we are running in dereference mode (such
+                        * as against OpenLDAP) then the DN in the msg
+                        * above does not contain the extended values,
+                        * and we need to look in the dereference
+                        * result */
+
+                       /* Look for this value in the attribute */
+
+                       if (dereference_control) {
+                               ret = handle_dereference(dn, 
+                                                        dereference_control->attributes,
+                                                        msg->elements[i].name,
+                                                        &msg->elements[i].values[j]);
+                               if (ret != LDB_SUCCESS) {
+                                       
+                                       return ldb_module_done(ac->req, NULL, NULL, ret);
+                               }
+                       }
+
+                       if (!ac->inject) {
+                               dn_str = talloc_steal(msg->elements[i].values, 
+                                                     ldb_dn_get_linearized(dn));
+                       } else {
+                               dn_str = talloc_steal(msg->elements[i].values, 
+                                                     ldb_dn_extended_linearized(msg->elements[i].values, 
+                                                                                dn, ac->extended_type));
+                       }
+                       msg->elements[i].values[j] = data_blob_string_const(dn_str);
+                       talloc_free(dn);
+               }
+       }
+       return ldb_module_send_entry(ac->req, msg);
+}
+
+
+static int extended_dn_out_search(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_control *control;
+       struct ldb_control *storage_format_control;
+       struct ldb_extended_dn_control *extended_ctrl = NULL;
+       struct ldb_control **saved_controls;
+       struct extended_search_context *ac;
+       struct ldb_request *down_req;
+       char **new_attrs;
+       const char * const *const_attrs;
+       int ret;
+
+       struct extended_dn_out_private *private = talloc_get_type(module->private_data, struct extended_dn_out_private);
+
+       /* check if there's an extended dn control */
+       control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID);
+       if (control && control->data) {
+               extended_ctrl = talloc_get_type(control->data, struct ldb_extended_dn_control);
+               if (!extended_ctrl) {
+                       return LDB_ERR_PROTOCOL_ERROR;
+               }
+       }
+
+       /* If we have not been asked for the extended DN, and we are
+        * in dereference mode, then the normal action is to ignore
+        * this module */
+       if (!private || (!control && private->dereference)) {
+               return ldb_next_request(module, req);
+       }
+
+       /* Look to see if, as we are in 'store DN+GUID+SID' mode, the
+        * client is after the storage format (to fill in linked
+        * attributes) */
+       storage_format_control = ldb_request_get_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID);
+       if (!control && storage_format_control && storage_format_control->data) {
+               extended_ctrl = talloc_get_type(storage_format_control->data, struct ldb_extended_dn_control);
+               if (!extended_ctrl) {
+                       ldb_set_errstring(module->ldb, "extended_dn_out: extended_ctrl was of the wrong data type");
+                       return LDB_ERR_PROTOCOL_ERROR;
+               }
+       }
+
+       ac = talloc_zero(req, struct extended_search_context);
+       if (ac == NULL) {
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ac->module = module;
+       ac->schema = dsdb_get_schema(module->ldb);
+       ac->req = req;
+       ac->control = control;
+       ac->inject = false;
+       ac->remove_guid = false;
+       ac->remove_sid = false;
+       
+       const_attrs = req->op.search.attrs;
+
+       if (!ac->schema) {
+               /* no schema yet? go on */
+               talloc_free(ac);
+               return ldb_next_request(module, req);
+       }
+
+       if (control || storage_format_control) {
+               ac->inject = true;
+               if (extended_ctrl) {
+                       ac->extended_type = extended_ctrl->type;
+               } else {
+                       ac->extended_type = 0;
+               }
+
+               /* check if attrs only is specified, in that case check wether we need to modify them */
+               if (req->op.search.attrs) {
+                       if (! is_attr_in_list(req->op.search.attrs, "objectGUID")) {
+                               ac->remove_guid = true;
+                       }
+                       if (! is_attr_in_list(req->op.search.attrs, "objectSID")) {
+                               ac->remove_sid = true;
+                       }
+                       if (ac->remove_guid || ac->remove_sid) {
+                               new_attrs = copy_attrs(ac, req->op.search.attrs);
+                               if (new_attrs == NULL) {
+                                       ldb_oom(module->ldb);
+                                       return LDB_ERR_OPERATIONS_ERROR;
+                               }
+
+                               if (ac->remove_guid) {
+                                       if (!add_attrs(ac, &new_attrs, "objectGUID"))
+                                               return LDB_ERR_OPERATIONS_ERROR;
+                               }
+                               if (ac->remove_sid) {
+                                       if (!add_attrs(ac, &new_attrs, "objectSID"))
+                                               return LDB_ERR_OPERATIONS_ERROR;
+                               }
+                               const_attrs = (const char * const *)new_attrs;
+                       }
+               }
+       }
+
+       ret = ldb_build_search_req_ex(&down_req,
+                                     module->ldb, ac,
+                                     req->op.search.base,
+                                     req->op.search.scope,
+                                     req->op.search.tree,
+                                     const_attrs,
+                                     req->controls,
+                                     ac, extended_callback,
+                                     req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* Remove extended DN and storage format controls */
+
+       if (control) {
+               /* save it locally and remove it from the list */
+               /* we do not need to replace them later as we
+                * are keeping the original req intact */
+               if (!save_controls(control, down_req, &saved_controls)) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+       }
+
+       if (storage_format_control) {
+               /* save it locally and remove it from the list */
+               /* we do not need to replace them later as we
+                * are keeping the original req intact */
+               if (!save_controls(storage_format_control, down_req, &saved_controls)) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+       }
+
+       if (private->dereference) {
+
+               /* Add in dereference control */
+               ret = ldb_request_add_control(down_req,
+                                             DSDB_OPENLDAP_DEREFERENCE_CONTROL,
+                                             false, private->dereference_control);
+       }
+
+       /* perform the search */
+       return ldb_next_request(module, down_req);
+}
+
+static int extended_dn_out_ldb_init(struct ldb_module *module)
+{
+       int ret;
+
+       struct extended_dn_out_private *private = talloc(module, struct extended_dn_out_private);
+
+       module->private_data = private;
+
+       if (!private) {
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       private->dereference = false;
+
+       ret = ldb_mod_register_control(module, LDB_CONTROL_EXTENDED_DN_OID);
+       if (ret != LDB_SUCCESS) {
+               ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+                       "extended_dn_out: Unable to register control with rootdse!\n");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       return ldb_next_init(module);
+}
+
+static int extended_dn_out_dereference_init(struct ldb_module *module)
+{
+       int ret, i;
+       struct extended_dn_out_private *private = talloc(module, struct extended_dn_out_private);
+       struct dsdb_openldap_dereference_control *dereference_control;
+       struct dsdb_attribute *cur;
+
+       struct dsdb_schema *schema;
+
+       module->private_data = private;
+
+       if (!private) {
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       private->dereference = true;
+
+       ret = ldb_mod_register_control(module, LDB_CONTROL_EXTENDED_DN_OID);
+       if (ret != LDB_SUCCESS) {
+               ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+                       "extended_dn_out: Unable to register control with rootdse!\n");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = ldb_next_init(module);
+
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       schema = dsdb_get_schema(module->ldb);
+       if (!schema) {
+               /* No schema on this DB */
+               return LDB_SUCCESS;
+       }
+
+       private->dereference_control = dereference_control
+               = talloc(private, struct dsdb_openldap_dereference_control);
+
+       if (!private->dereference_control) {
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       for (cur = schema->attributes; cur; cur = cur->next) {
+               static const char *attrs[] = {
+                       "entryUUID",
+                       "objectSID",
+                       NULL
+               };
+
+               if (strcmp(cur->syntax->attributeSyntax_oid, "2.5.5.1") != 0) {
+                       continue;
+               }
+               dereference_control->dereference
+                       = talloc_realloc(private, dereference_control, 
+                                        struct dsdb_openldap_dereference *, i + 1);
+               if (!dereference_control) {
+                       ldb_oom(module->ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               dereference_control->dereference[i] = talloc(dereference_control->dereference,  
+                                        struct dsdb_openldap_dereference);
+               if (!dereference_control->dereference[i]) {
+                       ldb_oom(module->ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               dereference_control->dereference[i]->source_attribute = cur->lDAPDisplayName;
+               dereference_control->dereference[i]->dereference_attribute = attrs;
+               i++;
+               dereference_control->dereference[i] = NULL;
+       }
+       return LDB_SUCCESS;
+}
+
+_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_out_ldb_module_ops = {
+       .name              = "extended_dn_out_ldb",
+       .search            = extended_dn_out_search,
+       .init_context      = extended_dn_out_ldb_init,
+};
+
+
+_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_out_dereference_module_ops = {
+       .name              = "extended_dn_out_dereference",
+       .search            = extended_dn_out_search,
+       .init_context      = extended_dn_out_dereference_init,
+};
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_out_dereference.c b/source4/dsdb/samdb/ldb_modules/extended_dn_out_dereference.c
new file mode 100644 (file)
index 0000000..60058a4
--- /dev/null
@@ -0,0 +1,19 @@
+static int extended_dn_out_dereference_init(struct ldb_module *module)
+{
+       int ret;
+
+       ret = ldb_mod_register_control(module, LDB_CONTROL_EXTENDED_DN_OID);
+       if (ret != LDB_SUCCESS) {
+               ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+                       "extended_dn_out: Unable to register control with rootdse!\n");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       return ldb_next_init(module);
+}
+
+_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_out_dereference_module_ops = {
+       .name              = "extended_dn_out_ldb",
+       .search            = extended_dn_out_search,
+       .init_context      = extended_dn_out_ldb_init,
+};
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_out_ldb.c b/source4/dsdb/samdb/ldb_modules/extended_dn_out_ldb.c
new file mode 100644 (file)
index 0000000..5570923
--- /dev/null
@@ -0,0 +1,20 @@
+static int extended_dn_out_ldb_init(struct ldb_module *module)
+{
+       int ret;
+
+       ret = ldb_mod_register_control(module, LDB_CONTROL_EXTENDED_DN_OID);
+       if (ret != LDB_SUCCESS) {
+               ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+                       "extended_dn_out: Unable to register control with rootdse!\n");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       return ldb_next_init(module);
+}
+
+_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_out_ldb_module_ops = {
+       .name              = "extended_dn_out_ldb",
+       .search            = extended_dn_out_search,
+       .init_context      = extended_dn_out_ldb_init,
+};
+
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_store.c b/source4/dsdb/samdb/ldb_modules/extended_dn_store.c
new file mode 100644 (file)
index 0000000..a49ce84
--- /dev/null
@@ -0,0 +1,429 @@
+/* 
+   ldb database library
+
+   Copyright (C) Simo Sorce 2005-2008
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2008
+
+   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 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 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/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb extended dn control module
+ *
+ *  Description: this module builds a special dn for returned search
+ *  results nad creates the special DN in the backend store for new
+ *  values.
+ *
+ *  This also has the curious result that we convert <SID=S-1-2-345>
+ *  in an attribute value into a normal DN for the rest of the stack
+ *  to process
+ *
+ *  Authors: Simo Sorce
+ *           Andrew Bartlett
+ */
+
+#include "includes.h"
+#include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
+#include "ldb/include/ldb_private.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "dsdb/samdb/samdb.h"
+#include "libcli/security/security.h"
+
+#include <time.h>
+
+struct extended_dn_replace_list {
+       struct extended_dn_replace_list *next;
+       struct ldb_dn *dn;
+       TALLOC_CTX *mem_ctx;
+       struct ldb_val *replace_dn;
+       struct extended_dn_context *ac;
+       struct ldb_request *search_req;
+};
+
+
+struct extended_dn_context {
+       const struct dsdb_schema *schema;
+       struct ldb_module *module;
+       struct ldb_request *req;
+       struct ldb_request *new_req;
+
+       struct extended_dn_replace_list *ops;
+       struct extended_dn_replace_list *cur;
+};
+
+
+static struct extended_dn_context *extended_dn_context_init(struct ldb_module *module,
+                                                           struct ldb_request *req)
+{
+       struct extended_dn_context *ac;
+
+       ac = talloc_zero(req, struct extended_dn_context);
+       if (ac == NULL) {
+               ldb_oom(module->ldb);
+               return NULL;
+       }
+
+       ac->schema = dsdb_get_schema(module->ldb);
+       ac->module = module;
+       ac->req = req;
+
+       return ac;
+}
+
+/* An extra layer of indirection because LDB does not allow the original request to be altered */
+
+static int extended_final_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       int ret = LDB_ERR_OPERATIONS_ERROR;
+       struct extended_dn_context *ac;
+       ac = talloc_get_type(req->context, struct extended_dn_context);
+
+       if (ares->error != LDB_SUCCESS) {
+               ret = ldb_module_done(ac->req, ares->controls,
+                                     ares->response, ares->error);
+       } else {
+               switch (ares->type) {
+               case LDB_REPLY_ENTRY:
+                       
+                       ret = ldb_module_send_entry(ac->req, ares->message);
+                       break;
+               case LDB_REPLY_REFERRAL:
+                       
+                       ret = ldb_module_send_referral(ac->req, ares->referral);
+                       break;
+               case LDB_REPLY_DONE:
+                       
+                       ret = ldb_module_done(ac->req, ares->controls,
+                                             ares->response, ares->error);
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int extended_replace_dn(struct ldb_request *req, struct ldb_reply *ares)
+{
+       struct extended_dn_replace_list *os = talloc_get_type(req->context, 
+                                                          struct extended_dn_replace_list);
+
+       if (!ares) {
+               return ldb_module_done(os->ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error == LDB_ERR_NO_SUCH_OBJECT) {
+               /* Don't worry too much about dangling references */
+
+               ldb_reset_err_string(os->ac->module->ldb);
+               if (os->next) {
+                       struct extended_dn_replace_list *next;
+
+                       next = os->next;
+
+                       talloc_free(os);
+
+                       os = next;
+                       return ldb_next_request(os->ac->module, next->search_req);
+               } else {
+                       /* Otherwise, we are done - let's run the
+                        * request now we have swapped the DNs for the
+                        * full versions */
+                       return ldb_next_request(os->ac->module, os->ac->req);
+               }
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(os->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:
+       {
+               /* This *must* be the right DN, as this is a base
+                * search.  We can't check, as it could be an extended
+                * DN, so a module below will resolve it */
+               struct ldb_dn *dn = ares->message->dn;
+
+               *os->replace_dn = data_blob_string_const(
+                       ldb_dn_extended_linearized(os->mem_ctx, 
+                                                  dn, 1));
+               if (os->replace_dn->data == NULL) {
+                       return ldb_module_done(os->ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
+               }
+               break;
+       }
+       case LDB_REPLY_REFERRAL:
+               /* ignore */
+               break;
+
+       case LDB_REPLY_DONE:
+
+               talloc_free(ares);
+               
+               /* Run the next search */
+
+               if (os->next) {
+                       struct extended_dn_replace_list *next;
+
+                       next = os->next;
+
+                       talloc_free(os);
+
+                       os = next;
+                       return ldb_next_request(os->ac->module, next->search_req);
+               } else {
+                       /* Otherwise, we are done - let's run the
+                        * request now we have swapped the DNs for the
+                        * full versions */
+                       return ldb_next_request(os->ac->module, os->ac->new_req);
+               }
+       }
+
+       talloc_free(ares);
+       return LDB_SUCCESS;
+}
+
+/* We have a 'normal' DN in the inbound request.  We need to find out
+ * what the GUID and SID are on the DN it points to, so we can
+ * construct an extended DN for storage.
+ *
+ * This creates a list of DNs to look up, and the plain DN to replace
+ */
+
+static int extended_store_replace(struct extended_dn_context *ac,
+                                 TALLOC_CTX *callback_mem_ctx,
+                                 struct ldb_val *plain_dn)
+{
+       int ret;
+       struct extended_dn_replace_list *os;
+       static const char *attrs[] = {
+               "objectSid",
+               "objectGUID",
+               NULL
+       };
+
+       os = talloc_zero(ac, struct extended_dn_replace_list);
+       if (!os) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       os->ac = ac;
+       
+       os->mem_ctx = callback_mem_ctx;
+
+       os->dn = ldb_dn_from_ldb_val(os, ac->module->ldb, plain_dn);
+       if (!os->dn || !ldb_dn_validate(os->dn)) {
+               talloc_free(os);
+               ldb_asprintf_errstring(ac->module->ldb, 
+                                      "could not parse %.*s as a DN", (int)plain_dn->length, plain_dn->data);
+               return LDB_ERR_INVALID_DN_SYNTAX;
+       }
+
+       os->replace_dn = plain_dn;
+
+       /* The search request here might happen to be for an
+        * 'extended' style DN, such as <GUID=abced...>.  The next
+        * module in the stack will convert this into a normal DN for
+        * processing */
+       ret = ldb_build_search_req(&os->search_req,
+                                  ac->module->ldb, os, os->dn, LDB_SCOPE_BASE, NULL, 
+                                  attrs, NULL, os, extended_replace_dn,
+                                  ac->req);
+
+       if (ret != LDB_SUCCESS) {
+               talloc_free(os);
+               return ret;
+       }
+
+       ret = ldb_request_add_control(os->search_req,
+                                     DSDB_CONTROL_DN_STORAGE_FORMAT_OID,
+                                     true, NULL);
+       if (ret != LDB_SUCCESS) {
+               talloc_free(os);
+               return ret;
+       }
+
+       if (ac->ops) {
+               ac->cur->next = os;
+       } else {
+               ac->ops = os;
+       }
+       ac->cur = os;
+
+       return LDB_SUCCESS;
+}
+
+
+/* add */
+static int extended_dn_add(struct ldb_module *module, struct ldb_request *req)
+{
+       struct extended_dn_context *ac;
+       int ret;
+       int i, j;
+
+       if (ldb_dn_is_special(req->op.add.message->dn)) {
+               /* do not manipulate our control entries */
+               return ldb_next_request(module, req);
+       }
+
+       ac = extended_dn_context_init(module, req);
+       if (!ac) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       if (!ac->schema) {
+               /* without schema, this doesn't make any sense */
+               talloc_free(ac);
+               return ldb_next_request(module, req);
+       }
+
+       for (i=0; i < req->op.add.message->num_elements; i++) {
+               const struct ldb_message_element *el = &req->op.add.message->elements[i];
+               const struct dsdb_attribute *schema_attr
+                       = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
+               if (!schema_attr) {
+                       continue;
+               }
+
+               /* We only setup an extended DN GUID on these particular DN objects */
+               if (strcmp(schema_attr->attributeSyntax_oid, "2.5.5.1") != 0) {
+                       continue;
+               }
+
+               /* Before we setup a procedure to modify the incoming message, we must copy it */
+               if (!ac->new_req) {
+                       struct ldb_message *msg = ldb_msg_copy(ac, req->op.add.message);
+                       if (!msg) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                  
+                       ret = ldb_build_add_req(&ac->new_req, module->ldb, ac, msg, req->controls, ac, extended_final_callback, req);
+                       if (ret != LDB_SUCCESS) {
+                               return ret;
+                       }
+               }
+               /* Re-calculate el */
+               el = &ac->new_req->op.add.message->elements[i];
+               for (j = 0; j < el->num_values; j++) {
+                       ret = extended_store_replace(ac, ac->new_req->op.add.message->elements, &el->values[j]);
+                       if (ret != LDB_SUCCESS) {
+                               return ret;
+                       }
+               }
+       }
+
+       /* if DNs were set continue */
+       if (ac->ops == NULL) {
+               talloc_free(ac);
+               return ldb_next_request(module, req);
+       }
+
+       /* start with the searches */
+       return ldb_next_request(module, ac->ops->search_req);
+}
+
+/* modify */
+static int extended_dn_modify(struct ldb_module *module, struct ldb_request *req)
+{
+       /* Look over list of modifications */
+       /* Find if any are for linked attributes */
+       /* Determine the effect of the modification */
+       /* Apply the modify to the linked entry */
+
+       int i, j;
+       struct extended_dn_context *ac;
+       int ret;
+
+       if (ldb_dn_is_special(req->op.mod.message->dn)) {
+               /* do not manipulate our control entries */
+               return ldb_next_request(module, req);
+       }
+
+       ac = extended_dn_context_init(module, req);
+       if (!ac) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       if (!ac->schema) {
+               /* without schema, this doesn't make any sense */
+               return ldb_next_request(module, req);
+       }
+
+       for (i=0; i < req->op.mod.message->num_elements; i++) {
+               const struct ldb_message_element *el = &req->op.mod.message->elements[i];
+               const struct dsdb_attribute *schema_attr
+                       = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
+               if (!schema_attr) {
+                       continue;
+               }
+
+               /* We only setup an extended DN GUID on these particular DN objects */
+               if (strcmp(schema_attr->attributeSyntax_oid, "2.5.5.1") != 0) {
+                       continue;
+               }
+               
+               /* Before we setup a procedure to modify the incoming message, we must copy it */
+               if (!ac->new_req) {
+                       struct ldb_message *msg = ldb_msg_copy(ac, req->op.mod.message);
+                       if (!msg) {
+                               ldb_oom(module->ldb);
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+                  
+                       ret = ldb_build_mod_req(&ac->new_req, module->ldb, ac, msg, req->controls, ac, extended_final_callback, req);
+                       if (ret != LDB_SUCCESS) {
+                               return ret;
+                       }
+               }
+               /* Re-calculate el */
+               el = &ac->new_req->op.mod.message->elements[i];
+               /* For each value being added, we need to setup the lookups to fill in the extended DN */
+               for (j = 0; j < el->num_values; j++) {
+                       struct ldb_dn *dn = ldb_dn_from_ldb_val(ac, module->ldb, &el->values[j]);
+                       if (!dn || !ldb_dn_validate(dn)) {
+                               ldb_asprintf_errstring(module->ldb, 
+                                                      "could not parse attribute %s as a DN", el->name);
+                               return LDB_ERR_INVALID_DN_SYNTAX;
+                       }
+                       if (((el->flags & LDB_FLAG_MOD_MASK) == LDB_FLAG_MOD_DELETE) && !ldb_dn_has_extended(dn)) {
+                               /* NO need to figure this DN out, it's going to be deleted anyway */
+                               continue;
+                       }
+                       ret = extended_store_replace(ac, req->op.mod.message->elements, &el->values[j]);
+                       if (ret != LDB_SUCCESS) {
+                               return ret;
+                       }
+               }
+       }
+
+       /* if DNs were set continue */
+       if (ac->ops == NULL) {
+               talloc_free(ac);
+               return ldb_next_request(module, req);
+       }
+
+       /* start with the searches */
+       return ldb_next_request(module, ac->ops->search_req);
+}
+
+_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_store_module_ops = {
+       .name              = "extended_dn_store",
+       .add               = extended_dn_add,
+       .modify            = extended_dn_modify,
+};
index f16eb215a6426c500c3a4222df7eaf4bf4cac0a8..49e91cbf6b21b2ce21564ba05416d0b928984b99 100644 (file)
 #include "ldb/include/ldb.h"
 #include "ldb/include/ldb_errors.h"
 #include "ldb/include/ldb_private.h"
+#include "ldb/include/dlinklist.h"
 #include "dsdb/samdb/samdb.h"
 
 struct la_op_store {
        struct la_op_store *next;
+       struct la_op_store *prev;
        enum la_op {LA_OP_ADD, LA_OP_DEL} op;
        struct ldb_dn *dn;
        char *name;
@@ -52,10 +54,12 @@ struct la_context {
        const struct dsdb_schema *schema;
        struct ldb_module *module;
        struct ldb_request *req;
-
+       struct ldb_dn *add_dn;
+       struct ldb_dn *del_dn;
        struct replace_context *rc;
        struct la_op_store *ops;
-       struct la_op_store *cur;
+       struct ldb_extended *op_response;
+       struct ldb_control **op_controls;
 };
 
 static struct la_context *linked_attributes_init(struct ldb_module *module,
@@ -65,7 +69,7 @@ static struct la_context *linked_attributes_init(struct ldb_module *module,
 
        ac = talloc_zero(req, struct la_context);
        if (ac == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
+               ldb_oom(module->ldb);
                return NULL;
        }
 
@@ -80,9 +84,9 @@ static struct la_context *linked_attributes_init(struct ldb_module *module,
  * series of modify requests */
 static int la_store_op(struct la_context *ac,
                       enum la_op op, struct ldb_val *dn,
-                       const char *name, const char *value)
+                       const char *name)
 {
-       struct la_op_store *os, *tmp;
+       struct la_op_store *os;
        struct ldb_dn *op_dn;
 
        op_dn = ldb_dn_from_ldb_val(ac, ac->module->ldb, dn);
@@ -92,68 +96,30 @@ static int la_store_op(struct la_context *ac,
                return LDB_ERR_INVALID_DN_SYNTAX;
        }
 
-       /* optimize out del - add operations that would end up
-        * with no changes */
-       if (ac->ops && op == LA_OP_DEL) {
-               /* do a linear search to find out if there is
-                * an equivalent add */
-               os = ac->ops;
-               while (os->next) {
-
-                       tmp = os->next;
-                       if (tmp->op == LA_OP_ADD) {
-
-                               if ((strcmp(name, tmp->name) == 0) &&
-                                   (strcmp(value, tmp->value) == 0) &&
-                                   (ldb_dn_compare(op_dn, tmp->dn) == 0)) {
-
-                                       break;
-                               }
-                       }
-                       os = os->next;
-               }
-               if (os->next) {
-                       /* pair found, remove it and return */
-                       os->next = tmp->next;
-                       talloc_free(tmp);
-                       talloc_free(op_dn);
-                       return LDB_SUCCESS;
-               }
-       }
-
        os = talloc_zero(ac, struct la_op_store);
        if (!os) {
+               ldb_oom(ac->module->ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
        os->op = op;
 
        os->dn = talloc_steal(os, op_dn);
-       if (!os->dn) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
 
        os->name = talloc_strdup(os, name);
        if (!os->name) {
+               ldb_oom(ac->module->ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       if ((op != LA_OP_DEL) && (value == NULL)) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       if (value) {
-               os->value = talloc_strdup(os, value);
-               if (!os->value) {
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-       }
-
-       if (ac->ops) {
-               ac->cur->next = os;
+       /* Do deletes before adds */
+       if (op == LA_OP_ADD) {
+               DLIST_ADD_END(ac->ops, os, struct la_op_store *);
        } else {
-               ac->ops = os;
+               /* By adding to the head of the list, we do deletes before
+                * adds when processing a replace */
+               DLIST_ADD(ac->ops, os);
        }
-       ac->cur = os;
 
        return LDB_SUCCESS;
 }
@@ -164,8 +130,6 @@ static int la_do_mod_request(struct la_context *ac);
 static int la_mod_callback(struct ldb_request *req,
                           struct ldb_reply *ares);
 static int la_down_req(struct la_context *ac);
-static int la_down_callback(struct ldb_request *req,
-                           struct ldb_reply *ares);
 
 
 
@@ -175,7 +139,6 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
        const struct dsdb_attribute *target_attr;
        struct la_context *ac;
        const char *attr_name;
-       const char *attr_val;
        int ret;
        int i, j;
 
@@ -231,12 +194,11 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
                }
 
                attr_name = target_attr->lDAPDisplayName;
-               attr_val = ldb_dn_get_linearized(ac->req->op.add.message->dn);
 
                for (j = 0; j < el->num_values; j++) {
                        ret = la_store_op(ac, LA_OP_ADD,
                                          &el->values[j],
-                                         attr_name, attr_val);
+                                         attr_name);
                        if (ret != LDB_SUCCESS) {
                                return ret;
                        }
@@ -245,6 +207,7 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
 
        /* if no linked attributes are present continue */
        if (ac->ops == NULL) {
+               /* nothing to do for this module, proceed */
                talloc_free(ac);
                return ldb_next_request(module, req);
        }
@@ -265,7 +228,6 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are
        struct replace_context *rc;
        struct la_context *ac;
        const char *attr_name;
-       const char *dn;
        int i, j;
        int ret = LDB_SUCCESS;
 
@@ -286,16 +248,18 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are
        case LDB_REPLY_ENTRY:
 
                if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
+                       ldb_asprintf_errstring(ac->module->ldb, 
+                                              "linked_attributes: %s is not the DN we were looking for", ldb_dn_get_linearized(ares->message->dn));
                        /* Guh?  We only asked for this DN */
-                       ldb_oom(ac->module->ldb);
                        talloc_free(ares);
                        return ldb_module_done(ac->req, NULL, NULL,
                                                LDB_ERR_OPERATIONS_ERROR);
                }
 
-               dn = ldb_dn_get_linearized(ac->req->op.add.message->dn);
+               ac->add_dn = ac->del_dn = talloc_steal(ac, ares->message->dn);
 
-               for (i = 0; i < rc->num_elements; i++) {
+               /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */
+               for (i = 0; rc && i < rc->num_elements; i++) {
 
                        schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
                        if (!schema_attr) {
@@ -330,11 +294,11 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are
                        }
                        attr_name = target_attr->lDAPDisplayName;
 
-                       /* make sure we manage each value */
+                       /* Now we know what was there, we can remove it for the re-add */
                        for (j = 0; j < search_el->num_values; j++) {
                                ret = la_store_op(ac, LA_OP_DEL,
                                                  &search_el->values[j],
-                                                 attr_name, dn);
+                                                 attr_name);
                                if (ret != LDB_SUCCESS) {
                                        talloc_free(ares);
                                        return ldb_module_done(ac->req,
@@ -353,10 +317,20 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are
 
                talloc_free(ares);
 
-               /* Start with the original request */
-               ret = la_down_req(ac);
-               if (ret != LDB_SUCCESS) {
-                       return ldb_module_done(ac->req, NULL, NULL, ret);
+               if (ac->req->operation == LDB_ADD) {
+                       /* Start the modifies to the backlinks */
+                       ret = la_do_mod_request(ac);
+
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ac->req, NULL, NULL,
+                                                      ret);
+                       }
+               } else {
+                       /* Start with the original request */
+                       ret = la_down_req(ac);
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ac->req, NULL, NULL, ret);
+                       }
                }
                return LDB_SUCCESS;
        }
@@ -377,6 +351,8 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
        int i, j;
        struct la_context *ac;
        struct ldb_request *search_req;
+       const char **attrs;
+
        int ret;
 
        if (ldb_dn_is_special(req->op.mod.message->dn)) {
@@ -394,12 +370,15 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                return ldb_next_request(module, req);
        }
 
-       ac->rc = NULL;
+       ac->rc = talloc_zero(ac, struct replace_context);
+       if (!ac->rc) {
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
        for (i=0; i < req->op.mod.message->num_elements; i++) {
                bool store_el = false;
                const char *attr_name;
-               const char *attr_val;
                const struct dsdb_attribute *target_attr;
                const struct ldb_message_element *el = &req->op.mod.message->elements[i];
                const struct dsdb_attribute *schema_attr
@@ -437,8 +416,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                }
 
                attr_name = target_attr->lDAPDisplayName;
-               attr_val = ldb_dn_get_linearized(ac->req->op.mod.message->dn);
-
+       
                switch (el->flags & LDB_FLAG_MOD_MASK) {
                case LDB_FLAG_MOD_REPLACE:
                        /* treat as just a normal add the delete part is handled by the callback */
@@ -452,7 +430,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                        for (j = 0; j < el->num_values; j++) {
                                ret = la_store_op(ac, LA_OP_ADD,
                                                  &el->values[j],
-                                                 attr_name, attr_val);
+                                                 attr_name);
                                if (ret != LDB_SUCCESS) {
                                        return ret;
                                }
@@ -466,7 +444,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                                for (j = 0; j < el->num_values; j++) {
                                        ret = la_store_op(ac, LA_OP_DEL,
                                                          &el->values[j],
-                                                         attr_name, attr_val);
+                                                         attr_name);
                                        if (ret != LDB_SUCCESS) {
                                                return ret;
                                        }
@@ -484,15 +462,6 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                if (store_el) {
                        struct ldb_message_element *search_el;
 
-                       /* Fill out ac->rc only if we have to find the old values */
-                       if (!ac->rc) {
-                               ac->rc = talloc_zero(ac, struct replace_context);
-                               if (!ac->rc) {
-                                       ldb_oom(module->ldb);
-                                       return LDB_ERR_OPERATIONS_ERROR;
-                               }
-                       }
-
                        search_el = talloc_realloc(ac->rc, ac->rc->el,
                                                   struct ldb_message_element,
                                                   ac->rc->num_elements +1);
@@ -506,25 +475,21 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                        ac->rc->num_elements++;
                }
        }
-
-       /* both replace and delete without values are handled in the callback
-        * after the search on the entry to be modified is performed */
-
-       /* Only bother doing a search of this entry (to find old
-        * values) if replace or delete operations are attempted */
-       if (ac->rc) {
-               const char **attrs;
-
-               attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements +1);
+       
+       if (ac->ops || ac->rc->el) {
+               /* both replace and delete without values are handled in the callback
+                * after the search on the entry to be modified is performed */
+               
+               attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1);
                if (!attrs) {
                        ldb_oom(module->ldb);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
-               for (i = 0; i < ac->rc->num_elements; i++) {
+               for (i = 0; ac->rc && i < ac->rc->num_elements; i++) {
                        attrs[i] = ac->rc->el[i].name;
                }
                attrs[i] = NULL;
-
+               
                /* The callback does all the hard work here */
                ret = ldb_build_search_req(&search_req, module->ldb, ac,
                                           req->op.mod.message->dn,
@@ -534,32 +499,31 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
                                           ac, la_mod_search_callback,
                                           req);
 
+               /* We need to figure out our own extended DN, to fill in as the backlink target */
+               if (ret == LDB_SUCCESS) {
+                       ret = ldb_request_add_control(search_req,
+                                                     LDB_CONTROL_EXTENDED_DN_OID,
+                                                     false, NULL);
+               }
                if (ret == LDB_SUCCESS) {
                        talloc_steal(search_req, attrs);
-
+                       
                        ret = ldb_next_request(module, search_req);
                }
 
-               
        } else {
-               if (ac->ops) {
-                       /* Start with the original request */
-                       ret = la_down_req(ac);
-               } else {
-                       /* nothing to do for this module, proceed */
-                       talloc_free(ac);
-                       ret = ldb_next_request(module, req);
-               }
+               /* nothing to do for this module, proceed */
+               talloc_free(ac);
+               ret = ldb_next_request(module, req);
        }
 
        return ret;
 }
 
 /* delete, rename */
-static int linked_attributes_op(struct ldb_module *module, struct ldb_request *req)
+static int linked_attributes_del(struct ldb_module *module, struct ldb_request *req)
 {
        struct ldb_request *search_req;
-       struct ldb_dn *base_dn;
        struct la_context *ac;
        const char **attrs;
        WERROR werr;
@@ -574,17 +538,6 @@ static int linked_attributes_op(struct ldb_module *module, struct ldb_request *r
           - Regain our sainity
        */
 
-       switch (req->operation) {
-       case LDB_RENAME:
-               base_dn = req->op.rename.olddn;
-               break;
-       case LDB_DELETE:
-               base_dn = req->op.del.dn;
-               break;
-       default:
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
        ac = linked_attributes_init(module, req);
        if (!ac) {
                return LDB_ERR_OPERATIONS_ERROR;
@@ -601,7 +554,7 @@ static int linked_attributes_op(struct ldb_module *module, struct ldb_request *r
        }
 
        ret = ldb_build_search_req(&search_req, module->ldb, req,
-                                  base_dn, LDB_SCOPE_BASE,
+                                  req->op.del.dn, LDB_SCOPE_BASE,
                                   "(objectClass=*)", attrs,
                                   NULL,
                                   ac, la_op_search_callback,
@@ -616,6 +569,35 @@ static int linked_attributes_op(struct ldb_module *module, struct ldb_request *r
        return ldb_next_request(module, search_req);
 }
 
+/* delete, rename */
+static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
+{
+       struct la_context *ac;
+
+       /* 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(module, req);
+       if (!ac) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       if (!ac->schema) {
+               /* without schema, this doesn't make any sense */
+               return ldb_next_request(module, req);
+       }
+
+       /* start with the original request */
+       return la_down_req(ac);
+}
+
+
 static int la_op_search_callback(struct ldb_request *req,
                                 struct ldb_reply *ares)
 {
@@ -624,8 +606,6 @@ static int la_op_search_callback(struct ldb_request *req,
        const struct dsdb_attribute *target_attr;
        const struct ldb_message_element *el;
        const char *attr_name;
-       const char *deldn;
-       const char *adddn;
        int i, j;
        int ret;
 
@@ -659,15 +639,16 @@ static int la_op_search_callback(struct ldb_request *req,
 
                switch (ac->req->operation) {
                case LDB_DELETE:
-                       deldn = ldb_dn_get_linearized(ac->req->op.del.dn);
-                       adddn = NULL;
+                       ac->del_dn = talloc_steal(ac, ares->message->dn);
                        break;
                case LDB_RENAME:
-                       deldn = ldb_dn_get_linearized(ac->req->op.rename.olddn);
-                       adddn = ldb_dn_get_linearized(ac->req->op.rename.newdn);
+                       ac->add_dn = talloc_steal(ac, ares->message->dn); 
+                       ac->del_dn = talloc_steal(ac, ac->req->op.rename.olddn);
                        break;
                default:
                        talloc_free(ares);
+                       ldb_set_errstring(ac->module->ldb,
+                                         "operations must be delete or rename");
                        return ldb_module_done(ac->req, NULL, NULL,
                                                LDB_ERR_OPERATIONS_ERROR);
                }
@@ -708,16 +689,15 @@ static int la_op_search_callback(struct ldb_request *req,
                        for (j = 0; j < el->num_values; j++) {
                                ret = la_store_op(ac, LA_OP_DEL,
                                                  &el->values[j],
-                                                 attr_name, deldn);
-                               if (ret != LDB_SUCCESS) {
-                                       talloc_free(ares);
-                                       return ldb_module_done(ac->req,
-                                                              NULL, NULL, ret);
+                                                 attr_name);
+
+                               /* for renames, ensure we add it back */
+                               if (ret == LDB_SUCCESS
+                                   && ac->req->operation == LDB_RENAME) {
+                                       ret = la_store_op(ac, LA_OP_ADD,
+                                                         &el->values[j],
+                                                         attr_name);
                                }
-                               if (!adddn) continue;
-                               ret = la_store_op(ac, LA_OP_ADD,
-                                                 &el->values[j],
-                                                 attr_name, adddn);
                                if (ret != LDB_SUCCESS) {
                                        talloc_free(ares);
                                        return ldb_module_done(ac->req,
@@ -736,10 +716,31 @@ static int la_op_search_callback(struct ldb_request *req,
 
                talloc_free(ares);
 
-               /* start the mod requests chain */
-               ret = la_down_req(ac);
-               if (ret != LDB_SUCCESS) {
-                       return ldb_module_done(ac->req, NULL, NULL, ret);
+
+               switch (ac->req->operation) {
+               case LDB_DELETE:
+                       /* start the mod requests chain */
+                       ret = la_down_req(ac);
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ac->req, NULL, NULL, ret);
+                       }
+                       break;
+               case LDB_RENAME:
+                       
+                       ret = la_do_mod_request(ac);
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ac->req, NULL, NULL,
+                                                      ret);
+                       }
+       
+                       return ret;
+                       
+               default:
+                       talloc_free(ares);
+                       ldb_set_errstring(ac->module->ldb,
+                                         "operations must be delete or rename");
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
                }
                return LDB_SUCCESS;
        }
@@ -757,6 +758,12 @@ static int la_do_mod_request(struct la_context *ac)
        struct ldb_context *ldb;
        int ret;
 
+       /* If we have no modifies in the queue, we are done! */
+       if (!ac->ops) {
+               return ldb_module_done(ac->req, ac->op_controls,
+                                      ac->op_response, LDB_SUCCESS);
+       }
+
        ldb = ac->module->ldb;
 
        /* Create the modify request */
@@ -765,10 +772,7 @@ static int la_do_mod_request(struct la_context *ac)
                ldb_oom(ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       new_msg->dn = ldb_dn_copy(new_msg, ac->ops->dn);
-       if (!new_msg->dn) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
+       new_msg->dn = ac->ops->dn;
 
        if (ac->ops->op == LA_OP_ADD) {
                ret = ldb_msg_add_empty(new_msg, ac->ops->name,
@@ -785,8 +789,19 @@ static int la_do_mod_request(struct la_context *ac)
                ldb_oom(ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ret_el->values[0] = data_blob_string_const(ac->ops->value);
        ret_el->num_values = 1;
+       if (ac->ops->op == LA_OP_ADD) {
+               ret_el->values[0] = data_blob_string_const(ldb_dn_extended_linearized(new_msg, ac->add_dn, 1));
+       } else {
+               ret_el->values[0] = data_blob_string_const(ldb_dn_extended_linearized(new_msg, ac->del_dn, 1));
+       }
+
+#if 0
+       ldb_debug(ac->module->ldb, LDB_DEBUG_WARNING,
+                 "link on %s %s: %s %s\n", 
+                 ldb_dn_get_linearized(new_msg->dn), ret_el->name, 
+                 ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted");
+#endif 
 
        /* use ac->ops as the mem_ctx so that the request will be freed
         * in the callback as soon as completed */
@@ -808,7 +823,6 @@ static int la_mod_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct la_context *ac;
        struct la_op_store *os;
-       int ret;
 
        ac = talloc_get_type(req->context, struct la_context);
 
@@ -831,30 +845,180 @@ static int la_mod_callback(struct ldb_request *req, struct ldb_reply *ares)
 
        talloc_free(ares);
 
-       if (ac->ops) {
-               os = ac->ops;
-               ac->ops = os->next;
+       os = ac->ops;
+       DLIST_REMOVE(ac->ops, os);
+
+       /* this frees the request too
+        * DO NOT access 'req' after this point */
+       talloc_free(os);
 
-               /* this frees the request too
-                * DO NOT access 'req' after this point */
-               talloc_free(os);
+       return la_do_mod_request(ac);
+}
+
+/* Having done the original operation, then try to fix up all the linked attributes for modify and delete */
+static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       int ret;
+       struct la_context *ac;
+       ac = talloc_get_type(req->context, struct la_context);
+
+       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);
        }
 
-       /* If we still have modifies in the queue, then run them */
-       if (ac->ops) {
-               ret = la_do_mod_request(ac);
-       } else {
-               /* Otherwise, we are done! */
-               ret = ldb_module_done(ac->req, ares->controls,
-                                     ares->response, ares->error);
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(ac->module->ldb,
+                                 "invalid ldb_reply_type in callback");
+               talloc_free(ares);
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
        }
+       
+       ac->op_controls = talloc_steal(ac, ares->controls);
+       ac->op_response = talloc_steal(ac, ares->response);
 
+       /* If we have modfies to make, this is the time to do them for modify and delete */
+       ret = la_do_mod_request(ac);
+       
        if (ret != LDB_SUCCESS) {
                return ldb_module_done(ac->req, NULL, NULL, ret);
        }
+       talloc_free(ares);
+
+       /* la_do_mod_request has already sent the callbacks */
        return LDB_SUCCESS;
+
+}
+
+/* Having done the original rename try to fix up all the linked attributes */
+static int la_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       int ret;
+       struct la_context *ac;
+       struct ldb_request *search_req;
+       const char **attrs;
+       WERROR werr;
+       ac = talloc_get_type(req->context, struct la_context);
+
+       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);
+       }
+
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(ac->module->ldb,
+                                 "invalid ldb_reply_type in callback");
+               talloc_free(ares);
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       
+       werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
+       if (!W_ERROR_IS_OK(werr)) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       ret = ldb_build_search_req(&search_req, ac->module->ldb, req,
+                                  ac->req->op.rename.newdn, LDB_SCOPE_BASE,
+                                  "(objectClass=*)", attrs,
+                                  NULL,
+                                  ac, la_op_search_callback,
+                                  req);
+       
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+               
+       talloc_steal(search_req, attrs);
+
+       if (ret == LDB_SUCCESS) {
+               ret = ldb_request_add_control(search_req,
+                                             LDB_CONTROL_EXTENDED_DN_OID,
+                                             false, NULL);
+       }
+       if (ret != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                      ret);
+       }
+       
+       ac->op_controls = talloc_steal(ac, ares->controls);
+       ac->op_response = talloc_steal(ac, ares->response);
+
+       return ldb_next_request(ac->module, search_req);
+}
+
+/* Having done the original add, then try to fix up all the linked attributes
+
+  This is done after the add so the links can get the extended DNs correctly.
+ */
+static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       int ret;
+       struct la_context *ac;
+       ac = talloc_get_type(req->context, struct la_context);
+
+       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);
+       }
+
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(ac->module->ldb,
+                                 "invalid ldb_reply_type in callback");
+               talloc_free(ares);
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       
+       if (ac->ops) {
+               struct ldb_request *search_req;
+               static const char *attrs[] = { NULL };
+               
+               /* The callback does all the hard work here - we need
+                * the objectGUID and SID of the added record */
+               ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
+                                          ac->req->op.add.message->dn,
+                                          LDB_SCOPE_BASE,
+                                          "(objectClass=*)", attrs,
+                                          NULL,
+                                          ac, la_mod_search_callback,
+                                          ac->req);
+               
+               if (ret == LDB_SUCCESS) {
+                       ret = ldb_request_add_control(search_req,
+                                                     LDB_CONTROL_EXTENDED_DN_OID,
+                                                     false, NULL);
+               }
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                              ret);
+               }
+
+               ac->op_controls = talloc_steal(ac, ares->controls);
+               ac->op_response = talloc_steal(ac, ares->response);
+
+               return ldb_next_request(ac->module, search_req);
+               
+       } else {
+               return ldb_module_done(ac->req, ares->controls,
+                                      ares->response, ares->error);
+       }
 }
 
+/* Reconstruct the original request, but pointing at our local callback to finish things off */
 static int la_down_req(struct la_context *ac)
 {
        struct ldb_request *down_req;
@@ -865,21 +1029,21 @@ static int la_down_req(struct la_context *ac)
                ret = ldb_build_add_req(&down_req, ac->module->ldb, ac,
                                        ac->req->op.add.message,
                                        ac->req->controls,
-                                       ac, la_down_callback,
+                                       ac, la_add_callback,
                                        ac->req);
                break;
        case LDB_MODIFY:
                ret = ldb_build_mod_req(&down_req, ac->module->ldb, ac,
                                        ac->req->op.mod.message,
                                        ac->req->controls,
-                                       ac, la_down_callback,
+                                       ac, la_mod_del_callback,
                                        ac->req);
                break;
        case LDB_DELETE:
                ret = ldb_build_del_req(&down_req, ac->module->ldb, ac,
                                        ac->req->op.del.dn,
                                        ac->req->controls,
-                                       ac, la_down_callback,
+                                       ac, la_mod_del_callback,
                                        ac->req);
                break;
        case LDB_RENAME:
@@ -887,7 +1051,7 @@ static int la_down_req(struct la_context *ac)
                                           ac->req->op.rename.olddn,
                                           ac->req->op.rename.newdn,
                                           ac->req->controls,
-                                          ac, la_down_callback,
+                                          ac, la_rename_callback,
                                           ac->req);
                break;
        default:
@@ -900,42 +1064,11 @@ static int la_down_req(struct la_context *ac)
        return ldb_next_request(ac->module, down_req);
 }
 
-/* Having done the original operation, then try to fix up all the linked attributes */
-static int la_down_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
-       struct la_context *ac;
-
-       ac = talloc_get_type(req->context, struct la_context);
-
-       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);
-       }
-
-       if (ares->type != LDB_REPLY_DONE) {
-               ldb_set_errstring(ac->module->ldb,
-                                 "invalid ldb_reply_type in callback");
-               talloc_free(ares);
-               return ldb_module_done(ac->req, NULL, NULL,
-                                       LDB_ERR_OPERATIONS_ERROR);
-       }
-       /* If we have modfies to make, then run them */
-       if (ac->ops) {
-               return la_do_mod_request(ac);
-       } else {
-               return ldb_module_done(ac->req, ares->controls,
-                                     ares->response, ares->error);
-       }
-}
 
 _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = {
        .name              = "linked_attributes",
        .add               = linked_attributes_add,
        .modify            = linked_attributes_modify,
-       .del               = linked_attributes_op,
-       .rename            = linked_attributes_op,
+       .del               = linked_attributes_del,
+       .rename            = linked_attributes_rename,
 };
index 622e44416634e6301aa730a0cda1d3ae4ca2e7c8..4e864e1452db887cd2d6bea835cb869f2ef85fde 100644 (file)
@@ -47,7 +47,8 @@
 
    Each incoming add/modify is split into a remote, and a local request, done in that order.
 
-   We maintain a list of attributes that are kept locally:
+   We maintain a list of attributes that are kept locally - perhaps
+   this should use the @KLUDGE_ACL list of passwordAttribute
  */
 
 static const char * const password_attrs[] = {
index 2366bc785684aa2bba79085e3f60a9d9c444ffa5..796edec98d00811ba9b726cd72bafac920600349 100644 (file)
@@ -114,8 +114,7 @@ static int normalize_search_callback(struct ldb_request *req, struct ldb_reply *
                                continue;
                        }
                        /* Look to see if this attributeSyntax is a DN */
-                       if (!((strcmp(attribute->attributeSyntax_oid, "2.5.5.1") == 0) ||
-                             (strcmp(attribute->attributeSyntax_oid, "2.5.5.7") == 0))) {
+                       if (strcmp(attribute->attributeSyntax_oid, "2.5.5.1") == 0) {
                                continue;
                        }
                        for (j = 0; j < msg->elements[i].num_values; j++) {
index b38e182cf7897ca4bbc8557e987ef57efa4c43fa..639d9100bfd771bc3b2d7f17e76cfa2fdd09bbd1 100644 (file)
@@ -301,8 +301,7 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
        int ret;
 
        /* see if its for the rootDSE - only a base search on the "" DN qualifies */
-       if (req->op.search.scope != LDB_SCOPE_BASE ||
-           ( ! ldb_dn_is_null(req->op.search.base))) {
+       if (!(req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base))) {
                /* Otherwise, pass down to the rest of the stack */
                return ldb_next_request(module, req);
        }
index c353914e2cda3d8bec0e6ea4aca27635254acd52..0e42f7869a9243294cc5d426f56c47bb2299a87e 100644 (file)
@@ -44,7 +44,7 @@ struct entryuuid_private {
 static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
 {
        struct GUID guid;
-       NTSTATUS status = GUID_from_string((char *)val->data, &guid);
+       NTSTATUS status = GUID_from_data_blob(val, &guid);
        enum ndr_err_code ndr_err;
        struct ldb_val out = data_blob(NULL, 0);
 
@@ -62,27 +62,13 @@ static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, co
 
 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
 {
-       struct GUID *guid;
        struct ldb_val out = data_blob(NULL, 0);
-       if (val->length >= 32 && val->data[val->length] == '\0') {
-               ldb_handler_copy(module->ldb, ctx, val, &out);
-       } else {
-               enum ndr_err_code ndr_err;
-
-               guid = talloc(ctx, struct GUID);
-               if (guid == NULL) {
-                       return out;
-               }
-               ndr_err = ndr_pull_struct_blob(val, guid, NULL, guid,
-                                              (ndr_pull_flags_fn_t)ndr_pull_GUID);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       talloc_free(guid);
-                       return out;
-               }
-               out = data_blob_string_const(GUID_string(ctx, guid));
-               talloc_free(guid);
+       struct GUID guid;
+       NTSTATUS status = GUID_from_data_blob(val, &guid);
+       if (!NT_STATUS_IS_OK(status)) {
+               return out;
        }
-       return out;
+       return data_blob_string_const(GUID_string(ctx, &guid));
 }
 
 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
@@ -107,27 +93,12 @@ static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx,
 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
 {
        struct ldb_val out = data_blob(NULL, 0);
-       if (val->length >= 32 && val->data[val->length] == '\0') {
-               struct GUID guid;
-               GUID_from_string((char *)val->data, &guid);
-               out = data_blob_string_const(NS_GUID_string(ctx, &guid));
-       } else {
-               enum ndr_err_code ndr_err;
-               struct GUID *guid_p;
-               guid_p = talloc(ctx, struct GUID);
-               if (guid_p == NULL) {
-                       return out;
-               }
-               ndr_err = ndr_pull_struct_blob(val, guid_p, NULL, guid_p,
-                                              (ndr_pull_flags_fn_t)ndr_pull_GUID);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       talloc_free(guid_p);
-                       return out;
-               }
-               out = data_blob_string_const(NS_GUID_string(ctx, guid_p));
-               talloc_free(guid_p);
+       struct GUID guid;
+       NTSTATUS status = GUID_from_data_blob(val, &guid);
+       if (!NT_STATUS_IS_OK(status)) {
+               return out;
        }
-       return out;
+       return data_blob_string_const(NS_GUID_string(ctx, &guid));
 }
 
 /* The backend holds binary sids, so just copy them back */
index 93068d66ef1dd4b47382c3445cd3bc54cef74c51..4c5b3b2348cbf6c90de57e130487c8daeeabbde0 100644 (file)
@@ -59,6 +59,11 @@ struct dsdb_control_current_partition {
 #define DSDB_CONTROL_REPLICATED_UPDATE_OID "1.3.6.1.4.1.7165.4.3.3"
 /* DSDB_CONTROL_REPLICATED_UPDATE_OID has NULL data */
 
+#define DSDB_CONTROL_DN_STORAGE_FORMAT_OID "1.3.6.1.4.1.7165.4.3.4"
+/* DSDB_CONTROL_DN_STORAGE_FORMAT_OID has NULL data and behaves very
+ * much like LDB_CONTROL_EXTENDED_DN_OID when the DB stores an
+ * extended DN, and otherwise returns normal DNs */
+
 #define DSDB_EXTENDED_REPLICATED_OBJECTS_OID "1.3.6.1.4.1.7165.4.4.1"
 struct dsdb_extended_replicated_object {
        struct ldb_message *msg;
@@ -100,4 +105,26 @@ struct dsdb_pdc_fsmo {
  */
 #define DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID "1.3.6.1.4.1.7165.4.4.2"
 
+#define DSDB_OPENLDAP_DEREFERENCE_CONTROL "1.3.6.1.4.1.1466.115.121.1.12"
+
+struct dsdb_openldap_dereference {
+       const char *source_attribute;
+       const char **dereference_attribute;
+};
+
+struct dsdb_openldap_dereference_control {
+       struct dsdb_openldap_dereference **dereference;
+};
+
+struct dsdb_openldap_dereference_result {
+       const char *source_attribute;
+       const char *dereferenced_dn;
+       int num_attributes;
+       struct ldb_message_element *attributes;
+};
+
+struct dsdb_openldap_dereference_result_control {
+       struct dsdb_openldap_dereference_result **attributes;
+};
+
 #endif /* __SAMDB_H__ */
index 2adff2a1dfad5d5e9c43075dddc3fb4a2f6196ac..4cdfeafe40118e19cb1efb50f06000f5fe5d8494 100644 (file)
@@ -159,6 +159,8 @@ static NTSTATUS ldapsrv_SearchRequest(struct ldapsrv_call *call)
        struct ldb_request *lreq;
        struct ldb_control *search_control;
        struct ldb_search_options_control *search_options;
+       struct ldb_control *extended_dn_control;
+       struct ldb_extended_dn_control *extended_dn_decoded = NULL;
        enum ldb_scope scope = LDB_SCOPE_DEFAULT;
        const char **attrs = NULL;
        const char *scope_str, *errstr = NULL;
@@ -166,6 +168,7 @@ static NTSTATUS ldapsrv_SearchRequest(struct ldapsrv_call *call)
        int result = -1;
        int ldb_ret = -1;
        int i, j;
+       int extended_type = 1;
 
        DEBUG(10, ("SearchRequest"));
        DEBUGADD(10, (" basedn: %s", req->basedn));
@@ -245,6 +248,18 @@ static NTSTATUS ldapsrv_SearchRequest(struct ldapsrv_call *call)
                        ldb_request_add_control(lreq, LDB_CONTROL_SEARCH_OPTIONS_OID, false, search_options);
                }
        }
+
+       extended_dn_control = ldb_request_get_control(lreq, LDB_CONTROL_EXTENDED_DN_OID);
+
+       if (extended_dn_control) {
+               if (extended_dn_control->data) {
+                       extended_dn_decoded = talloc_get_type(extended_dn_control->data, struct ldb_extended_dn_control);
+                       extended_type = extended_dn_decoded->type;
+               } else {
+                       extended_type = 0;
+               }
+       }
+
        ldb_set_timeout(samdb, lreq, req->timelimit);
 
        ldb_ret = ldb_request(samdb, lreq);
@@ -266,7 +281,7 @@ static NTSTATUS ldapsrv_SearchRequest(struct ldapsrv_call *call)
                        talloc_steal(ent_r, res->msgs[i]);
                        
                        ent = &ent_r->msg->r.SearchResultEntry;
-                       ent->dn = ldb_dn_alloc_linearized(ent_r, res->msgs[i]->dn);
+                       ent->dn = ldb_dn_extended_linearized(ent_r, res->msgs[i]->dn, extended_type);
                        ent->num_attributes = 0;
                        ent->attributes = NULL;
                        if (res->msgs[i]->num_elements == 0) {
index a16582d29458a1e0b23cfa7e822c0e1e8fecf4a1..5ab31d771bd6a753098d5f47323eb17682116b08 100644 (file)
@@ -64,8 +64,8 @@ static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
        if (sid == NULL) {
                return -1;
        }
-       ndr_err = ndr_pull_struct_blob(in, sid, NULL, sid,
-                                      (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+       ndr_err = ndr_pull_struct_blob_all(in, sid, NULL, sid,
+                                          (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                talloc_free(sid);
                return -1;
@@ -139,6 +139,36 @@ static int ldb_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
        return ldb_handler_copy(ldb, mem_ctx, in, out);
 }
 
+static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
+                             const struct ldb_val *in, struct ldb_val *out)
+{
+       struct dom_sid sid;
+       enum ndr_err_code ndr_err;
+       if (ldb_comparision_objectSid_isString(in)) {
+               if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
+                       return 0;
+               }
+       }
+       
+       /* Perhaps not a string after all */
+       *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
+
+       if (!out->data) {
+               return -1;
+       }
+
+       (*out).length = strhex_to_str((char *)out->data, out->length,
+                                    (const char *)in->data, in->length);
+
+       /* Check it looks like a SID */
+       ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &sid,
+                                          (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return -1;
+       }
+       return 0;
+}
+
 /*
   convert a ldif formatted objectGUID to a NDR formatted blob
 */
@@ -146,16 +176,10 @@ static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
                                const struct ldb_val *in, struct ldb_val *out)
 {
        struct GUID guid;
-       char *guid_string;
        NTSTATUS status;
        enum ndr_err_code ndr_err;
-       guid_string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
-       if (!guid_string) {
-               return -1;
-       }
 
-       status = GUID_from_string(guid_string, &guid);
-       talloc_free(guid_string);
+       status = GUID_from_data_blob(in, &guid);
        if (!NT_STATUS_IS_OK(status)) {
                return -1;
        }
@@ -176,8 +200,8 @@ static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
 {
        struct GUID guid;
        enum ndr_err_code ndr_err;
-       ndr_err = ndr_pull_struct_blob(in, mem_ctx, NULL, &guid,
-                                      (ndr_pull_flags_fn_t)ndr_pull_GUID);
+       ndr_err = ndr_pull_struct_blob_all(in, mem_ctx, NULL, &guid,
+                                          (ndr_pull_flags_fn_t)ndr_pull_GUID);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                return -1;
        }
@@ -191,20 +215,42 @@ static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
 
 static bool ldb_comparision_objectGUID_isString(const struct ldb_val *v)
 {
-       struct GUID guid;
-       NTSTATUS status;
-
-       if (v->length < 33) return false;
+       if (v->length != 36 && v->length != 38) return false;
 
-       /* see if the input if null-terninated (safety check for the below) */
-       if (v->data[v->length] != '\0') return false;
+       /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
+       return true;
+}
 
-       status = GUID_from_string((const char *)v->data, &guid);
-       if (!NT_STATUS_IS_OK(status)) {
-               return false;
+static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
+                             const struct ldb_val *in, struct ldb_val *out)
+{
+       struct GUID guid;
+       enum ndr_err_code ndr_err;
+       if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
+               return 0;
        }
 
-       return true;
+       /* Try as 'hex' form */
+       if (in->length != 32) {
+               return -1;
+       }
+               
+       *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
+       
+       if (!out->data) {
+               return -1;
+       }
+       
+       (*out).length = strhex_to_str((char *)out->data, out->length,
+                                     (const char *)in->data, in->length);
+       
+       /* Check it looks like a GUID */
+       ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &guid,
+                                          (ndr_pull_flags_fn_t)ndr_pull_GUID);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return -1;
+       }
+       return 0;
 }
 
 /*
@@ -293,8 +339,9 @@ static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ct
        if (sd == NULL) {
                return -1;
        }
+       /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
        ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
-                                      (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+                                          (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                talloc_free(sd);
                return -1;
@@ -494,10 +541,10 @@ static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
        if (blob == NULL) {
                return -1;
        }
-       ndr_err = ndr_pull_struct_blob(in, blob, 
-                                      lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
-                                      blob,
-                                      (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
+       ndr_err = ndr_pull_struct_blob_all(in, blob, 
+                                          lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
+                                          blob,
+                                          (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                talloc_free(blob);
                return -1;
@@ -578,41 +625,71 @@ static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
        return ret;
 }
 
+static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
+                                const struct ldb_val *in, struct ldb_val *out)
+{
+       *out = data_blob_string_const(data_blob_hex_string(mem_ctx, in));
+       if (!out->data) {
+               return -1;
+       }
+       return 0;
+}
+
+
 #define LDB_SYNTAX_SAMBA_GUID                  "LDB_SYNTAX_SAMBA_GUID"
 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY       "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
 #define LDB_SYNTAX_SAMBA_PREFIX_MAP    "LDB_SYNTAX_SAMBA_PREFIX_MAP"
 
 static const struct ldb_schema_syntax samba_syntaxes[] = {
        {
-               .name           = LDB_SYNTAX_SAMBA_SID,
-               .ldif_read_fn   = ldif_read_objectSid,
-               .ldif_write_fn  = ldif_write_objectSid,
-               .canonicalise_fn= ldb_canonicalise_objectSid,
-               .comparison_fn  = ldb_comparison_objectSid
+               .name             = LDB_SYNTAX_SAMBA_SID,
+               .ldif_read_fn     = ldif_read_objectSid,
+               .ldif_write_fn    = ldif_write_objectSid,
+               .canonicalise_fn  = ldb_canonicalise_objectSid,
+               .comparison_fn    = ldb_comparison_objectSid
+       },{
+               .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
+               .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
+               .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
+               .canonicalise_fn  = ldb_handler_copy,
+               .comparison_fn    = ldb_comparison_binary
+       },{
+               .name             = LDB_SYNTAX_SAMBA_GUID,
+               .ldif_read_fn     = ldif_read_objectGUID,
+               .ldif_write_fn    = ldif_write_objectGUID,
+               .canonicalise_fn  = ldb_canonicalise_objectGUID,
+               .comparison_fn    = ldb_comparison_objectGUID
        },{
-               .name           = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
-               .ldif_read_fn   = ldif_read_ntSecurityDescriptor,
-               .ldif_write_fn  = ldif_write_ntSecurityDescriptor,
-               .canonicalise_fn= ldb_handler_copy,
-               .comparison_fn  = ldb_comparison_binary
+               .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
+               .ldif_read_fn     = ldb_handler_copy,
+               .ldif_write_fn    = ldb_handler_copy,
+               .canonicalise_fn  = ldif_canonicalise_objectCategory,
+               .comparison_fn    = ldif_comparison_objectCategory
        },{
-               .name           = LDB_SYNTAX_SAMBA_GUID,
-               .ldif_read_fn   = ldif_read_objectGUID,
-               .ldif_write_fn  = ldif_write_objectGUID,
-               .canonicalise_fn= ldb_canonicalise_objectGUID,
-               .comparison_fn  = ldb_comparison_objectGUID
+               .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
+               .ldif_read_fn     = ldif_read_prefixMap,
+               .ldif_write_fn    = ldif_write_prefixMap,
+               .canonicalise_fn  = ldif_canonicalise_prefixMap,
+               .comparison_fn    = ldif_comparison_prefixMap
+       }
+};
+
+static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
+       {
+               .name             = "SID",
+               .read_fn          = extended_dn_read_SID,
+               .write_clear_fn   = ldif_write_objectSid,
+               .write_hex_fn     = extended_dn_write_hex
        },{
-               .name           = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
-               .ldif_read_fn   = ldb_handler_copy,
-               .ldif_write_fn  = ldb_handler_copy,
-               .canonicalise_fn= ldif_canonicalise_objectCategory,
-               .comparison_fn  = ldif_comparison_objectCategory
+               .name             = "GUID",
+               .read_fn          = extended_dn_read_GUID,
+               .write_clear_fn   = ldif_write_objectGUID,
+               .write_hex_fn     = extended_dn_write_hex
        },{
-               .name           = LDB_SYNTAX_SAMBA_PREFIX_MAP,
-               .ldif_read_fn   = ldif_read_prefixMap,
-               .ldif_write_fn  = ldif_write_prefixMap,
-               .canonicalise_fn= ldif_canonicalise_prefixMap,
-               .comparison_fn  = ldif_comparison_prefixMap
+               .name             = "WKGUID",
+               .read_fn          = ldb_handler_copy,
+               .write_clear_fn   = ldb_handler_copy,
+               .write_hex_fn     = ldb_handler_copy
        }
 };
 
@@ -679,5 +756,15 @@ int ldb_register_samba_handlers(struct ldb_context *ldb)
                }
        }
 
+       for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
+               int ret;
+               ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+
+               
+       }
+
        return LDB_SUCCESS;
 }
index 747f2417811a9069b1ed4391b70672b6d54f590b..48f9e11cafd111f72d2770743d9d1604193e47e4 100644 (file)
@@ -225,3 +225,50 @@ int ldb_setup_wellknown_attributes(struct ldb_context *ldb)
        return LDB_SUCCESS;
 }
 
+
+/*
+  add a extended dn syntax to the ldb_schema
+*/
+int ldb_dn_extended_add_syntax(struct ldb_context *ldb, 
+                              unsigned flags,
+                              const struct ldb_dn_extended_syntax *syntax)
+{
+       int n;
+       struct ldb_dn_extended_syntax *a;
+
+       if (!syntax) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       n = ldb->schema.num_dn_extended_syntax + 1;
+
+       a = talloc_realloc(ldb, ldb->schema.dn_extended_syntax,
+                          struct ldb_dn_extended_syntax, n);
+
+       if (!a) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       a[ldb->schema.num_dn_extended_syntax] = *syntax;
+       ldb->schema.dn_extended_syntax = a;
+
+       ldb->schema.num_dn_extended_syntax = n;
+
+       return 0;
+}
+
+/*
+  return the extended dn syntax for a given name
+*/
+const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_context *ldb,
+                                                                   const char *name)
+{
+       int i;
+       for (i=0; i < ldb->schema.num_dn_extended_syntax; i++) {
+               if (ldb_attr_cmp(ldb->schema.dn_extended_syntax[i].name, name) == 0) {
+                       return &ldb->schema.dn_extended_syntax[i];
+               }
+       }
+       return NULL;
+}
+
index e3f8551407a393042af393f3886c95f52857f910..6fad5012b699527c15f199525512fe556e73d07a 100644 (file)
@@ -53,6 +53,26 @@ struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char
        return NULL;
 }
 
+/* check if a control with the specified "oid" exist and return it */
+/* returns NULL if not found */
+struct ldb_control *ldb_reply_get_control(struct ldb_reply *rep, const char *oid)
+{
+       int i;
+
+       /* check if there's a paged request control */
+       if (rep->controls != NULL) {
+               for (i = 0; rep->controls[i]; i++) {
+                       if (strcmp(oid, rep->controls[i]->oid) == 0) {
+                               break;
+                       }
+               }
+
+               return rep->controls[i];
+       }
+
+       return NULL;
+}
+
 /* saves the current controls list into the "saver" and replace the one in req with a new one excluding
 the "exclude" control */
 /* returns False on error */
index e36aea4e697fd8b2dddf5bdfdcaad64d18aa7c2a..23069ca2bbf7655b7eb028f5e23e93bc6e47ab5e 100644 (file)
@@ -52,6 +52,12 @@ struct ldb_dn_component {
        struct ldb_val cf_value;
 };
 
+struct ldb_dn_extended_component {
+
+       char *name;
+       struct ldb_val value;
+};
+
 struct ldb_dn {
 
        struct ldb_context *ldb;
@@ -63,11 +69,14 @@ struct ldb_dn {
        bool valid_case;
 
        char *linearized;
+       char *extended_linearized;
        char *casefold;
 
        unsigned int comp_num;
        struct ldb_dn_component *components;
 
+       unsigned int extended_comp_num;
+       struct ldb_dn_extended_component *extended_components;
 };
 
 /* strdn may be NULL */
@@ -85,28 +94,34 @@ struct ldb_dn *ldb_dn_from_ldb_val(void *mem_ctx, struct ldb_context *ldb, const
        if (strdn->data && strdn->length) {
                if (strdn->data[0] == '@') {
                        dn->special = true;
+               } 
+               dn->extended_linearized = talloc_strndup(dn, (const char *)strdn->data, strdn->length);
+               LDB_DN_NULL_FAILED(dn->extended_linearized);
+       
+               if (strdn->data[0] == '<') {
+                       const char *p_save, *p = dn->extended_linearized;
+                       do {
+                               p_save = p;
+                               p = strstr(p, ">;");
+                               if (p) {
+                                       p = p + 2;
+                               }
+                       } while (p);
+                       
+                       if (p_save == dn->extended_linearized) {
+                               dn->linearized = talloc_strdup(dn, "");
+                       } else {
+                               dn->linearized = talloc_strdup(dn, p_save);
+                       }
+                       LDB_DN_NULL_FAILED(dn->linearized);
+               } else {
+                       dn->linearized = dn->extended_linearized;
+                       dn->extended_linearized = NULL;
                }
-               if (strdn->length >= 6 && strncasecmp((const char *)strdn->data, "<GUID=", 6) == 0) {
-                       /* this is special DN returned when the
-                        * exploded_dn control is used */
-                       dn->special = true;
-                       /* FIXME: add a GUID string to ldb_dn structure */
-               } else if (strdn->length >= 5 && strncasecmp((const char *)strdn->data, "<SID=", 5) == 0) {
-                       /* this is special DN returned when the
-                        * exploded_dn control is used */
-                       dn->special = true;
-                       /* FIXME: add a SID string to ldb_dn structure */
-               } else if (strdn->length >= 8 && strncasecmp((const char *)strdn->data, "<WKGUID=", 8) == 0) {
-                       /* this is special DN returned when the
-                        * exploded_dn control is used */
-                       dn->special = true;
-                       /* FIXME: add a WKGUID string to ldb_dn structure */
-               }
-               dn->linearized = talloc_strndup(dn, (const char *)strdn->data, strdn->length);
        } else {
                dn->linearized = talloc_strdup(dn, "");
+               LDB_DN_NULL_FAILED(dn->linearized);
        }
-       LDB_DN_NULL_FAILED(dn->linearized);
 
        return dn;
 
@@ -126,47 +141,21 @@ struct ldb_dn *ldb_dn_new(void *mem_ctx, struct ldb_context *ldb, const char *st
 
 struct ldb_dn *ldb_dn_new_fmt(void *mem_ctx, struct ldb_context *ldb, const char *new_fmt, ...)
 {
-       struct ldb_dn *dn;
        char *strdn;
        va_list ap;
 
        if ( (! mem_ctx) || (! ldb)) return NULL;
 
-       dn = talloc_zero(mem_ctx, struct ldb_dn);
-       LDB_DN_NULL_FAILED(dn);
-
-       dn->ldb = ldb;
-
        va_start(ap, new_fmt);
-       strdn = talloc_vasprintf(dn, new_fmt, ap);
+       strdn = talloc_vasprintf(mem_ctx, new_fmt, ap);
        va_end(ap);
-       LDB_DN_NULL_FAILED(strdn);
-
-       if (strdn[0] == '@') {
-               dn->special = true;
-       }
-       if (strncasecmp(strdn, "<GUID=", 6) == 0) {
-               /* this is special DN returned when the
-                * exploded_dn control is used */
-               dn->special = true;
-               /* FIXME: add a GUID string to ldb_dn structure */
-       } else if (strncasecmp(strdn, "<SID=", 5) == 0) {
-               /* this is special DN returned when the
-                * exploded_dn control is used */
-               dn->special = true;
-               /* FIXME: add a SID string to ldb_dn structure */
-       } else if (strncasecmp(strdn, "<WKGUID=", 8) == 0) {
-               /* this is special DN returned when the
-                * exploded_dn control is used */
-               dn->special = true;
-               /* FIXME: add a WKGUID string to ldb_dn structure */
-       }
-       dn->linearized = strdn;
 
-       return dn;
-
-failed:
-       talloc_free(dn);
+       if (strdn) {
+               struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, strdn);
+               talloc_free(strdn);
+               return dn;
+       }
+       
        return NULL;
 }
 
@@ -235,15 +224,19 @@ char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value)
 */
 static bool ldb_dn_explode(struct ldb_dn *dn)
 {
-       char *p, *data, *d, *dt, *t;
+       char *p, *ex_name, *ex_value, *data, *d, *dt, *t;
        bool trim = false;
+       bool in_extended = false;
+       bool in_ex_name = false;
+       bool in_ex_value = false;
        bool in_attr = false;
        bool in_value = false;
        bool in_quote = false;
        bool is_oid = false;
        bool escape = false;
        unsigned x;
-       int l;
+       int l, ret;
+       char *parse_dn;
 
        if ( ! dn || dn->invalid) return false;
 
@@ -251,12 +244,18 @@ static bool ldb_dn_explode(struct ldb_dn *dn)
                return true;
        }
 
-       if ( ! dn->linearized) {
+       if (dn->extended_linearized) {
+               parse_dn = dn->extended_linearized;
+       } else {
+               parse_dn = dn->linearized;
+       }
+
+       if ( ! parse_dn ) {
                return false;
        }
 
        /* Empty DNs */
-       if (dn->linearized[0] == '\0') {
+       if (parse_dn[0] == '\0') {
                return true;
        }
 
@@ -268,6 +267,9 @@ static bool ldb_dn_explode(struct ldb_dn *dn)
        /* make sure we free this if alloced previously before replacing */
        talloc_free(dn->components);
 
+       talloc_free(dn->extended_components);
+       dn->extended_components = NULL;
+
        /* in the common case we have 3 or more components */
        /* make sure all components are zeroed, other functions depend on this */
        dn->components = talloc_zero_array(dn, struct ldb_dn_component, 3);
@@ -277,19 +279,109 @@ static bool ldb_dn_explode(struct ldb_dn *dn)
        dn->comp_num = 0;
 
        /* Components data space is allocated here once */
-       data = talloc_array(dn->components, char, strlen(dn->linearized) + 1);
+       data = talloc_array(dn->components, char, strlen(parse_dn) + 1);
        if (!data) {
                return false;
        }
 
-       p = dn->linearized;
-       in_attr = true;
+       p = parse_dn;
+       in_extended = true;
+       in_ex_name = false;
+       in_ex_value = false;
        trim = true;
        t = NULL;
        d = dt = data;
 
        while (*p) {
+               if (in_extended) {
+
+                       if (!in_ex_name && !in_ex_value) {
+
+                               if (p[0] == '<') {
+                                       p++;
+                                       ex_name = d;
+                                       in_ex_name = true;
+                                       continue;
+                               } else if (p[0] == '\0') {
+                                       p++;
+                                       continue;
+                               } else {
+                                       in_extended = false;
+                                       in_attr = true;
+                                       dt = d;
+
+                                       continue;
+                               }
+                       }
+                       
+                       if (in_ex_name && *p == '=') {
+                               *d++ = '\0';
+                               p++;
+                               ex_value = d;
+                               in_ex_name = false;
+                               in_ex_value = true;
+                               continue;
+                       }
+
+                       if (in_ex_value && *p == '>') {
+                               const struct ldb_dn_extended_syntax *extended_syntax;
+                               struct ldb_val ex_val = {
+                                       .data = ex_value,
+                                       .length = d - ex_value
+                               };
+                                       
+                               *d++ = '\0';
+                               p++;
+                               in_ex_value = false;
+
+                               /* Process name and ex_value */
+
+                               dn->extended_components = talloc_realloc(dn,
+                                                                        dn->extended_components,
+                                                                        struct ldb_dn_extended_component,
+                                                                        dn->extended_comp_num + 1);
+                               if ( ! dn->extended_components) {
+                                       /* ouch ! */
+                                       goto failed;
+                               }
+
+                               extended_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, ex_name);
+                               if (!extended_syntax) {
+                                       /* We don't know about this type of extended DN */
+                                       goto failed;
+                               }
+
+                               dn->extended_components[dn->extended_comp_num].name = talloc_strdup(dn->extended_components, ex_name);
+                               if (!dn->extended_components[dn->extended_comp_num].name) {
+                                       /* ouch */
+                                       goto failed;
+                               }
+                               ret = extended_syntax->read_fn(dn->ldb, dn->extended_components,
+                                                              &ex_val, &dn->extended_components[dn->extended_comp_num].value);
+                               if (ret != LDB_SUCCESS) {
+                                       dn->invalid = true;
+                                       goto failed;
+                               }
+
+                               dn->extended_comp_num++;
 
+                               if (*p == '\0') {
+                                       /* We have reached the end (extended component only)! */
+                                       talloc_free(data);
+                                       return true;
+
+                               } else if (*p == ';') {
+                                       p++;
+                                       continue;
+                               } else {
+                                       dn->invalid = true;
+                                       goto failed;
+                               }
+                       }
+
+                       *d++ = *p++;
+                       continue;
+               }
                if (in_attr) {
                        if (trim) {
                                if (*p == ' ') {
@@ -315,6 +407,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn)
                                        goto failed;
                                }
                                
+                               /* Copy this character across from parse_dn, now we have trimmed out spaces */
                                *d++ = *p++;
                                continue;
                        }
@@ -339,6 +432,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn)
                                trim = true;
                                l = 0;
 
+                               /* Terminate this string in d (which is a copy of parse_dn with spaces trimmed) */
                                *d++ = '\0';
                                dn->components[dn->comp_num].name = talloc_strdup(dn->components, dt);
                                if ( ! dn->components[dn->comp_num].name) {
@@ -614,6 +708,74 @@ const char *ldb_dn_get_linearized(struct ldb_dn *dn)
        return dn->linearized;
 }
 
+char *ldb_dn_extended_linearized(void *mem_ctx, struct ldb_dn *dn, int mode)
+{
+       const char *linearized = ldb_dn_get_linearized(dn);
+       char *p;
+       int i;
+
+       if (!linearized) {
+               return NULL;
+       }
+
+       if (!ldb_dn_has_extended(dn)) {
+               return talloc_strdup(mem_ctx, linearized);
+       }
+       
+       if (!ldb_dn_validate(dn)) {
+               return NULL;
+       }
+
+       for (i=0; i < dn->extended_comp_num; i++) {
+               struct ldb_val val;
+               int ret;
+               const struct ldb_dn_extended_syntax *extended_syntax;
+               const char *name = dn->extended_components[i].name;
+               
+               extended_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, name);
+
+               if (mode == 1) {
+                       ret = extended_syntax->write_clear_fn(dn->ldb, mem_ctx,
+                                                             &dn->extended_components[i].value,
+                                                             &val);
+               } else if (mode == 0) {
+                       ret = extended_syntax->write_hex_fn(dn->ldb, mem_ctx,
+                                                             &dn->extended_components[i].value,
+                                                             &val);
+               } else {
+                       ret = -1;
+               }
+
+               if (ret != LDB_SUCCESS) {
+                       return NULL;
+               }
+
+               if (i == 0) {
+                       p = talloc_asprintf(mem_ctx, "<%s=%s>", dn->extended_components[i].name, val.data);
+               } else {
+                       p = talloc_asprintf_append(p, ";<%s=%s>",  dn->extended_components[i].name, val.data);
+               }
+
+               talloc_free(val.data);
+
+               if (!p) {
+                       return NULL;
+               }
+       }
+
+       if (dn->extended_comp_num && *linearized) {
+               p = talloc_asprintf_append(p, ";%s", linearized);
+       }
+
+       if (!p) {
+               return NULL;
+       }
+
+       return p;
+}
+
+
+
 char *ldb_dn_alloc_linearized(void *mem_ctx, struct ldb_dn *dn)
 {
        return talloc_strdup(mem_ctx, ldb_dn_get_linearized(dn));
@@ -909,6 +1071,30 @@ static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_d
        return dst;
 }
 
+static struct ldb_dn_extended_component ldb_dn_extended_copy_component(void *mem_ctx, struct ldb_dn_extended_component *src)
+{
+       struct ldb_dn_extended_component dst;
+
+       memset(&dst, 0, sizeof(dst));
+
+       if (src == NULL) {
+               return dst;
+       }
+
+       dst.value = ldb_val_dup(mem_ctx, &(src->value));
+       if (dst.value.data == NULL) {
+               return dst;
+       }
+
+       dst.name = talloc_strdup(mem_ctx, src->name);
+       if (dst.name == NULL) {
+               LDB_FREE(dst.value.data);
+               return dst;
+       }
+
+       return dst;
+}
+
 struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn)
 {
        struct ldb_dn *new_dn;
@@ -942,6 +1128,24 @@ struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn)
                }
        }
 
+       if (dn->extended_components) {
+               int i;
+
+               new_dn->extended_components = talloc_zero_array(new_dn, struct ldb_dn_extended_component, dn->extended_comp_num);
+               if ( ! new_dn->extended_components) {
+                       talloc_free(new_dn);
+                       return NULL;
+               }
+
+               for (i = 0; i < dn->extended_comp_num; i++) {
+                       new_dn->extended_components[i] = ldb_dn_extended_copy_component(new_dn->extended_components, &dn->extended_components[i]);
+                       if ( ! new_dn->extended_components[i].value.data) {
+                               talloc_free(new_dn);
+                               return NULL;
+                       }
+               }
+       }
+
        if (dn->casefold) {
                new_dn->casefold = talloc_strdup(new_dn, dn->casefold);
                if ( ! new_dn->casefold) {
@@ -958,6 +1162,14 @@ struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn)
                }
        }
 
+       if (dn->extended_linearized) {
+               new_dn->extended_linearized = talloc_strdup(new_dn, dn->extended_linearized);
+               if ( ! new_dn->extended_linearized) {
+                       talloc_free(new_dn);
+                       return NULL;
+               }
+       }
+
        return new_dn;
 }
 
@@ -1037,6 +1249,13 @@ bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base)
                dn->linearized = t;
        }
 
+       /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */
+       if (dn->extended_linearized) {
+               LDB_FREE(dn->extended_linearized);
+       }
+
+       LDB_FREE(dn->extended_components);
+       dn->extended_comp_num = 0;
        return true;
 }
 
@@ -1149,6 +1368,12 @@ bool ldb_dn_add_child(struct ldb_dn *dn, struct ldb_dn *child)
                dn->linearized = t;
        }
 
+       /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */
+       LDB_FREE(dn->extended_linearized);
+
+       LDB_FREE(dn->extended_components);
+       dn->extended_comp_num = 0;
+
        return true;
 }
 
@@ -1218,6 +1443,12 @@ bool ldb_dn_remove_base_components(struct ldb_dn *dn, unsigned int num)
        LDB_FREE(dn->casefold);
        LDB_FREE(dn->linearized);
 
+       /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */
+       LDB_FREE(dn->extended_linearized);
+
+       LDB_FREE(dn->extended_components);
+       dn->extended_comp_num = 0;
+
        return true;
 }
 
@@ -1256,6 +1487,11 @@ bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num)
        LDB_FREE(dn->casefold);
        LDB_FREE(dn->linearized);
 
+       /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */
+       LDB_FREE(dn->extended_linearized);
+
+       LDB_FREE(dn->extended_components);
+       dn->extended_comp_num = 0;
        return true;
 }
 
@@ -1273,6 +1509,11 @@ struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, struct ldb_dn *dn)
                return NULL;
        }
 
+       /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */
+       LDB_FREE(dn->extended_linearized);
+
+       LDB_FREE(dn->extended_components);
+       dn->extended_comp_num = 0;
        return new_dn;
 }
 
@@ -1434,9 +1675,97 @@ int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const str
        LDB_FREE(dn->casefold);
        LDB_FREE(dn->linearized);
 
+       /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */
+       LDB_FREE(dn->extended_linearized);
+
+       dn->extended_comp_num = 0;
+       LDB_FREE(dn->extended_components);
        return LDB_SUCCESS;
 }
 
+const struct ldb_val *ldb_dn_get_extended_component(struct ldb_dn *dn, const char *name)
+{
+       int i;
+       if ( ! ldb_dn_validate(dn)) {
+               return NULL;
+       }
+       for (i=0; i < dn->extended_comp_num; i++) {
+               if (ldb_attr_cmp(dn->extended_components[i].name, name) == 0) {
+                       return &dn->extended_components[i].value;
+               }
+       }
+       return NULL;
+}
+
+int ldb_dn_set_extended_component(struct ldb_dn *dn, const char *name, const struct ldb_val *val)
+{
+       struct ldb_dn_extended_component *p;
+       int i;
+                               
+       if ( ! ldb_dn_validate(dn)) {
+               return LDB_ERR_OTHER;
+       }
+
+       for (i=0; i < dn->extended_comp_num; i++) {
+               if (ldb_attr_cmp(dn->extended_components[i].name, name) == 0) {
+                       if (val) {
+                               dn->extended_components[i].value = ldb_val_dup(dn->extended_components, val);
+
+                               dn->extended_components[i].name = talloc_strdup(dn->extended_components, name);
+                               if (!dn->extended_components[i].name || !dn->extended_components[i].value.data) {
+                                       dn->invalid = true;
+                                       return LDB_ERR_OPERATIONS_ERROR;
+                               }
+       
+                       } else {
+                               if (i != (dn->extended_comp_num - 1)) {
+                                       memmove(&dn->extended_components[i], &dn->extended_components[i+1],
+                                               ((dn->extended_comp_num-1) - i)*sizeof(*dn->extended_components));
+                               }
+                               dn->extended_comp_num--;
+                               
+                               dn->extended_components = talloc_realloc(dn,
+                                                  dn->extended_components,
+                                                  struct ldb_dn_extended_component,
+                                                  dn->extended_comp_num);
+                               if (!dn->extended_components) {
+                                       dn->invalid = true;
+                                       return LDB_ERR_OPERATIONS_ERROR;
+                               }
+                               return 0;
+                       }
+               }
+       }
+
+       p = dn->extended_components
+               = talloc_realloc(dn,
+                                dn->extended_components,
+                                struct ldb_dn_extended_component,
+                                dn->extended_comp_num + 1);
+       if (!dn->extended_components) {
+               dn->invalid = true;
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       p[dn->extended_comp_num].value = ldb_val_dup(dn->extended_components, val);
+       p[dn->extended_comp_num].name = talloc_strdup(p, name);
+       
+       if (!dn->extended_components[i].name || !dn->extended_components[i].value.data) {
+               dn->invalid = true;
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       dn->extended_components = p;
+       dn->extended_comp_num++;
+       
+       return 0;
+}
+
+void ldb_dn_remove_extended_components(struct ldb_dn *dn)
+{
+       dn->extended_comp_num = 0;
+       LDB_FREE(dn->extended_components);      
+}
+
 bool ldb_dn_is_valid(struct ldb_dn *dn)
 {
        if ( ! dn) return false;
@@ -1449,6 +1778,13 @@ bool ldb_dn_is_special(struct ldb_dn *dn)
        return dn->special;
 }
 
+bool ldb_dn_has_extended(struct ldb_dn *dn)
+{
+       if ( ! dn || dn->invalid) return false;
+       if (dn->extended_linearized && (dn->extended_linearized[0] == '<')) return true;
+       return dn->extended_comp_num != 0;
+}
+
 bool ldb_dn_check_special(struct ldb_dn *dn, const char *check)
 {
        if ( ! dn || dn->invalid) return false;
@@ -1458,6 +1794,7 @@ bool ldb_dn_check_special(struct ldb_dn *dn, const char *check)
 bool ldb_dn_is_null(struct ldb_dn *dn)
 {
        if ( ! dn || dn->invalid) return false;
+       if (ldb_dn_has_extended(dn)) return false;
        if (dn->linearized && (dn->linearized[0] == '\0')) return true;
        return false;
 }
index 69490e670bf98be466d2061f098e08534c3a6b92..92af72ce61fb58dac8214d9fa046320df72721cf 100644 (file)
@@ -278,13 +278,15 @@ int ldb_ldif_write(struct ldb_context *ldb,
        TALLOC_CTX *mem_ctx;
        unsigned int i, j;
        int total=0, ret;
+       char *p;
        const struct ldb_message *msg;
 
        mem_ctx = talloc_named_const(NULL, 0, "ldb_ldif_write");
 
        msg = ldif->msg;
-
-       ret = fprintf_fn(private_data, "dn: %s\n", ldb_dn_get_linearized(msg->dn));
+       p = ldb_dn_extended_linearized(mem_ctx, msg->dn, 1);
+       ret = fprintf_fn(private_data, "dn: %s\n", p);
+       talloc_free(p);
        CHECK_RET;
 
        if (ldif->changetype != LDB_CHANGETYPE_NONE) {
index 9bc5c183d842922d6cdab5f2af01d270507856c7..9399a015cd195fbf4a2ececcac197383d042f781 100644 (file)
@@ -326,7 +326,6 @@ typedef int (*ldb_attr_comparison_t)(struct ldb_context *, TALLOC_CTX *mem_ctx,
   attribute handler structure
 
   attr                 -> The attribute name
-  flags                        -> LDB_ATTR_FLAG_*
   ldif_read_fn         -> convert from ldif to binary format
   ldif_write_fn                -> convert from binary to ldif format
   canonicalise_fn      -> canonicalise a value, for use by indexing and dn construction
@@ -350,6 +349,16 @@ struct ldb_schema_attribute {
 const struct ldb_schema_attribute *ldb_schema_attribute_by_name(struct ldb_context *ldb,
                                                                const char *name);
 
+struct ldb_dn_extended_syntax {
+       const char *name;
+       ldb_attr_handler_t read_fn;
+       ldb_attr_handler_t write_clear_fn;
+       ldb_attr_handler_t write_hex_fn;
+};
+
+const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_context *ldb,
+                                                                   const char *name);
+
 /**
    The attribute is not returned by default
 */
@@ -1065,6 +1074,15 @@ int ldb_request_add_control(struct ldb_request *req, const char *oid, bool criti
 */
 struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char *oid);
 
+/**
+   check if a control with the specified "oid" exist and return it 
+  \param rep the reply struct where to add the control
+  \param oid the object identifier of the control as string
+
+  \return the control, NULL if not found 
+*/
+struct ldb_control *ldb_reply_get_control(struct ldb_reply *rep, const char *oid);
+
 /**
   Search the database
 
@@ -1736,5 +1754,15 @@ void ldb_qsort (void *const pbase, size_t total_elems, size_t size, void *opaque
    \return array of ldb_control elements
 */
 struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char **control_strings);
+char *ldb_dn_extended_linearized(void *mem_ctx, struct ldb_dn *dn, int mode);
+const struct ldb_val *ldb_dn_get_extended_component(struct ldb_dn *dn, const char *name);
+int ldb_dn_set_extended_component(struct ldb_dn *dn, const char *name, const struct ldb_val *val);
+
+void ldb_dn_remove_extended_components(struct ldb_dn *dn);
+bool ldb_dn_has_extended(struct ldb_dn *dn);
+
+int ldb_dn_extended_add_syntax(struct ldb_context *ldb, 
+                              unsigned flags,
+                              const struct ldb_dn_extended_syntax *syntax);
 
 #endif
index 8f7e010bee764bdbcd2c74a002a55dd2eba7a2f3..38818a9c4b4c1eb504ffa5c5e0ada576cbbe5bd5 100644 (file)
@@ -84,6 +84,9 @@ struct ldb_schema {
        /* attribute handling table */
        unsigned num_attributes;
        struct ldb_schema_attribute *attributes;
+
+       unsigned num_dn_extended_syntax;
+       struct ldb_dn_extended_syntax *dn_extended_syntax;
 };
 
 /*
index 6ecbfbfa08acf08bfc4d1c0fda660b59b9aa7ef9..a5ad78c4a964f55f078ac38e8de53ef462832715 100644 (file)
@@ -574,6 +574,8 @@ static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *
         if (ldif == NULL) {
             return Py_None;
         } else {
+           /* We don't want this attached to the 'ldb' any more */
+            talloc_steal(NULL, ldif);
             return Py_BuildValue((char *)"(iO)", ldif->changetype, 
                    SWIG_NewPointerObj(ldif->msg, SWIGTYPE_p_ldb_message, 0));
         }
index 4cf36441fd63852bba4f295404564e27c756d50b..0ef5034a635199121af3db468ea94741cc1cd38c 100644 (file)
@@ -1,5 +1,5 @@
 # This file was automatically generated by SWIG (http://www.swig.org).
-# Version 1.3.36
+# Version 1.3.35
 #
 # Don't modify this file, modify the SWIG interface instead.
 
index 93e81d42449cbb1f35c135f1cf567d7735b9f062..002983db26d64be9743f600a383bdc291337cfe9 100644 (file)
@@ -428,7 +428,7 @@ static int ildb_search(struct ildb_context *ac)
        if (req->op.search.base == NULL) {
                msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
        } else {
-               msg->r.SearchRequest.basedn  = ldb_dn_alloc_linearized(msg, req->op.search.base);
+               msg->r.SearchRequest.basedn  = ldb_dn_extended_linearized(msg, req->op.search.base, 0);
        }
        if (msg->r.SearchRequest.basedn == NULL) {
                ldb_set_errstring(ac->module->ldb, "Unable to determine baseDN");
@@ -473,7 +473,7 @@ static int ildb_add(struct ildb_context *ac)
 
        msg->type = LDAP_TAG_AddRequest;
 
-       msg->r.AddRequest.dn = ldb_dn_alloc_linearized(msg, req->op.add.message->dn);
+       msg->r.AddRequest.dn = ldb_dn_extended_linearized(msg, req->op.add.message->dn, 0);
        if (msg->r.AddRequest.dn == NULL) {
                talloc_free(msg);
                return LDB_ERR_INVALID_DN_SYNTAX;
@@ -516,7 +516,7 @@ static int ildb_modify(struct ildb_context *ac)
 
        msg->type = LDAP_TAG_ModifyRequest;
 
-       msg->r.ModifyRequest.dn = ldb_dn_alloc_linearized(msg, req->op.mod.message->dn);
+       msg->r.ModifyRequest.dn = ldb_dn_extended_linearized(msg, req->op.mod.message->dn, 0);
        if (msg->r.ModifyRequest.dn == NULL) {
                talloc_free(msg);
                return LDB_ERR_INVALID_DN_SYNTAX;
@@ -557,7 +557,7 @@ static int ildb_delete(struct ildb_context *ac)
 
        msg->type = LDAP_TAG_DelRequest;
 
-       msg->r.DelRequest.dn = ldb_dn_alloc_linearized(msg, req->op.del.dn);
+       msg->r.DelRequest.dn = ldb_dn_extended_linearized(msg, req->op.del.dn, 0);
        if (msg->r.DelRequest.dn == NULL) {
                talloc_free(msg);
                return LDB_ERR_INVALID_DN_SYNTAX;
@@ -580,7 +580,7 @@ static int ildb_rename(struct ildb_context *ac)
        }
 
        msg->type = LDAP_TAG_ModifyDNRequest;
-       msg->r.ModifyDNRequest.dn = ldb_dn_alloc_linearized(msg, req->op.rename.olddn);
+       msg->r.ModifyDNRequest.dn = ldb_dn_extended_linearized(msg, req->op.rename.olddn, 0);
        if (msg->r.ModifyDNRequest.dn == NULL) {
                talloc_free(msg);
                return LDB_ERR_INVALID_DN_SYNTAX;
index 3cf5ec613a7d5f4dd78cbf3ef41f086efd75da1e..78e85aaec77c644f5ca39790578485bc80bdcd6e 100644 (file)
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------------
  * This file was automatically generated by SWIG (http://www.swig.org).
- * Version 1.3.36
+ * Version 1.3.35
  * 
  * This file is not intended to be easily readable and contains a number of 
  * coding conventions designed to improve portability and efficiency. Do not make
 # endif
 #endif
 
-#ifndef SWIG_MSC_UNSUPPRESS_4505
-# if defined(_MSC_VER)
-#   pragma warning(disable : 4505) /* unreferenced local function has been removed */
-# endif 
-#endif
-
 #ifndef SWIGUNUSEDPARM
 # ifdef __cplusplus
 #   define SWIGUNUSEDPARM(p)
@@ -2497,7 +2491,7 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags)
 #define SWIGTYPE_p_ldb_parse_tree swig_types[11]
 #define SWIGTYPE_p_ldb_result swig_types[12]
 #define SWIGTYPE_p_ldb_val swig_types[13]
-#define SWIGTYPE_p_long_long swig_types[14]
+#define SWIGTYPE_p_long swig_types[14]
 #define SWIGTYPE_p_p_char swig_types[15]
 #define SWIGTYPE_p_p_ldb_control swig_types[16]
 #define SWIGTYPE_p_p_ldb_result swig_types[17]
@@ -2506,11 +2500,10 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags)
 #define SWIGTYPE_p_unsigned_char swig_types[20]
 #define SWIGTYPE_p_unsigned_int swig_types[21]
 #define SWIGTYPE_p_unsigned_long swig_types[22]
-#define SWIGTYPE_p_unsigned_long_long swig_types[23]
-#define SWIGTYPE_p_unsigned_short swig_types[24]
-#define SWIGTYPE_p_void swig_types[25]
-static swig_type_info *swig_types[27];
-static swig_module_info swig_module = {swig_types, 26, 0, 0, 0, 0};
+#define SWIGTYPE_p_unsigned_short swig_types[23]
+#define SWIGTYPE_p_void swig_types[24]
+static swig_type_info *swig_types[26];
+static swig_module_info swig_module = {swig_types, 25, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -2542,7 +2535,7 @@ static swig_module_info swig_module = {swig_types, 26, 0, 0, 0, 0};
 
 #define SWIG_name    "_ldb"
 
-#define SWIGVERSION 0x010336 
+#define SWIGVERSION 0x010335 
 #define SWIG_VERSION SWIGVERSION
 
 
@@ -3067,6 +3060,7 @@ static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *
         if (ldif == NULL) {
             return Py_None;
         } else {
+           talloc_steal(NULL, ldif);
             return Py_BuildValue((char *)"(iO)", ldif->changetype, 
                    SWIG_NewPointerObj(ldif->msg, SWIGTYPE_p_ldb_message, 0));
         }
@@ -3547,6 +3541,7 @@ SWIGINTERN PyObject *_wrap_ldb_val_to_py_object(PyObject *SWIGUNUSEDPARM(self),
   struct ldb_context *arg1 = (struct ldb_context *) 0 ;
   struct ldb_message_element *arg2 = (struct ldb_message_element *) 0 ;
   struct ldb_val *arg3 = (struct ldb_val *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -3559,7 +3554,6 @@ SWIGINTERN PyObject *_wrap_ldb_val_to_py_object(PyObject *SWIGUNUSEDPARM(self),
   char *  kwnames[] = {
     (char *) "ldb_ctx",(char *) "el",(char *) "val", NULL 
   };
-  PyObject *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:ldb_val_to_py_object",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -3592,6 +3586,7 @@ SWIGINTERN PyObject *_wrap_new_Dn(PyObject *SWIGUNUSEDPARM(self), PyObject *args
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
   char *arg2 = (char *) 0 ;
+  ldb_dn *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -3602,7 +3597,6 @@ SWIGINTERN PyObject *_wrap_new_Dn(PyObject *SWIGUNUSEDPARM(self), PyObject *args
   char *  kwnames[] = {
     (char *) "ldb_ctx",(char *) "str", NULL 
   };
-  ldb_dn *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:new_Dn",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -3643,6 +3637,7 @@ SWIGINTERN PyObject *_wrap_delete_Dn(PyObject *SWIGUNUSEDPARM(self), PyObject *a
   }
   arg1 = (ldb_dn *)(argp1);
   delete_ldb_dn(arg1);
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -3653,10 +3648,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn_validate(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  bool result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  bool result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3676,10 +3671,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn_get_casefold(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3699,10 +3694,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn___str__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3722,10 +3717,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn_parent(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  ldb_dn *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_dn *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3746,6 +3741,7 @@ SWIGINTERN PyObject *_wrap_Dn___cmp__(PyObject *SWIGUNUSEDPARM(self), PyObject *
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
   ldb_dn *arg2 = (ldb_dn *) 0 ;
+  int result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -3755,7 +3751,6 @@ SWIGINTERN PyObject *_wrap_Dn___cmp__(PyObject *SWIGUNUSEDPARM(self), PyObject *
   char *  kwnames[] = {
     (char *) "self",(char *) "other", NULL 
   };
-  int result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn___cmp__",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 |  0 );
@@ -3779,10 +3774,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn_is_valid(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  bool result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  bool result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3802,10 +3797,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn_is_special(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  bool result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  bool result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3825,10 +3820,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn_is_null(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  bool result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  bool result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3849,6 +3844,7 @@ SWIGINTERN PyObject *_wrap_Dn_check_special(PyObject *SWIGUNUSEDPARM(self), PyOb
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
   char *arg2 = (char *) 0 ;
+  bool result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -3859,7 +3855,6 @@ SWIGINTERN PyObject *_wrap_Dn_check_special(PyObject *SWIGUNUSEDPARM(self), PyOb
   char *  kwnames[] = {
     (char *) "self",(char *) "name", NULL 
   };
-  bool result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn_check_special",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 |  0 );
@@ -3885,10 +3880,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn___len__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  int result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  int result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3909,6 +3904,7 @@ SWIGINTERN PyObject *_wrap_Dn_add_child(PyObject *SWIGUNUSEDPARM(self), PyObject
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
   ldb_dn *arg2 = (ldb_dn *) 0 ;
+  bool result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -3918,7 +3914,6 @@ SWIGINTERN PyObject *_wrap_Dn_add_child(PyObject *SWIGUNUSEDPARM(self), PyObject
   char *  kwnames[] = {
     (char *) "self",(char *) "child", NULL 
   };
-  bool result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn_add_child",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 |  0 );
@@ -3943,6 +3938,7 @@ SWIGINTERN PyObject *_wrap_Dn_add_base(PyObject *SWIGUNUSEDPARM(self), PyObject
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
   ldb_dn *arg2 = (ldb_dn *) 0 ;
+  bool result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -3952,7 +3948,6 @@ SWIGINTERN PyObject *_wrap_Dn_add_base(PyObject *SWIGUNUSEDPARM(self), PyObject
   char *  kwnames[] = {
     (char *) "self",(char *) "base", NULL 
   };
-  bool result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn_add_base",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 |  0 );
@@ -3976,10 +3971,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn_canonical_str(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -3999,10 +3994,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn_canonical_ex_str(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4022,10 +4017,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Dn___repr__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4046,6 +4041,7 @@ SWIGINTERN PyObject *_wrap_Dn___add__(PyObject *SWIGUNUSEDPARM(self), PyObject *
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) 0 ;
   ldb_dn *arg2 = (ldb_dn *) 0 ;
+  ldb_dn *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -4055,7 +4051,6 @@ SWIGINTERN PyObject *_wrap_Dn___add__(PyObject *SWIGUNUSEDPARM(self), PyObject *
   char *  kwnames[] = {
     (char *) "self",(char *) "other", NULL 
   };
-  ldb_dn *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Dn___add__",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_dn, 0 |  0 );
@@ -4091,6 +4086,7 @@ SWIGINTERN PyObject *_wrap_MessageElement___cmp__(PyObject *SWIGUNUSEDPARM(self)
   PyObject *resultobj = 0;
   ldb_message_element *arg1 = (ldb_message_element *) 0 ;
   ldb_message_element *arg2 = (ldb_message_element *) 0 ;
+  int result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -4100,7 +4096,6 @@ SWIGINTERN PyObject *_wrap_MessageElement___cmp__(PyObject *SWIGUNUSEDPARM(self)
   char *  kwnames[] = {
     (char *) "self",(char *) "other", NULL 
   };
-  int result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:MessageElement___cmp__",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message_element, 0 |  0 );
@@ -4124,10 +4119,10 @@ fail:
 SWIGINTERN PyObject *_wrap_MessageElement___iter__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_message_element *arg1 = (ldb_message_element *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  PyObject *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4147,10 +4142,10 @@ fail:
 SWIGINTERN PyObject *_wrap_MessageElement___set__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_message_element *arg1 = (ldb_message_element *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  PyObject *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4172,6 +4167,7 @@ SWIGINTERN PyObject *_wrap_new_MessageElement(PyObject *SWIGUNUSEDPARM(self), Py
   PyObject *arg1 = (PyObject *) 0 ;
   int arg2 = (int) 0 ;
   char *arg3 = (char *) NULL ;
+  ldb_message_element *result = 0 ;
   int val2 ;
   int ecode2 = 0 ;
   int res3 ;
@@ -4183,7 +4179,6 @@ SWIGINTERN PyObject *_wrap_new_MessageElement(PyObject *SWIGUNUSEDPARM(self), Py
   char *  kwnames[] = {
     (char *) "set_obj",(char *) "flags",(char *) "name", NULL 
   };
-  ldb_message_element *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OO:new_MessageElement",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   arg1 = obj0;
@@ -4214,10 +4209,10 @@ fail:
 SWIGINTERN PyObject *_wrap_MessageElement___len__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_message_element *arg1 = (ldb_message_element *) 0 ;
+  int result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  int result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4238,6 +4233,7 @@ SWIGINTERN PyObject *_wrap_MessageElement_get(PyObject *SWIGUNUSEDPARM(self), Py
   PyObject *resultobj = 0;
   ldb_message_element *arg1 = (ldb_message_element *) 0 ;
   int arg2 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
@@ -4247,7 +4243,6 @@ SWIGINTERN PyObject *_wrap_MessageElement_get(PyObject *SWIGUNUSEDPARM(self), Py
   char *  kwnames[] = {
     (char *) "self",(char *) "i", NULL 
   };
-  PyObject *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:MessageElement_get",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message_element, 0 |  0 );
@@ -4283,6 +4278,7 @@ SWIGINTERN PyObject *_wrap_delete_MessageElement(PyObject *SWIGUNUSEDPARM(self),
   }
   arg1 = (ldb_message_element *)(argp1);
   delete_ldb_message_element(arg1);
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -4304,13 +4300,13 @@ SWIGINTERN PyObject *MessageElement_swiginit(PyObject *SWIGUNUSEDPARM(self), PyO
 SWIGINTERN PyObject *_wrap_ldb_msg_list_elements(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   ldb_msg *arg1 = (ldb_msg *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   char *  kwnames[] = {
     (char *) "msg", NULL 
   };
-  PyObject *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:ldb_msg_list_elements",kwnames,&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message, 0 |  0 );
@@ -4354,6 +4350,7 @@ SWIGINTERN PyObject *_wrap_Message_dn_set(PyObject *SWIGUNUSEDPARM(self), PyObje
   SWIG_exception(SWIG_ValueError, 
     "Message can not be None");
   if (arg1) (arg1)->dn = arg2;
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -4364,10 +4361,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Message_dn_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_msg *arg1 = (ldb_msg *) 0 ;
+  ldb_dn *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_dn *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4390,13 +4387,13 @@ fail:
 SWIGINTERN PyObject *_wrap_new_Message(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   ldb_dn *arg1 = (ldb_dn *) NULL ;
+  ldb_msg *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   char *  kwnames[] = {
     (char *) "dn", NULL 
   };
-  ldb_msg *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|O:new_Message",kwnames,&obj0)) SWIG_fail;
   if (obj0) {
@@ -4432,6 +4429,7 @@ SWIGINTERN PyObject *_wrap_delete_Message(PyObject *SWIGUNUSEDPARM(self), PyObje
   SWIG_exception(SWIG_ValueError, 
     "Message can not be None");
   delete_ldb_msg(arg1);
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -4443,6 +4441,7 @@ SWIGINTERN PyObject *_wrap_Message_find_element(PyObject *SWIGUNUSEDPARM(self),
   PyObject *resultobj = 0;
   ldb_msg *arg1 = (ldb_msg *) 0 ;
   char *arg2 = (char *) 0 ;
+  ldb_message_element *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -4453,7 +4452,6 @@ SWIGINTERN PyObject *_wrap_Message_find_element(PyObject *SWIGUNUSEDPARM(self),
   char *  kwnames[] = {
     (char *) "self",(char *) "name", NULL 
   };
-  ldb_message_element *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Message_find_element",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_message, 0 |  0 );
@@ -4596,10 +4594,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Message___len__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_msg *arg1 = (ldb_msg *) 0 ;
+  unsigned int result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  unsigned int result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4622,10 +4620,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Message_keys(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_msg *arg1 = (ldb_msg *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  PyObject *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4648,10 +4646,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Message___iter__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_msg *arg1 = (ldb_msg *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  PyObject *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4724,13 +4722,13 @@ SWIGINTERN PyObject *Message_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *
 SWIGINTERN PyObject *_wrap_ldb_ldif_to_pyobject(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   ldb_ldif *arg1 = (ldb_ldif *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   char *  kwnames[] = {
     (char *) "ldif", NULL 
   };
-  PyObject *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:ldb_ldif_to_pyobject",kwnames,&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_ldif, 0 |  0 );
@@ -4771,6 +4769,7 @@ SWIGINTERN PyObject *_wrap_Ldb_firstmodule_set(PyObject *SWIGUNUSEDPARM(self), P
   SWIG_exception(SWIG_ValueError, 
     "ldb context must be non-NULL");
   if (arg1) (arg1)->modules = arg2;
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -4781,10 +4780,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_firstmodule_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  struct ldb_module *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  struct ldb_module *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -4823,6 +4822,7 @@ SWIGINTERN PyObject *_wrap_Ldb_connect(PyObject *SWIGUNUSEDPARM(self), PyObject
   char *arg2 = (char *) 0 ;
   unsigned int arg3 = (unsigned int) 0 ;
   char **arg4 = (char **) (char **)NULL ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -4839,7 +4839,6 @@ SWIGINTERN PyObject *_wrap_Ldb_connect(PyObject *SWIGUNUSEDPARM(self), PyObject
   char *  kwnames[] = {
     (char *) "self",(char *) "url",(char *) "flags",(char *) "options", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|OO:Ldb_connect",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -4901,6 +4900,7 @@ SWIGINTERN PyObject *_wrap_delete_Ldb(PyObject *SWIGUNUSEDPARM(self), PyObject *
   SWIG_exception(SWIG_ValueError, 
     "ldb context must be non-NULL");
   delete_ldb(arg1);
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -4918,6 +4918,7 @@ SWIGINTERN PyObject *_wrap_Ldb_search_ex(PyObject *SWIGUNUSEDPARM(self), PyObjec
   char **arg6 = (char **) NULL ;
   struct ldb_control **arg7 = (struct ldb_control **) NULL ;
   struct ldb_result **arg8 = (struct ldb_result **) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val4 ;
@@ -4938,7 +4939,6 @@ SWIGINTERN PyObject *_wrap_Ldb_search_ex(PyObject *SWIGUNUSEDPARM(self), PyObjec
   char *  kwnames[] = {
     (char *) "self",(char *) "base",(char *) "scope",(char *) "expression",(char *) "attrs",(char *) "controls", NULL 
   };
-  ldb_error result;
   
   arg2 = NULL;
   arg8 = &temp_ldb_result8;
@@ -5022,6 +5022,7 @@ SWIGINTERN PyObject *_wrap_Ldb_delete(PyObject *SWIGUNUSEDPARM(self), PyObject *
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
   ldb_dn *arg2 = (ldb_dn *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
@@ -5029,7 +5030,6 @@ SWIGINTERN PyObject *_wrap_Ldb_delete(PyObject *SWIGUNUSEDPARM(self), PyObject *
   char *  kwnames[] = {
     (char *) "self",(char *) "dn", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_delete",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5062,6 +5062,7 @@ SWIGINTERN PyObject *_wrap_Ldb_rename(PyObject *SWIGUNUSEDPARM(self), PyObject *
   ldb *arg1 = (ldb *) 0 ;
   ldb_dn *arg2 = (ldb_dn *) 0 ;
   ldb_dn *arg3 = (ldb_dn *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
@@ -5070,7 +5071,6 @@ SWIGINTERN PyObject *_wrap_Ldb_rename(PyObject *SWIGUNUSEDPARM(self), PyObject *
   char *  kwnames[] = {
     (char *) "self",(char *) "olddn",(char *) "newdn", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Ldb_rename",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5108,6 +5108,7 @@ SWIGINTERN PyObject *_wrap_Ldb_parse_control_strings(PyObject *SWIGUNUSEDPARM(se
   ldb *arg1 = (ldb *) 0 ;
   TALLOC_CTX *arg2 = (TALLOC_CTX *) 0 ;
   char **arg3 = (char **) 0 ;
+  struct ldb_control **result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
@@ -5115,7 +5116,6 @@ SWIGINTERN PyObject *_wrap_Ldb_parse_control_strings(PyObject *SWIGUNUSEDPARM(se
   char *  kwnames[] = {
     (char *) "self",(char *) "control_strings", NULL 
   };
-  struct ldb_control **result = 0 ;
   
   arg2 = NULL;
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_parse_control_strings",kwnames,&obj0,&obj1)) SWIG_fail;
@@ -5156,6 +5156,7 @@ SWIGINTERN PyObject *_wrap_Ldb_add(PyObject *SWIGUNUSEDPARM(self), PyObject *arg
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
   ldb_msg *arg2 = (ldb_msg *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
@@ -5163,7 +5164,6 @@ SWIGINTERN PyObject *_wrap_Ldb_add(PyObject *SWIGUNUSEDPARM(self), PyObject *arg
   char *  kwnames[] = {
     (char *) "self",(char *) "add_msg", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_add",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5236,6 +5236,7 @@ SWIGINTERN PyObject *_wrap_Ldb_modify(PyObject *SWIGUNUSEDPARM(self), PyObject *
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
   ldb_msg *arg2 = (ldb_msg *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -5245,7 +5246,6 @@ SWIGINTERN PyObject *_wrap_Ldb_modify(PyObject *SWIGUNUSEDPARM(self), PyObject *
   char *  kwnames[] = {
     (char *) "self",(char *) "message", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_modify",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5279,10 +5279,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_get_config_basedn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  ldb_dn *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_dn *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5305,10 +5305,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_get_root_basedn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  ldb_dn *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_dn *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5331,10 +5331,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_get_schema_basedn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  ldb_dn *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_dn *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5357,10 +5357,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_get_default_basedn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  ldb_dn *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_dn *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5385,6 +5385,7 @@ SWIGINTERN PyObject *_wrap_Ldb_schema_format_value(PyObject *SWIGUNUSEDPARM(self
   ldb *arg1 = (ldb *) 0 ;
   char *arg2 = (char *) 0 ;
   PyObject *arg3 = (PyObject *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -5396,7 +5397,6 @@ SWIGINTERN PyObject *_wrap_Ldb_schema_format_value(PyObject *SWIGUNUSEDPARM(self
   char *  kwnames[] = {
     (char *) "self",(char *) "element_name",(char *) "val", NULL 
   };
-  PyObject *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Ldb_schema_format_value",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5426,10 +5426,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_errstring(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5529,6 +5529,7 @@ SWIGINTERN PyObject *_wrap_Ldb_set_debug(PyObject *SWIGUNUSEDPARM(self), PyObjec
   ldb *arg1 = (ldb *) 0 ;
   void (*arg2)(void *,enum ldb_debug_level,char const *,va_list) = (void (*)(void *,enum ldb_debug_level,char const *,va_list)) 0 ;
   void *arg3 = (void *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
@@ -5536,7 +5537,6 @@ SWIGINTERN PyObject *_wrap_Ldb_set_debug(PyObject *SWIGUNUSEDPARM(self), PyObjec
   char *  kwnames[] = {
     (char *) "self",(char *) "debug", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_set_debug",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5569,6 +5569,7 @@ SWIGINTERN PyObject *_wrap_Ldb_set_opaque(PyObject *SWIGUNUSEDPARM(self), PyObje
   ldb *arg1 = (ldb *) 0 ;
   char *arg2 = (char *) 0 ;
   void *arg3 = (void *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -5581,7 +5582,6 @@ SWIGINTERN PyObject *_wrap_Ldb_set_opaque(PyObject *SWIGUNUSEDPARM(self), PyObje
   char *  kwnames[] = {
     (char *) "self",(char *) "name",(char *) "value", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Ldb_set_opaque",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5619,6 +5619,7 @@ SWIGINTERN PyObject *_wrap_Ldb_get_opaque(PyObject *SWIGUNUSEDPARM(self), PyObje
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
   char *arg2 = (char *) 0 ;
+  void *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -5629,7 +5630,6 @@ SWIGINTERN PyObject *_wrap_Ldb_get_opaque(PyObject *SWIGUNUSEDPARM(self), PyObje
   char *  kwnames[] = {
     (char *) "self",(char *) "name", NULL 
   };
-  void *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_get_opaque",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5658,10 +5658,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_transaction_start(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_error result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5688,10 +5688,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_transaction_commit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_error result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5718,10 +5718,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_transaction_cancel(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_error result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5790,6 +5790,7 @@ SWIGINTERN PyObject *_wrap_Ldb_schema_attribute_add(PyObject *SWIGUNUSEDPARM(sel
   char *arg2 = (char *) 0 ;
   unsigned int arg3 ;
   char *arg4 = (char *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -5807,7 +5808,6 @@ SWIGINTERN PyObject *_wrap_Ldb_schema_attribute_add(PyObject *SWIGUNUSEDPARM(sel
   char *  kwnames[] = {
     (char *) "self",(char *) "attribute",(char *) "flags",(char *) "syntax", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOO:Ldb_schema_attribute_add",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5852,10 +5852,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb_setup_wellknown_attributes(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_error result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -5884,6 +5884,7 @@ SWIGINTERN PyObject *_wrap_Ldb___contains__(PyObject *SWIGUNUSEDPARM(self), PyOb
   ldb *arg1 = (ldb *) 0 ;
   ldb_dn *arg2 = (ldb_dn *) 0 ;
   struct ldb_result **arg3 = (struct ldb_result **) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   struct ldb_result *tmp3 ;
@@ -5892,7 +5893,6 @@ SWIGINTERN PyObject *_wrap_Ldb___contains__(PyObject *SWIGUNUSEDPARM(self), PyOb
   char *  kwnames[] = {
     (char *) "self",(char *) "dn", NULL 
   };
-  ldb_error result;
   
   arg3 = &tmp3;
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb___contains__",kwnames,&obj0,&obj1)) SWIG_fail;
@@ -5928,6 +5928,7 @@ SWIGINTERN PyObject *_wrap_Ldb_parse_ldif(PyObject *SWIGUNUSEDPARM(self), PyObje
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
   char *arg2 = (char *) 0 ;
+  PyObject *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -5938,7 +5939,6 @@ SWIGINTERN PyObject *_wrap_Ldb_parse_ldif(PyObject *SWIGUNUSEDPARM(self), PyObje
   char *  kwnames[] = {
     (char *) "self",(char *) "s", NULL 
   };
-  PyObject *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Ldb_parse_ldif",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 |  0 );
@@ -5967,10 +5967,10 @@ fail:
 SWIGINTERN PyObject *_wrap_Ldb___repr__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb *arg1 = (ldb *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -6004,6 +6004,7 @@ SWIGINTERN PyObject *Ldb_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args
 SWIGINTERN PyObject *_wrap_valid_attr_name(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   char *arg1 = (char *) 0 ;
+  int result;
   int res1 ;
   char *buf1 = 0 ;
   int alloc1 = 0 ;
@@ -6011,7 +6012,6 @@ SWIGINTERN PyObject *_wrap_valid_attr_name(PyObject *SWIGUNUSEDPARM(self), PyObj
   char *  kwnames[] = {
     (char *) "s", NULL 
   };
-  int result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:valid_attr_name",kwnames,&obj0)) SWIG_fail;
   res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
@@ -6032,13 +6032,13 @@ fail:
 SWIGINTERN PyObject *_wrap_timestring(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   time_t arg1 ;
+  char *result = 0 ;
   unsigned long val1 ;
   int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
   char *  kwnames[] = {
     (char *) "t", NULL 
   };
-  char *result = 0 ;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:timestring",kwnames,&obj0)) SWIG_fail;
   ecode1 = SWIG_AsVal_unsigned_SS_long(obj0, &val1);
@@ -6057,6 +6057,7 @@ fail:
 SWIGINTERN PyObject *_wrap_string_to_time(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   char *arg1 = (char *) 0 ;
+  time_t result;
   int res1 ;
   char *buf1 = 0 ;
   int alloc1 = 0 ;
@@ -6064,7 +6065,6 @@ SWIGINTERN PyObject *_wrap_string_to_time(PyObject *SWIGUNUSEDPARM(self), PyObje
   char *  kwnames[] = {
     (char *) "s", NULL 
   };
-  time_t result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:string_to_time",kwnames,&obj0)) SWIG_fail;
   res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
@@ -6104,6 +6104,7 @@ SWIGINTERN PyObject *_wrap_ldb_module_prev_set(PyObject *SWIGUNUSEDPARM(self), P
   }
   arg2 = (struct ldb_module *)(argp2);
   if (arg1) (arg1)->prev = arg2;
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -6114,10 +6115,10 @@ fail:
 SWIGINTERN PyObject *_wrap_ldb_module_prev_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
+  struct ldb_module *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  struct ldb_module *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -6156,6 +6157,7 @@ SWIGINTERN PyObject *_wrap_ldb_module_next_set(PyObject *SWIGUNUSEDPARM(self), P
   }
   arg2 = (struct ldb_module *)(argp2);
   if (arg1) (arg1)->next = arg2;
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -6166,10 +6168,10 @@ fail:
 SWIGINTERN PyObject *_wrap_ldb_module_next_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
+  struct ldb_module *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  struct ldb_module *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -6189,10 +6191,10 @@ fail:
 SWIGINTERN PyObject *_wrap_ldb_module___str__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -6212,10 +6214,10 @@ fail:
 SWIGINTERN PyObject *_wrap_ldb_module___repr__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
+  char *result = 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  char *result = 0 ;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -6240,6 +6242,7 @@ SWIGINTERN PyObject *_wrap_ldb_module_search(PyObject *SWIGUNUSEDPARM(self), PyO
   struct ldb_parse_tree *arg4 = (struct ldb_parse_tree *) 0 ;
   char **arg5 = (char **) 0 ;
   struct ldb_result **arg6 = (struct ldb_result **) 0 ;
+  int result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -6258,7 +6261,6 @@ SWIGINTERN PyObject *_wrap_ldb_module_search(PyObject *SWIGUNUSEDPARM(self), PyO
   char *  kwnames[] = {
     (char *) "self",(char *) "base",(char *) "scope",(char *) "tree",(char *) "attrs", NULL 
   };
-  int result;
   
   arg6 = &temp_ldb_result6;
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOO:ldb_module_search",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
@@ -6317,6 +6319,7 @@ SWIGINTERN PyObject *_wrap_ldb_module_add(PyObject *SWIGUNUSEDPARM(self), PyObje
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
   struct ldb_message *arg2 = (struct ldb_message *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -6326,7 +6329,6 @@ SWIGINTERN PyObject *_wrap_ldb_module_add(PyObject *SWIGUNUSEDPARM(self), PyObje
   char *  kwnames[] = {
     (char *) "self",(char *) "message", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:ldb_module_add",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_module, 0 |  0 );
@@ -6355,6 +6357,7 @@ SWIGINTERN PyObject *_wrap_ldb_module_modify(PyObject *SWIGUNUSEDPARM(self), PyO
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
   struct ldb_message *arg2 = (struct ldb_message *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -6364,7 +6367,6 @@ SWIGINTERN PyObject *_wrap_ldb_module_modify(PyObject *SWIGUNUSEDPARM(self), PyO
   char *  kwnames[] = {
     (char *) "self",(char *) "message", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:ldb_module_modify",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_module, 0 |  0 );
@@ -6393,6 +6395,7 @@ SWIGINTERN PyObject *_wrap_ldb_module_delete(PyObject *SWIGUNUSEDPARM(self), PyO
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
   struct ldb_dn *arg2 = (struct ldb_dn *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -6402,7 +6405,6 @@ SWIGINTERN PyObject *_wrap_ldb_module_delete(PyObject *SWIGUNUSEDPARM(self), PyO
   char *  kwnames[] = {
     (char *) "self",(char *) "dn", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:ldb_module_delete",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_module, 0 |  0 );
@@ -6432,6 +6434,7 @@ SWIGINTERN PyObject *_wrap_ldb_module_rename(PyObject *SWIGUNUSEDPARM(self), PyO
   ldb_module *arg1 = (ldb_module *) 0 ;
   struct ldb_dn *arg2 = (struct ldb_dn *) 0 ;
   struct ldb_dn *arg3 = (struct ldb_dn *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
@@ -6444,7 +6447,6 @@ SWIGINTERN PyObject *_wrap_ldb_module_rename(PyObject *SWIGUNUSEDPARM(self), PyO
   char *  kwnames[] = {
     (char *) "self",(char *) "olddn",(char *) "newdn", NULL 
   };
-  ldb_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:ldb_module_rename",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_module, 0 |  0 );
@@ -6477,10 +6479,10 @@ fail:
 SWIGINTERN PyObject *_wrap_ldb_module_start_transaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_error result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -6504,10 +6506,10 @@ fail:
 SWIGINTERN PyObject *_wrap_ldb_module_end_transaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_error result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -6531,10 +6533,10 @@ fail:
 SWIGINTERN PyObject *_wrap_ldb_module_del_transaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   ldb_module *arg1 = (ldb_module *) 0 ;
+  ldb_error result;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject *swig_obj[1] ;
-  ldb_error result;
   
   if (!args) SWIG_fail;
   swig_obj[0] = args;
@@ -6583,6 +6585,7 @@ SWIGINTERN PyObject *_wrap_delete_ldb_module(PyObject *SWIGUNUSEDPARM(self), PyO
   }
   arg1 = (ldb_module *)(argp1);
   free((char *) arg1);
+  
   resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
@@ -6604,11 +6607,11 @@ SWIGINTERN PyObject *ldb_module_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObjec
 SWIGINTERN PyObject *_wrap_register_module(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   struct ldb_module_ops *arg1 = (struct ldb_module_ops *) 0 ;
+  ldb_int_error result;
   PyObject * obj0 = 0 ;
   char *  kwnames[] = {
     (char *)"arg1", NULL 
   };
-  ldb_int_error result;
   
   if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:register_module",kwnames,&obj0)) SWIG_fail;
   arg1 = talloc_zero(talloc_autofree_context(), struct ldb_module_ops);
@@ -6833,7 +6836,7 @@ static PyMethodDef SwigMethods[] = {
 static swig_type_info _swigt__p_TALLOC_CTX = {"_p_TALLOC_CTX", "TALLOC_CTX *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void = {"_p_f_p_void_enum_ldb_debug_level_p_q_const__char_va_list__void", "void (*)(void *,enum ldb_debug_level,char const *,va_list)", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "int *|int_least32_t *|int32_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ldb_context = {"_p_ldb_context", "struct ldb_context *|ldb *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ldb_dn = {"_p_ldb_dn", "struct ldb_dn *|ldb_dn *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ldb_ldif = {"_p_ldb_ldif", "struct ldb_ldif *|ldb_ldif *", 0, 0, (void*)0, 0};
@@ -6844,16 +6847,15 @@ static swig_type_info _swigt__p_ldb_module_ops = {"_p_ldb_module_ops", "struct l
 static swig_type_info _swigt__p_ldb_parse_tree = {"_p_ldb_parse_tree", "struct ldb_parse_tree *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ldb_result = {"_p_ldb_result", "struct ldb_result *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ldb_val = {"_p_ldb_val", "struct ldb_val *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_long = {"_p_long", "intptr_t *|int_least64_t *|int_fast32_t *|int_fast64_t *|int64_t *|long *|int_fast16_t *|intmax_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_ldb_control = {"_p_p_ldb_control", "struct ldb_control **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_ldb_result = {"_p_p_ldb_result", "struct ldb_result **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_unsigned_long = {"_p_unsigned_long", "unsigned long *|time_t *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uint_least32_t *|uint32_t *|unsigned int *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_unsigned_long = {"_p_unsigned_long", "uintptr_t *|uint_least64_t *|uint_fast32_t *|uint_fast64_t *|uint64_t *|unsigned long *|time_t *|uint_fast16_t *|uintmax_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_void = {"_p_void", "void *", 0, 0, (void*)0, 0};
 
@@ -6872,7 +6874,7 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_ldb_parse_tree,
   &_swigt__p_ldb_result,
   &_swigt__p_ldb_val,
-  &_swigt__p_long_long,
+  &_swigt__p_long,
   &_swigt__p_p_char,
   &_swigt__p_p_ldb_control,
   &_swigt__p_p_ldb_result,
@@ -6881,7 +6883,6 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_unsigned_char,
   &_swigt__p_unsigned_int,
   &_swigt__p_unsigned_long,
-  &_swigt__p_unsigned_long_long,
   &_swigt__p_unsigned_short,
   &_swigt__p_void,
 };
@@ -6900,7 +6901,7 @@ static swig_cast_info _swigc__p_ldb_module_ops[] = {  {&_swigt__p_ldb_module_ops
 static swig_cast_info _swigc__p_ldb_parse_tree[] = {  {&_swigt__p_ldb_parse_tree, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ldb_result[] = {  {&_swigt__p_ldb_result, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ldb_val[] = {  {&_swigt__p_ldb_val, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_long_long[] = {  {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_long[] = {  {&_swigt__p_long, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_ldb_control[] = {  {&_swigt__p_p_ldb_control, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_ldb_result[] = {  {&_swigt__p_p_ldb_result, 0, 0, 0},{0, 0, 0, 0}};
@@ -6909,7 +6910,6 @@ static swig_cast_info _swigc__p_signed_char[] = {  {&_swigt__p_signed_char, 0, 0
 static swig_cast_info _swigc__p_unsigned_char[] = {  {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_unsigned_int[] = {  {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_unsigned_long[] = {  {&_swigt__p_unsigned_long, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_unsigned_long_long[] = {  {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_unsigned_short[] = {  {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_void[] = {  {&_swigt__p_void, 0, 0, 0},{0, 0, 0, 0}};
 
@@ -6928,7 +6928,7 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_ldb_parse_tree,
   _swigc__p_ldb_result,
   _swigc__p_ldb_val,
-  _swigc__p_long_long,
+  _swigc__p_long,
   _swigc__p_p_char,
   _swigc__p_p_ldb_control,
   _swigc__p_p_ldb_result,
@@ -6937,7 +6937,6 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_unsigned_char,
   _swigc__p_unsigned_int,
   _swigc__p_unsigned_long,
-  _swigc__p_unsigned_long_long,
   _swigc__p_unsigned_short,
   _swigc__p_void,
 };
index 71fd98876eb1248faab2aa51cb3c59aa5013e94e..5c11d1fda9ed11d9f01d9684e3e20f491baff0dd 100755 (executable)
@@ -436,7 +436,13 @@ member: cn=ldaptestuser3,cn=users,""" + self.base_dn + """
 
         print "Testing Renames"
 
-        ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
+        attrs = ["objectGUID", "objectSid"]
+        print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
+        res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
+        self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
+
+        #Check rename works with extended/alternate DN forms 
+        ldb.rename("<SID=" + ldb.schema_format_value("objectSID", res_user[0]["objectSID"][0]) + ">" , "cn=ldaptestuser3,cn=users," + self.base_dn)
 
         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
 
@@ -585,7 +591,7 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
 
         print "Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)) to check subtree renames and linked attributes"
         res = ldb.search(self.base_dn, expression="(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group))", scope=SCOPE_SUBTREE)
-        self.assertEquals(len(res), 1, "Could not find (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)), perhaps linked attributes are not conistant with subtree renames?")
+        self.assertEquals(len(res), 1, "Could not find (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)), perhaps linked attributes are not consistant with subtree renames?")
 
         print "Testing ldb.rename (into itself) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn
         try:
@@ -737,8 +743,8 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
         self.assertEquals(len(res6), 1, "Could not find (&(cn=*daptestcomputer)(objectCategory=compuTER))")
 
         self.assertEquals(res[0].dn, res6[0].dn)
-
-        ldb.delete(res[0].dn)
+        
+        ldb.delete("<GUID=" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + ">")
 
         print "Testing ldb.search for (&(cn=ldaptest2computer)(objectClass=user))"
         res = ldb.search(expression="(&(cn=ldaptest2computer)(objectClass=user))")
@@ -754,25 +760,26 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
         self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306369)
         self.assertEquals(int(res[0]["userAccountControl"][0]), 4096)
 
-        ldb.delete(res[0].dn)
+        ldb.delete("<SID=" + ldb.schema_format_value("objectSID", res[0]["objectSID"][0]) + ">")
 
-        attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "memberOf", "allowedAttributes", "allowedAttributesEffective"]
+        attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "memberOf", "allowedAttributes", "allowedAttributesEffective"]
         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
-        res = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
-        self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
-
-        self.assertEquals(res[0].dn, ("CN=ldaptestuser2,CN=Users," + self.base_dn))
-        self.assertEquals(res[0]["cn"], "ldaptestuser2")
-        self.assertEquals(res[0]["name"], "ldaptestuser2")
-        self.assertEquals(res[0]["objectClass"], ["top", "person", "organizationalPerson", "user"])
-        self.assertTrue("objectGUID" in res[0])
-        self.assertTrue("whenCreated" in res[0])
-        self.assertTrue("nTSecurityDescriptor" in res[0])
-        self.assertTrue("allowedAttributes" in res[0])
-        self.assertTrue("allowedAttributesEffective" in res[0])
-        self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
-
-        attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member", "allowedAttributes", "allowedAttributesEffective"]
+        res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
+        self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
+
+        self.assertEquals(res_user[0].dn, ("CN=ldaptestuser2,CN=Users," + self.base_dn))
+        self.assertEquals(res_user[0]["cn"], "ldaptestuser2")
+        self.assertEquals(res_user[0]["name"], "ldaptestuser2")
+        self.assertEquals(res_user[0]["objectClass"], ["top", "person", "organizationalPerson", "user"])
+        self.assertTrue("objectSid" in res_user[0])
+        self.assertTrue("objectGUID" in res_user[0])
+        self.assertTrue("whenCreated" in res_user[0])
+        self.assertTrue("nTSecurityDescriptor" in res_user[0])
+        self.assertTrue("allowedAttributes" in res_user[0])
+        self.assertTrue("allowedAttributesEffective" in res_user[0])
+        self.assertEquals(res_user[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
+
+        attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "member", "allowedAttributes", "allowedAttributesEffective"]
         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group))"
         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
@@ -781,7 +788,8 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
         self.assertEquals(res[0]["cn"], "ldaptestgroup2")
         self.assertEquals(res[0]["name"], "ldaptestgroup2")
         self.assertEquals(res[0]["objectClass"], ["top", "group"])
-        self.assertTrue("objectGuid" not in res[0])
+        self.assertTrue("objectGUID" in res[0])
+        self.assertTrue("objectSid" in res[0])
         self.assertTrue("whenCreated" in res[0])
         self.assertTrue("nTSecurityDescriptor" in res[0])
         self.assertTrue("allowedAttributes" in res[0])
@@ -791,6 +799,7 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
             memberUP.append(m.upper())
         self.assertTrue(("CN=ldaptestuser2,CN=Users," + self.base_dn).upper() in memberUP)
 
+        print "Testing Linked attribute behaviours"
         ldb.modify_ldif("""
 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
 changetype: modify
@@ -799,9 +808,15 @@ member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """
 member: CN=ldaptestutf8user Ã¨Ã¹Ã©Ã¬Ã²Ã ,CN=Users,""" + self.base_dn + """
 """)
         
-        print "Testing Linked attribute behaviours"
         ldb.modify_ldif("""
-dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
+dn: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
+changetype: modify
+replace: member
+member: CN=ldaptestutf8user Ã¨Ã¹Ã©Ã¬Ã²Ã ,CN=Users,""" + self.base_dn + """
+""")
+        
+        ldb.modify_ldif("""
+dn: <SID=""" + ldb.schema_format_value("objectSid", res[0]["objectSid"][0]) + """>
 changetype: modify
 delete: member
 """)
@@ -810,7 +825,7 @@ delete: member
 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
 changetype: modify
 add: member
-member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """
+member: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
 member: CN=ldaptestutf8user Ã¨Ã¹Ã©Ã¬Ã²Ã ,CN=Users,""" + self.base_dn + """
 """)
         
@@ -824,7 +839,7 @@ replace: member
 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
 changetype: modify
 add: member
-member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """
+member: <SID=""" + ldb.schema_format_value("objectSid", res_user[0]["objectSid"][0]) + """>
 member: CN=ldaptestutf8user Ã¨Ã¹Ã©Ã¬Ã²Ã ,CN=Users,""" + self.base_dn + """
 """)
         
index 87c89daf9f47301a2665f2011bf24122c0028ce6..589b29f13480e7602f7d1bb4eba784503f55749d 100644 (file)
@@ -504,9 +504,9 @@ static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
        return result;
 }
 
-static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
-                                        struct asn1_data *data,
-                                        const char **result)
+bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
+                                 struct asn1_data *data,
+                                 const char **result)
 {
        DATA_BLOB string;
        if (!asn1_read_OctetString(data, mem_ctx, &string))
@@ -911,9 +911,9 @@ static void ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
        
 }
 
-static void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
-                               struct ldb_message_element **attributes,
-                               int *num_attributes)
+void ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+                        struct ldb_message_element **attributes,
+                        int *num_attributes)
 {
        asn1_start_tag(data, ASN1_SEQUENCE(0));
        while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
index 930d97c40d0b2b3a0765c3a3fc27d5bfe596aeee..1f2d0d41249932d8bc9a0cbb3ebefeaa9360a2af 100644 (file)
@@ -24,6 +24,7 @@
 #include "libcli/ldap/ldap.h"
 #include "lib/ldb/include/ldb.h"
 #include "libcli/ldap/ldap_proto.h"
+#include "dsdb/samdb/samdb.h"
 
 struct control_handler {
        const char *oid;
@@ -1087,6 +1088,101 @@ static bool encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out)
        return true;
 }
 
+static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out)
+{
+       struct dsdb_openldap_dereference_control *control = talloc_get_type(in, struct dsdb_openldap_dereference_control);
+       int i,j;
+       struct asn1_data *data = asn1_init(mem_ctx);
+
+       if (!data) return false;
+       
+       if (!control) return false;
+       
+       if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+               return false;
+       }
+       
+       for (i=0; control->dereference && control->dereference[i]; i++) {
+               if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+                       return false;
+               }
+               if (!asn1_write_OctetString(data, control->dereference[i]->source_attribute, strlen(control->dereference[i]->source_attribute))) {
+                       return false;
+               }
+               if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+                       return false;
+               }
+               for (j=0; control->dereference && control->dereference[i]->dereference_attribute[j]; j++) {
+                       if (!asn1_write_OctetString(data, control->dereference[i]->dereference_attribute[j], 
+                                                   strlen(control->dereference[i]->dereference_attribute[j]))) {
+                               return false;
+                       }
+               }
+               
+               asn1_pop_tag(data);
+               asn1_pop_tag(data);
+       }
+       asn1_pop_tag(data);
+       return true;
+}
+
+static bool decode_openldap_dereference(void *mem_ctx, DATA_BLOB in, void **out)
+{
+       struct asn1_data *data = asn1_init(mem_ctx);
+       struct dsdb_openldap_dereference_result_control *control;
+       struct dsdb_openldap_dereference_result **r;
+       int i = 0;
+       if (!data) return false;
+
+       control = talloc(mem_ctx, struct dsdb_openldap_dereference_result_control);
+       if (!control) return false;
+
+       r = control->attributes = talloc_array(control, struct dsdb_openldap_dereference_result *, 0);
+       if (!r) return false;
+               
+       if (!asn1_load(data, in)) {
+               return false;
+       }
+
+       control = talloc(mem_ctx, struct dsdb_openldap_dereference_result_control);
+       if (!control) {
+               return false;
+       }
+
+       if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+               return false;
+       }
+
+       while (asn1_tag_remaining(data) > 0) {                                  
+               i++;
+               r = talloc_realloc(r, control, struct dsdb_openldap_dereference_result *, i + 1);
+               
+               r[i] = talloc(r, struct dsdb_openldap_dereference_result);
+
+               if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+                       return false;
+               }
+               
+               asn1_read_OctetString_talloc(r[i], data, &r[i]->source_attribute);
+               asn1_read_OctetString_talloc(r[i], data, &r[i]->dereferenced_dn);
+               ldap_decode_attribs(r[i], data, &r[i]->attributes,
+                                   &r[i]->num_attributes);
+               
+               if (!asn1_end_tag(data)) {
+                       return false;
+               }
+               r[i+1] = NULL;
+       }
+
+       if (!asn1_end_tag(data)) {
+               return false;
+       }
+
+       *out = control;
+
+       return true;
+}
+
 struct control_handler ldap_known_controls[] = {
        { "1.2.840.113556.1.4.319", decode_paged_results_request, encode_paged_results_request },
        { "1.2.840.113556.1.4.529", decode_extended_dn_request, encode_extended_dn_request },
@@ -1107,6 +1203,7 @@ struct control_handler ldap_known_controls[] = {
        { "1.3.6.1.4.1.7165.4.3.2", NULL, NULL },
 /* DSDB_EXTENDED_REPLICATED_OBJECTS_OID is internal only, and has no network representation */
        { "1.3.6.1.4.1.7165.4.4.1", NULL, NULL },
+       { DSDB_OPENLDAP_DEREFERENCE_CONTROL, decode_openldap_dereference, encode_openldap_dereference},
        { NULL, NULL, NULL }
 };
 
index 823d5e6ff6778ab00218717c33ec250d075386d7..963410e03d9bc991c91c88de4baffa8841773640 100644 (file)
@@ -459,8 +459,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
                     "ranged_results",
                     "anr",
                     "server_sort",
-                    "extended_dn",
                     "asq",
+                    "extended_dn_store",
+                    "extended_dn_in",
                     "rdn_name",
                     "objectclass",
                     "samldb",
@@ -470,9 +471,10 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
     tdb_modules_list = [
                     "subtree_rename",
                     "subtree_delete",
-                    "linked_attributes"]
+                    "linked_attributes",
+                    "extended_dn_out_ldb"]
     modules_list2 = ["show_deleted",
-                    "partition"]
+                     "partition"]
  
     domaindn_ldb = "users.ldb"
     if ldap_backend is not None:
@@ -488,11 +490,11 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
     if ldap_backend_type == "fedora-ds":
         backend_modules = ["nsuniqueid", "paged_searches"]
         # We can handle linked attributes here, as we don't have directory-side subtree operations
-        tdb_modules_list = ["linked_attributes"]
+        tdb_modules_list = ["linked_attributes", "extended_dn_out_dereference"]
     elif ldap_backend_type == "openldap":
         backend_modules = ["normalise", "entryuuid", "paged_searches"]
         # OpenLDAP handles subtree renames, so we don't want to do any of these things
-        tdb_modules_list = None
+        tdb_modules_list = ["extended_dn_out_dereference"]
     elif ldap_backend is not None:
         raise "LDAP Backend specified, but LDAP Backend Type not specified"
     elif serverrole == "domain controller":
index a7b501e8a8741b4ed20e1b4dd760a0f8590c1fd5..7b13a193cb530c803b37ae7ab7cc597aec8c028f 100644 (file)
@@ -61,9 +61,6 @@ uASCompat: 1
 replace: modifiedCount
 modifiedCount: 1
 -
-replace: objectCategory
-objectCategory: CN=Domain-DNS,${SCHEMADN}
--
 replace: fSMORoleOwner
 fSMORoleOwner: CN=NTDS Settings,${SERVERDN}
 -
index c27157d7137f905b10c4be3ef3f53839c0d89a43..d42795b94dca9129311dee573fe222348888eeac 100644 (file)
@@ -244,7 +244,7 @@ systemAuxiliaryClass: samDomain
 defaultSecurityDescriptor: D:(A;;RPLCLORC;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)
 systemFlags: 16
 defaultHidingValue: TRUE
-defaultObjectCategory: CN=Builtin-Domain,${SCHEMADN}
+defaultObjectCategory: CN=Samba4-Local-Domain,${SCHEMADN}
 
 
 dn: CN=Samba4Top,${SCHEMADN}
index eaff5d5fdab3c710acdd828dbcd16538cc6fe23f..71fa391003d7c5c611f194164c5b940bd03783d7 100644 (file)
@@ -107,7 +107,7 @@ PRIVATE_DEPENDENCIES = \
                RPC_NDR_LSA RPC_NDR_EPMAPPER RPC_NDR_DFS RPC_NDR_FRSAPI RPC_NDR_SPOOLSS \
                RPC_NDR_SRVSVC RPC_NDR_WKSSVC RPC_NDR_ROT RPC_NDR_DSSETUP \
                RPC_NDR_REMACT RPC_NDR_OXIDRESOLVER RPC_NDR_NTSVCS WB_HELPER LIBSAMBA-NET \
-               LIBCLI_AUTH POPT_CREDENTIALS TORTURE_LDAP TORTURE_UTIL TORTURE_RAP \
+               LIBCLI_AUTH POPT_CREDENTIALS TORTURE_LDAP TORTURE_LDB TORTURE_UTIL TORTURE_RAP \
                dcerpc_server service process_model ntvfs SERVICE_SMB RPC_NDR_BROWSER
 
 torture_rpc_OBJ_FILES = $(addprefix $(torturesrcdir)/rpc/, \
@@ -190,6 +190,20 @@ TORTURE_LDAP_OBJ_FILES = $(addprefix $(torturesrcdir)/ldap/, common.o basic.o sc
 
 $(eval $(call proto_header_template,$(torturesrcdir)/ldap/proto.h,$(TORTURE_LDAP_OBJ_FILES:.o=.c)))
 
+#################################
+# Start SUBSYSTEM TORTURE_LDB
+[MODULE::TORTURE_LDB]
+SUBSYSTEM = smbtorture
+INIT_FUNCTION = torture_ldb_init
+PRIVATE_DEPENDENCIES = \
+               LDB_WRAP
+# End SUBSYSTEM TORTURE_LDB
+#################################
+
+TORTURE_LDB_OBJ_FILES = $(addprefix $(torturesrcdir)/ldb/, ldb.o)
+
+$(eval $(call proto_header_template,$(torturesrcdir)/ldb/proto.h,$(TORTURE_LDB_OBJ_FILES:.o=.c)))
+
 #################################
 # Start SUBSYSTEM TORTURE_NBT
 [MODULE::TORTURE_NBT]
diff --git a/source4/torture/ldb/ldb.c b/source4/torture/ldb/ldb.c
new file mode 100644 (file)
index 0000000..f67ce1e
--- /dev/null
@@ -0,0 +1,737 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   Test LDB attribute functions
+
+   Copyright (C) Andrew Bartlet <abartlet@samba.org> 2008
+   
+   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 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 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/>.
+*/
+
+#include "includes.h"
+#include "lib/events/events.h"
+#include "lib/ldb/include/ldb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "lib/ldb-samba/ldif_handlers.h"
+#include "ldb_wrap.h"
+#include "dsdb/samdb/samdb.h"
+#include "param/param.h"
+#include "torture/smbtorture.h"
+#include "torture/ldb/proto.h"
+
+static const char *sid = "S-1-5-21-4177067393-1453636373-93818737";
+static const char *hex_sid = "01040000000000051500000081FDF8F815BBA456718F9705";
+static const char *guid = "975ac5fa-35d9-431d-b86a-845bcd34fff9";
+static const char *guid2 = "{975ac5fa-35d9-431d-b86a-845bcd34fff9}";
+static const char *hex_guid = "FAC55A97D9351D43B86A845BCD34FFF9";
+
+static bool torture_ldb_attrs(struct torture_context *torture)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(torture);
+       struct ldb_context *ldb;
+       const struct ldb_schema_attribute *attr;
+       struct ldb_val string_sid_blob, binary_sid_blob;
+       struct ldb_val string_guid_blob, string_guid_blob2, binary_guid_blob;
+
+       DATA_BLOB sid_blob = strhex_to_data_blob(mem_ctx, hex_sid);
+       DATA_BLOB guid_blob = strhex_to_data_blob(mem_ctx, hex_guid);
+
+       torture_assert(torture, 
+                      ldb = ldb_init(mem_ctx, torture->ev),
+                      "Failed to init ldb");
+
+       torture_assert_int_equal(torture, 
+                                ldb_register_samba_handlers(ldb), 0, 
+                                "Failed to register Samba handlers");
+
+       ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+       /* Test SID behaviour */
+       torture_assert(torture, attr = ldb_schema_attribute_by_name(ldb, "objectSid"), 
+                      "Failed to get objectSid schema attribute");
+       
+       string_sid_blob = data_blob_string_const(sid);
+
+       torture_assert_int_equal(torture, 
+                                attr->syntax->ldif_read_fn(ldb, mem_ctx, 
+                                                           &string_sid_blob, &binary_sid_blob), 0,
+                                "Failed to parse string SID");
+       
+       torture_assert_data_blob_equal(torture, binary_sid_blob, sid_blob, 
+                                      "Read SID into blob form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->ldif_read_fn(ldb, mem_ctx, 
+                                                           &sid_blob, &binary_sid_blob), -1,
+                                "Should have failed to parse binary SID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->ldif_write_fn(ldb, mem_ctx, &binary_sid_blob, &string_sid_blob), 0,
+                                "Failed to parse binary SID");
+       
+       torture_assert_data_blob_equal(torture, 
+                                      string_sid_blob, data_blob_string_const(sid),
+                                      "Write SID into string form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->comparison_fn(ldb, mem_ctx, &binary_sid_blob, &string_sid_blob), 0,
+                                "Failed to compare binary and string SID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->comparison_fn(ldb, mem_ctx, &string_sid_blob, &binary_sid_blob), 0,
+                                "Failed to compare string and binary binary SID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->comparison_fn(ldb, mem_ctx, &string_sid_blob, &string_sid_blob), 0,
+                                "Failed to compare string and string SID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->comparison_fn(ldb, mem_ctx, &binary_sid_blob, &binary_sid_blob), 0,
+                                "Failed to compare binary and binary SID");
+       
+       torture_assert(torture, attr->syntax->comparison_fn(ldb, mem_ctx, &guid_blob, &binary_sid_blob) != 0,
+                      "Failed to distinguish binary GUID and binary SID");
+
+
+       /* Test GUID behaviour */
+       torture_assert(torture, attr = ldb_schema_attribute_by_name(ldb, "objectGUID"), 
+                      "Failed to get objectGUID schema attribute");
+       
+       string_guid_blob = data_blob_string_const(guid);
+
+       torture_assert_int_equal(torture, 
+                                attr->syntax->ldif_read_fn(ldb, mem_ctx, 
+                                                           &string_guid_blob, &binary_guid_blob), 0,
+                                "Failed to parse string GUID");
+       
+       torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob, 
+                                      "Read GUID into blob form failed");
+       
+       string_guid_blob2 = data_blob_string_const(guid2);
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->ldif_read_fn(ldb, mem_ctx, 
+                                                           &string_guid_blob2, &binary_guid_blob), 0,
+                                "Failed to parse string GUID");
+       
+       torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob, 
+                                      "Read GUID into blob form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->ldif_read_fn(ldb, mem_ctx, 
+                                                           &guid_blob, &binary_guid_blob), 0,
+                                "Failed to parse binary GUID");
+       
+       torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob, 
+                                      "Read GUID into blob form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->ldif_write_fn(ldb, mem_ctx, &binary_guid_blob, &string_guid_blob), 0,
+                                "Failed to print binary GUID as string");
+
+       torture_assert_data_blob_equal(torture, string_sid_blob, data_blob_string_const(sid),
+                                      "Write SID into string form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->comparison_fn(ldb, mem_ctx, &binary_guid_blob, &string_guid_blob), 0,
+                                "Failed to compare binary and string GUID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->comparison_fn(ldb, mem_ctx, &string_guid_blob, &binary_guid_blob), 0,
+                                "Failed to compare string and binary binary GUID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->comparison_fn(ldb, mem_ctx, &string_guid_blob, &string_guid_blob), 0,
+                                "Failed to compare string and string GUID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->syntax->comparison_fn(ldb, mem_ctx, &binary_guid_blob, &binary_guid_blob), 0,
+                                "Failed to compare binary and binary GUID");
+       
+       
+       
+       talloc_free(mem_ctx);
+       return true;
+}
+
+static bool torture_ldb_dn_attrs(struct torture_context *torture)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(torture);
+       struct ldb_context *ldb;
+       const struct ldb_dn_extended_syntax *attr;
+       struct ldb_val string_sid_blob, binary_sid_blob;
+       struct ldb_val string_guid_blob, binary_guid_blob;
+       struct ldb_val hex_sid_blob, hex_guid_blob;
+
+       DATA_BLOB sid_blob = strhex_to_data_blob(mem_ctx, hex_sid);
+       DATA_BLOB guid_blob = strhex_to_data_blob(mem_ctx, hex_guid);
+
+       torture_assert(torture, 
+                      ldb = ldb_init(mem_ctx, torture->ev),
+                      "Failed to init ldb");
+
+       torture_assert_int_equal(torture, 
+                                ldb_register_samba_handlers(ldb), 0, 
+                                "Failed to register Samba handlers");
+
+       ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+       /* Test SID behaviour */
+       torture_assert(torture, attr = ldb_dn_extended_syntax_by_name(ldb, "SID"), 
+                      "Failed to get SID DN syntax");
+       
+       string_sid_blob = data_blob_string_const(sid);
+
+       torture_assert_int_equal(torture, 
+                                attr->read_fn(ldb, mem_ctx, 
+                                              &string_sid_blob, &binary_sid_blob), 0,
+                                "Failed to parse string SID");
+       
+       torture_assert_data_blob_equal(torture, binary_sid_blob, sid_blob, 
+                                      "Read SID into blob form failed");
+
+       hex_sid_blob = data_blob_string_const(hex_sid);
+       
+       torture_assert_int_equal(torture, 
+                                attr->read_fn(ldb, mem_ctx, 
+                                              &hex_sid_blob, &binary_sid_blob), 0,
+                                "Failed to parse HEX SID");
+       
+       torture_assert_data_blob_equal(torture, binary_sid_blob, sid_blob, 
+                                      "Read SID into blob form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->read_fn(ldb, mem_ctx, 
+                                              &sid_blob, &binary_sid_blob), -1,
+                                "Should have failed to parse binary SID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->write_hex_fn(ldb, mem_ctx, &sid_blob, &hex_sid_blob), 0,
+                                "Failed to parse binary SID");
+       
+       torture_assert_data_blob_equal(torture, 
+                                      hex_sid_blob, data_blob_string_const(hex_sid),
+                                      "Write SID into HEX string form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->write_clear_fn(ldb, mem_ctx, &sid_blob, &string_sid_blob), 0,
+                                "Failed to parse binary SID");
+       
+       torture_assert_data_blob_equal(torture, 
+                                      string_sid_blob, data_blob_string_const(sid),
+                                      "Write SID into clear string form failed");
+       
+
+       /* Test GUID behaviour */
+       torture_assert(torture, attr = ldb_dn_extended_syntax_by_name(ldb, "GUID"), 
+                      "Failed to get GUID DN syntax");
+       
+       string_guid_blob = data_blob_string_const(guid);
+
+       torture_assert_int_equal(torture, 
+                                attr->read_fn(ldb, mem_ctx, 
+                                              &string_guid_blob, &binary_guid_blob), 0,
+                                "Failed to parse string GUID");
+       
+       torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob, 
+                                      "Read GUID into blob form failed");
+       
+       hex_guid_blob = data_blob_string_const(hex_guid);
+       
+       torture_assert_int_equal(torture, 
+                                attr->read_fn(ldb, mem_ctx, 
+                                              &hex_guid_blob, &binary_guid_blob), 0,
+                                "Failed to parse HEX GUID");
+       
+       torture_assert_data_blob_equal(torture, binary_guid_blob, guid_blob, 
+                                      "Read GUID into blob form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->read_fn(ldb, mem_ctx, 
+                                              &guid_blob, &binary_guid_blob), -1,
+                                "Should have failed to parse binary GUID");
+       
+       torture_assert_int_equal(torture, 
+                                attr->write_hex_fn(ldb, mem_ctx, &guid_blob, &hex_guid_blob), 0,
+                                "Failed to parse binary GUID");
+       
+       torture_assert_data_blob_equal(torture, 
+                                      hex_guid_blob, data_blob_string_const(hex_guid),
+                                      "Write GUID into HEX string form failed");
+       
+       torture_assert_int_equal(torture, 
+                                attr->write_clear_fn(ldb, mem_ctx, &guid_blob, &string_guid_blob), 0,
+                                "Failed to parse binary GUID");
+       
+       torture_assert_data_blob_equal(torture, 
+                                      string_guid_blob, data_blob_string_const(guid),
+                                      "Write GUID into clear string form failed");
+       
+
+
+       talloc_free(mem_ctx);
+       return true;
+}
+
+static bool torture_ldb_dn_extended(struct torture_context *torture)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(torture);
+       struct ldb_context *ldb;
+       struct ldb_dn *dn, *dn2;
+       struct ldb_val string_sid_blob = data_blob_string_const(sid);
+       struct ldb_val string_guid_blob = data_blob_string_const(guid);
+
+       DATA_BLOB sid_blob = strhex_to_data_blob(mem_ctx, hex_sid);
+       DATA_BLOB guid_blob = strhex_to_data_blob(mem_ctx, hex_guid);
+
+       const char *dn_str = "cn=admin,cn=users,dc=samba,dc=org";
+
+       torture_assert(torture, 
+                      ldb = ldb_init(mem_ctx, torture->ev),
+                      "Failed to init ldb");
+
+       torture_assert_int_equal(torture, 
+                                ldb_register_samba_handlers(ldb), 0, 
+                                "Failed to register Samba handlers");
+
+       ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+       /* Check behaviour of a normal DN */
+       torture_assert(torture, 
+                      dn = ldb_dn_new(mem_ctx, ldb, dn_str), 
+                      "Failed to create a 'normal' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn),
+                      "Failed to validate 'normal' DN");
+
+       torture_assert(torture, ldb_dn_has_extended(dn) == false, 
+                      "Should not find plain DN to be 'extended'");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL, 
+                      "Should not find an SID on plain DN");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL, 
+                      "Should not find an GUID on plain DN");
+       
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "WKGUID") == NULL, 
+                      "Should not find an WKGUID on plain DN");
+       
+       /* Now make an extended DN */
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;<SID=%s>;%s",
+                                          guid, sid, dn_str), 
+                      "Failed to create an 'extended' DN");
+
+       torture_assert(torture, 
+                      dn2 = ldb_dn_copy(mem_ctx, dn), 
+                      "Failed to copy the 'extended' DN");
+       talloc_free(dn);
+       dn = dn2;
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn),
+                      "Failed to validate 'extended' DN");
+
+       torture_assert(torture, ldb_dn_has_extended(dn) == true, 
+                      "Should find extended DN to be 'extended'");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL, 
+                      "Should find an SID on extended DN");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL, 
+                      "Should find an GUID on extended DN");
+       
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob, 
+                                      "Extended DN SID incorect");
+
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob, 
+                                      "Extended DN GUID incorect");
+
+       torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), dn_str, 
+                                "linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_get_casefold(dn), strupper_talloc(mem_ctx, dn_str), 
+                                "casefolded DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_get_component_name(dn, 0), "cn", 
+                                "componet zero incorrect");
+
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_component_val(dn, 0), data_blob_string_const("admin"), 
+                                "componet zero incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 1),
+                                talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s", 
+                                                guid, sid, dn_str),
+                                "Clear extended linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 0),
+                                talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s", 
+                                                hex_guid, hex_sid, dn_str),
+                                "HEX extended linearized DN incorrect");
+
+       torture_assert(torture, ldb_dn_remove_child_components(dn, 1) == true,
+                                "Failed to remove DN child");
+                      
+       torture_assert(torture, ldb_dn_has_extended(dn) == false, 
+                      "Extended DN flag should be cleared after child element removal");
+       
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL, 
+                      "Should not find an SID on DN");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL, 
+                      "Should not find an GUID on DN");
+
+
+       /* TODO:  test setting these in the other order, and ensure it still comes out 'GUID first' */
+       torture_assert_int_equal(torture, ldb_dn_set_extended_component(dn, "GUID", &guid_blob), 0, 
+                      "Failed to set a GUID on DN");
+       
+       torture_assert_int_equal(torture, ldb_dn_set_extended_component(dn, "SID", &sid_blob), 0, 
+                      "Failed to set a SID on DN");
+
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob, 
+                                      "Extended DN SID incorect");
+
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob, 
+                                      "Extended DN GUID incorect");
+
+       torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "cn=users,dc=samba,dc=org", 
+                                "linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 1),
+                                talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s", 
+                                                guid, sid, "cn=users,dc=samba,dc=org"),
+                                "Clear extended linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 0),
+                                talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s", 
+                                                hex_guid, hex_sid, "cn=users,dc=samba,dc=org"),
+                                "HEX extended linearized DN incorrect");
+
+       /* Now check a 'just GUID' DN (clear format) */
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>",
+                                          guid), 
+                      "Failed to create an 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn),
+                      "Failed to validate 'extended' DN");
+
+       torture_assert(torture, ldb_dn_has_extended(dn) == true, 
+                      "Should find extended DN to be 'extended'");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL, 
+                      "Should not find an SID on this DN");
+
+       torture_assert_int_equal(torture, ldb_dn_get_comp_num(dn), 0, 
+                      "Should not find an 'normal' componet on this DN");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL, 
+                      "Should find an GUID on this DN");
+       
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob, 
+                                      "Extended DN GUID incorect");
+
+       torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "", 
+                                "linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 1),
+                                talloc_asprintf(mem_ctx, "<GUID=%s>", 
+                                                guid),
+                                "Clear extended linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 0),
+                                talloc_asprintf(mem_ctx, "<GUID=%s>", 
+                                                hex_guid),
+                                "HEX extended linearized DN incorrect");
+
+       /* Now check a 'just GUID' DN (HEX format) */
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>",
+                                          hex_guid), 
+                      "Failed to create an 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn),
+                      "Failed to validate 'extended' DN");
+
+       torture_assert(torture, ldb_dn_has_extended(dn) == true, 
+                      "Should find extended DN to be 'extended'");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL, 
+                      "Should not find an SID on this DN");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL, 
+                      "Should find an GUID on this DN");
+       
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob, 
+                                      "Extended DN GUID incorect");
+
+       torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "", 
+                                "linearized DN incorrect");
+
+       /* Now check a 'just SID' DN (clear format) */
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>",
+                                          sid), 
+                      "Failed to create an 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn),
+                      "Failed to validate 'extended' DN");
+
+       torture_assert(torture, ldb_dn_has_extended(dn) == true, 
+                      "Should find extended DN to be 'extended'");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL, 
+                      "Should not find an SID on this DN");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL, 
+                      "Should find an SID on this DN");
+       
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob, 
+                                      "Extended DN SID incorect");
+
+       torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "", 
+                                "linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 1),
+                                talloc_asprintf(mem_ctx, "<SID=%s>", 
+                                                sid),
+                                "Clear extended linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 0),
+                                talloc_asprintf(mem_ctx, "<SID=%s>", 
+                                                hex_sid),
+                                "HEX extended linearized DN incorrect");
+
+       /* Now check a 'just SID' DN (HEX format) */
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>",
+                                          hex_sid), 
+                      "Failed to create an 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn),
+                      "Failed to validate 'extended' DN");
+
+       torture_assert(torture, ldb_dn_has_extended(dn) == true, 
+                      "Should find extended DN to be 'extended'");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL, 
+                      "Should not find an SID on this DN");
+
+       torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL, 
+                      "Should find an SID on this DN");
+       
+       torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob, 
+                                      "Extended DN SID incorect");
+
+       torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "", 
+                                "linearized DN incorrect");
+
+       talloc_free(mem_ctx);
+       return true;
+}
+
+
+static bool torture_ldb_dn(struct torture_context *torture)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(torture);
+       struct ldb_context *ldb;
+       struct ldb_dn *dn;
+       struct ldb_dn *child_dn;
+       struct ldb_dn *typo_dn;
+
+       torture_assert(torture, 
+                      ldb = ldb_init(mem_ctx, torture->ev),
+                      "Failed to init ldb");
+
+       torture_assert_int_equal(torture, 
+                                ldb_register_samba_handlers(ldb), 0, 
+                                "Failed to register Samba handlers");
+
+       ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+       /* Check behaviour of a normal DN */
+       torture_assert(torture, 
+                      dn = ldb_dn_new(mem_ctx, ldb, NULL), 
+                      "Failed to create a NULL DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn),
+                      "Failed to validate NULL DN");
+
+       torture_assert(torture, 
+                      ldb_dn_add_base_fmt(dn, "dc=org"), 
+                      "Failed to add base DN");
+
+       torture_assert(torture, 
+                      ldb_dn_add_child_fmt(dn, "dc=samba"), 
+                      "Failed to add base DN");
+
+       torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "dc=samba,dc=org", 
+                                "linearized DN incorrect");
+
+       torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 0), "dc=samba,dc=org", 
+                                "extended linearized DN incorrect");
+
+       /* Check child DN comparisons */
+       torture_assert(torture, 
+                      child_dn = ldb_dn_new(mem_ctx, ldb, "CN=users,DC=SAMBA,DC=org"), 
+                      "Failed to create child DN");
+
+       torture_assert(torture, 
+                      ldb_dn_compare(dn, child_dn) != 0,
+                      "Comparison on dc=samba,dc=org and CN=users,DC=SAMBA,DC=org should != 0");
+
+       torture_assert(torture, 
+                      ldb_dn_compare_base(child_dn, dn) != 0,
+                      "Base Comparison of CN=users,DC=SAMBA,DC=org and dc=samba,dc=org should != 0");
+
+       torture_assert(torture, 
+                      ldb_dn_compare_base(dn, child_dn) == 0,
+                      "Base Comparison on dc=samba,dc=org and CN=users,DC=SAMBA,DC=org should == 0");
+
+       /* Check comparisons with a truncated DN */
+       torture_assert(torture, 
+                      typo_dn = ldb_dn_new(mem_ctx, ldb, "c=samba,dc=org"), 
+                      "Failed to create 'typo' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_compare(dn, typo_dn) != 0,
+                      "Comparison on dc=samba,dc=org and c=samba,dc=org should != 0");
+
+       torture_assert(torture, 
+                      ldb_dn_compare_base(typo_dn, dn) != 0,
+                      "Base Comparison of c=samba,dc=org and dc=samba,dc=org should != 0");
+
+       torture_assert(torture, 
+                      ldb_dn_compare_base(dn, typo_dn) != 0,
+                      "Base Comparison on dc=samba,dc=org and c=samba,dc=org should != 0");
+
+       talloc_free(mem_ctx);
+       return true;
+}
+
+static bool torture_ldb_dn_invalid_extended(struct torture_context *torture)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(torture);
+       struct ldb_context *ldb;
+       struct ldb_dn *dn;
+
+       const char *dn_str = "cn=admin,cn=users,dc=samba,dc=org";
+
+       torture_assert(torture, 
+                      ldb = ldb_init(mem_ctx, torture->ev),
+                      "Failed to init ldb");
+
+       torture_assert_int_equal(torture, 
+                                ldb_register_samba_handlers(ldb), 0, 
+                                "Failed to register Samba handlers");
+
+       ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+       /* Check behaviour of a normal DN */
+       torture_assert(torture, 
+                      dn = ldb_dn_new(mem_ctx, ldb, "samba,dc=org"), 
+                      "Failed to create a 'normal' invalid DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn) == false,
+                      "should have failed to validate 'normal' invalid DN");
+
+       /* Now make an extended DN */
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<PID=%s>;%s",
+                                          sid, dn_str), 
+                      "Failed to create an invalid 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn) == false,
+                      "should have failed to validate 'extended' DN");
+
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>%s",
+                                          sid, dn_str), 
+                      "Failed to create an invalid 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn) == false,
+                      "should have failed to validate 'extended' DN");
+
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;",
+                                          sid), 
+                      "Failed to create an invalid 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn) == false,
+                      "should have failed to validate 'extended' DN");
+
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;",
+                                          hex_sid), 
+                      "Failed to create an invalid 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn) == false,
+                      "should have failed to validate 'extended' DN");
+
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>;",
+                                          hex_guid), 
+                      "Failed to create an invalid 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn) == false,
+                      "should have failed to validate 'extended' DN");
+
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>;",
+                                          guid), 
+                      "Failed to create an invalid 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn) == false,
+                      "should have failed to validate 'extended' DN");
+
+       torture_assert(torture, 
+                      dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=>"), 
+                      "Failed to create an invalid 'extended' DN");
+
+       torture_assert(torture, 
+                      ldb_dn_validate(dn) == false,
+                      "should have failed to validate 'extended' DN");
+
+       return true;
+}
+
+NTSTATUS torture_ldb_init(void)
+{
+       struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "LDB");
+       torture_suite_add_simple_test(suite, "ATTRS", torture_ldb_attrs);
+       torture_suite_add_simple_test(suite, "DN-ATTRS", torture_ldb_dn_attrs);
+       torture_suite_add_simple_test(suite, "DN-EXTENDED", torture_ldb_dn_extended);
+       torture_suite_add_simple_test(suite, "DN-INVALID-EXTENDED", torture_ldb_dn_invalid_extended);
+       torture_suite_add_simple_test(suite, "DN", torture_ldb_dn);
+
+       suite->description = talloc_strdup(suite, "LDB (samba-specific behaviour) tests");
+
+       torture_register_suite(suite);
+
+       return NT_STATUS_OK;
+}
index dc98c2cc9a7f752d4e050f09b09684e148d9d998..3f9a6607cf57acd03c5e5167233e92bdca9db7ab 100644 (file)
@@ -50,6 +50,7 @@ _PUBLIC_ int torture_init(void)
 {
        extern NTSTATUS torture_base_init(void);
        extern NTSTATUS torture_ldap_init(void);
+       extern NTSTATUS torture_ldb_init(void);
        extern NTSTATUS torture_local_init(void);
        extern NTSTATUS torture_nbt_init(void);
        extern NTSTATUS torture_nbench_init(void);
index 5209abeb2c2b04a7d744df5ef2a84acc3710c0e8..042457e9e3d0068007d0d8b43aef70f64c2618f2 100755 (executable)
@@ -181,21 +181,23 @@ if [ x"$st" != x"0" ]; then
 fi
 
 echo "Getting HEX GUID/SID of $BASEDN"
-HEXDN=`bin/ldbsearch $CONFIGURATION $options -b "$BASEDN" -H $p://$SERVER -s base "(objectClass=*)" --controls=extended_dn:1:0 | grep 'dn: ' | cut -d ' ' -f2-`
+HEXDN=`bin/ldbsearch $CONFIGURATION $options -b "$BASEDN" -H $p://$SERVER -s base "(objectClass=*)" --controls=extended_dn:1:0 distinguishedName | grep 'distinguishedName: ' | cut -d ' ' -f2-`
 HEXGUID=`echo "$HEXDN" | cut -d ';' -f1`
-HEXSID=`echo "$HEXDN" | cut -d ';' -f2`
 echo "HEXGUID[$HEXGUID]"
-echo "HEXSID[$HEXSID]"
 
 echo "Getting STR GUID/SID of $BASEDN"
-STRDN=`bin/ldbsearch $CONFIGURATION $options -b "$BASEDN" -H $p://$SERVER -s base "(objectClass=*)" --controls=extended_dn:1:1 | grep 'dn: ' | cut -d ' ' -f2-`
+STRDN=`bin/ldbsearch $CONFIGURATION $options -b "$BASEDN" -H $p://$SERVER -s base "(objectClass=*)" --controls=extended_dn:1:1 distinguishedName | grep 'distinguishedName: ' | cut -d ' ' -f2-`
 echo "STRDN: $STRDN"
 STRGUID=`echo "$STRDN" | cut -d ';' -f1`
-STRSID=`echo "$STRDN" | cut -d ';' -f2`
 echo "STRGUID[$STRGUID]"
+
+echo "Getting STR GUID/SID of $BASEDN"
+STRDN=`bin/ldbsearch $CONFIGURATION $options -b "$BASEDN" -H $p://$SERVER -s base "(objectClass=*)" --controls=extended_dn:1:1 | grep 'dn: ' | cut -d ' ' -f2-`
+echo "STRDN: $STRDN"
+STRSID=`echo "$STRDN" | cut -d ';' -f2`
 echo "STRSID[$STRSID]"
 
-SPECIALDNS="$HEXGUID $HEXSID $STRGUID $STRSID"
+SPECIALDNS="$HEXGUID $STRGUID $STRSID"
 for SPDN in $SPECIALDNS; do
        echo "Search for $SPDN"
        nentries=`bin/ldbsearch $options $CONFIGURATION -H $p://$SERVER -s base -b "$SPDN" '(objectClass=*)' | grep "dn: $BASEDN"  | wc -l`