mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +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
|
||||
################################################
|
||||
|
||||
# ################################################
|
||||
# # Start MODULE ldb_objectclass
|
||||
# [MODULE::ldb_objectclass]
|
||||
# INIT_FUNCTION = ldb_objectclass_init
|
||||
# SUBSYSTEM = ldb
|
||||
# OBJ_FILES = \
|
||||
# modules/objectclass.o
|
||||
# # End MODULE ldb_objectclass
|
||||
# ################################################
|
||||
################################################
|
||||
# Start MODULE ldb_objectclass
|
||||
[MODULE::ldb_objectclass]
|
||||
INIT_FUNCTION = ldb_objectclass_init
|
||||
SUBSYSTEM = ldb
|
||||
OBJ_FILES = \
|
||||
modules/objectclass.o
|
||||
# End MODULE ldb_objectclass
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE ldb_rdn_name
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*
|
||||
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
|
||||
** library. This does NOT imply that all of Samba is released
|
||||
@ -35,98 +36,256 @@
|
||||
#include "includes.h"
|
||||
#include "ldb/include/includes.h"
|
||||
|
||||
/* It turns out the MMC assumes that the last objectClass in the list
|
||||
* 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...
|
||||
*/
|
||||
struct oc_async_context {
|
||||
|
||||
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;
|
||||
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 *prev, *next;
|
||||
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;
|
||||
int i;
|
||||
int layer;
|
||||
int ret;
|
||||
|
||||
ac = talloc_get_type(h->private_data, struct oc_async_context);
|
||||
|
||||
struct ldb_message_element *objectclass_element;
|
||||
|
||||
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) {
|
||||
mem_ctx = talloc_new(ac);
|
||||
if (mem_ctx == NULL) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
search_request = talloc(mem_ctx, struct ldb_request);
|
||||
if (!search_request) {
|
||||
ac->mod_req = talloc(ac, struct ldb_request);
|
||||
if (ac->mod_req == NULL) {
|
||||
talloc_free(mem_ctx);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
search_request->operation = LDB_REQ_SEARCH;
|
||||
search_request->op.search.base = msg->dn;
|
||||
search_request->op.search.scope = LDB_SCOPE_BASE;
|
||||
search_request->op.search.tree = ldb_parse_tree(module->ldb, NULL);
|
||||
search_request->op.search.attrs = attrs;
|
||||
search_request->controls = NULL;
|
||||
|
||||
ret = ldb_next_request(module, search_request);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
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... */
|
||||
ac->mod_req->operation = LDB_MODIFY;
|
||||
ac->mod_req->controls = NULL;
|
||||
ac->mod_req->async.context = ac;
|
||||
ac->mod_req->async.callback = NULL;
|
||||
ac->mod_req->async.timeout = ac->orig_req->async.timeout;
|
||||
|
||||
/* use a new message structure */
|
||||
ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
|
||||
if (msg == NULL) {
|
||||
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: could not create new modify msg"));
|
||||
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 */
|
||||
objectclass_element = ldb_msg_find_element(res->msgs[0], "objectClass");
|
||||
objectclass_element = ldb_msg_find_element(ac->search_res->message,
|
||||
"objectClass");
|
||||
if (!objectclass_element) {
|
||||
/* Perhaps the above was a remove? Move along now, nothing to see here */
|
||||
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++) {
|
||||
current = talloc(mem_ctx, struct class_list);
|
||||
if (!current) {
|
||||
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: out of memory allocating objectclass list"));
|
||||
talloc_free(mem_ctx);
|
||||
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 */
|
||||
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 */
|
||||
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 *);
|
||||
|
||||
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 could do a constrained add/del, but we are meant to be
|
||||
* 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) {
|
||||
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: could not clear objectclass in modify msg"));
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Move from the linked list back into an ldb msg */
|
||||
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) {
|
||||
ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "objectclass: could not re-add sorted objectclass to modify msg"));
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ldb_msg_sanity_check(modify_msg);
|
||||
ret = ldb_msg_sanity_check(msg);
|
||||
if (ret != LDB_SUCCESS) {
|
||||
talloc_free(mem_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
modify_request = talloc(mem_ctx, struct ldb_request);
|
||||
if (!modify_request) {
|
||||
talloc_free(mem_ctx);
|
||||
|
||||
h->state = LDB_ASYNC_INIT;
|
||||
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;
|
||||
}
|
||||
|
||||
modify_request->operation = LDB_REQ_MODIFY;
|
||||
modify_request->op.mod.message = modify_msg;
|
||||
modify_request->controls = NULL;
|
||||
if (handle->state == LDB_ASYNC_DONE) {
|
||||
return handle->status;
|
||||
}
|
||||
|
||||
/* And now push the write into the database */
|
||||
ret = ldb_next_request(module, modify_request);
|
||||
|
||||
talloc_free(mem_ctx);
|
||||
handle->state = LDB_ASYNC_PENDING;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
/* only care about add and modify requests */
|
||||
case LDB_REQ_ADD:
|
||||
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);
|
||||
|
||||
if (type == LDB_WAIT_ALL) {
|
||||
return oc_async_wait_all(handle);
|
||||
} else {
|
||||
return oc_async_wait(handle);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ldb_module_ops objectclass_ops = {
|
||||
.name = "objectclass",
|
||||
.request = objectclass_request,
|
||||
.add = objectclass_add,
|
||||
.modify = objectclass_modify,
|
||||
.async_wait = objectclass_async_wait
|
||||
};
|
||||
|
||||
int ldb_objectclass_init(void)
|
||||
{
|
||||
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)
|
||||
|
||||
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
|
||||
");
|
||||
if (!ok) {
|
||||
println(ldb.errstring());
|
||||
assert(ok);
|
||||
ok = ldb.del("cn=ldaptestuser,cn=users," + base_dn);
|
||||
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("
|
||||
dn: cn=ldaptestuser2,cn=users," + base_dn + "
|
||||
objectClass: user
|
||||
objectClass: person
|
||||
objectClass: user
|
||||
cn: LDAPtestUSER2
|
||||
");
|
||||
if (!ok) {
|
||||
println(ldb.errstring());
|
||||
assert(ok);
|
||||
ok = ldb.del("cn=ldaptestuser2,cn=users," + base_dn);
|
||||
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("
|
||||
dn: cn=ldaptestutf8user èùéìòà ,cn=users," + base_dn + "
|
||||
dn: cn=ldaptestutf8user èùéìòà ,cn=users," + base_dn + "
|
||||
objectClass: user
|
||||
");
|
||||
if (!ok) {
|
||||
println(ldb.errstring());
|
||||
assert(ok);
|
||||
ok = ldb.del("cn=ldaptestutf8user èùéìòà ,cn=users," + base_dn);
|
||||
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))");
|
||||
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].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].whenCreated != undefined);
|
||||
|
||||
@ -76,12 +158,20 @@ objectClass: user
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
println("Testing ldb.search");
|
||||
println("Testing ldb.search for (&(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].cn == "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].whenCreated != undefined);
|
||||
|
||||
@ -91,12 +181,21 @@ objectClass: user
|
||||
assert(ok);
|
||||
}
|
||||
|
||||
println("Testing ldb.search");
|
||||
println("Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
|
||||
var res = ldb.search("(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
|
||||
|
||||
assert(res[0].dn == "cn=ldaptestutf8user èùéìòà,cn=users," + base_dn);
|
||||
assert(res[0].cn == "ldaptestutf8user èùéìòà");
|
||||
assert(res[0].name == "ldaptestutf8user èùéìòà");
|
||||
if (res.length != 1) {
|
||||
println("Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
|
||||
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].whenCreated != undefined);
|
||||
|
||||
@ -105,6 +204,17 @@ objectClass: user
|
||||
println(ldb.errstring());
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user