mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +03:00
r16028: Re-add the objectclass module, in the new async scheme.
Add a test to show that we need this, and to prove it works (for add
at least).
Andrew Bartlett
(This used to be commit f72079029a
)
This commit is contained in:
parent
dc4ccc6f65
commit
b31c685ec2
@ -38,15 +38,15 @@ OBJ_FILES = \
|
|||||||
# End MODULE ldb_operational
|
# End MODULE ldb_operational
|
||||||
################################################
|
################################################
|
||||||
|
|
||||||
# ################################################
|
################################################
|
||||||
# # Start MODULE ldb_objectclass
|
# Start MODULE ldb_objectclass
|
||||||
# [MODULE::ldb_objectclass]
|
[MODULE::ldb_objectclass]
|
||||||
# INIT_FUNCTION = ldb_objectclass_init
|
INIT_FUNCTION = ldb_objectclass_init
|
||||||
# SUBSYSTEM = ldb
|
SUBSYSTEM = ldb
|
||||||
# OBJ_FILES = \
|
OBJ_FILES = \
|
||||||
# modules/objectclass.o
|
modules/objectclass.o
|
||||||
# # End MODULE ldb_objectclass
|
# End MODULE ldb_objectclass
|
||||||
# ################################################
|
################################################
|
||||||
|
|
||||||
################################################
|
################################################
|
||||||
# Start MODULE ldb_rdn_name
|
# Start MODULE ldb_rdn_name
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
ldb database library
|
ldb database library
|
||||||
|
|
||||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
|
Copyright (C) Simo Sorce 2006
|
||||||
|
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
|
||||||
|
|
||||||
** NOTE! The following LGPL license applies to the ldb
|
** NOTE! The following LGPL license applies to the ldb
|
||||||
** library. This does NOT imply that all of Samba is released
|
** library. This does NOT imply that all of Samba is released
|
||||||
@ -35,98 +36,256 @@
|
|||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include "ldb/include/includes.h"
|
#include "ldb/include/includes.h"
|
||||||
|
|
||||||
/* It turns out the MMC assumes that the last objectClass in the list
|
struct oc_async_context {
|
||||||
* is the most specific subclass. As such, we must sort the list,
|
|
||||||
* according to the schema.
|
|
||||||
*
|
|
||||||
* For performance, we do this on the add/modify, not on the search
|
|
||||||
*
|
|
||||||
* We perform the original add/modify, then search for that is now in
|
|
||||||
* the objectClass list. We can then then replace that with the new
|
|
||||||
* sorted list. The backend is expected to preserve ordering for
|
|
||||||
* subsequent searches.
|
|
||||||
*
|
|
||||||
* We are in a transaction, so this is all perfectly safe...
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int objectclass_handle(struct ldb_module *module, struct ldb_request *req, const struct ldb_message *msg)
|
enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step;
|
||||||
|
|
||||||
|
struct ldb_module *module;
|
||||||
|
struct ldb_request *orig_req;
|
||||||
|
|
||||||
|
struct ldb_request *down_req;
|
||||||
|
|
||||||
|
struct ldb_request *search_req;
|
||||||
|
struct ldb_async_result *search_res;
|
||||||
|
|
||||||
|
struct ldb_request *mod_req;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ldb_async_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
|
||||||
{
|
{
|
||||||
|
struct oc_async_context *ac;
|
||||||
|
struct ldb_async_handle *h;
|
||||||
|
|
||||||
|
h = talloc_zero(req, struct ldb_async_handle);
|
||||||
|
if (h == NULL) {
|
||||||
|
ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->module = module;
|
||||||
|
|
||||||
|
ac = talloc_zero(h, struct oc_async_context);
|
||||||
|
if (ac == NULL) {
|
||||||
|
ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
|
||||||
|
talloc_free(h);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->private_data = (void *)ac;
|
||||||
|
|
||||||
|
h->state = LDB_ASYNC_INIT;
|
||||||
|
h->status = LDB_SUCCESS;
|
||||||
|
|
||||||
|
ac->module = module;
|
||||||
|
ac->orig_req = req;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
|
||||||
|
{
|
||||||
|
struct ldb_async_handle *h;
|
||||||
|
struct oc_async_context *ac;
|
||||||
|
struct ldb_message_element *objectClassAttr;
|
||||||
|
|
||||||
|
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
|
||||||
|
|
||||||
|
if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
|
||||||
|
return ldb_next_request(module, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
objectClassAttr = ldb_msg_find_element(req->op.add.message, "objectClass");
|
||||||
|
|
||||||
|
/* If no part of this touches the objectClass, then we don't
|
||||||
|
* need to make any changes. */
|
||||||
|
/* If the only operation is the deletion of the objectClass then go on */
|
||||||
|
if (!objectClassAttr) {
|
||||||
|
ldb_set_errstring(module->ldb, talloc_asprintf(ac, "Object class violation: no objectClass present"));
|
||||||
|
return LDB_ERR_OBJECT_CLASS_VIOLATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = oc_init_handle(req, module);
|
||||||
|
if (!h) {
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
ac = talloc_get_type(h->private_data, struct oc_async_context);
|
||||||
|
|
||||||
|
/* return or own handle to deal with this call */
|
||||||
|
req->async.handle = h;
|
||||||
|
|
||||||
|
/* prepare the first operation */
|
||||||
|
ac->down_req = talloc_zero(ac, struct ldb_request);
|
||||||
|
if (ac->down_req == NULL) {
|
||||||
|
ldb_set_errstring(module->ldb, talloc_asprintf(module->ldb, "Out of memory!"));
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(ac->down_req) = *req; /* copy the request */
|
||||||
|
|
||||||
|
ac->down_req->async.context = NULL;
|
||||||
|
ac->down_req->async.callback = NULL;
|
||||||
|
|
||||||
|
ac->step = OC_DO_REQ;
|
||||||
|
|
||||||
|
return ldb_next_request(module, ac->down_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
|
||||||
|
{
|
||||||
|
struct ldb_async_handle *h;
|
||||||
|
struct oc_async_context *ac;
|
||||||
|
struct ldb_message_element *objectClassAttr;
|
||||||
|
|
||||||
|
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
|
||||||
|
|
||||||
|
if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
|
||||||
|
return ldb_next_request(module, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
objectClassAttr = ldb_msg_find_element(req->op.mod.message, "objectClass");
|
||||||
|
|
||||||
|
/* If no part of this touches the objectClass, then we don't
|
||||||
|
* need to make any changes. */
|
||||||
|
/* If the only operation is the deletion of the objectClass then go on */
|
||||||
|
if (!objectClassAttr) {
|
||||||
|
return ldb_next_request(module, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
h = oc_init_handle(req, module);
|
||||||
|
if (!h) {
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
ac = talloc_get_type(h->private_data, struct oc_async_context);
|
||||||
|
|
||||||
|
/* return or own handle to deal with this call */
|
||||||
|
req->async.handle = h;
|
||||||
|
|
||||||
|
/* prepare the first operation */
|
||||||
|
ac->down_req = talloc_zero(ac, struct ldb_request);
|
||||||
|
if (ac->down_req == NULL) {
|
||||||
|
ldb_set_errstring(module->ldb, talloc_asprintf(module->ldb, "Out of memory!"));
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(ac->down_req) = *req; /* copy the request */
|
||||||
|
|
||||||
|
ac->down_req->async.context = NULL;
|
||||||
|
ac->down_req->async.callback = NULL;
|
||||||
|
|
||||||
|
ac->step = OC_DO_REQ;
|
||||||
|
|
||||||
|
return ldb_next_request(module, ac->down_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
|
||||||
|
{
|
||||||
|
struct oc_async_context *ac;
|
||||||
|
|
||||||
|
if (!context || !ares) {
|
||||||
|
ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ac = talloc_get_type(context, struct oc_async_context);
|
||||||
|
|
||||||
|
/* we are interested only in the single reply (base search) we receive here */
|
||||||
|
if (ares->type == LDB_REPLY_ENTRY) {
|
||||||
|
if (ac->search_res != NULL) {
|
||||||
|
ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results"));
|
||||||
|
talloc_free(ares);
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ac->search_res = talloc_steal(ac, ares);
|
||||||
|
} else {
|
||||||
|
talloc_free(ares);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LDB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int objectclass_search_self(struct ldb_async_handle *h) {
|
||||||
|
|
||||||
|
struct oc_async_context *ac;
|
||||||
|
static const char * const attrs[] = { "objectClass", NULL };
|
||||||
|
|
||||||
|
ac = talloc_get_type(h->private_data, struct oc_async_context);
|
||||||
|
|
||||||
|
/* prepare the search operation */
|
||||||
|
ac->search_req = talloc_zero(ac, struct ldb_request);
|
||||||
|
if (ac->search_req == NULL) {
|
||||||
|
ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ac->search_req->operation = LDB_SEARCH;
|
||||||
|
ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
|
||||||
|
ac->search_req->op.search.scope = LDB_SCOPE_BASE;
|
||||||
|
ac->search_req->op.search.tree = ldb_parse_tree(ac->module->ldb, NULL);
|
||||||
|
if (ac->search_req->op.search.tree == NULL) {
|
||||||
|
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: Internal error producing null search"));
|
||||||
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
}
|
||||||
|
ac->search_req->op.search.attrs = attrs;
|
||||||
|
ac->search_req->controls = NULL;
|
||||||
|
ac->search_req->async.context = ac;
|
||||||
|
ac->search_req->async.callback = get_self_callback;
|
||||||
|
ac->search_req->async.timeout = ac->orig_req->async.timeout;
|
||||||
|
|
||||||
|
ac->step = OC_SEARCH_SELF;
|
||||||
|
|
||||||
|
return ldb_next_request(ac->module, ac->search_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int objectclass_do_mod(struct ldb_async_handle *h) {
|
||||||
|
|
||||||
|
struct oc_async_context *ac;
|
||||||
|
struct ldb_message_element *objectclass_element;
|
||||||
|
struct ldb_message *msg;
|
||||||
TALLOC_CTX *mem_ctx;
|
TALLOC_CTX *mem_ctx;
|
||||||
int ret;
|
|
||||||
struct ldb_request *search_request;
|
|
||||||
struct ldb_request *modify_request;
|
|
||||||
struct ldb_message *modify_msg;
|
|
||||||
struct ldb_result *res;
|
|
||||||
const char *attrs[] = { "objectClass", NULL };
|
|
||||||
struct class_list {
|
struct class_list {
|
||||||
struct class_list *prev, *next;
|
struct class_list *prev, *next;
|
||||||
const char *objectclass;
|
const char *objectclass;
|
||||||
};
|
};
|
||||||
struct class_list *sorted = NULL, *parent_class = NULL,
|
struct class_list *sorted = NULL, *parent_class = NULL,
|
||||||
*subclass = NULL, *unsorted = NULL, *current, *poss_subclass;
|
*subclass = NULL, *unsorted = NULL, *current, *poss_subclass;
|
||||||
int i;
|
int i;
|
||||||
int layer;
|
int layer;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ac = talloc_get_type(h->private_data, struct oc_async_context);
|
||||||
|
|
||||||
struct ldb_message_element *objectclass_element;
|
mem_ctx = talloc_new(ac);
|
||||||
|
if (mem_ctx == NULL) {
|
||||||
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_handle\n");
|
|
||||||
|
|
||||||
if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
|
|
||||||
return ldb_next_request(module, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ldb_next_request(module, req);
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ldb_msg_find_element(msg, "objectClass") == NULL ) {
|
|
||||||
/* No sign of the objectClass: no change, nothing to see here */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Thanks to transactions: Now do a search, find the full list
|
|
||||||
* of objectClasses and do the sort */
|
|
||||||
|
|
||||||
mem_ctx = talloc_new(module);
|
|
||||||
if (!mem_ctx) {
|
|
||||||
return LDB_ERR_OPERATIONS_ERROR;
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
search_request = talloc(mem_ctx, struct ldb_request);
|
ac->mod_req = talloc(ac, struct ldb_request);
|
||||||
if (!search_request) {
|
if (ac->mod_req == NULL) {
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
return LDB_ERR_OPERATIONS_ERROR;
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
search_request->operation = LDB_REQ_SEARCH;
|
ac->mod_req->operation = LDB_MODIFY;
|
||||||
search_request->op.search.base = msg->dn;
|
ac->mod_req->controls = NULL;
|
||||||
search_request->op.search.scope = LDB_SCOPE_BASE;
|
ac->mod_req->async.context = ac;
|
||||||
search_request->op.search.tree = ldb_parse_tree(module->ldb, NULL);
|
ac->mod_req->async.callback = NULL;
|
||||||
search_request->op.search.attrs = attrs;
|
ac->mod_req->async.timeout = ac->orig_req->async.timeout;
|
||||||
search_request->controls = NULL;
|
|
||||||
|
/* use a new message structure */
|
||||||
ret = ldb_next_request(module, search_request);
|
ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
|
||||||
if (ret) {
|
if (msg == NULL) {
|
||||||
return ret;
|
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: could not create new modify msg"));
|
||||||
}
|
|
||||||
|
|
||||||
res = search_request->op.search.res;
|
|
||||||
talloc_steal(mem_ctx, res);
|
|
||||||
if (res->count != 1) {
|
|
||||||
ldb_set_errstring(module->ldb,
|
|
||||||
talloc_asprintf(mem_ctx, "objectClass_handle: "
|
|
||||||
"search for %s found %d != 1 objects, for entry we just added/modified",
|
|
||||||
ldb_dn_linearize(mem_ctx, msg->dn),
|
|
||||||
res->count));
|
|
||||||
/* What happened? The above add/modify worked... */
|
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
return LDB_ERR_NO_SUCH_OBJECT;
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* modify dn */
|
||||||
|
msg->dn = ac->orig_req->op.mod.message->dn;
|
||||||
|
|
||||||
/* This is now the objectClass list from the database */
|
/* This is now the objectClass list from the database */
|
||||||
objectclass_element = ldb_msg_find_element(res->msgs[0], "objectClass");
|
objectclass_element = ldb_msg_find_element(ac->search_res->message,
|
||||||
|
"objectClass");
|
||||||
if (!objectclass_element) {
|
if (!objectclass_element) {
|
||||||
/* Perhaps the above was a remove? Move along now, nothing to see here */
|
/* Perhaps the above was a remove? Move along now, nothing to see here */
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
@ -166,6 +325,7 @@ static int objectclass_handle(struct ldb_module *module, struct ldb_request *req
|
|||||||
for (i=0; i < objectclass_element->num_values; i++) {
|
for (i=0; i < objectclass_element->num_values; i++) {
|
||||||
current = talloc(mem_ctx, struct class_list);
|
current = talloc(mem_ctx, struct class_list);
|
||||||
if (!current) {
|
if (!current) {
|
||||||
|
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: out of memory allocating objectclass list"));
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
return LDB_ERR_OPERATIONS_ERROR;
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
}
|
}
|
||||||
@ -189,7 +349,7 @@ static int objectclass_handle(struct ldb_module *module, struct ldb_request *req
|
|||||||
|
|
||||||
/* Ensure we don't bother if there are no unsorted entries left */
|
/* Ensure we don't bother if there are no unsorted entries left */
|
||||||
for (current = parent_class; unsorted && current; current = current->next) {
|
for (current = parent_class; unsorted && current; current = current->next) {
|
||||||
const char **subclasses = ldb_subclass_list(module->ldb, current->objectclass);
|
const char **subclasses = ldb_subclass_list(ac->module->ldb, current->objectclass);
|
||||||
|
|
||||||
/* Walk the list of possible subclasses in unsorted */
|
/* Walk the list of possible subclasses in unsorted */
|
||||||
for (poss_subclass = unsorted; poss_subclass; ) {
|
for (poss_subclass = unsorted; poss_subclass; ) {
|
||||||
@ -231,78 +391,162 @@ static int objectclass_handle(struct ldb_module *module, struct ldb_request *req
|
|||||||
*/
|
*/
|
||||||
DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
|
DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
|
||||||
|
|
||||||
modify_msg = ldb_msg_new(mem_ctx);
|
|
||||||
if (!modify_msg) {
|
|
||||||
talloc_free(mem_ctx);
|
|
||||||
return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
}
|
|
||||||
modify_msg->dn = talloc_reference(modify_msg, msg->dn);
|
|
||||||
|
|
||||||
/* We must completely replace the existing objectClass entry.
|
/* We must completely replace the existing objectClass entry.
|
||||||
* We could do a constrained add/del, but we are meant to be
|
* We could do a constrained add/del, but we are meant to be
|
||||||
* in a transaction... */
|
* in a transaction... */
|
||||||
|
|
||||||
ret = ldb_msg_add_empty(modify_msg, "objectClass", LDB_FLAG_MOD_REPLACE);
|
ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE);
|
||||||
if (ret != LDB_SUCCESS) {
|
if (ret != LDB_SUCCESS) {
|
||||||
|
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: could not clear objectclass in modify msg"));
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move from the linked list back into an ldb msg */
|
/* Move from the linked list back into an ldb msg */
|
||||||
for (current = sorted; current; current = current->next) {
|
for (current = sorted; current; current = current->next) {
|
||||||
ret = ldb_msg_add_string(modify_msg, "objectClass", current->objectclass);
|
ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
|
||||||
if (ret != LDB_SUCCESS) {
|
if (ret != LDB_SUCCESS) {
|
||||||
|
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: could not re-add sorted objectclass to modify msg"));
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ldb_msg_sanity_check(modify_msg);
|
ret = ldb_msg_sanity_check(msg);
|
||||||
if (ret != LDB_SUCCESS) {
|
if (ret != LDB_SUCCESS) {
|
||||||
talloc_free(mem_ctx);
|
talloc_free(mem_ctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
modify_request = talloc(mem_ctx, struct ldb_request);
|
|
||||||
if (!modify_request) {
|
h->state = LDB_ASYNC_INIT;
|
||||||
talloc_free(mem_ctx);
|
h->status = LDB_SUCCESS;
|
||||||
|
|
||||||
|
ac->step = OC_DO_MOD;
|
||||||
|
|
||||||
|
talloc_free(mem_ctx);
|
||||||
|
/* perform the search */
|
||||||
|
return ldb_next_request(ac->module, ac->mod_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int oc_async_wait(struct ldb_async_handle *handle) {
|
||||||
|
struct oc_async_context *ac;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!handle || !handle->private_data) {
|
||||||
return LDB_ERR_OPERATIONS_ERROR;
|
return LDB_ERR_OPERATIONS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
modify_request->operation = LDB_REQ_MODIFY;
|
if (handle->state == LDB_ASYNC_DONE) {
|
||||||
modify_request->op.mod.message = modify_msg;
|
return handle->status;
|
||||||
modify_request->controls = NULL;
|
}
|
||||||
|
|
||||||
/* And now push the write into the database */
|
handle->state = LDB_ASYNC_PENDING;
|
||||||
ret = ldb_next_request(module, modify_request);
|
handle->status = LDB_SUCCESS;
|
||||||
|
|
||||||
talloc_free(mem_ctx);
|
ac = talloc_get_type(handle->private_data, struct oc_async_context);
|
||||||
|
|
||||||
|
switch (ac->step) {
|
||||||
|
case OC_DO_REQ:
|
||||||
|
ret = ldb_async_wait(ac->down_req->async.handle, LDB_WAIT_NONE);
|
||||||
|
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
handle->status = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ac->down_req->async.handle->status != LDB_SUCCESS) {
|
||||||
|
handle->status = ac->down_req->async.handle->status;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ac->down_req->async.handle->state != LDB_ASYNC_DONE) {
|
||||||
|
return LDB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mods done, go on */
|
||||||
|
return objectclass_search_self(handle);
|
||||||
|
|
||||||
|
case OC_SEARCH_SELF:
|
||||||
|
ret = ldb_async_wait(ac->search_req->async.handle, LDB_WAIT_NONE);
|
||||||
|
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
handle->status = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ac->search_req->async.handle->status != LDB_SUCCESS) {
|
||||||
|
handle->status = ac->search_req->async.handle->status;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ac->search_req->async.handle->state != LDB_ASYNC_DONE) {
|
||||||
|
return LDB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* self search done, go on */
|
||||||
|
return objectclass_do_mod(handle);
|
||||||
|
|
||||||
|
case OC_DO_MOD:
|
||||||
|
ret = ldb_async_wait(ac->mod_req->async.handle, LDB_WAIT_NONE);
|
||||||
|
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
handle->status = ret;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ac->mod_req->async.handle->status != LDB_SUCCESS) {
|
||||||
|
handle->status = ac->mod_req->async.handle->status;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ac->mod_req->async.handle->state != LDB_ASYNC_DONE) {
|
||||||
|
return LDB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = LDB_ERR_OPERATIONS_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = LDB_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
handle->state = LDB_ASYNC_DONE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int objectclass_request(struct ldb_module *module, struct ldb_request *req)
|
static int oc_async_wait_all(struct ldb_async_handle *handle) {
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while (handle->state != LDB_ASYNC_DONE) {
|
||||||
|
ret = oc_async_wait(handle);
|
||||||
|
if (ret != LDB_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int objectclass_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type)
|
||||||
{
|
{
|
||||||
switch (req->operation) {
|
if (type == LDB_WAIT_ALL) {
|
||||||
|
return oc_async_wait_all(handle);
|
||||||
/* only care about add and modify requests */
|
} else {
|
||||||
case LDB_REQ_ADD:
|
return oc_async_wait(handle);
|
||||||
return objectclass_handle(module, req, req->op.add.message);
|
|
||||||
|
|
||||||
case LDB_REQ_MODIFY:
|
|
||||||
return objectclass_handle(module, req, req->op.mod.message);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return ldb_next_request(module, req);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ldb_module_ops objectclass_ops = {
|
static const struct ldb_module_ops objectclass_ops = {
|
||||||
.name = "objectclass",
|
.name = "objectclass",
|
||||||
.request = objectclass_request,
|
.add = objectclass_add,
|
||||||
|
.modify = objectclass_modify,
|
||||||
|
.async_wait = objectclass_async_wait
|
||||||
};
|
};
|
||||||
|
|
||||||
int ldb_objectclass_init(void)
|
int ldb_objectclass_init(void)
|
||||||
{
|
{
|
||||||
return ldb_register_module(&objectclass_ops);
|
return ldb_register_module(&objectclass_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,5 +85,5 @@ vendorVersion: ${VERSION}
|
|||||||
# - samldb must be before password_hash, because password_hash checks that the objectclass is of type person (filled in by samldb)
|
# - samldb must be before password_hash, because password_hash checks that the objectclass is of type person (filled in by samldb)
|
||||||
|
|
||||||
dn: @MODULES
|
dn: @MODULES
|
||||||
@LIST: rootdse,kludge_acl,paged_results,server_sort,extended_dn,asq,samldb,password_hash,operational,objectguid,rdn_name
|
@LIST: rootdse,kludge_acl,paged_results,server_sort,extended_dn,asq,samldb,objectclass,password_hash,operational,objectguid,rdn_name
|
||||||
|
|
||||||
|
@ -37,36 +37,118 @@ objectClass: person
|
|||||||
cn: LDAPtestUSER
|
cn: LDAPtestUSER
|
||||||
");
|
");
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
println(ldb.errstring());
|
ok = ldb.del("cn=ldaptestuser,cn=users," + base_dn);
|
||||||
assert(ok);
|
if (!ok) {
|
||||||
|
println(ldb.errstring());
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
|
ok = ldb.add("
|
||||||
|
dn: cn=ldaptestuser,cn=users," + base_dn + "
|
||||||
|
objectClass: user
|
||||||
|
objectClass: person
|
||||||
|
cn: LDAPtestUSER
|
||||||
|
");
|
||||||
|
if (!ok) {
|
||||||
|
println(ldb.errstring());
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = ldb.add("
|
ok = ldb.add("
|
||||||
dn: cn=ldaptestuser2,cn=users," + base_dn + "
|
dn: cn=ldaptestuser2,cn=users," + base_dn + "
|
||||||
objectClass: user
|
|
||||||
objectClass: person
|
objectClass: person
|
||||||
|
objectClass: user
|
||||||
cn: LDAPtestUSER2
|
cn: LDAPtestUSER2
|
||||||
");
|
");
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
println(ldb.errstring());
|
ok = ldb.del("cn=ldaptestuser2,cn=users," + base_dn);
|
||||||
assert(ok);
|
if (!ok) {
|
||||||
|
println(ldb.errstring());
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
|
ok = ldb.add("
|
||||||
|
dn: cn=ldaptestuser2,cn=users," + base_dn + "
|
||||||
|
objectClass: person
|
||||||
|
objectClass: user
|
||||||
|
cn: LDAPtestUSER2
|
||||||
|
");
|
||||||
|
if (!ok) {
|
||||||
|
println(ldb.errstring());
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = ldb.add("
|
ok = ldb.add("
|
||||||
dn: cn=ldaptestutf8user èùéìòà ,cn=users," + base_dn + "
|
dn: cn=ldaptestutf8user èùéìòà ,cn=users," + base_dn + "
|
||||||
objectClass: user
|
objectClass: user
|
||||||
");
|
");
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
println(ldb.errstring());
|
ok = ldb.del("cn=ldaptestutf8user èùéìòà ,cn=users," + base_dn);
|
||||||
assert(ok);
|
if (!ok) {
|
||||||
|
println(ldb.errstring());
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
|
ok = ldb.add("
|
||||||
|
dn: cn=ldaptestutf8user èùéìòà ,cn=users," + base_dn + "
|
||||||
|
objectClass: user
|
||||||
|
");
|
||||||
|
if (!ok) {
|
||||||
|
println(ldb.errstring());
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Testing ldb.search");
|
ok = ldb.add("
|
||||||
|
dn: cn=ldaptestutf8user2 èùéìòà ,cn=users," + base_dn + "
|
||||||
|
objectClass: user
|
||||||
|
");
|
||||||
|
if (!ok) {
|
||||||
|
ok = ldb.del("cn=ldaptestutf8user2 èùéìòà ,cn=users," + base_dn);
|
||||||
|
if (!ok) {
|
||||||
|
println(ldb.errstring());
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
|
ok = ldb.add("
|
||||||
|
dn: cn=ldaptestutf8user2 èùéìòà ,cn=users," + base_dn + "
|
||||||
|
objectClass: user
|
||||||
|
");
|
||||||
|
if (!ok) {
|
||||||
|
println(ldb.errstring());
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Testing ldb.search for (&(cn=ldaptestuser)(objectClass=user))");
|
||||||
var res = ldb.search("(&(cn=ldaptestuser)(objectClass=user))");
|
var res = ldb.search("(&(cn=ldaptestuser)(objectClass=user))");
|
||||||
|
if (res.length != 1) {
|
||||||
|
println("Could not find (&(cn=ldaptestuser)(objectClass=user))");
|
||||||
|
assert(res.length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
assert(res[0].dn == "cn=ldaptestuser,cn=users," + base_dn);
|
assert(res[0].dn == "cn=ldaptestuser,cn=users," + base_dn);
|
||||||
assert(res[0].cn == "ldaptestuser");
|
assert(res[0].cn == "ldaptestuser");
|
||||||
assert(res[0].name == "ldaptestuser");
|
assert(res[0].name == "ldaptestuser");
|
||||||
|
assert(res[0].objectClass[0] == "top");
|
||||||
|
assert(res[0].objectClass[1] == "person");
|
||||||
|
assert(res[0].objectClass[2] == "organizationalPerson");
|
||||||
|
assert(res[0].objectClass[3] == "user");
|
||||||
|
assert(res[0].objectGUID != undefined);
|
||||||
|
assert(res[0].whenCreated != undefined);
|
||||||
|
|
||||||
|
println("Testing ldb.search for (&(cn=ldaptestuser)(objectClass=user))");
|
||||||
|
var res = ldb.search("(&(cn=ldaptestuser)(objectClass=user))");
|
||||||
|
if (res.length != 1) {
|
||||||
|
println("Could not find (&(cn=ldaptestuser)(objectClass=user))");
|
||||||
|
assert(res.length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(res[0].dn == "cn=ldaptestuser,cn=users," + base_dn);
|
||||||
|
assert(res[0].cn == "ldaptestuser");
|
||||||
|
assert(res[0].name == "ldaptestuser");
|
||||||
|
assert(res[0].objectClass[0] == "top");
|
||||||
|
assert(res[0].objectClass[1] == "person");
|
||||||
|
assert(res[0].objectClass[2] == "organizationalPerson");
|
||||||
|
assert(res[0].objectClass[3] == "user");
|
||||||
assert(res[0].objectGUID != undefined);
|
assert(res[0].objectGUID != undefined);
|
||||||
assert(res[0].whenCreated != undefined);
|
assert(res[0].whenCreated != undefined);
|
||||||
|
|
||||||
@ -76,12 +158,20 @@ objectClass: user
|
|||||||
assert(ok);
|
assert(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Testing ldb.search");
|
println("Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))");
|
||||||
var res = ldb.search("(&(cn=ldaptestUSer2)(objectClass=user))");
|
var res = ldb.search("(&(cn=ldaptestUSer2)(objectClass=user))");
|
||||||
|
if (res.length != 1) {
|
||||||
|
println("Could not find (&(cn=ldaptestUSer2)(objectClass=user))");
|
||||||
|
assert(res.length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
assert(res[0].dn == "cn=ldaptestuser2,cn=users," + base_dn);
|
assert(res[0].dn == "cn=ldaptestuser2,cn=users," + base_dn);
|
||||||
assert(res[0].cn == "ldaptestuser2");
|
assert(res[0].cn == "ldaptestuser2");
|
||||||
assert(res[0].name == "ldaptestuser2");
|
assert(res[0].name == "ldaptestuser2");
|
||||||
|
assert(res[0].objectClass[0] == "top");
|
||||||
|
assert(res[0].objectClass[1] == "person");
|
||||||
|
assert(res[0].objectClass[2] == "organizationalPerson");
|
||||||
|
assert(res[0].objectClass[3] == "user");
|
||||||
assert(res[0].objectGUID != undefined);
|
assert(res[0].objectGUID != undefined);
|
||||||
assert(res[0].whenCreated != undefined);
|
assert(res[0].whenCreated != undefined);
|
||||||
|
|
||||||
@ -91,12 +181,21 @@ objectClass: user
|
|||||||
assert(ok);
|
assert(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Testing ldb.search");
|
println("Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
|
||||||
var res = ldb.search("(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
|
var res = ldb.search("(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
|
||||||
|
|
||||||
assert(res[0].dn == "cn=ldaptestutf8user èùéìòà,cn=users," + base_dn);
|
if (res.length != 1) {
|
||||||
assert(res[0].cn == "ldaptestutf8user èùéìòà");
|
println("Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
|
||||||
assert(res[0].name == "ldaptestutf8user èùéìòà");
|
assert(res.length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(res[0].dn == "cn=ldaptestutf8user èùéìòà,cn=users," + base_dn);
|
||||||
|
assert(res[0].cn == "ldaptestutf8user èùéìòà");
|
||||||
|
assert(res[0].name == "ldaptestutf8user èùéìòà");
|
||||||
|
assert(res[0].objectClass[0] == "top");
|
||||||
|
assert(res[0].objectClass[1] == "person");
|
||||||
|
assert(res[0].objectClass[2] == "organizationalPerson");
|
||||||
|
assert(res[0].objectClass[3] == "user");
|
||||||
assert(res[0].objectGUID != undefined);
|
assert(res[0].objectGUID != undefined);
|
||||||
assert(res[0].whenCreated != undefined);
|
assert(res[0].whenCreated != undefined);
|
||||||
|
|
||||||
@ -105,6 +204,17 @@ objectClass: user
|
|||||||
println(ldb.errstring());
|
println(ldb.errstring());
|
||||||
assert(ok);
|
assert(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println("Testing ldb.search for (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))");
|
||||||
|
var res = ldb.search("(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
|
||||||
|
|
||||||
|
if (res.length != 1) {
|
||||||
|
println("Could not find (expect space collapse, win2k3 fails) (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))");
|
||||||
|
} else {
|
||||||
|
assert(res[0].dn == "cn=ldaptestutf8user2 èùéìòà,cn=users," + base_dn);
|
||||||
|
assert(res[0].cn == "ldaptestutf8user2 èùéìòà");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_basedn(ldb)
|
function find_basedn(ldb)
|
||||||
|
Loading…
Reference in New Issue
Block a user