Copyright (C) Jelmer Vernooij 2005
Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+ Copyright (C) Simo Sorce 2008
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
*/
#include "ldb_includes.h"
-
#include "ldb_map.h"
#include "ldb_map_private.h"
/* Extract mappings from private data. */
const struct ldb_map_context *map_get_context(struct ldb_module *module)
{
- const struct map_private *data = talloc_get_type(module->private_data, struct map_private);
+ const struct map_private *data = talloc_get_type(ldb_module_get_private(module), struct map_private);
return data->context;
}
/* Create a generic request context. */
-static struct map_context *map_init_context(struct ldb_handle *h, struct ldb_request *req)
-{
- struct map_context *ac;
-
- ac = talloc_zero(h, struct map_context);
- if (ac == NULL) {
- map_oom(h->module);
- return NULL;
- }
-
- ac->module = h->module;
- ac->orig_req = req;
-
- return ac;
-}
-
-/* Create a search request context. */
-struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares)
-{
- struct map_search_context *sc;
-
- sc = talloc_zero(ac, struct map_search_context);
- if (sc == NULL) {
- map_oom(ac->module);
- return NULL;
- }
-
- sc->ac = ac;
- sc->local_res = NULL;
- sc->remote_res = ares;
-
- return sc;
-}
-
-/* Create a request context and handle. */
-struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module)
+struct map_context *map_init_context(struct ldb_module *module,
+ struct ldb_request *req)
{
+ struct ldb_context *ldb;
struct map_context *ac;
- struct ldb_handle *h;
-
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
- map_oom(module);
- return NULL;
- }
- h->module = module;
+ ldb = ldb_module_get_ctx(module);
- ac = map_init_context(h, req);
+ ac = talloc_zero(req, struct map_context);
if (ac == NULL) {
- talloc_free(h);
+ ldb_set_errstring(ldb, "Out of Memory");
return NULL;
}
- h->private_data = (void *)ac;
-
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
+ ac->module = module;
+ ac->req = req;
- return h;
+ return ac;
}
-
/* Dealing with DNs for different partitions
* ========================================= */
int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request)
{
const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
struct ldb_message *msg;
+ ldb = ldb_module_get_ctx(module);
+
switch (request->operation) {
case LDB_SEARCH:
if (request->op.search.base) {
break;
default:
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
- "Invalid remote request!\n");
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Invalid remote request!");
return LDB_ERR_OPERATIONS_ERROR;
}
struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
{
const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
struct ldb_dn *newdn;
const struct ldb_map_attribute *map;
enum ldb_map_attr_type map_type;
return NULL;
}
+ ldb = ldb_module_get_ctx(module);
+
newdn = ldb_dn_copy(mem_ctx, dn);
if (newdn == NULL) {
map_oom(module);
switch (map_type) {
case MAP_IGNORE:
case MAP_GENERATE:
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
"MAP_IGNORE/MAP_GENERATE attribute '%s' "
- "used in DN!\n", ldb_dn_get_component_name(dn, i));
+ "used in DN!", ldb_dn_get_component_name(dn, i));
goto failed;
case MAP_CONVERT:
if (map->u.convert.convert_local == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
"'convert_local' not set for attribute '%s' "
- "used in DN!\n", ldb_dn_get_component_name(dn, i));
+ "used in DN!", ldb_dn_get_component_name(dn, i));
goto failed;
}
/* fall through */
struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn)
{
const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
struct ldb_dn *newdn;
const struct ldb_map_attribute *map;
enum ldb_map_attr_type map_type;
return NULL;
}
+ ldb = ldb_module_get_ctx(module);
+
newdn = ldb_dn_copy(mem_ctx, dn);
if (newdn == NULL) {
map_oom(module);
switch (map_type) {
case MAP_IGNORE:
case MAP_GENERATE:
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
"MAP_IGNORE/MAP_GENERATE attribute '%s' "
- "used in DN!\n", ldb_dn_get_component_name(dn, i));
+ "used in DN!", ldb_dn_get_component_name(dn, i));
goto failed;
case MAP_CONVERT:
if (map->u.convert.convert_remote == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
"'convert_remote' not set for attribute '%s' "
- "used in DN!\n", ldb_dn_get_component_name(dn, i));
+ "used in DN!", ldb_dn_get_component_name(dn, i));
goto failed;
}
/* fall through */
/* Map a DN contained in an ldb value into the remote partition. */
static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
{
+ struct ldb_context *ldb;
struct ldb_dn *dn, *newdn;
struct ldb_val newval;
- dn = ldb_dn_new(mem_ctx, module->ldb, (char *)val->data);
+ ldb = ldb_module_get_ctx(module);
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
if (! ldb_dn_validate(dn)) {
newval.length = 0;
newval.data = NULL;
/* Map a DN contained in an ldb value into the local partition. */
static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val)
{
+ struct ldb_context *ldb;
struct ldb_dn *dn, *newdn;
struct ldb_val newval;
- dn = ldb_dn_new(mem_ctx, module->ldb, (char *)val->data);
+ ldb = ldb_module_get_ctx(module);
+
+ dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val);
if (! ldb_dn_validate(dn)) {
newval.length = 0;
newval.data = NULL;
static void map_objectclass_generate_remote(struct ldb_module *module, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local)
{
const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
struct ldb_message_element *el, *oc;
struct ldb_val val;
bool found_extensibleObject = false;
int i;
+ ldb = ldb_module_get_ctx(module);
+
/* Find old local objectClass */
oc = ldb_msg_find_element(old, "objectClass");
if (oc == NULL) {
/* Prepare new element */
el = talloc_zero(remote, struct ldb_message_element);
if (el == NULL) {
- ldb_oom(module->ldb);
+ ldb_oom(ldb);
return; /* TODO: fail? */
}
el->values = talloc_array(el, struct ldb_val, el->num_values);
if (el->values == NULL) {
talloc_free(el);
- ldb_oom(module->ldb);
+ ldb_oom(ldb);
return; /* TODO: fail? */
}
/* Generate a local message with a mapped objectClass. */
static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *local_attr, const struct ldb_message *remote)
{
+ const struct ldb_map_context *data = map_get_context(module);
+ struct ldb_context *ldb;
struct ldb_message_element *el, *oc;
struct ldb_val val;
int i;
+ ldb = ldb_module_get_ctx(module);
+
/* Find old remote objectClass */
oc = ldb_msg_find_element(remote, "objectClass");
if (oc == NULL) {
/* Prepare new element */
el = talloc_zero(mem_ctx, struct ldb_message_element);
if (el == NULL) {
- ldb_oom(module->ldb);
+ ldb_oom(ldb);
return NULL;
}
el->values = talloc_array(el, struct ldb_val, el->num_values);
if (el->values == NULL) {
talloc_free(el);
- ldb_oom(module->ldb);
+ ldb_oom(ldb);
return NULL;
}
el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]);
}
- val.data = (uint8_t *)talloc_strdup(el->values, "extensibleObject");
+ val.data = (uint8_t *)talloc_strdup(el->values, data->add_objectclass);
val.length = strlen((char *)val.data);
- /* Remove last value if it was "extensibleObject" */
+ /* Remove last value if it was the string in data->add_objectclass (eg samba4top, extensibleObject) */
if (ldb_val_equal_exact(&val, &el->values[i-1])) {
el->num_values--;
el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values);
if (el->values == NULL) {
talloc_free(el);
- ldb_oom(module->ldb);
+ ldb_oom(ldb);
return NULL;
}
}
/* Auxiliary request construction
* ============================== */
-/* Store the DN of a single search result in context. */
-static int map_search_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
-{
- struct map_context *ac;
-
- if (context == NULL || ares == NULL) {
- ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ac = talloc_get_type(context, struct map_context);
-
- /* We are interested only in the single reply */
- if (ares->type != LDB_REPLY_ENTRY) {
- talloc_free(ares);
- return LDB_SUCCESS;
- }
-
- /* We have already found a remote DN */
- if (ac->local_dn) {
- ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search"));
- talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* Store local DN */
- ac->local_dn = ares->message->dn;
-
- return LDB_SUCCESS;
-}
-
/* Build a request to search a record by its DN. */
-struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback)
+struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_map_callback_t callback)
{
+ const struct ldb_parse_tree *search_tree;
+ struct ldb_context *ldb;
struct ldb_request *req;
+ int ret;
- req = talloc_zero(ac, struct ldb_request);
- if (req == NULL) {
- map_oom(ac->module);
- return NULL;
- }
-
- req->operation = LDB_SEARCH;
- req->op.search.base = dn;
- req->op.search.scope = LDB_SCOPE_BASE;
- req->op.search.attrs = attrs;
+ ldb = ldb_module_get_ctx(ac->module);
if (tree) {
- req->op.search.tree = tree;
+ search_tree = tree;
} else {
- req->op.search.tree = ldb_parse_tree(req, NULL);
- if (req->op.search.tree == NULL) {
- talloc_free(req);
+ search_tree = ldb_parse_tree(ac, NULL);
+ if (search_tree == NULL) {
return NULL;
}
}
- req->controls = NULL;
- req->context = context;
- req->callback = callback;
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req);
-
- return req;
-}
-
-/* Build a request to search the local record by its DN. */
-struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn)
-{
- /* attrs[] is returned from this function in
- * ac->search_req->op.search.attrs, so it must be static, as
- * otherwise the compiler can put it on the stack */
- static const char * const attrs[] = { IS_MAPPED, NULL };
- struct ldb_parse_tree *tree;
-
- /* Limit search to records with 'IS_MAPPED' present */
- /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */
- tree = talloc_zero(ac, struct ldb_parse_tree);
- if (tree == NULL) {
- map_oom(ac->module);
+ ret = ldb_build_search_req_ex(&req, ldb, ac,
+ dn, LDB_SCOPE_BASE,
+ search_tree, attrs,
+ NULL,
+ context, callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
return NULL;
}
- tree->operation = LDB_OP_PRESENT;
- tree->u.present.attr = talloc_strdup(tree, IS_MAPPED);
-
- return map_search_base_req(ac, dn, attrs, tree, ac, map_search_self_callback);
+ return req;
}
/* Build a request to update the 'IS_MAPPED' attribute */
-struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn)
+struct ldb_request *map_build_fixup_req(struct map_context *ac,
+ struct ldb_dn *olddn,
+ struct ldb_dn *newdn,
+ void *context,
+ ldb_map_callback_t callback)
{
+ struct ldb_context *ldb;
struct ldb_request *req;
struct ldb_message *msg;
const char *dn;
+ int ret;
- /* Prepare request */
- req = talloc_zero(ac, struct ldb_request);
- if (req == NULL) {
- map_oom(ac->module);
- return NULL;
- }
+ ldb = ldb_module_get_ctx(ac->module);
/* Prepare message */
- msg = ldb_msg_new(req);
+ msg = ldb_msg_new(ac);
if (msg == NULL) {
map_oom(ac->module);
- goto failed;
+ return NULL;
}
/* Update local 'IS_MAPPED' to the new remote DN */
goto failed;
}
- req->operation = LDB_MODIFY;
- req->op.mod.message = msg;
- req->controls = NULL;
- req->handle = NULL;
- req->context = NULL;
- req->callback = NULL;
+ /* Prepare request */
+ ret = ldb_build_mod_req(&req, ldb,
+ ac, msg, NULL,
+ context, callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ goto failed;
+ }
+ talloc_steal(req, msg);
return req;
-
failed:
- talloc_free(req);
+ talloc_free(msg);
return NULL;
}
-
-/* Asynchronous call structure
- * =========================== */
-
-/* Figure out which request is currently pending. */
-static struct ldb_request *map_get_req(struct map_context *ac)
-{
- switch (ac->step) {
- case MAP_SEARCH_SELF_MODIFY:
- case MAP_SEARCH_SELF_DELETE:
- case MAP_SEARCH_SELF_RENAME:
- return ac->search_req;
-
- case MAP_ADD_REMOTE:
- case MAP_MODIFY_REMOTE:
- case MAP_DELETE_REMOTE:
- case MAP_RENAME_REMOTE:
- return ac->remote_req;
-
- case MAP_RENAME_FIXUP:
- return ac->down_req;
-
- case MAP_ADD_LOCAL:
- case MAP_MODIFY_LOCAL:
- case MAP_DELETE_LOCAL:
- case MAP_RENAME_LOCAL:
- return ac->local_req;
-
- case MAP_SEARCH_REMOTE:
- /* Can't happen */
- break;
- }
-
- return NULL; /* unreachable; silences a warning */
-}
-
-typedef int (*map_next_function)(struct ldb_handle *handle);
-
-/* Figure out the next request to run. */
-static map_next_function map_get_next(struct map_context *ac)
-{
- switch (ac->step) {
- case MAP_SEARCH_REMOTE:
- return NULL;
-
- case MAP_ADD_LOCAL:
- return map_add_do_remote;
- case MAP_ADD_REMOTE:
- return NULL;
-
- case MAP_SEARCH_SELF_MODIFY:
- return map_modify_do_local;
- case MAP_MODIFY_LOCAL:
- return map_modify_do_remote;
- case MAP_MODIFY_REMOTE:
- return NULL;
-
- case MAP_SEARCH_SELF_DELETE:
- return map_delete_do_local;
- case MAP_DELETE_LOCAL:
- return map_delete_do_remote;
- case MAP_DELETE_REMOTE:
- return NULL;
-
- case MAP_SEARCH_SELF_RENAME:
- return map_rename_do_local;
- case MAP_RENAME_LOCAL:
- return map_rename_do_fixup;
- case MAP_RENAME_FIXUP:
- return map_rename_do_remote;
- case MAP_RENAME_REMOTE:
- return NULL;
- }
-
- return NULL; /* unreachable; silences a warning */
-}
-
-/* Wait for the current pending request to finish and continue with the next. */
-static int map_wait_next(struct ldb_handle *handle)
-{
- struct map_context *ac;
- struct ldb_request *req;
- map_next_function next;
- int ret;
-
- if (handle == NULL || handle->private_data == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
- }
-
- handle->state = LDB_ASYNC_PENDING;
- handle->status = LDB_SUCCESS;
-
- ac = talloc_get_type(handle->private_data, struct map_context);
-
- if (ac->step == MAP_SEARCH_REMOTE) {
- int i;
- for (i = 0; i < ac->num_searches; i++) {
- req = ac->search_reqs[i];
- ret = ldb_wait(req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (req->handle->status != LDB_SUCCESS) {
- handle->status = req->handle->status;
- goto done;
- }
- if (req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
- }
- } else {
-
- req = map_get_req(ac);
-
- ret = ldb_wait(req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (req->handle->status != LDB_SUCCESS) {
- handle->status = req->handle->status;
- goto done;
- }
- if (req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- next = map_get_next(ac);
- if (next) {
- return next(handle);
- }
- }
-
- ret = LDB_SUCCESS;
-
-done:
- handle->state = LDB_ASYNC_DONE;
- return ret;
-}
-
-/* Wait for all current pending requests to finish. */
-static int map_wait_all(struct ldb_handle *handle)
-{
- int ret;
-
- while (handle->state != LDB_ASYNC_DONE) {
- ret = map_wait_next(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
-
- return handle->status;
-}
-
-/* Wait for pending requests to finish. */
-int map_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- if (type == LDB_WAIT_ALL) {
- return map_wait_all(handle);
- } else {
- return map_wait_next(handle);
- }
-}
-
-
/* Module initialization
* ===================== */
static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name)
{
static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL };
+ struct ldb_context *ldb;
struct ldb_dn *dn;
struct ldb_message *msg;
struct ldb_result *res;
return LDB_SUCCESS;
}
- dn = ldb_dn_new_fmt(data, module->ldb, "%s=%s", MAP_DN_NAME, name);
+ ldb = ldb_module_get_ctx(module);
+
+ dn = ldb_dn_new_fmt(data, ldb, "%s=%s", MAP_DN_NAME, name);
if ( ! ldb_dn_validate(dn)) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
- "Failed to construct '%s' DN!\n", MAP_DN_NAME);
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Failed to construct '%s' DN!", MAP_DN_NAME);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, attrs, &res);
+ ret = ldb_search(ldb, data, &res, dn, LDB_SCOPE_BASE, attrs, NULL);
talloc_free(dn);
if (ret != LDB_SUCCESS) {
return ret;
}
if (res->count == 0) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
- "No results for '%s=%s'!\n", MAP_DN_NAME, name);
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "No results for '%s=%s'!", MAP_DN_NAME, name);
talloc_free(res);
return LDB_ERR_CONSTRAINT_VIOLATION;
}
if (res->count > 1) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
- "Too many results for '%s=%s'!\n", MAP_DN_NAME, name);
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_map: "
+ "Too many results for '%s=%s'!", MAP_DN_NAME, name);
talloc_free(res);
return LDB_ERR_CONSTRAINT_VIOLATION;
}
msg = res->msgs[0];
- data->local_base_dn = ldb_msg_find_attr_as_dn(module->ldb, data, msg, MAP_DN_FROM);
- data->remote_base_dn = ldb_msg_find_attr_as_dn(module->ldb, data, msg, MAP_DN_TO);
+ data->local_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_FROM);
+ data->remote_base_dn = ldb_msg_find_attr_as_dn(ldb, data, msg, MAP_DN_TO);
talloc_free(res);
return LDB_SUCCESS;
return LDB_ERR_OPERATIONS_ERROR;
}
- module->private_data = data;
+ ldb_module_set_private(module, data);
data->context = talloc_zero(data, struct ldb_map_context);
if (!data->context) {