From: Andrew Bartlett Date: Mon, 8 Dec 2008 20:27:02 +0000 (+1100) Subject: Merge branch 'master' of ssh://git.samba.org/data/git/samba into extended-dn X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=d30a7f7cfd5a054361f66943b5a198d3607e6d82;hp=53c41661bd9692c7bdba04b7de6adc3887ab529f;p=abartlet%2Fsamba.git%2F.git Merge branch 'master' of ssh://git.samba.org/data/git/samba into extended-dn --- diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 13870662562..19375bb923f 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -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 index a0602d92815..00000000000 --- a/source4/dsdb/samdb/ldb_modules/extended_dn.c +++ /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 . -*/ - -/* - * 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 - -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, ";;%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, ";%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, ";;%s", - object_guid, object_sid, - ldb_dn_get_linearized(msg->dn)); - } else { - new_dn = talloc_asprintf(msg, ";%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, "'); - 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, "'); - 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, "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 index 00000000000..f21c171b7bc --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c @@ -0,0 +1,394 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005-2008 + Copyright (C) Andrew Bartlett 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 . +*/ + +/* + * Name: ldb + * + * Component: ldb extended dn control module + * + * Description: this module interprets DNs of the form 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 index 00000000000..0333b82efc7 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_out.c @@ -0,0 +1,582 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005-2008 + Copyright (C) Andrew Bartlett 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 . +*/ + +/* + * 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 index 00000000000..60058a4e95a --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_out_dereference.c @@ -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 index 00000000000..55709237a3c --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_out_ldb.c @@ -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 index 00000000000..a49ce84eecd --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_store.c @@ -0,0 +1,429 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005-2008 + Copyright (C) Andrew Bartlett 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 . +*/ + +/* + * 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 + * 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 + +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 . 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, +}; diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index f16eb215a64..49e91cbf6b2 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -32,10 +32,12 @@ #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, }; diff --git a/source4/dsdb/samdb/ldb_modules/local_password.c b/source4/dsdb/samdb/ldb_modules/local_password.c index 622e4441663..4e864e1452d 100644 --- a/source4/dsdb/samdb/ldb_modules/local_password.c +++ b/source4/dsdb/samdb/ldb_modules/local_password.c @@ -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[] = { diff --git a/source4/dsdb/samdb/ldb_modules/normalise.c b/source4/dsdb/samdb/ldb_modules/normalise.c index 2366bc78568..796edec98d0 100644 --- a/source4/dsdb/samdb/ldb_modules/normalise.c +++ b/source4/dsdb/samdb/ldb_modules/normalise.c @@ -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++) { diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index b38e182cf78..639d9100bfd 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -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); } diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c index c353914e2cd..0e42f7869a9 100644 --- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c +++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c @@ -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 */ diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 93068d66ef1..4c5b3b2348c 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -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__ */ diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c index 2adff2a1dfa..4cdfeafe401 100644 --- a/source4/ldap_server/ldap_backend.c +++ b/source4/ldap_server/ldap_backend.c @@ -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) { diff --git a/source4/lib/ldb-samba/ldif_handlers.c b/source4/lib/ldb-samba/ldif_handlers.c index a16582d2945..5ab31d771bd 100644 --- a/source4/lib/ldb-samba/ldif_handlers.c +++ b/source4/lib/ldb-samba/ldif_handlers.c @@ -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; } diff --git a/source4/lib/ldb/common/ldb_attributes.c b/source4/lib/ldb/common/ldb_attributes.c index 747f2417811..48f9e11cafd 100644 --- a/source4/lib/ldb/common/ldb_attributes.c +++ b/source4/lib/ldb/common/ldb_attributes.c @@ -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; +} + diff --git a/source4/lib/ldb/common/ldb_controls.c b/source4/lib/ldb/common/ldb_controls.c index e3f8551407a..6fad5012b69 100644 --- a/source4/lib/ldb/common/ldb_controls.c +++ b/source4/lib/ldb/common/ldb_controls.c @@ -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 */ diff --git a/source4/lib/ldb/common/ldb_dn.c b/source4/lib/ldb/common/ldb_dn.c index e36aea4e697..23069ca2bbf 100644 --- a/source4/lib/ldb/common/ldb_dn.c +++ b/source4/lib/ldb/common/ldb_dn.c @@ -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, "special = true; - /* FIXME: add a GUID string to ldb_dn structure */ - } else if (strdn->length >= 5 && strncasecmp((const char *)strdn->data, "special = true; - /* FIXME: add a SID string to ldb_dn structure */ - } else if (strdn->length >= 8 && strncasecmp((const char *)strdn->data, "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, "special = true; - /* FIXME: add a GUID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "special = true; - /* FIXME: add a SID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "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; } diff --git a/source4/lib/ldb/common/ldb_ldif.c b/source4/lib/ldb/common/ldb_ldif.c index 69490e670bf..92af72ce61f 100644 --- a/source4/lib/ldb/common/ldb_ldif.c +++ b/source4/lib/ldb/common/ldb_ldif.c @@ -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) { diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 9bc5c183d84..9399a015cd1 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -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 diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h index 8f7e010bee7..38818a9c4b4 100644 --- a/source4/lib/ldb/include/ldb_private.h +++ b/source4/lib/ldb/include/ldb_private.h @@ -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; }; /* diff --git a/source4/lib/ldb/ldb.i b/source4/lib/ldb/ldb.i index 6ecbfbfa08a..a5ad78c4a96 100644 --- a/source4/lib/ldb/ldb.i +++ b/source4/lib/ldb/ldb.i @@ -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)); } diff --git a/source4/lib/ldb/ldb.py b/source4/lib/ldb/ldb.py index 4cf36441fd6..0ef5034a635 100644 --- a/source4/lib/ldb/ldb.py +++ b/source4/lib/ldb/ldb.py @@ -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. diff --git a/source4/lib/ldb/ldb_ildap/ldb_ildap.c b/source4/lib/ldb/ldb_ildap/ldb_ildap.c index 93e81d42449..002983db26d 100644 --- a/source4/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source4/lib/ldb/ldb_ildap/ldb_ildap.c @@ -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; diff --git a/source4/lib/ldb/ldb_wrap.c b/source4/lib/ldb/ldb_wrap.c index 3cf5ec613a7..78e85aaec77 100644 --- a/source4/lib/ldb/ldb_wrap.c +++ b/source4/lib/ldb/ldb_wrap.c @@ -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 @@ -52,12 +52,6 @@ # 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, }; diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index 71fd98876eb..5c11d1fda9e 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -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("" , "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("") 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("") - 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: +changetype: modify +replace: member +member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """ +""") + + ldb.modify_ldif(""" +dn: 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: 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: member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """ """) diff --git a/source4/libcli/ldap/ldap.c b/source4/libcli/ldap/ldap.c index 87c89daf9f4..589b29f1348 100644 --- a/source4/libcli/ldap/ldap.c +++ b/source4/libcli/ldap/ldap.c @@ -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))) { diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c index 930d97c40d0..1f2d0d41249 100644 --- a/source4/libcli/ldap/ldap_controls.c +++ b/source4/libcli/ldap/ldap_controls.c @@ -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 } }; diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 823d5e6ff67..963410e03d9 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -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": diff --git a/source4/setup/provision_basedn_modify.ldif b/source4/setup/provision_basedn_modify.ldif index a7b501e8a87..7b13a193cb5 100644 --- a/source4/setup/provision_basedn_modify.ldif +++ b/source4/setup/provision_basedn_modify.ldif @@ -61,9 +61,6 @@ uASCompat: 1 replace: modifiedCount modifiedCount: 1 - -replace: objectCategory -objectCategory: CN=Domain-DNS,${SCHEMADN} -- replace: fSMORoleOwner fSMORoleOwner: CN=NTDS Settings,${SERVERDN} - diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif index c27157d7137..d42795b94dc 100644 --- a/source4/setup/schema_samba4.ldif +++ b/source4/setup/schema_samba4.ldif @@ -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} diff --git a/source4/torture/config.mk b/source4/torture/config.mk index eaff5d5fdab..71fa391003d 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -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 index 00000000000..f67ce1eb466 --- /dev/null +++ b/source4/torture/ldb/ldb.c @@ -0,0 +1,737 @@ +/* + Unix SMB/CIFS implementation. + + Test LDB attribute functions + + Copyright (C) Andrew Bartlet 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 . +*/ + +#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, ";;%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, ";;%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, ";;%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, ";;%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, ";;%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), + "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), + "Clear extended linearized DN incorrect"); + + torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 0), + talloc_asprintf(mem_ctx, "", + 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, "", + 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), + "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), + "Clear extended linearized DN incorrect"); + + torture_assert_str_equal(torture, ldb_dn_extended_linearized(mem_ctx, dn, 0), + talloc_asprintf(mem_ctx, "", + 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, "", + 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, ";%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, "%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, ";", + 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, ";", + 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, ";", + 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, ";", + 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, ""), + "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; +} diff --git a/source4/torture/torture.c b/source4/torture/torture.c index dc98c2cc9a7..3f9a6607cf5 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -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); diff --git a/testprogs/blackbox/test_ldb.sh b/testprogs/blackbox/test_ldb.sh index 5209abeb2c2..042457e9e3d 100755 --- a/testprogs/blackbox/test_ldb.sh +++ b/testprogs/blackbox/test_ldb.sh @@ -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`