1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-03 12:58:35 +03:00

r26182: Extend our linked attribute testsuite to cover many more possible

modifications, and then extend our implementation to match.

Andrew Bartlett
This commit is contained in:
Andrew Bartlett 2007-11-28 04:24:12 +01:00 committed by Stefan Metzmacher
parent 19e3516000
commit 65d17f0ad7
2 changed files with 347 additions and 84 deletions

View File

@ -34,19 +34,28 @@
#include "dsdb/samdb/samdb.h"
struct linked_attributes_context {
enum la_step {LA_SEARCH, LA_DO_OPS} step;
enum la_step {LA_SEARCH, LA_DO_OPS, LA_DO_ORIG} step;
struct ldb_module *module;
struct ldb_handle *handle;
struct ldb_request *orig_req;
struct ldb_request *search_req;
struct ldb_request **down_req;
struct ldb_request *orig_down_req;
int num_requests;
int finished_requests;
const char **linked_attrs;
};
struct replace_context {
struct linked_attributes_context *ac;
struct ldb_message_element *el;
};
static int linked_attributes_rename_del_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares);
static struct linked_attributes_context *linked_attributes_init_handle(struct ldb_request *req,
struct ldb_module *module)
{
@ -73,6 +82,14 @@ static struct linked_attributes_context *linked_attributes_init_handle(struct ld
ac->module = module;
ac->handle = h;
ac->orig_req = req;
ac->orig_down_req = talloc(ac, struct ldb_request);
if (!ac->orig_down_req) {
ldb_oom(ac->module->ldb);
return NULL;
}
*ac->orig_down_req = *req;
req->handle = h;
@ -211,7 +228,7 @@ static int setup_modifies(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
/* add */
static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
{
int i, ret;
int i;
struct linked_attributes_context *ac;
const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
@ -231,29 +248,8 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
return LDB_ERR_OPERATIONS_ERROR;
}
/* prepare the first operation */
ac->down_req = talloc_realloc(ac, ac->down_req,
struct ldb_request *, 1);
if (!ac->down_req) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->step = LA_DO_OPS;
ac->down_req[0] = talloc(ac->down_req, struct ldb_request);
if (!ac->down_req[0]) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
*(ac->down_req[0]) = *req; /* copy the request */
ac->num_requests++;
/* Run the original request */
ret = ldb_next_request(module, ac->down_req[0]);
if (ret != LDB_SUCCESS) {
return ret;
}
/* Need to ensure we only have forward links being specified */
for (i=0; i < req->op.add.message->num_elements; i++) {
const struct ldb_message_element *el = &req->op.add.message->elements[i];
@ -279,12 +275,77 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
/* Even link IDs are for the originating attribute */
}
ac->step = LA_DO_OPS;
/* Now call the common routine to setup the modifies across all the attributes */
return setup_modifies(module->ldb, ac, ac, req->op.add.message, NULL, req->op.add.message->dn);
}
static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct replace_context *ac2 = talloc_get_type(context, struct replace_context);
struct linked_attributes_context *ac = ac2->ac;
/* OK, we have one search result here: */
/* Only entries are interesting, and we only want the olddn */
if (ares->type == LDB_REPLY_ENTRY
&& ldb_dn_compare(ares->message->dn, ac->orig_req->op.mod.message->dn) == 0) {
/* only bother at all if there were some linked attributes found */
struct ldb_message_element *search_el
= ldb_msg_find_element(ares->message,
ac2->el->name);
/* See if this element already exists */
if (search_el) {
int ret;
struct ldb_message *msg = ldb_msg_new(ac);
if (!msg) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
/* Lazy option: Delete and add the elements on all members */
msg->num_elements = 1;
msg->elements = search_el;
msg->dn = ac->orig_req->op.mod.message->dn;
ret = setup_modifies(ac->module->ldb, ac2, ac, msg, ares->message->dn, NULL);
if (ret != LDB_SUCCESS) {
return ret;
}
msg->elements = ac2->el;
ret = setup_modifies(ac->module->ldb, ac2, ac, msg, NULL, ares->message->dn);
if (ret != LDB_SUCCESS) {
return ret;
}
} else {
/* Looks like it doesn't exist, process like an 'add' */
struct ldb_message *msg = ldb_msg_new(ac);
if (!msg) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
msg->num_elements = 1;
msg->elements = ac2->el;
msg->dn = ac->orig_req->op.mod.message->dn;
return setup_modifies(ac->module->ldb, ac2, ac, msg, NULL, ac->orig_req->op.mod.message->dn);
}
talloc_free(ares);
return LDB_SUCCESS;
} else if (ares->type == LDB_REPLY_ENTRY) {
/* Guh? We only asked for this DN */
return LDB_ERR_OPERATIONS_ERROR;
} else {
talloc_free(ares);
return LDB_SUCCESS;
}
}
/* modify */
static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
{
@ -293,7 +354,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
/* Determine the effect of the modification */
/* Apply the modify to the linked entry */
int i, j, ret;
int i, j;
struct linked_attributes_context *ac;
const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
@ -314,31 +375,11 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
}
/* prepare the first operation */
ac->down_req = talloc_realloc(ac, ac->down_req,
struct ldb_request *, 1);
if (!ac->down_req) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->down_req[0] = talloc(ac->down_req, struct ldb_request);
if (!ac->down_req[0]) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
*(ac->down_req[0]) = *req; /* copy the request */
ac->num_requests++;
ac->step = LA_DO_OPS;
/* Run the original request */
ret = ldb_next_request(module, ac->down_req[0]);
if (ret != LDB_SUCCESS) {
return ret;
}
for (i=0; i < req->op.mod.message->num_elements; i++) {
int ret;
struct ldb_request *new_req;
const struct dsdb_attribute *target_attr;
const struct ldb_message_element *el = &req->op.mod.message->elements[i];
const struct dsdb_attribute *schema_attr
@ -370,18 +411,109 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
if ((el->flags & LDB_FLAG_MOD_MASK) == LDB_FLAG_MOD_REPLACE) {
ldb_asprintf_errstring(module->ldb,
"attribute %s may not be replaced, only added or deleted", req->op.mod.message->elements[i].name);
return LDB_ERR_UNWILLING_TO_PERFORM;
if (((el->flags & LDB_FLAG_MOD_MASK) == LDB_FLAG_MOD_REPLACE)
&& el->num_values > 0) {
struct replace_context *ac2 = talloc(ac, struct replace_context);
const char **attrs = talloc_array(ac, const char *, 2);
if (!attrs || !ac2) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
attrs[0] = el->name;
attrs[1] = NULL;
ac2->ac = ac;
ac2->el = el;
/* We need to setup a search, compare with the list, and then setup add/del as required */
/* The callback does all the hard work here */
ret = ldb_build_search_req(&new_req, module->ldb, req,
req->op.mod.message->dn,
LDB_SCOPE_BASE,
"(objectClass=*)",
attrs,
NULL,
ac2,
linked_attributes_mod_replace_search_callback);
if (ret != LDB_SUCCESS) {
return ret;
}
talloc_steal(new_req, attrs);
/* Create a spot in the list for the requests */
ac->down_req = talloc_realloc(ac, ac->down_req,
struct ldb_request *, ac->num_requests + 1);
if (!ac->down_req) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->down_req[ac->num_requests] = talloc_steal(ac->down_req, new_req);
ac->num_requests++;
ret = ldb_next_request(module, new_req);
if (ret != LDB_SUCCESS) {
return ret;
}
continue;
} else if (((el->flags & LDB_FLAG_MOD_MASK) & (LDB_FLAG_MOD_DELETE|LDB_FLAG_MOD_REPLACE))
&& el->num_values == 0) {
const char **attrs = talloc_array(ac, const char *, 2);
if (!attrs) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
attrs[0] = el->name;
attrs[1] = NULL;
/* We need to setup a search, and then setup del as required */
/* The callback does all the hard work here, acting identically to if we had delted the whole entry */
ret = ldb_build_search_req(&new_req, module->ldb, req,
req->op.mod.message->dn,
LDB_SCOPE_BASE,
"(objectClass=*)",
attrs,
NULL,
ac,
linked_attributes_rename_del_search_callback);
if (ret != LDB_SUCCESS) {
return ret;
}
talloc_steal(new_req, attrs);
/* Create a spot in the list for the requests */
ac->down_req = talloc_realloc(ac, ac->down_req,
struct ldb_request *, ac->num_requests + 1);
if (!ac->down_req) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->down_req[ac->num_requests] = talloc_steal(ac->down_req, new_req);
ac->num_requests++;
ret = ldb_next_request(module, new_req);
if (ret != LDB_SUCCESS) {
return ret;
}
continue;
}
/* Prepare the modify (mod element) on the targets */
/* For each value being moded, we need to setup the modify */
for (j=0; j < el->num_values; j++) {
struct ldb_request *new_req;
/* Create the modify request */
struct ldb_message *new_msg = ldb_msg_new(ac->down_req);
struct ldb_message *new_msg = ldb_msg_new(ac);
if (!new_msg) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
@ -406,7 +538,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
return ret;
}
ret = ldb_build_mod_req(&new_req, module->ldb, ac->down_req,
ret = ldb_build_mod_req(&new_req, module->ldb, ac,
new_msg,
NULL,
NULL,
@ -426,7 +558,7 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->down_req[ac->num_requests] = new_req;
ac->down_req[ac->num_requests] = talloc_steal(ac->down_req, new_req);
ac->num_requests++;
/* Run the new request */
@ -436,12 +568,11 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
}
}
}
return ret;
return LDB_SUCCESS;
}
static int linked_attributes_rename_del_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct ldb_request *req;
struct linked_attributes_context *ac = talloc_get_type(context, struct linked_attributes_context);
struct ldb_dn *olddn, *newdn;
@ -452,6 +583,13 @@ static int linked_attributes_rename_del_search_callback(struct ldb_context *ldb,
newdn = NULL;
break;
}
/* This isn't the general modify case, just the modify when we are asked to delete all values */
case LDB_MODIFY:
{
olddn = ac->orig_req->op.mod.message->dn;
newdn = NULL;
break;
}
case LDB_RENAME:
{
olddn = ac->orig_req->op.rename.olddn;
@ -478,21 +616,6 @@ static int linked_attributes_rename_del_search_callback(struct ldb_context *ldb,
} else if (ares->type == LDB_REPLY_ENTRY) {
/* Guh? We only asked for this DN */
return LDB_ERR_OPERATIONS_ERROR;
} else if (ares->type == LDB_REPLY_DONE) {
req = talloc(ac, struct ldb_request);
*req = *ac->orig_req;
talloc_free(ares);
ac->down_req = talloc_realloc(ac, ac->down_req,
struct ldb_request *, ac->num_requests + 1);
if (!ac->down_req) {
ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->down_req[ac->num_requests] = req;
ac->num_requests++;
return ldb_next_request(ac->module, req);
} else {
talloc_free(ares);
@ -660,6 +783,27 @@ static int linked_attributes_wait_none(struct ldb_handle *handle) {
return LDB_SUCCESS;
}
}
/* Now run the original request */
ac->step = LA_DO_ORIG;
return ldb_next_request(ac->module, ac->orig_down_req);
case LA_DO_ORIG:
ret = ldb_wait(ac->orig_down_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->orig_down_req->handle->status != LDB_SUCCESS) {
handle->status = ac->orig_down_req->handle->status;
goto done;
}
if (ac->orig_down_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
ret = LDB_SUCCESS;
}
done:

View File

@ -230,16 +230,17 @@ member: cn=ldaptestuser3,cn=users," + base_dn + "
assert(res.msgs[0].cn == "ldaptestUSER3");
assert(res.msgs[0].name == "ldaptestUSER3");
println("Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")");
var res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")");
if (res.error != 0 || res.msgs.length != 1) {
println("Could not find (dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")");
assert(res.error == 0);
assert(res.msgs.length == 1);
}
assert(res.msgs[0].dn == ("CN=ldaptestUSER3,CN=Users," + base_dn));
assert(res.msgs[0].cn == "ldaptestUSER3");
assert(res.msgs[0].name == "ldaptestUSER3");
// This is a Samba special, and does not exist in real AD
// println("Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")");
// var res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")");
// if (res.error != 0 || res.msgs.length != 1) {
// println("Could not find (dn=CN=ldaptestUSER3,CN=Users," + base_dn + ")");
// assert(res.error == 0);
// assert(res.msgs.length == 1);
// }
// assert(res.msgs[0].dn == ("CN=ldaptestUSER3,CN=Users," + base_dn));
// assert(res.msgs[0].cn == "ldaptestUSER3");
// assert(res.msgs[0].name == "ldaptestUSER3");
println("Testing ldb.search for (distinguishedName=CN=ldaptestUSER3,CN=Users," + base_dn + ")");
var res = ldb.search("(distinguishedName=CN=ldaptestUSER3,CN=Users," + base_dn + ")");
@ -347,6 +348,18 @@ cn: LDAPtestUSER4
}
}
ok = ldb.modify("
dn: cn=ldaptestgroup2,cn=users," + base_dn + "
changetype: modify
add: member
member: cn=ldaptestuser4,cn=ldaptestcontainer," + base_dn + "
");
if (ok.error != 0) {
println("Failure adding ldaptestuser4 to a group");
println(ok.errstr);
assert(ok.error == 0);
}
println("Testing ldb.rename of cn=ldaptestcontainer," + base_dn + " to cn=ldaptestcontainer2," + base_dn);
ok = ldb.rename("CN=ldaptestcontainer," + base_dn, "CN=ldaptestcontainer2," + base_dn);
if (ok.error != 0) {
@ -385,6 +398,15 @@ cn: LDAPtestUSER4
}
assert(res.msgs[0].dn == ("CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn));
assert(strupper(res.msgs[0].memberOf[0]) == strupper(("CN=ldaptestgroup2,CN=Users," + base_dn)));
println("Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn + ")(objectclass=group)) to check subtree renames and linked attributes");
var res = ldb.search("(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn + ")(objectclass=group))", base_dn, ldb.SCOPE_SUBTREE);
if (res.error != 0 || res.msgs.length != 1) {
println("Could not find (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + base_dn + ")(objectclass=group)), perhaps linked attributes are not conistant with subtree renames?");
assert(res.error == 0);
assert(res.msgs.length == 1);
}
println("Testing ldb.rename (into itself) of cn=ldaptestcontainer2," + base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer2," + base_dn);
ok = ldb.rename("cn=ldaptestcontainer2," + base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer2," + base_dn);
@ -734,12 +756,109 @@ objectClass: user
assert(res.msgs[0].member[0] == ("CN=ldaptestuser2,CN=Users," + base_dn));
assert(res.msgs[0].member.length == 1);
ok = ldb.modify("
dn: cn=ldaptestgroup2,cn=users," + base_dn + "
changetype: modify
replace: member
member: CN=ldaptestuser2,CN=Users," + base_dn + "
member: CN=ldaptestutf8user èùéìòà,CN=Users," + base_dn + "
");
if (ok.error != 0) {
println("Failure testing replace of linked attributes");
println(ok.errstr);
assert(ok.error == 0);
}
println("Testing Linked attribute behaviours");
ok = ldb.modify("
dn: cn=ldaptestgroup2,cn=users," + base_dn + "
changetype: modify
delete: member
");
if (ok.error != 0) {
println("Failure testing delete of linked attributes");
println(ok.errstr);
assert(ok.error == 0);
}
ok = ldb.modify("
dn: cn=ldaptestgroup2,cn=users," + base_dn + "
changetype: modify
add: member
member: CN=ldaptestuser2,CN=Users," + base_dn + "
member: CN=ldaptestutf8user èùéìòà,CN=Users," + base_dn + "
");
if (ok.error != 0) {
println("Failure testing add of linked attributes");
println(ok.errstr);
assert(ok.error == 0);
}
ok = ldb.modify("
dn: cn=ldaptestgroup2,cn=users," + base_dn + "
changetype: modify
replace: member
");
if (ok.error != 0) {
println("Failure testing replace of linked attributes");
println(ok.errstr);
assert(ok.error == 0);
}
ok = ldb.modify("
dn: cn=ldaptestgroup2,cn=users," + base_dn + "
changetype: modify
add: member
member: CN=ldaptestuser2,CN=Users," + base_dn + "
member: CN=ldaptestutf8user èùéìòà,CN=Users," + base_dn + "
");
if (ok.error != 0) {
println("Failure testing add of linked attributes");
println(ok.errstr);
assert(ok.error == 0);
}
ok = ldb.modify("
dn: cn=ldaptestgroup2,cn=users," + base_dn + "
changetype: modify
delete: member
member: CN=ldaptestutf8user èùéìòà,CN=Users," + base_dn + "
");
if (ok.error != 0) {
println("Failure testing replace of linked attributes");
println(ok.errstr);
assert(ok.error == 0);
}
var res = ldb.search("(&(cn=ldaptestgroup2)(objectClass=group))", base_dn, ldb.SCOPE_SUBTREE, attrs);
if (res.error != 0 || res.msgs.length != 1) {
println("Could not find (&(cn=ldaptestgroup2)(objectClass=group))");
assert(res.error == 0);
assert(res.msgs.length == 1);
}
assert(res.msgs[0].dn == ("CN=ldaptestgroup2,CN=Users," + base_dn));
assert(res.msgs[0].member[0] == ("CN=ldaptestuser2,CN=Users," + base_dn));
assert(res.msgs[0].member.length == 1);
ok = ldb.del(("CN=ldaptestuser2,CN=Users," + base_dn));
if (ok.error != 0) {
println(ok.errstr);
assert(ok.error == 0);
}
var attrs = new Array("cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member");
println("Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete");
var res = ldb.search("(&(cn=ldaptestgroup2)(objectClass=group))", base_dn, ldb.SCOPE_SUBTREE, attrs);
if (res.error != 0 || res.msgs.length != 1) {
println("Could not find (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete");
assert(res.error == 0);
assert(res.msgs.length == 1);
}
assert(res.msgs[0].dn == ("CN=ldaptestgroup2,CN=Users," + base_dn));
assert(res.msgs[0].member == undefined);
println("Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");
var res = ldb.search("(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))");