1
0
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:
Andrew Bartlett 2006-06-03 11:57:20 +00:00 committed by Gerald (Jerry) Carter
parent dc4ccc6f65
commit b31c685ec2
4 changed files with 484 additions and 130 deletions

View File

@ -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

View File

@ -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);
} }

View File

@ -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

View File

@ -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)