summaryrefslogtreecommitdiff
path: root/source4/dsdb/samdb/ldb_modules
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules')
-rw-r--r--source4/dsdb/samdb/ldb_modules/anr.c180
-rw-r--r--source4/dsdb/samdb/ldb_modules/extended_dn.c501
-rw-r--r--source4/dsdb/samdb/ldb_modules/instancetype.c66
-rw-r--r--source4/dsdb/samdb/ldb_modules/kludge_acl.c236
-rw-r--r--source4/dsdb/samdb/ldb_modules/linked_attributes.c1347
-rw-r--r--source4/dsdb/samdb/ldb_modules/local_password.c1124
-rw-r--r--source4/dsdb/samdb/ldb_modules/naming_fsmo.c10
-rw-r--r--source4/dsdb/samdb/ldb_modules/normalise.c150
-rw-r--r--source4/dsdb/samdb/ldb_modules/objectclass.c766
-rw-r--r--source4/dsdb/samdb/ldb_modules/objectguid.c101
-rw-r--r--source4/dsdb/samdb/ldb_modules/partition.c864
-rw-r--r--source4/dsdb/samdb/ldb_modules/password_hash.c934
-rw-r--r--source4/dsdb/samdb/ldb_modules/pdc_fsmo.c10
-rw-r--r--source4/dsdb/samdb/ldb_modules/proxy.c148
-rw-r--r--source4/dsdb/samdb/ldb_modules/ranged_results.c165
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c781
-rw-r--r--source4/dsdb/samdb/ldb_modules/rootdse.c122
-rw-r--r--source4/dsdb/samdb/ldb_modules/samldb.c1596
-rw-r--r--source4/dsdb/samdb/ldb_modules/schema_fsmo.c114
-rw-r--r--source4/dsdb/samdb/ldb_modules/show_deleted.c166
-rw-r--r--source4/dsdb/samdb/ldb_modules/simple_ldap_map.c115
-rw-r--r--source4/dsdb/samdb/ldb_modules/subtree_delete.c232
-rw-r--r--source4/dsdb/samdb/ldb_modules/subtree_rename.c332
-rw-r--r--source4/dsdb/samdb/ldb_modules/tests/samba3sam.py515
-rw-r--r--source4/dsdb/samdb/ldb_modules/update_keytab.c249
25 files changed, 6049 insertions, 4775 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/anr.c b/source4/dsdb/samdb/ldb_modules/anr.c
index 4e2c527fe9..da23030ed3 100644
--- a/source4/dsdb/samdb/ldb_modules/anr.c
+++ b/source4/dsdb/samdb/ldb_modules/anr.c
@@ -1,7 +1,8 @@
/*
ldb database library
- Copyright (C) Amdrew Bartlett <abartlet@samba.org> 2007
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+ Copyright (C) Simo Sorce <idra@samba.org> 2008
Copyright (C) Andrew Tridgell 2004
This program is free software; you can redistribute it and/or modify
@@ -35,7 +36,7 @@
/**
* Make a and 'and' or 'or' tree from the two supplied elements
*/
-struct ldb_parse_tree *make_parse_list(struct ldb_module *module,
+static struct ldb_parse_tree *make_parse_list(struct ldb_module *module,
TALLOC_CTX *mem_ctx, enum ldb_parse_op op,
struct ldb_parse_tree *first_arm, struct ldb_parse_tree *second_arm)
{
@@ -62,7 +63,7 @@ struct ldb_parse_tree *make_parse_list(struct ldb_module *module,
/**
* Make an equality or prefix match tree, from the attribute, operation and matching value supplied
*/
-struct ldb_parse_tree *make_match_tree(struct ldb_module *module,
+static struct ldb_parse_tree *make_match_tree(struct ldb_module *module,
TALLOC_CTX *mem_ctx, enum ldb_parse_op op,
const char *attr, const DATA_BLOB *match)
{
@@ -99,6 +100,7 @@ struct ldb_parse_tree *make_match_tree(struct ldb_module *module,
struct anr_context {
bool found_anr;
struct ldb_module *module;
+ struct ldb_request *req;
};
/**
@@ -106,39 +108,35 @@ struct anr_context {
* parse tree with an 'or' of all the anr attributes in the schema.
*/
-typedef struct ldb_parse_tree *(*anr_parse_tree_callback_t)(TALLOC_CTX *mem_ctx,
- const struct ldb_val *match,
- void *context);
-
-
/**
- * Callback function to do the heavy lifting for the for the parse tree walker
+ * Callback function to do the heavy lifting for the parse tree walker
*/
-struct ldb_parse_tree *anr_replace_callback(TALLOC_CTX *mem_ctx,
- const struct ldb_val *match,
- void *context)
+static int anr_replace_value(struct anr_context *ac,
+ TALLOC_CTX *mem_ctx,
+ const struct ldb_val *match,
+ struct ldb_parse_tree **ntree)
{
struct ldb_parse_tree *tree = NULL;
- struct anr_context *anr_context = talloc_get_type(context, struct anr_context);
- struct ldb_module *module = anr_context->module;
+ struct ldb_module *module = ac->module;
struct ldb_parse_tree *match_tree;
- uint8_t *p;
- enum ldb_parse_op op;
struct dsdb_attribute *cur;
const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
+ uint8_t *p;
+ enum ldb_parse_op op;
+
if (!schema) {
ldb_asprintf_errstring(module->ldb, "no schema with which to construct anr filter");
- return NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
}
- anr_context->found_anr = true;
+ ac->found_anr = true;
if (match->length > 1 && match->data[0] == '=') {
- DATA_BLOB *match2 = talloc(tree, DATA_BLOB);
+ DATA_BLOB *match2 = talloc(mem_ctx, DATA_BLOB);
*match2 = data_blob_const(match->data+1, match->length - 1);
if (match2 == NULL){
ldb_oom(module->ldb);
- return NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
}
match = match2;
op = LDB_OP_EQUALITY;
@@ -154,7 +152,7 @@ struct ldb_parse_tree *anr_replace_callback(TALLOC_CTX *mem_ctx,
tree = make_parse_list(module, mem_ctx, LDB_OP_OR, tree, match_tree);
if (tree == NULL) {
ldb_oom(module->ldb);
- return NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
}
} else {
tree = match_tree;
@@ -173,7 +171,7 @@ struct ldb_parse_tree *anr_replace_callback(TALLOC_CTX *mem_ctx,
DATA_BLOB *second_match = talloc(tree, DATA_BLOB);
if (!first_match || !second_match) {
ldb_oom(module->ldb);
- return NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
}
*first_match = data_blob_const(match->data, p-match->data);
*second_match = data_blob_const(p+1, match->length - (p-match->data) - 1);
@@ -183,26 +181,26 @@ struct ldb_parse_tree *anr_replace_callback(TALLOC_CTX *mem_ctx,
match_tree_1 = make_match_tree(module, mem_ctx, op, "givenName", first_match);
match_tree_2 = make_match_tree(module, mem_ctx, op, "sn", second_match);
- first_split_filter = make_parse_list(module, context, LDB_OP_AND, match_tree_1, match_tree_2);
+ first_split_filter = make_parse_list(module, ac, LDB_OP_AND, match_tree_1, match_tree_2);
if (first_split_filter == NULL){
ldb_oom(module->ldb);
- return NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
}
match_tree_1 = make_match_tree(module, mem_ctx, op, "sn", first_match);
match_tree_2 = make_match_tree(module, mem_ctx, op, "givenName", second_match);
- second_split_filter = make_parse_list(module, context, LDB_OP_AND, match_tree_1, match_tree_2);
+ second_split_filter = make_parse_list(module, ac, LDB_OP_AND, match_tree_1, match_tree_2);
if (second_split_filter == NULL){
ldb_oom(module->ldb);
- return NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
}
split_filters = make_parse_list(module, mem_ctx, LDB_OP_OR,
first_split_filter, second_split_filter);
if (split_filters == NULL) {
ldb_oom(module->ldb);
- return NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
}
if (tree) {
@@ -212,38 +210,46 @@ struct ldb_parse_tree *anr_replace_callback(TALLOC_CTX *mem_ctx,
tree = split_filters;
}
}
- return tree;
+ *ntree = tree;
+ return LDB_SUCCESS;
}
/*
replace any occurances of an attribute with a new, generated attribute tree
*/
-struct ldb_parse_tree *anr_replace_subtrees(struct ldb_parse_tree *tree,
- const char *attr,
- anr_parse_tree_callback_t callback,
- void *context)
+static int anr_replace_subtrees(struct anr_context *ac,
+ struct ldb_parse_tree *tree,
+ const char *attr,
+ struct ldb_parse_tree **ntree)
{
+ int ret;
int i;
- struct ldb_parse_tree *tmp;
switch (tree->operation) {
case LDB_OP_AND:
case LDB_OP_OR:
for (i=0;i<tree->u.list.num_elements;i++) {
- tmp = anr_replace_subtrees(tree->u.list.elements[i],
- attr, callback, context);
- if (tmp) tree->u.list.elements[i] = tmp;
+ ret = anr_replace_subtrees(ac, tree->u.list.elements[i],
+ attr, &tree->u.list.elements[i]);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ *ntree = tree;
}
break;
case LDB_OP_NOT:
- tmp = anr_replace_subtrees(tree->u.isnot.child, attr, callback, context);
- if (tmp) tree->u.isnot.child = tmp;
+ ret = anr_replace_subtrees(ac, tree->u.isnot.child, attr, &tree->u.isnot.child);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ *ntree = tree;
break;
case LDB_OP_EQUALITY:
if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
- tmp = callback(tree, &tree->u.equality.value,
- context);
- if (tmp) tree = tmp;
+ ret = anr_replace_value(ac, tree, &tree->u.equality.value, ntree);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
break;
case LDB_OP_SUBSTRING:
@@ -252,53 +258,97 @@ struct ldb_parse_tree *anr_replace_subtrees(struct ldb_parse_tree *tree,
tree->u.substring.end_with_wildcard == 1 &&
tree->u.substring.chunks[0] != NULL &&
tree->u.substring.chunks[1] == NULL) {
- tmp = callback(tree, tree->u.substring.chunks[0], context);
- if (tmp) tree = tmp;
+ ret = anr_replace_value(ac, tree, tree->u.substring.chunks[0], ntree);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
}
break;
+ default:
+ break;
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int anr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct anr_context *ac;
+
+ ac = talloc_get_type(req->context, struct anr_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ return ldb_module_send_entry(ac->req, ares->message);
+
+ case LDB_REPLY_REFERRAL:
+ return ldb_module_send_referral(ac->req, ares->referral);
+
+ case LDB_REPLY_DONE:
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+
}
- return tree;
+ return LDB_SUCCESS;
}
/* search */
static int anr_search(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_parse_tree *anr_tree;
- struct anr_context *context = talloc(req, struct anr_context);
- if (!context) {
+ struct ldb_request *down_req;
+ struct anr_context *ac;
+ int ret;
+
+ ac = talloc(req, struct anr_context);
+ if (!ac) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- context->module = module;
- context->found_anr = false;
+ ac->module = module;
+ ac->req = req;
+ ac->found_anr = false;
#if 0
printf("oldanr : %s\n", ldb_filter_from_tree (0, req->op.search.tree));
#endif
- /* Yes, this is a problem with req->op.search.tree being const... */
- anr_tree = anr_replace_subtrees(req->op.search.tree, "anr", anr_replace_callback, context);
- if (!anr_tree) {
- talloc_free(context);
+ ret = anr_replace_subtrees(ac, req->op.search.tree, "anr", &anr_tree);
+ if (ret != LDB_SUCCESS) {
return LDB_ERR_OPERATIONS_ERROR;
}
- if (context->found_anr) {
- /* The above function modifies the tree if it finds "anr", so no
- * point just setting this on the down_req */
-#if 0
- printf("newtree: %s\n", ldb_filter_from_tree (0, anr_tree));
-#endif
- req->op.search.tree = talloc_steal(req, anr_tree);
- } else {
- if (anr_tree != req->op.search.tree) {
- talloc_free(anr_tree);
- }
- talloc_free(context);
+ if (!ac->found_anr) {
+ talloc_free(ac);
+ return ldb_next_request(module, req);
}
- return ldb_next_request(module, req);
+
+ ret = ldb_build_search_req_ex(&down_req,
+ module->ldb, ac,
+ req->op.search.base,
+ req->op.search.scope,
+ anr_tree,
+ req->op.search.attrs,
+ req->controls,
+ ac, anr_search_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ talloc_steal(down_req, anr_tree);
+
+ return ldb_next_request(module, down_req);
}
_PUBLIC_ const struct ldb_module_ops ldb_anr_module_ops = {
diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn.c b/source4/dsdb/samdb/ldb_modules/extended_dn.c
index 84bf5e4843..a0602d9281 100644
--- a/source4/dsdb/samdb/ldb_modules/extended_dn.c
+++ b/source4/dsdb/samdb/ldb_modules/extended_dn.c
@@ -1,7 +1,7 @@
/*
ldb database library
- Copyright (C) Simo Sorce 2005
+ Copyright (C) Simo Sorce 2005-2008
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
@@ -95,7 +95,7 @@ static bool add_attrs(void *mem_ctx, char ***attrs, const char *attr)
return true;
}
-static bool inject_extended_dn(struct ldb_message *msg,
+static int inject_extended_dn(struct ldb_message *msg,
struct ldb_context *ldb,
int type,
bool remove_guid,
@@ -113,8 +113,9 @@ static bool inject_extended_dn(struct ldb_message *msg,
guid_blob = ldb_msg_find_ldb_val(msg, "objectGUID");
sid_blob = ldb_msg_find_ldb_val(msg, "objectSID");
- if (!guid_blob)
- return false;
+ if (!guid_blob) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
switch (type) {
case 0:
@@ -123,7 +124,7 @@ static bool inject_extended_dn(struct ldb_message *msg,
const char *lower_guid_hex = strlower_talloc(msg, data_blob_hex_string(msg, guid_blob));
const char *lower_sid_hex = strlower_talloc(msg, data_blob_hex_string(msg, sid_blob));
if (!lower_guid_hex || !lower_sid_hex) {
- return false;
+ return LDB_ERR_OPERATIONS_ERROR;
}
new_dn = talloc_asprintf(msg, "<GUID=%s>;<SID=%s>;%s",
lower_guid_hex,
@@ -132,7 +133,7 @@ static bool inject_extended_dn(struct ldb_message *msg,
} else {
const char *lower_guid_hex = strlower_talloc(msg, data_blob_hex_string(msg, guid_blob));
if (!lower_guid_hex) {
- return false;
+ return LDB_ERR_OPERATIONS_ERROR;
}
new_dn = talloc_asprintf(msg, "<GUID=%s>;%s",
lower_guid_hex,
@@ -151,8 +152,8 @@ static bool inject_extended_dn(struct ldb_message *msg,
if (sid) {
object_sid = dom_sid_string(msg, sid);
if (!object_sid)
- return false;
-
+ return LDB_ERR_OPERATIONS_ERROR;
+
}
/* Normal, sane format */
@@ -167,11 +168,11 @@ static bool inject_extended_dn(struct ldb_message *msg,
}
break;
default:
- return false;
+ return LDB_ERR_OPERATIONS_ERROR;
}
if (!new_dn) {
- return false;
+ return LDB_ERR_OPERATIONS_ERROR;
}
if (remove_guid) {
@@ -184,50 +185,186 @@ static bool inject_extended_dn(struct ldb_message *msg,
msg->dn = ldb_dn_new(msg, ldb, new_dn);
if (! ldb_dn_validate(msg->dn))
- return false;
+ return LDB_ERR_OPERATIONS_ERROR;
val = ldb_msg_find_ldb_val(msg, "distinguishedName");
if (val) {
ldb_msg_remove_attr(msg, "distinguishedName");
if (ldb_msg_add_steal_string(msg, "distinguishedName", new_dn))
- return false;
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return true;
+ return LDB_SUCCESS;
}
/* search */
struct extended_context {
struct ldb_module *module;
- void *up_context;
- int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
-
- const char * const *attrs;
+ struct ldb_request *req;
+ struct ldb_control *control;
+ struct ldb_dn *basedn;
+ char *wellknown_object;
+ bool inject;
bool remove_guid;
bool remove_sid;
int extended_type;
+ const char * const *cast_attrs;
};
-static int extended_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int extended_callback(struct ldb_request *req, struct ldb_reply *ares)
{
struct extended_context *ac;
+ int ret;
- ac = talloc_get_type(context, struct extended_context);
+ ac = talloc_get_type(req->context, struct extended_context);
- if (ares->type == LDB_REPLY_ENTRY) {
- /* for each record returned post-process to add any derived
- attributes that have been asked for */
- if (!inject_extended_dn(ares->message, ldb, ac->extended_type, ac->remove_guid, ac->remove_sid)) {
- goto error;
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (ac->inject) {
+ /* for each record returned post-process to add any derived
+ attributes that have been asked for */
+ ret = inject_extended_dn(ares->message, ac->module->ldb,
+ ac->extended_type, ac->remove_guid,
+ ac->remove_sid);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
}
+
+ return ldb_module_send_entry(ac->req, ares->message);
+
+ case LDB_REPLY_REFERRAL:
+ return ldb_module_send_referral(ac->req, ares->referral);
+
+ case LDB_REPLY_DONE:
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+
+ }
+ return LDB_SUCCESS;
+}
+
+static int extended_base_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct extended_context *ac;
+ struct ldb_request *down_req;
+ struct ldb_control **saved_controls;
+ struct ldb_message_element *el;
+ int ret;
+ size_t i;
+ size_t wkn_len = 0;
+ char *valstr = NULL;
+ const char *found = NULL;
+
+ ac = talloc_get_type(req->context, struct extended_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- return ac->up_callback(ldb, ac->up_context, ares);
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (!ac->wellknown_object) {
+ ac->basedn = ares->message->dn;
+ break;
+ }
+
+ wkn_len = strlen(ac->wellknown_object);
-error:
- talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ el = ldb_msg_find_element(ares->message, "wellKnownObjects");
+ if (!el) {
+ ac->basedn = NULL;
+ break;
+ }
+
+ for (i=0; i < el->num_values; i++) {
+ valstr = talloc_strndup(ac,
+ (const char *)el->values[i].data,
+ el->values[i].length);
+ if (!valstr) {
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (strncasecmp(valstr, ac->wellknown_object, wkn_len) != 0) {
+ talloc_free(valstr);
+ continue;
+ }
+
+ found = &valstr[wkn_len];
+ break;
+ }
+
+ if (!found) {
+ break;
+ }
+
+ ac->basedn = ldb_dn_new(ac, ac->module->ldb, found);
+ talloc_free(valstr);
+ if (!ac->basedn) {
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ break;
+
+ case LDB_REPLY_DONE:
+
+ if (!ac->basedn) {
+ const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
+ ldb_dn_get_linearized(ac->req->op.search.base));
+ ldb_set_errstring(ac->module->ldb, str);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_NO_SUCH_OBJECT);
+ }
+
+ ret = ldb_build_search_req_ex(&down_req,
+ ac->module->ldb, ac,
+ ac->basedn,
+ ac->req->op.search.scope,
+ ac->req->op.search.tree,
+ ac->cast_attrs,
+ ac->req->controls,
+ ac, extended_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ac->control) {
+ /* save it locally and remove it from the list */
+ /* we do not need to replace them later as we
+ * are keeping the original req intact */
+ if (!save_controls(ac->control, down_req, &saved_controls)) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ }
+
+ /* perform the search */
+ return ldb_next_request(ac->module, down_req);
+ }
+ return LDB_SUCCESS;
}
static int extended_search(struct ldb_module *module, struct ldb_request *req)
@@ -239,126 +376,286 @@ static int extended_search(struct ldb_module *module, struct ldb_request *req)
struct ldb_request *down_req;
char **new_attrs;
int ret;
+ struct ldb_dn *base_dn = NULL;
+ enum ldb_scope base_dn_scope = LDB_SCOPE_BASE;
+ const char *base_dn_filter = NULL;
+ const char * const *base_dn_attrs = NULL;
+ char *wellknown_object = NULL;
+ static const char *dnattr[] = {
+ "distinguishedName",
+ NULL
+ };
+ static const char *wkattr[] = {
+ "wellKnownObjects",
+ NULL
+ };
+
+ if (ldb_dn_is_special(req->op.search.base)) {
+ char *dn;
+
+ dn = ldb_dn_alloc_linearized(req, req->op.search.base);
+ if (!dn) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (strncasecmp(dn, "<SID=", 5) == 0) {
+ char *str;
+ char *valstr;
+ char *p;
+
+ p = strchr(dn, '=');
+ if (!p) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ p[0] = '\0';
+ p++;
+
+ str = p;
+
+ p = strchr(str, '>');
+ if (!p) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ p[0] = '\0';
+
+ if (strncasecmp(str, "S-", 2) == 0) {
+ valstr = str;
+ } else {
+ DATA_BLOB binary;
+ binary = strhex_to_data_blob(NULL, str);
+ if (!binary.data) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ valstr = ldb_binary_encode(req, binary);
+ data_blob_free(&binary);
+ if (!valstr) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ /* TODO: do a search over all partitions */
+ base_dn = ldb_get_default_basedn(module->ldb);
+ base_dn_filter = talloc_asprintf(req, "(objectSid=%s)", valstr);
+ if (!base_dn_filter) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ base_dn_scope = LDB_SCOPE_SUBTREE;
+ base_dn_attrs = dnattr;
+ } else if (strncasecmp(dn, "<GUID=", 6) == 0) {
+ char *str;
+ char *valstr;
+ char *p;
+
+ p = strchr(dn, '=');
+ if (!p) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ p[0] = '\0';
+ p++;
+
+ str = p;
+
+ p = strchr(str, '>');
+ if (!p) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ p[0] = '\0';
+
+ if (strchr(str, '-')) {
+ valstr = str;
+ } else {
+ DATA_BLOB binary;
+ binary = strhex_to_data_blob(NULL, str);
+ if (!binary.data) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ valstr = ldb_binary_encode(req, binary);
+ data_blob_free(&binary);
+ if (!valstr) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ /* TODO: do a search over all partitions */
+ base_dn = ldb_get_default_basedn(module->ldb);
+ base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)", valstr);
+ if (!base_dn_filter) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ base_dn_scope = LDB_SCOPE_SUBTREE;
+ base_dn_attrs = dnattr;
+ } else if (strncasecmp(dn, "<WKGUID=", 8) == 0) {
+ char *tail_str;
+ char *p;
+
+ p = strchr(dn, ',');
+ if (!p) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ p[0] = '\0';
+ p++;
+
+ wellknown_object = talloc_asprintf(req, "B:32:%s:", &dn[8]);
+ if (!wellknown_object) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ tail_str = p;
+ p = strchr(tail_str, '>');
+ if (!p) {
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ p[0] = '\0';
+
+ base_dn = ldb_dn_new(req, module->ldb, tail_str);
+ if (!base_dn) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ base_dn_filter = talloc_strdup(req, "(objectClass=*)");
+ if (!base_dn_filter) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ base_dn_scope = LDB_SCOPE_BASE;
+ base_dn_attrs = wkattr;
+ }
+ talloc_free(dn);
+ }
/* check if there's an extended dn control */
control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID);
- if (control == NULL) {
+ if (control == NULL && base_dn_filter == NULL) {
/* not found go on */
return ldb_next_request(module, req);
}
- if (control->data) {
+ if (control && control->data) {
extended_ctrl = talloc_get_type(control->data, struct ldb_extended_dn_control);
if (!extended_ctrl) {
return LDB_ERR_PROTOCOL_ERROR;
}
}
- ac = talloc(req, struct extended_context);
+ ac = talloc_zero(req, struct extended_context);
if (ac == NULL) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->module = module;
- ac->up_context = req->context;
- ac->up_callback = req->callback;
- ac->attrs = req->op.search.attrs;
+ ac->req = req;
+ ac->control = control;
+ ac->basedn = NULL;
+ ac->wellknown_object = wellknown_object;
+ ac->inject = false;
ac->remove_guid = false;
ac->remove_sid = false;
- if (extended_ctrl) {
- ac->extended_type = extended_ctrl->type;
- } else {
- ac->extended_type = 0;
- }
-
- down_req = talloc_zero(req, struct ldb_request);
- if (down_req == NULL) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- down_req->operation = req->operation;
- down_req->op.search.base = req->op.search.base;
- down_req->op.search.scope = req->op.search.scope;
- down_req->op.search.tree = req->op.search.tree;
- /* check if attrs only is specified, in that case check wether we need to modify them */
- if (req->op.search.attrs) {
- if (! is_attr_in_list(req->op.search.attrs, "objectGUID")) {
- ac->remove_guid = true;
+ if (control) {
+ ac->inject = true;
+ if (extended_ctrl) {
+ ac->extended_type = extended_ctrl->type;
+ } else {
+ ac->extended_type = 0;
}
- if (! is_attr_in_list(req->op.search.attrs, "objectSID")) {
- ac->remove_sid = true;
- }
- if (ac->remove_guid || ac->remove_sid) {
- new_attrs = copy_attrs(down_req, req->op.search.attrs);
- if (new_attrs == NULL) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+
+ /* check if attrs only is specified, in that case check wether we need to modify them */
+ if (req->op.search.attrs) {
+ if (! is_attr_in_list(req->op.search.attrs, "objectGUID")) {
+ ac->remove_guid = true;
}
-
- if (ac->remove_guid) {
- if (!add_attrs(down_req, &new_attrs, "objectGUID"))
- return LDB_ERR_OPERATIONS_ERROR;
+ if (! is_attr_in_list(req->op.search.attrs, "objectSID")) {
+ ac->remove_sid = true;
}
- if (ac->remove_sid) {
- if (!add_attrs(down_req, &new_attrs, "objectSID"))
+ if (ac->remove_guid || ac->remove_sid) {
+ new_attrs = copy_attrs(ac, req->op.search.attrs);
+ if (new_attrs == NULL) {
+ ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
- }
+ }
- down_req->op.search.attrs = (const char * const *)new_attrs;
+ if (ac->remove_guid) {
+ if (!add_attrs(ac, &new_attrs, "objectGUID"))
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ac->remove_sid) {
+ if (!add_attrs(ac, &new_attrs, "objectSID"))
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->cast_attrs = (const char * const *)new_attrs;
+ } else {
+ ac->cast_attrs = req->op.search.attrs;
+ }
}
}
- down_req->controls = req->controls;
+ if (base_dn) {
+ ret = ldb_build_search_req(&down_req,
+ module->ldb, ac,
+ base_dn,
+ base_dn_scope,
+ base_dn_filter,
+ base_dn_attrs,
+ NULL,
+ ac, extended_base_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- /* save it locally and remove it from the list */
- /* we do not need to replace them later as we
- * are keeping the original req intact */
- if (!save_controls(control, down_req, &saved_controls)) {
- return LDB_ERR_OPERATIONS_ERROR;
+ /* perform the search */
+ return ldb_next_request(module, down_req);
}
- down_req->context = ac;
- down_req->callback = extended_callback;
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* perform the search */
- ret = ldb_next_request(module, down_req);
+ ret = ldb_build_search_req_ex(&down_req,
+ module->ldb, ac,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ ac->cast_attrs,
+ req->controls,
+ ac, extended_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ if (ac->control) {
+ /* save it locally and remove it from the list */
+ /* we do not need to replace them later as we
+ * are keeping the original req intact */
+ if (!save_controls(control, down_req, &saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
}
- return ret;
+ /* perform the search */
+ return ldb_next_request(module, down_req);
}
static int extended_init(struct ldb_module *module)
{
- struct ldb_request *req;
int ret;
- req = talloc(module, struct ldb_request);
- if (req == NULL) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_REQ_REGISTER_CONTROL;
- req->op.reg_control.oid = LDB_CONTROL_EXTENDED_DN_OID;
- req->controls = NULL;
-
- ret = ldb_request(module->ldb, req);
+ ret = ldb_mod_register_control(module, LDB_CONTROL_EXTENDED_DN_OID);
if (ret != LDB_SUCCESS) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "extended_dn: Unable to register control with rootdse!\n");
- talloc_free(req);
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "extended_dn: Unable to register control with rootdse!\n");
return LDB_ERR_OPERATIONS_ERROR;
}
- talloc_free(req);
return ldb_next_init(module);
}
diff --git a/source4/dsdb/samdb/ldb_modules/instancetype.c b/source4/dsdb/samdb/ldb_modules/instancetype.c
index fd5aa5e18a..492ef1c92b 100644
--- a/source4/dsdb/samdb/ldb_modules/instancetype.c
+++ b/source4/dsdb/samdb/ldb_modules/instancetype.c
@@ -1,7 +1,7 @@
/*
ldb database library
- Copyright (C) Simo Sorce 2004-2006
+ Copyright (C) Simo Sorce 2004-2008
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
Copyright (C) Andrew Tridgell 2005
Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
@@ -41,11 +41,43 @@
#include "dsdb/samdb/samdb.h"
#include "dsdb/common/flags.h"
+struct it_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+};
+
+static int it_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct it_context *ac;
+
+ ac = talloc_get_type(req->context, struct it_context);
+
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+}
+
/* add_record: add instancetype attribute */
static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_request *down_req;
struct ldb_message *msg;
+ struct it_context *ac;
uint32_t instance_type;
int ret;
const struct ldb_control *partition_ctrl;
@@ -70,18 +102,16 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
struct dsdb_control_current_partition);
SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
- ldb_oom(module->ldb);
+ ac = talloc(req, struct it_context);
+ if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
- *down_req = *req;
+ ac->module = module;
+ ac->req = req;
/* we have to copy the message as the caller might have it as a const */
- down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
+ msg = ldb_msg_copy_shallow(ac, req->op.add.message);
if (msg == NULL) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -99,23 +129,21 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
ret = ldb_msg_add_fmt(msg, "instanceType", "%u", instance_type);
if (ret != LDB_SUCCESS) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ ret = ldb_build_add_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, it_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return ret;
+ /* go on with the call chain */
+ return ldb_next_request(module, down_req);
}
_PUBLIC_ const struct ldb_module_ops ldb_instancetype_module_ops = {
diff --git a/source4/dsdb/samdb/ldb_modules/kludge_acl.c b/source4/dsdb/samdb/ldb_modules/kludge_acl.c
index bc998a835a..6acbf45afd 100644
--- a/source4/dsdb/samdb/ldb_modules/kludge_acl.c
+++ b/source4/dsdb/samdb/ldb_modules/kludge_acl.c
@@ -2,7 +2,7 @@
ldb database library
Copyright (C) Andrew Bartlett 2005
- Copyright (C) Simo Sorce 2006
+ Copyright (C) Simo Sorce 2006-2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -74,15 +74,14 @@ static const char *user_name(TALLOC_CTX *mem_ctx, struct ldb_module *module)
struct kludge_acl_context {
struct ldb_module *module;
- void *up_context;
- int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
+ struct ldb_request *req;
enum security_user_level user_type;
bool allowedAttributes;
bool allowedAttributesEffective;
bool allowedChildClasses;
bool allowedChildClassesEffective;
- const char **attrs;
+ const char * const *attrs;
};
/* read all objectClasses */
@@ -142,7 +141,7 @@ static int kludge_acl_allowedAttributes(struct ldb_context *ldb, struct ldb_mess
ldb_msg_add_string(msg, attrName, attr_list[i]);
}
talloc_free(mem_ctx);
- return 0;
+ return LDB_SUCCESS;
}
/* read all objectClasses */
@@ -191,6 +190,7 @@ static int kludge_acl_childClasses(struct ldb_context *ldb, struct ldb_message *
(comparison_fn_t)data_blob_cmp);
for (i=1 ; i < allowedClasses->num_values; i++) {
+
struct ldb_val *val1 = &allowedClasses->values[i-1];
struct ldb_val *val2 = &allowedClasses->values[i];
if (data_blob_cmp(val1, val2) == 0) {
@@ -201,86 +201,117 @@ static int kludge_acl_childClasses(struct ldb_context *ldb, struct ldb_message *
}
}
- return 0;
+ return LDB_SUCCESS;
}
/* find all attributes allowed by all these objectClasses */
-static int kludge_acl_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int kludge_acl_callback(struct ldb_request *req, struct ldb_reply *ares)
{
struct kludge_acl_context *ac;
struct kludge_private_data *data;
int i, ret;
- ac = talloc_get_type(context, struct kludge_acl_context);
+ ac = talloc_get_type(req->context, struct kludge_acl_context);
data = talloc_get_type(ac->module->private_data, struct kludge_private_data);
- if (ares->type != LDB_REPLY_ENTRY) {
- return ac->up_callback(ldb, ac->up_context, ares);
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- if (ac->allowedAttributes) {
- ret = kludge_acl_allowedAttributes(ldb, ares->message, "allowedAttributes");
- if (ret != LDB_SUCCESS) {
- return ret;
-
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (ac->allowedAttributes) {
+ ret = kludge_acl_allowedAttributes(ac->module->ldb,
+ ares->message,
+ "allowedAttributes");
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
}
- }
- if (ac->allowedChildClasses) {
- ret = kludge_acl_childClasses(ldb, ares->message, "allowedChildClasses");
- if (ret != LDB_SUCCESS) {
- return ret;
+ if (ac->allowedChildClasses) {
+ ret = kludge_acl_childClasses(ac->module->ldb,
+ ares->message,
+ "allowedChildClasses");
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
}
- }
- if (data && data->password_attrs) /* if we are not initialized just get through */
- {
- switch (ac->user_type) {
- case SECURITY_SYSTEM:
- if (ac->allowedAttributesEffective) {
- ret = kludge_acl_allowedAttributes(ldb, ares->message, "allowedAttributesEffective");
- if (ret != LDB_SUCCESS) {
- return ret;
+ if (data && data->password_attrs) /* if we are not initialized just get through */
+ {
+ switch (ac->user_type) {
+ case SECURITY_SYSTEM:
+ if (ac->allowedAttributesEffective) {
+ ret = kludge_acl_allowedAttributes(ac->module->ldb, ares->message,
+ "allowedAttributesEffective");
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
}
- }
- if (ac->allowedChildClassesEffective) {
- ret = kludge_acl_childClasses(ldb, ares->message, "allowedChildClassesEffective");
- if (ret != LDB_SUCCESS) {
- return ret;
+ if (ac->allowedChildClassesEffective) {
+ ret = kludge_acl_childClasses(ac->module->ldb, ares->message,
+ "allowedChildClassesEffective");
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
}
- }
- break;
- case SECURITY_ADMINISTRATOR:
- if (ac->allowedAttributesEffective) {
- ret = kludge_acl_allowedAttributes(ldb, ares->message, "allowedAttributesEffective");
- if (ret != LDB_SUCCESS) {
- return ret;
+ break;
+
+ case SECURITY_ADMINISTRATOR:
+ if (ac->allowedAttributesEffective) {
+ ret = kludge_acl_allowedAttributes(ac->module->ldb, ares->message,
+ "allowedAttributesEffective");
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
}
- }
- if (ac->allowedChildClassesEffective) {
- ret = kludge_acl_childClasses(ldb, ares->message, "allowedChildClassesEffective");
- if (ret != LDB_SUCCESS) {
- return ret;
+ if (ac->allowedChildClassesEffective) {
+ ret = kludge_acl_childClasses(ac->module->ldb, ares->message,
+ "allowedChildClassesEffective");
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ }
+ /* fall through */
+ default:
+ /* remove password attributes */
+ for (i = 0; data->password_attrs[i]; i++) {
+ ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
}
}
- /* fall though */
- default:
- /* remove password attributes */
- for (i = 0; data->password_attrs[i]; i++) {
- ldb_msg_remove_attr(ares->message, data->password_attrs[i]);
+ }
+
+ if (ac->allowedAttributes ||
+ ac->allowedAttributesEffective ||
+ ac->allowedChildClasses ||
+ ac->allowedChildClassesEffective) {
+
+ if (!ldb_attr_in_list(ac->attrs, "objectClass") &&
+ !ldb_attr_in_list(ac->attrs, "*")) {
+
+ ldb_msg_remove_attr(ares->message,
+ "objectClass");
}
}
- }
- if ((ac->allowedAttributes || ac->allowedAttributesEffective
- || ac->allowedChildClasses || ac->allowedChildClassesEffective) &&
- (!ldb_attr_in_list(ac->attrs, "objectClass") &&
- !ldb_attr_in_list(ac->attrs, "*"))) {
- ldb_msg_remove_attr(ares->message, "objectClass");
- }
+ return ldb_module_send_entry(ac->req, ares->message);
+
+ case LDB_REPLY_REFERRAL:
+ return ldb_module_send_referral(ac->req, ares->referral);
- return ac->up_callback(ldb, ac->up_context, ares);
+ case LDB_REPLY_DONE:
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+
+ }
+ return LDB_SUCCESS;
}
static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
@@ -288,9 +319,10 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
struct kludge_acl_context *ac;
struct ldb_request *down_req;
struct kludge_private_data *data;
+ const char * const *attrs;
int ret, i;
-
- req->handle = NULL;
+ struct ldb_control *sd_control;
+ struct ldb_control **sd_saved_controls;
ac = talloc(req, struct kludge_acl_context);
if (ac == NULL) {
@@ -301,23 +333,10 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
data = talloc_get_type(module->private_data, struct kludge_private_data);
ac->module = module;
- ac->up_context = req->context;
- ac->up_callback = req->callback;
+ ac->req = req;
ac->user_type = what_is_user(module);
ac->attrs = req->op.search.attrs;
- down_req = talloc_zero(req, struct ldb_request);
- if (down_req == NULL) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- down_req->operation = req->operation;
- down_req->op.search.base = req->op.search.base;
- down_req->op.search.scope = req->op.search.scope;
- down_req->op.search.tree = req->op.search.tree;
- down_req->op.search.attrs = req->op.search.attrs;
-
ac->allowedAttributes = ldb_attr_in_list(req->op.search.attrs, "allowedAttributes");
ac->allowedAttributesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedAttributesEffective");
@@ -327,12 +346,11 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
if (ac->allowedAttributes || ac->allowedAttributesEffective || ac->allowedChildClasses || ac->allowedChildClassesEffective) {
- down_req->op.search.attrs
- = ldb_attr_list_copy_add(down_req, down_req->op.search.attrs, "objectClass");
+ attrs = ldb_attr_list_copy_add(ac, req->op.search.attrs, "objectClass");
+ } else {
+ attrs = req->op.search.attrs;
}
- /* FIXME: I hink we should copy the tree and keep the original
- * unmodified. SSS */
/* replace any attributes in the parse tree that are private,
so we don't allow a search for 'userPassword=penguin',
just as we would not allow that attribute to be returned */
@@ -340,30 +358,45 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
case SECURITY_SYSTEM:
break;
default:
+ /* FIXME: We should copy the tree and keep the original unmodified. */
/* remove password attributes */
- for (i = 0; data && data->password_attrs && data->password_attrs[i]; i++) {
- ldb_parse_tree_attr_replace(down_req->op.search.tree,
+
+ if (!data || !data->password_attrs) {
+ break;
+ }
+ for (i = 0; data->password_attrs[i]; i++) {
+ ldb_parse_tree_attr_replace(req->op.search.tree,
data->password_attrs[i],
"kludgeACLredactedattribute");
}
}
- down_req->controls = req->controls;
-
- down_req->context = ac;
- down_req->callback = kludge_acl_callback;
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* perform the search */
- ret = ldb_next_request(module, down_req);
+ ret = ldb_build_search_req_ex(&down_req,
+ module->ldb, ac,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ attrs,
+ req->controls,
+ ac, kludge_acl_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ /* check if there's an SD_FLAGS control */
+ sd_control = ldb_request_get_control(down_req, LDB_CONTROL_SD_FLAGS_OID);
+ if (sd_control) {
+ /* save it locally and remove it from the list */
+ /* we do not need to replace them later as we
+ * are keeping the original req intact */
+ if (!save_controls(sd_control, down_req, &sd_saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
}
- return ret;
+ /* perform the search */
+ return ldb_next_request(module, down_req);
}
/* ANY change type */
@@ -409,14 +442,12 @@ static int kludge_acl_init(struct ldb_module *module)
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_search(module->ldb, ldb_dn_new(mem_ctx, module->ldb, "@KLUDGEACL"),
- LDB_SCOPE_BASE,
- NULL, attrs,
- &res);
+ ret = ldb_search(module->ldb, mem_ctx, &res,
+ ldb_dn_new(mem_ctx, module->ldb, "@KLUDGEACL"),
+ LDB_SCOPE_BASE, attrs, NULL);
if (ret != LDB_SUCCESS) {
goto done;
}
- talloc_steal(mem_ctx, res);
if (res->count == 0) {
goto done;
}
@@ -444,6 +475,13 @@ static int kludge_acl_init(struct ldb_module *module)
}
data->password_attrs[i] = NULL;
+ ret = ldb_mod_register_control(module, LDB_CONTROL_SD_FLAGS_OID);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "partition: Unable to register control with rootdse!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
done:
talloc_free(mem_ctx);
return ldb_next_init(module);
diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c
index e64472432d..14fd107d81 100644
--- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c
+++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c
@@ -2,6 +2,7 @@
ldb database library
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+ Copyright (C) Simo Sorce <idra@samba.org> 2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,234 +34,176 @@
#include "ldb/include/ldb_private.h"
#include "dsdb/samdb/samdb.h"
-struct linked_attributes_context {
- 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 la_op_store {
+ struct la_op_store *next;
+ enum la_op {LA_OP_ADD, LA_OP_DEL} op;
+ struct ldb_dn *dn;
+ char *name;
+ char *value;
};
struct replace_context {
- struct linked_attributes_context *ac;
+ struct la_context *ac;
+ unsigned int num_elements;
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)
-{
- struct linked_attributes_context *ac;
- struct ldb_handle *h;
+struct la_context {
+ const struct dsdb_schema *schema;
+ struct ldb_module *module;
+ struct ldb_request *req;
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- return NULL;
- }
+ struct replace_context *rc;
+ struct la_op_store *ops;
+ struct la_op_store *cur;
+};
- h->module = module;
+static struct la_context *linked_attributes_init(struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct la_context *ac;
- ac = talloc_zero(h, struct linked_attributes_context);
+ ac = talloc_zero(req, struct la_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
- talloc_free(h);
return NULL;
}
- h->private_data = ac;
-
+ ac->schema = dsdb_get_schema(module->ldb);
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;
+ ac->req = req;
return ac;
}
/* Common routine to handle reading the attributes and creating a
* series of modify requests */
-
-static int setup_modifies(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
- struct linked_attributes_context *ac,
- const struct ldb_message *msg,
- struct ldb_dn *olddn, struct ldb_dn *newdn)
+static int la_store_op(struct la_context *ac,
+ enum la_op op, char *dn,
+ const char *name, const char *value)
{
- int i, j, ret = LDB_SUCCESS;
- const struct dsdb_schema *schema = dsdb_get_schema(ldb);
- /* Look up each of the returned attributes */
- /* Find their schema */
- /* And it is an actual entry: now create a series of modify requests */
- for (i=0; i < msg->num_elements; i++) {
- int otherid;
- const struct dsdb_attribute *target_attr;
- const struct ldb_message_element *el = &msg->elements[i];
- const struct dsdb_attribute *schema_attr
- = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
- if (!schema_attr) {
- ldb_asprintf_errstring(ldb,
- "attribute %s is not a valid attribute in schema", el->name);
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
- }
- /* We have a valid attribute, but if it's not linked they maybe we just got an extra return on our search... */
- if (schema_attr->linkID == 0) {
- continue;
- }
-
- /* Depending on which direction this link is in, we need to find it's partner */
- if ((schema_attr->linkID & 1) == 1) {
- otherid = schema_attr->linkID - 1;
- } else {
- otherid = schema_attr->linkID + 1;
- }
-
- /* Now find the target attribute */
- target_attr = dsdb_attribute_by_linkID(schema, otherid);
- if (!target_attr) {
- ldb_asprintf_errstring(ldb,
- "attribute %s does not have valid link target", el->name);
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
- }
-
- /* For each value being moded, we need to setup the modify */
- for (j=0; j < el->num_values; j++) {
- struct ldb_message_element *ret_el;
- struct ldb_request *new_req;
- struct ldb_message *new_msg;
-
- /* 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(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ struct la_op_store *os, *tmp;
+ struct ldb_dn *op_dn;
- /* Create the modify request */
- new_msg = ldb_msg_new(ac->down_req);
- if (!new_msg) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- new_msg->dn = ldb_dn_from_ldb_val(new_msg, ldb, &el->values[j]);
- if (!new_msg->dn) {
- ldb_asprintf_errstring(ldb,
- "attribute %s value %s was not a valid DN", msg->elements[i].name,
- el->values[j].data);
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
-
- if (olddn) {
- ret = ldb_msg_add_empty(new_msg, target_attr->lDAPDisplayName,
- LDB_FLAG_MOD_DELETE, &ret_el);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
- if (!ret_el->values) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ret_el->values[0] = data_blob_string_const(ldb_dn_get_linearized(olddn));
- ret_el->num_values = 1;
- }
-
- if (newdn) {
- ret = ldb_msg_add_empty(new_msg, target_attr->lDAPDisplayName,
- LDB_FLAG_MOD_ADD, &ret_el);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
- if (!ret_el->values) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ op_dn = ldb_dn_new(ac, ac->module->ldb, dn);
+ if (!op_dn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* optimize out del - add operations that would end up
+ * with no changes */
+ if (ac->ops && op == LA_OP_DEL) {
+ /* do a linear search to find out if there is
+ * an equivalent add */
+ os = ac->ops;
+ while (os->next) {
+
+ tmp = os->next;
+ if (tmp->op == LA_OP_ADD) {
+
+ if ((strcmp(name, tmp->name) == 0) &&
+ (strcmp(value, tmp->value) == 0) &&
+ (ldb_dn_compare(op_dn, tmp->dn) == 0)) {
+
+ break;
}
- ret_el->values[0] = data_blob_string_const(ldb_dn_get_linearized(newdn));
- ret_el->num_values = 1;
}
+ os = os->next;
+ }
+ if (os->next) {
+ /* pair found, remove it and return */
+ os->next = tmp->next;
+ talloc_free(tmp);
+ talloc_free(op_dn);
+ return LDB_SUCCESS;
+ }
+ }
- ret = ldb_build_mod_req(&new_req, ldb, ac->down_req,
- new_msg,
- NULL,
- NULL,
- NULL);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_steal(new_req, new_msg);
-
- ldb_set_timeout_from_prev_req(ldb, ac->orig_req, new_req);
-
- ac->down_req[ac->num_requests] = new_req;
- ac->num_requests++;
-
-
- /* Run the new request */
- ret = ldb_next_request(ac->module, new_req);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ os = talloc_zero(ac, struct la_op_store);
+ if (!os) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ os->op = op;
+
+ os->dn = talloc_steal(os, op_dn);
+ if (!os->dn) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ os->name = talloc_strdup(os, name);
+ if (!os->name) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if ((op != LA_OP_DEL) && (value == NULL)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (value) {
+ os->value = talloc_strdup(os, value);
+ if (!os->value) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
}
- return ret;
+
+ if (ac->ops) {
+ ac->cur->next = os;
+ } else {
+ ac->ops = os;
+ }
+ ac->cur = os;
+
+ return LDB_SUCCESS;
}
+static int la_op_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+static int la_do_mod_request(struct la_context *ac);
+static int la_mod_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+static int la_down_req(struct la_context *ac);
+static int la_down_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+
+
+
/* add */
static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req)
{
- int i;
- struct linked_attributes_context *ac;
-
- const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
- if (!schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
- }
+ const struct dsdb_attribute *target_attr;
+ struct la_context *ac;
+ const char *attr_name;
+ const char *attr_val;
+ int ret;
+ int i, j;
if (ldb_dn_is_special(req->op.mod.message->dn)) {
/* do not manipulate our control entries */
return ldb_next_request(module, req);
}
-
- ac = linked_attributes_init_handle(req, module);
+ ac = linked_attributes_init(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
- ac->step = LA_DO_OPS;
-
+
+ if (!ac->schema) {
+ /* without schema, this doesn't make any sense */
+ talloc_free(ac);
+ return ldb_next_request(module, req);
+ }
+
/* 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];
const struct dsdb_attribute *schema_attr
- = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+ = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
if (!schema_attr) {
ldb_asprintf_errstring(module->ldb,
- "attribute %s is not a valid attribute in schema", req->op.add.message->elements[i].name);
+ "attribute %s is not a valid attribute in schema", el->name);
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
- /* We have a valid attribute, not find out if it is linked */
+ /* We have a valid attribute, now find out if it is linked */
if (schema_attr->linkID == 0) {
continue;
}
@@ -268,160 +211,155 @@ static int linked_attributes_add(struct ldb_module *module, struct ldb_request *
if ((schema_attr->linkID & 1) == 1) {
/* Odd is for the target. Illigal to modify */
ldb_asprintf_errstring(module->ldb,
- "attribute %s must not be modified directly, it is a linked attribute", req->op.add.message->elements[i].name);
+ "attribute %s must not be modified directly, it is a linked attribute", el->name);
return LDB_ERR_UNWILLING_TO_PERFORM;
}
/* Even link IDs are for the originating attribute */
- }
-
- /* 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);
-}
+ target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
+ if (!target_attr) {
+ /*
+ * windows 2003 has a broken schema where
+ * the definition of msDS-IsDomainFor
+ * is missing (which is supposed to be
+ * the backlink of the msDS-HasDomainNCs
+ * attribute
+ */
+ continue;
+ }
-struct merge {
- struct ldb_dn *dn;
- bool add;
- bool ignore;
-};
+ attr_name = target_attr->lDAPDisplayName;
+ attr_val = ldb_dn_get_linearized(ac->req->op.add.message->dn);
-static int merge_cmp(struct merge *merge1, struct merge *merge2) {
- int ret;
- ret = ldb_dn_compare(merge1->dn, merge2->dn);
- if (ret == 0) {
- if (merge1->add == merge2->add) {
- return 0;
- }
- if (merge1->add == true) {
- return 1;
+ for (j = 0; j < el->num_values; j++) {
+ ret = la_store_op(ac, LA_OP_ADD,
+ (char *)el->values[j].data,
+ attr_name, attr_val);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
- return -1;
}
- return ret;
+
+ /* if no linked attributes are present continue */
+ if (ac->ops == NULL) {
+ talloc_free(ac);
+ return ldb_next_request(module, req);
+ }
+
+ /* start with the first one */
+ return la_do_mod_request(ac);
}
-static int linked_attributes_mod_replace_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int la_mod_search_callback(struct ldb_request *req, 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: */
+ const struct dsdb_attribute *schema_attr;
+ const struct dsdb_attribute *target_attr;
+ struct ldb_message_element *search_el;
+ struct replace_context *rc;
+ struct la_context *ac;
+ const char *attr_name;
+ const char *dn;
+ int i, j;
+ int ret = LDB_SUCCESS;
- /* 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) {
+ ac = talloc_get_type(req->context, struct la_context);
+ rc = ac->rc;
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- struct merge *merged_list = NULL;
+ /* Only entries are interesting, and we only want the olddn */
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+ if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) {
+ /* Guh? We only asked for this DN */
+ ldb_oom(ac->module->ldb);
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
- int ret, size = 0, i;
- struct ldb_message *msg = ldb_msg_new(ac);
- if (!msg) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ dn = ldb_dn_get_linearized(ac->req->op.add.message->dn);
- /* Add all the existing elements, marking as 'proposed for delete' by setting .add = false */
- for (i=0; i < search_el->num_values; i++) {
- merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1);
- merged_list[size].dn = ldb_dn_from_ldb_val(merged_list, ldb, &search_el->values[i]);
- merged_list[size].add = false;
- merged_list[size].ignore = false;
- size++;
- }
+ for (i = 0; i < rc->num_elements; i++) {
- /* Add all the new replacement elements, marking as 'proposed for add' by setting .add = true */
- for (i=0; i < ac2->el->num_values; i++) {
- merged_list = talloc_realloc(ares, merged_list, struct merge, size + 1);
- merged_list[size].dn = ldb_dn_from_ldb_val(merged_list, ldb, &ac2->el->values[i]);
- merged_list[size].add = true;
- merged_list[size].ignore = false;
- size++;
+ schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name);
+ if (!schema_attr) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "attribute %s is not a valid attribute in schema",
+ rc->el[i].name);
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OBJECT_CLASS_VIOLATION);
}
- /* Sort the list, so we can pick out an add and delete for the same DN, and eliminate them */
- qsort(merged_list, size,
- sizeof(*merged_list),
- (comparison_fn_t)merge_cmp);
-
- /* Now things are sorted, it is trivial to mark pairs of DNs as 'ignore' */
- for (i=0; i + 1 < size; i++) {
- if (ldb_dn_compare(merged_list[i].dn,
- merged_list[i+1].dn) == 0
- /* Fortunetly the sort also sorts 'add == false' first */
- && merged_list[i].add == false
- && merged_list[i+1].add == true) {
-
- /* Mark as ignore, so we include neither in the actual operations */
- merged_list[i].ignore = true;
- merged_list[i+1].ignore = true;
- }
- }
+ search_el = ldb_msg_find_element(ares->message,
+ rc->el[i].name);
- /* Arrange to delete anything the search found that we don't re-add */
- for (i=0; i < size; i++) {
- if (merged_list[i].ignore == false
- && merged_list[i].add == false) {
- ldb_msg_add_steal_string(msg, search_el->name,
- ldb_dn_get_linearized(merged_list[i].dn));
- }
+ /* See if this element already exists */
+ /* otherwise just ignore as
+ * the add has already been scheduled */
+ if ( ! search_el) {
+ continue;
}
- /* The DN to set on the linked attributes is the original DN of the modify message */
- 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;
+ target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
+ if (!target_attr) {
+ /*
+ * windows 2003 has a broken schema where
+ * the definition of msDS-IsDomainFor
+ * is missing (which is supposed to be
+ * the backlink of the msDS-HasDomainNCs
+ * attribute
+ */
+ continue;
}
+ attr_name = target_attr->lDAPDisplayName;
- /* Now add links for all the actually new elements */
- for (i=0; i < size; i++) {
- if (merged_list[i].ignore == false && merged_list[i].add == true) {
- ldb_msg_add_steal_string(msg, search_el->name,
- ldb_dn_get_linearized(merged_list[i].dn));
+ /* make sure we manage each value */
+ for (j = 0; j < search_el->num_values; j++) {
+ ret = la_store_op(ac, LA_OP_DEL,
+ (char *)search_el->values[j].data,
+ attr_name, dn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
}
}
+ }
- ret = setup_modifies(ac->module->ldb, ac2, ac, msg, NULL, ares->message->dn);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_free(merged_list);
+ break;
- } 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;
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ break;
- 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;
+ case LDB_REPLY_DONE:
- } else {
talloc_free(ares);
+
+ /* All mods set up, start with the first one */
+ ret = la_do_mod_request(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
return LDB_SUCCESS;
}
-
-
+
+ talloc_free(ares);
+ return ret;
}
+
+
/* modify */
static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req)
{
@@ -431,523 +369,556 @@ static int linked_attributes_modify(struct ldb_module *module, struct ldb_reques
/* Apply the modify to the linked entry */
int i, j;
- struct linked_attributes_context *ac;
-
- const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
- if (!schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
- }
+ struct la_context *ac;
+ struct ldb_request *search_req;
+ int ret;
if (ldb_dn_is_special(req->op.mod.message->dn)) {
/* do not manipulate our control entries */
return ldb_next_request(module, req);
}
-
- ac = linked_attributes_init_handle(req, module);
+ ac = linked_attributes_init(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
- /* prepare the first operation */
- ac->step = LA_DO_OPS;
+
+ if (!ac->schema) {
+ /* without schema, this doesn't make any sense */
+ return ldb_next_request(module, req);
+ }
+
+ ac->rc = NULL;
for (i=0; i < req->op.mod.message->num_elements; i++) {
- int ret;
- struct ldb_request *new_req;
+ bool store_el = false;
+ const char *attr_name;
+ const char *attr_val;
const struct dsdb_attribute *target_attr;
const struct ldb_message_element *el = &req->op.mod.message->elements[i];
const struct dsdb_attribute *schema_attr
- = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+ = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
if (!schema_attr) {
ldb_asprintf_errstring(module->ldb,
- "attribute %s is not a valid attribute in schema", req->op.mod.message->elements[i].name);
+ "attribute %s is not a valid attribute in schema", el->name);
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
- /* We have a valid attribute, not find out if it is linked */
+ /* We have a valid attribute, now find out if it is linked */
if (schema_attr->linkID == 0) {
continue;
}
if ((schema_attr->linkID & 1) == 1) {
- /* Odd is for the target. Illigal to modify */
+ /* Odd is for the target. Illegal to modify */
ldb_asprintf_errstring(module->ldb,
- "attribute %s must not be modified directly, it is a linked attribute", req->op.mod.message->elements[i].name);
+ "attribute %s must not be modified directly, it is a linked attribute", el->name);
return LDB_ERR_UNWILLING_TO_PERFORM;
}
/* Even link IDs are for the originating attribute */
/* Now find the target attribute */
- target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1);
+ target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
if (!target_attr) {
- ldb_asprintf_errstring(module->ldb,
- "attribute %s does not have valid link target", req->op.mod.message->elements[i].name);
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ /*
+ * windows 2003 has a broken schema where
+ * the definition of msDS-IsDomainFor
+ * is missing (which is supposed to be
+ * the backlink of the msDS-HasDomainNCs
+ * attribute
+ */
+ continue;
}
- /* Replace with new set of values */
- 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);
-
- ret = ldb_set_timeout_from_prev_req(module->ldb, req, new_req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ attr_name = target_attr->lDAPDisplayName;
+ attr_val = ldb_dn_get_linearized(ac->req->op.mod.message->dn);
- /* 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;
- }
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_REPLACE:
+ /* treat as just a normal add the delete part is handled by the callback */
+ store_el = true;
- ac->down_req[ac->num_requests] = talloc_steal(ac->down_req, new_req);
- ac->num_requests++;
+ /* break intentionally missing */
- ret = ldb_next_request(module, new_req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- continue;
+ case LDB_FLAG_MOD_ADD:
- /* Delete all values case */
- } 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;
+ /* For each value being added, we need to setup the adds */
+ for (j = 0; j < el->num_values; j++) {
+ ret = la_store_op(ac, LA_OP_ADD,
+ (char *)el->values[j].data,
+ attr_name, attr_val);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
- 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);
+ break;
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_steal(new_req, attrs);
-
- ret = ldb_set_timeout_from_prev_req(module->ldb, req, new_req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ case LDB_FLAG_MOD_DELETE:
- /* 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;
+ if (el->num_values) {
+ /* For each value being deleted, we need to setup the delete */
+ for (j = 0; j < el->num_values; j++) {
+ ret = la_store_op(ac, LA_OP_DEL,
+ (char *)el->values[j].data,
+ attr_name, attr_val);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ } else {
+ store_el = true;
}
- 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;
+ break;
}
- /* Prepare the modify (mod element) on the targets, for a normal modify request */
-
- /* For each value being moded, we need to setup the modify */
- for (j=0; j < el->num_values; j++) {
- /* Create the modify request */
- struct ldb_message *new_msg = ldb_msg_new(ac);
- if (!new_msg) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- new_msg->dn = ldb_dn_from_ldb_val(new_msg, module->ldb, &el->values[j]);
- if (!new_msg->dn) {
- ldb_asprintf_errstring(module->ldb,
- "attribute %s value %s was not a valid DN", req->op.mod.message->elements[i].name,
- el->values[j].data);
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
+ if (store_el) {
+ struct ldb_message_element *search_el;
- ret = ldb_msg_add_empty(new_msg, target_attr->lDAPDisplayName,
- el->flags & LDB_FLAG_MOD_MASK, NULL);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_msg_add_string(new_msg, target_attr->lDAPDisplayName,
- ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
- if (ret != LDB_SUCCESS) {
- return ret;
+ if (!ac->rc) {
+ ac->rc = talloc_zero(ac, struct replace_context);
+ if (!ac->rc) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
}
- ret = ldb_build_mod_req(&new_req, module->ldb, ac,
- new_msg,
- NULL,
- NULL,
- NULL);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- talloc_steal(new_req, new_msg);
-
- ret = ldb_set_timeout_from_prev_req(module->ldb, req, new_req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- /* Now add it to the list */
- 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);
+ search_el = talloc_realloc(ac->rc, ac->rc->el,
+ struct ldb_message_element,
+ ac->rc->num_elements +1);
+ if (!search_el) {
+ ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- ac->down_req[ac->num_requests] = talloc_steal(ac->down_req, new_req);
- ac->num_requests++;
+ ac->rc->el = search_el;
- /* Run the new request */
- ret = ldb_next_request(module, new_req);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ ac->rc->el[ac->rc->num_elements] = *el;
+ ac->rc->num_elements++;
}
}
- return LDB_SUCCESS;
-}
-static int linked_attributes_rename_del_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
-{
- struct linked_attributes_context *ac = talloc_get_type(context, struct linked_attributes_context);
- struct ldb_dn *olddn, *newdn;
-
- switch (ac->orig_req->operation) {
- case LDB_DELETE:
- {
- olddn = ac->orig_req->op.del.dn;
- 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;
- newdn = ac->orig_req->op.rename.newdn;
- break;
- }
- default:
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
+ /* both replace and delete without values are handled in the callback
+ * after the search on the entry to be modified is performed */
+ if (ac->rc) {
+ const char **attrs;
+
+ attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements +1);
+ if (!attrs) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ for (i = 0; i < ac->rc->num_elements; i++) {
+ attrs[i] = ac->rc->el[i].name;
+ }
+ attrs[i] = NULL;
- /* OK, we have one search result here: */
+ /* The callback does all the hard work here */
+ ret = ldb_build_search_req(&search_req, module->ldb, ac,
+ req->op.mod.message->dn,
+ LDB_SCOPE_BASE,
+ "(objectClass=*)", attrs,
+ NULL,
+ ac, la_mod_search_callback,
+ req);
- /* Only entries are interesting, and we only want the olddn */
- if (ares->type == LDB_REPLY_ENTRY
- && ldb_dn_compare(ares->message->dn, olddn) == 0) {
- /* only bother at all if there were some linked attributes found */
- if (ares->message->num_elements > 0) {
- return setup_modifies(ldb, ac, ac,
- ares->message, olddn, newdn);
+ if (ret == LDB_SUCCESS) {
+ talloc_steal(search_req, attrs);
+
+ ret = ldb_next_request(module, search_req);
}
- 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;
+ if (ac->ops) {
+ /* start the mod requests chain */
+ ret = la_do_mod_request(ac);
+ } else {
+ /* nothing to do for this module, proceed */
+ talloc_free(ac);
+ ret = ldb_next_request(module, req);
+ }
}
-
-
+
+ return ret;
}
-/* rename */
-static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req)
+
+/* delete, rename */
+static int linked_attributes_op(struct ldb_module *module, struct ldb_request *req)
{
- /* Look up list of linked attributes */
+ struct ldb_request *search_req;
+ struct ldb_dn *base_dn;
+ struct la_context *ac;
const char **attrs;
WERROR werr;
int ret;
- struct linked_attributes_context *ac;
- struct ldb_request *new_req;
- const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
- if (!schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
- }
/* This gets complex: We need to:
- - Do a search for the entry
+ - Do a search for the entry
- Wait for these result to appear
- - In the callback for the result, issue a modify request based on the linked attributes found
+ - In the callback for the result, issue a modify
+ request based on the linked attributes found
- Wait for each modify result
- - Regain our sainity
+ - Regain our sainity
*/
- ac = linked_attributes_init_handle(req, module);
+ switch (req->operation) {
+ case LDB_RENAME:
+ base_dn = req->op.rename.olddn;
+ break;
+ case LDB_DELETE:
+ base_dn = req->op.del.dn;
+ break;
+ default:
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac = linked_attributes_init(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
- werr = dsdb_linked_attribute_lDAPDisplayName_list(schema, ac, &attrs);
+
+ if (!ac->schema) {
+ /* without schema, this doesn't make any sense */
+ return ldb_next_request(module, req);
+ }
+
+ werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs);
if (!W_ERROR_IS_OK(werr)) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
- ret = ldb_build_search_req(&new_req, module->ldb, req,
- req->op.rename.olddn,
- LDB_SCOPE_BASE,
- "(objectClass=*)",
- attrs,
- NULL,
- ac,
- linked_attributes_rename_del_search_callback);
+
+ ret = ldb_build_search_req(&search_req, module->ldb, req,
+ base_dn, LDB_SCOPE_BASE,
+ "(objectClass=*)", attrs,
+ NULL,
+ ac, la_op_search_callback,
+ req);
if (ret != LDB_SUCCESS) {
return ret;
}
- talloc_steal(new_req, attrs);
+ talloc_steal(search_req, attrs);
- ret = ldb_set_timeout_from_prev_req(module->ldb, req, new_req);
+ return ldb_next_request(module, search_req);
+}
- if (ret != LDB_SUCCESS) {
- return ret;
+static int la_op_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct la_context *ac;
+ const struct dsdb_attribute *schema_attr;
+ const struct dsdb_attribute *target_attr;
+ const struct ldb_message_element *el;
+ const char *attr_name;
+ const char *deldn;
+ const char *adddn;
+ int i, j;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct la_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ /* Only entries are interesting, and we only want the olddn */
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ ret = ldb_dn_compare(ares->message->dn, req->op.search.base);
+ if (ret != 0) {
+ /* Guh? We only asked for this DN */
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->message->num_elements == 0) {
+ /* only bother at all if there were some
+ * linked attributes found */
+ talloc_free(ares);
+ return LDB_SUCCESS;
+ }
+
+ switch (ac->req->operation) {
+ case LDB_DELETE:
+ deldn = ldb_dn_get_linearized(ac->req->op.del.dn);
+ adddn = NULL;
+ break;
+ case LDB_RENAME:
+ deldn = ldb_dn_get_linearized(ac->req->op.rename.olddn);
+ adddn = ldb_dn_get_linearized(ac->req->op.rename.newdn);
+ break;
+ default:
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ for (i = 0; i < ares->message->num_elements; i++) {
+ el = &ares->message->elements[i];
+
+ schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name);
+ if (!schema_attr) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "attribute %s is not a valid attribute"
+ " in schema", el->name);
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OBJECT_CLASS_VIOLATION);
+ }
+
+ /* Valid attribute, now find out if it is linked */
+ if (schema_attr->linkID == 0) {
+ /* Not a linked attribute, skip */
+ continue;
+ }
+
+ if ((schema_attr->linkID & 1) == 0) {
+ /* Odd is for the target. */
+ target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1);
+ if (!target_attr) {
+ continue;
+ }
+ attr_name = target_attr->lDAPDisplayName;
+ } else {
+ target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID - 1);
+ if (!target_attr) {
+ continue;
+ }
+ attr_name = target_attr->lDAPDisplayName;
+ }
+ for (j = 0; j < el->num_values; j++) {
+ ret = la_store_op(ac, LA_OP_DEL,
+ (char *)el->values[j].data,
+ attr_name, deldn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+ if (!adddn) continue;
+ ret = la_store_op(ac, LA_OP_ADD,
+ (char *)el->values[j].data,
+ attr_name, adddn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+ }
+ }
+
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ break;
+
+ case LDB_REPLY_DONE:
+
+ talloc_free(ares);
+
+ if (ac->ops) {
+ /* start the mod requests chain */
+ ret = la_do_mod_request(ac);
+ } else {
+ ret = la_down_req(ac);
+ }
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ return LDB_SUCCESS;
}
- ac->search_req = new_req;
- ac->step = LA_SEARCH;
- return ldb_next_request(module, new_req);
+ talloc_free(ares);
+ return LDB_SUCCESS;
}
-/* delete */
-static int linked_attributes_delete(struct ldb_module *module, struct ldb_request *req)
+/* do a linked attributes modify request */
+static int la_do_mod_request(struct la_context *ac)
{
- /* Look up list of linked attributes */
- const char **attrs;
- WERROR werr;
+ struct ldb_message_element *ret_el;
+ struct ldb_request *mod_req;
+ struct ldb_message *new_msg;
+ struct ldb_context *ldb;
int ret;
- struct ldb_request *new_req;
- struct linked_attributes_context *ac;
- const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
- if (!schema) {
- /* without schema, this doesn't make any sense */
- return ldb_next_request(module, req);
- }
- /* This gets complex: We need to:
- - Do a search for the entry
- - Wait for these result to appear
- - In the callback for the result, issue a modify request based on the linked attributes found
- - Wait for each modify result
- - Regain our sainity
- */
+ ldb = ac->module->ldb;
- ac = linked_attributes_init_handle(req, module);
- if (!ac) {
+ /* Create the modify request */
+ new_msg = ldb_msg_new(ac);
+ if (!new_msg) {
+ ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
-
- werr = dsdb_linked_attribute_lDAPDisplayName_list(schema, ac, &attrs);
- if (!W_ERROR_IS_OK(werr)) {
+ new_msg->dn = ldb_dn_copy(new_msg, ac->ops->dn);
+ if (!new_msg->dn) {
return LDB_ERR_OPERATIONS_ERROR;
- };
-
- ret = ldb_build_search_req(&new_req, module->ldb, req,
- req->op.del.dn,
- LDB_SCOPE_BASE,
- "(objectClass=*)",
- attrs,
- NULL,
- ac,
- linked_attributes_rename_del_search_callback);
+ }
+ if (ac->ops->op == LA_OP_ADD) {
+ ret = ldb_msg_add_empty(new_msg, ac->ops->name,
+ LDB_FLAG_MOD_ADD, &ret_el);
+ } else {
+ ret = ldb_msg_add_empty(new_msg, ac->ops->name,
+ LDB_FLAG_MOD_DELETE, &ret_el);
+ }
if (ret != LDB_SUCCESS) {
return ret;
}
-
- talloc_steal(new_req, attrs);
-
- ret = ldb_set_timeout_from_prev_req(module->ldb, req, new_req);
-
+ ret_el->values = talloc_array(new_msg, struct ldb_val, 1);
+ if (!ret_el->values) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret_el->values[0] = data_blob_string_const(ac->ops->value);
+ ret_el->num_values = 1;
+
+ /* use ac->ops as the mem_ctx so that the request will be freed
+ * in the callback as soon as completed */
+ ret = ldb_build_mod_req(&mod_req, ldb, ac->ops,
+ new_msg,
+ NULL,
+ ac, la_mod_callback,
+ ac->req);
if (ret != LDB_SUCCESS) {
return ret;
}
+ talloc_steal(mod_req, new_msg);
- ac->search_req = new_req;
- ac->step = LA_SEARCH;
- return ldb_next_request(module, new_req);
+ /* Run the new request */
+ return ldb_next_request(ac->module, mod_req);
}
+static int la_mod_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct la_context *ac;
+ struct la_op_store *os;
+ int ret;
-static int linked_attributes_wait_none(struct ldb_handle *handle) {
- struct linked_attributes_context *ac;
- int i, ret = LDB_ERR_OPERATIONS_ERROR;
- if (!handle || !handle->private_data) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ ac = talloc_get_type(req->context, struct la_context);
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- handle->state = LDB_ASYNC_PENDING;
- handle->status = LDB_SUCCESS;
-
- ac = talloc_get_type(handle->private_data, struct linked_attributes_context);
-
- switch (ac->step) {
- case LA_SEARCH:
- ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->search_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->search_req->handle->status;
- goto done;
- }
-
- if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
- ac->step = LA_DO_OPS;
- return LDB_SUCCESS;
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb,
+ "invalid ldb_reply_type in callback");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
- case LA_DO_OPS:
- for (i=0; i < ac->num_requests; i++) {
- ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req[i]->handle->status;
- goto done;
- }
-
- if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
- }
+ talloc_free(ares);
- /* Now run the original request */
- ac->step = LA_DO_ORIG;
- return ldb_next_request(ac->module, ac->orig_down_req);
+ if (ac->ops) {
+ os = ac->ops;
+ ac->ops = os->next;
- 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;
+ /* this frees the request too
+ * DO NOT access 'req' after this point */
+ talloc_free(os);
}
-done:
- handle->state = LDB_ASYNC_DONE;
- return ret;
+ /* as last op run the original request */
+ if (ac->ops) {
+ ret = la_do_mod_request(ac);
+ } else {
+ ret = la_down_req(ac);
+ }
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ return LDB_SUCCESS;
}
-static int linked_attributes_wait_all(struct ldb_handle *handle) {
-
+static int la_down_req(struct la_context *ac)
+{
+ struct ldb_request *down_req;
int ret;
- while (handle->state != LDB_ASYNC_DONE) {
- ret = linked_attributes_wait_none(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ switch (ac->req->operation) {
+ case LDB_ADD:
+ ret = ldb_build_add_req(&down_req, ac->module->ldb, ac,
+ ac->req->op.add.message,
+ ac->req->controls,
+ ac, la_down_callback,
+ ac->req);
+ break;
+ case LDB_MODIFY:
+ ret = ldb_build_mod_req(&down_req, ac->module->ldb, ac,
+ ac->req->op.mod.message,
+ ac->req->controls,
+ ac, la_down_callback,
+ ac->req);
+ break;
+ case LDB_DELETE:
+ ret = ldb_build_del_req(&down_req, ac->module->ldb, ac,
+ ac->req->op.del.dn,
+ ac->req->controls,
+ ac, la_down_callback,
+ ac->req);
+ break;
+ case LDB_RENAME:
+ ret = ldb_build_rename_req(&down_req, ac->module->ldb, ac,
+ ac->req->op.rename.olddn,
+ ac->req->op.rename.newdn,
+ ac->req->controls,
+ ac, la_down_callback,
+ ac->req);
+ break;
+ default:
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return handle->status;
+ return ldb_next_request(ac->module, down_req);
}
-static int linked_attributes_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+static int la_down_callback(struct ldb_request *req, struct ldb_reply *ares)
{
- if (type == LDB_WAIT_ALL) {
- return linked_attributes_wait_all(handle);
- } else {
- return linked_attributes_wait_none(handle);
+ struct la_context *ac;
+
+ ac = talloc_get_type(req->context, struct la_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb,
+ "invalid ldb_reply_type in callback");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
_PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = {
.name = "linked_attributes",
.add = linked_attributes_add,
.modify = linked_attributes_modify,
- .del = linked_attributes_delete,
- .rename = linked_attributes_rename,
- .wait = linked_attributes_wait,
+ .del = linked_attributes_op,
+ .rename = linked_attributes_op,
};
diff --git a/source4/dsdb/samdb/ldb_modules/local_password.c b/source4/dsdb/samdb/ldb_modules/local_password.c
index a411c01513..622e444166 100644
--- a/source4/dsdb/samdb/ldb_modules/local_password.c
+++ b/source4/dsdb/samdb/ldb_modules/local_password.c
@@ -1,7 +1,7 @@
/*
ldb database module
- Copyright (C) Simo Sorce 2004-2006
+ Copyright (C) Simo Sorce 2004-2008
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
Copyright (C) Andrew Tridgell 2004
@@ -44,7 +44,7 @@
This allows the password database to be syncronised in a multi-master
fashion, seperate to the more difficult concerns of the main
database. (With passwords, the last writer always wins)
-
+
Each incoming add/modify is split into a remote, and a local request, done in that order.
We maintain a list of attributes that are kept locally:
@@ -62,73 +62,89 @@ static const char * const password_attrs[] = {
/* And we merge them back into search requests when asked to do so */
-struct lpdb_context {
+struct lpdb_reply {
+ struct lpdb_reply *next;
+ struct ldb_reply *remote;
+ struct ldb_dn *local_dn;
+};
- enum lpdb_type {LPDB_ADD, LPDB_MOD, LPDB_SEARCH} type;
- enum lpdb_step {LPDB_ADD_REMOTE, LPDB_MOD_REMOTE, LPDB_MOD_SEARCH_SELF, LPDB_LOCAL, LPDB_SEARCH_REMOTE} step;
+struct lpdb_context {
struct ldb_module *module;
- struct ldb_request *orig_req;
- struct ldb_request *remote_req;
- struct ldb_request *search_req;
- struct ldb_request *local_req;
+ struct ldb_request *req;
struct ldb_message *local_message;
+ struct lpdb_reply *list;
+ struct lpdb_reply *current;
+ struct ldb_reply *remote_done;
+ struct ldb_reply *remote;
+
bool added_objectGUID;
bool added_objectClass;
- struct ldb_reply *search_res;
-};
-
-struct lpdb_local_search_context {
- struct lpdb_context *ac;
- struct ldb_reply *remote_res;
- struct ldb_reply *local_res;
};
-static struct ldb_handle *lpdb_init_handle(struct ldb_request *req, struct ldb_module *module, enum lpdb_type type)
+static struct lpdb_context *lpdb_init_context(struct ldb_module *module,
+ struct ldb_request *req)
{
struct lpdb_context *ac;
- struct ldb_handle *h;
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
+ ac = talloc_zero(req, struct lpdb_context);
+ if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
- h->module = module;
+ ac->module = module;
+ ac->req = req;
- ac = talloc_zero(h, struct lpdb_context);
- if (ac == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- talloc_free(h);
- return NULL;
- }
+ return ac;
+}
- h->private_data = (void *)ac;
+static int lpdb_local_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct lpdb_context *ac;
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
+ ac = talloc_get_type(req->context, struct lpdb_context);
- ac->type = type;
- ac->module = module;
- ac->orig_req = req;
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb, "Unexpected reply type");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
- return h;
+ talloc_free(ares);
+ return ldb_module_done(ac->req,
+ ac->remote_done->controls,
+ ac->remote_done->response,
+ ac->remote_done->error);
}
-/* Add a record, splitting password attributes from the user's main
- * record */
+/*****************************************************************************
+ * ADD
+ ****************************************************************************/
+
+static int lpdb_add_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
static int local_password_add(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_handle *h;
- struct lpdb_context *ac;
struct ldb_message *remote_message;
- struct ldb_message *local_message;
+ struct ldb_request *remote_req;
+ struct lpdb_context *ac;
struct GUID objectGUID;
+ int ret;
int i;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_add\n");
@@ -163,22 +179,12 @@ static int local_password_add(struct ldb_module *module, struct ldb_request *req
}
/* From here, we assume we have password attributes to split off */
- h = lpdb_init_handle(req, module, LPDB_ADD);
- if (!h) {
+ ac = lpdb_init_context(module, req);
+ if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct lpdb_context);
- ac->orig_req = req;
-
- ac->remote_req = talloc(ac, struct ldb_request);
- if (ac->remote_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *(ac->remote_req) = *(ac->orig_req);
-
- remote_message = ldb_msg_copy_shallow(ac->remote_req, ac->orig_req->op.add.message);
+ remote_message = ldb_msg_copy_shallow(remote_req, req->op.add.message);
if (remote_message == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -188,81 +194,113 @@ static int local_password_add(struct ldb_module *module, struct ldb_request *req
ldb_msg_remove_attr(remote_message, password_attrs[i]);
}
- ac->remote_req->op.add.message = remote_message;
-
- ac->remote_req->context = NULL;
- ac->remote_req->callback = NULL;
-
- ac->local_req = talloc(ac, struct ldb_request);
- if (ac->local_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ /* Find the objectGUID to use as the key */
+ objectGUID = samdb_result_guid(ac->req->op.add.message, "objectGUID");
- *(ac->local_req) = *(ac->orig_req);
- local_message = ldb_msg_copy_shallow(ac->local_req, ac->orig_req->op.add.message);
- if (local_message == NULL) {
+ ac->local_message = ldb_msg_copy_shallow(ac, req->op.add.message);
+ if (ac->local_message == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* Remove anything seen in the remote message from the local
* message (leaving only password attributes) */
- for (i=0;i<ac->remote_req->op.add.message->num_elements;i++) {
- ldb_msg_remove_attr(local_message, ac->remote_req->op.add.message->elements[i].name);
+ for (i=0; i < remote_message->num_elements; i++) {
+ ldb_msg_remove_attr(ac->local_message, remote_message->elements[i].name);
}
/* We must have an objectGUID already, or we don't know where
* to add the password. This may be changed to an 'add and
* search', to allow the directory to create the objectGUID */
- if (ldb_msg_find_ldb_val(ac->orig_req->op.add.message, "objectGUID") == NULL) {
- ldb_set_errstring(module->ldb,
- "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
+ if (ldb_msg_find_ldb_val(req->op.add.message, "objectGUID") == NULL) {
+ ldb_set_errstring(module->ldb,
+ "no objectGUID found in search: "
+ "local_password module must be "
+ "onfigured below objectGUID module!\n");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
- /* Find the objectGUID to use as the key */
- objectGUID = samdb_result_guid(ac->orig_req->op.add.message, "objectGUID");
-
- local_message->dn = ldb_dn_new(local_message, module->ldb, LOCAL_BASE);
- ldb_dn_add_child_fmt(local_message->dn, PASSWORD_GUID_ATTR "=%s", GUID_string(local_message, &objectGUID));
-
- ac->local_req->op.add.message = local_message;
-
- ac->local_req->context = NULL;
- ac->local_req->callback = NULL;
-
- ac->step = LPDB_ADD_REMOTE;
+ ac->local_message->dn = ldb_dn_new(ac->local_message,
+ module->ldb, LOCAL_BASE);
+ if ((ac->local_message->dn == NULL) ||
+ ( ! ldb_dn_add_child_fmt(ac->local_message->dn,
+ PASSWORD_GUID_ATTR "=%s",
+ GUID_string(ac->local_message,
+ &objectGUID)))) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- /* Return our own handle do deal with this call */
- req->handle = h;
+ ret = ldb_build_add_req(&remote_req, module->ldb, ac,
+ remote_message,
+ req->controls,
+ ac, lpdb_add_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
- return ldb_next_request(module, ac->remote_req);
+ return ldb_next_request(module, remote_req);
}
-/* After adding the remote entry, add the local one */
-static int local_password_add_local(struct ldb_handle *h) {
-
+/* Add a record, splitting password attributes from the user's main
+ * record */
+static int lpdb_add_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_request *local_req;
struct lpdb_context *ac;
- ac = talloc_get_type(h->private_data, struct lpdb_context);
+ int ret;
+
+ ac = talloc_get_type(req->context, struct lpdb_context);
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- ac->step = LPDB_LOCAL;
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb, "Unexpected reply type");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
+ ac->remote_done = talloc_steal(ac, ares);
- /* perform the local add */
- return ldb_next_request(ac->module, ac->local_req);
+ ret = ldb_build_add_req(&local_req, ac->module->ldb, ac,
+ ac->local_message,
+ NULL,
+ ac, lpdb_local_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ ret = ldb_next_request(ac->module, local_req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ return LDB_SUCCESS;
}
-static int local_password_mod_search_self(struct ldb_handle *h);
+/*****************************************************************************
+ * MODIFY
+ ****************************************************************************/
+
+static int lpdb_modify_callabck(struct ldb_request *req,
+ struct ldb_reply *ares);
+static int lpdb_mod_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
static int local_password_modify(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_handle *h;
struct lpdb_context *ac;
struct ldb_message *remote_message;
- struct ldb_message *local_message;
+ struct ldb_request *remote_req;
+ int ret;
int i;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_modify\n");
@@ -289,243 +327,565 @@ static int local_password_modify(struct ldb_module *module, struct ldb_request *
}
/* From here, we assume we have password attributes to split off */
- h = lpdb_init_handle(req, module, LPDB_MOD);
- if (!h) {
+ ac = lpdb_init_context(module, req);
+ if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct lpdb_context);
- ac->orig_req = req;
-
- ac->remote_req = talloc(ac, struct ldb_request);
- if (ac->remote_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *(ac->remote_req) = *(ac->orig_req);
- remote_message = ldb_msg_copy_shallow(ac->remote_req, ac->orig_req->op.mod.message);
+ remote_message = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
if (remote_message == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
+
/* Remove any password attributes from the remote message */
for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
ldb_msg_remove_attr(remote_message, password_attrs[i]);
}
- ac->remote_req->op.mod.message = remote_message;
-
- ac->remote_req->context = NULL;
- ac->remote_req->callback = NULL;
-
- ac->local_req = talloc(ac, struct ldb_request);
- if (ac->local_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *(ac->local_req) = *(ac->orig_req);
- local_message = ldb_msg_copy_shallow(ac->local_req, ac->orig_req->op.mod.message);
- if (local_message == NULL) {
+ ac->local_message = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
+ if (ac->local_message == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* Remove anything seen in the remote message from the local
* message (leaving only password attributes) */
- for (i=0;i<ac->remote_req->op.mod.message->num_elements;i++) {
- ldb_msg_remove_attr(local_message, ac->remote_req->op.mod.message->elements[i].name);
+ for (i=0; i < remote_message->num_elements;i++) {
+ ldb_msg_remove_attr(ac->local_message, remote_message->elements[i].name);
}
- ac->local_req->op.mod.message = local_message;
- ac->local_message = local_message;
+ ret = ldb_build_mod_req(&remote_req, module->ldb, ac,
+ remote_message,
+ req->controls,
+ ac, lpdb_modify_callabck,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
- ac->local_req->context = NULL;
- ac->local_req->callback = NULL;
+ return ldb_next_request(module, remote_req);
+}
- ac->step = LPDB_MOD_REMOTE;
+/* On a modify, we don't have the objectGUID handy, so we need to
+ * search our DN for it */
+static int lpdb_modify_callabck(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ static const char * const attrs[] = { "objectGUID", "objectClass", NULL };
+ struct ldb_request *search_req;
+ struct lpdb_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct lpdb_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb, "Unexpected reply type");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ac->remote_done = talloc_steal(ac, ares);
- /* Return our own handle do deal with this call */
- req->handle = h;
+ /* prepare the search operation */
+ ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
+ ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
+ "(objectclass=*)", attrs,
+ NULL,
+ ac, lpdb_mod_search_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
- return ldb_next_request(module, ac->remote_req);
+ ret = ldb_next_request(ac->module, search_req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ return LDB_SUCCESS;
}
-/* Called when we search for our oen entry. Stores the one entry we
+/* Called when we search for our own entry. Stores the one entry we
* expect (as it is a base search) on the context pointer */
-static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int lpdb_mod_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
+ struct ldb_request *local_req;
struct lpdb_context *ac;
+ struct ldb_dn *local_dn;
+ struct GUID objectGUID;
+ int ret = LDB_SUCCESS;
- ac = talloc_get_type(context, struct lpdb_context);
+ ac = talloc_get_type(req->context, struct lpdb_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- /* 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, "Too many results");
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (ac->remote != NULL) {
+ ldb_set_errstring(ac->module->ldb, "Too many results");
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- ac->search_res = talloc_steal(ac, ares);
- } else {
+ ac->remote = talloc_steal(ac, ares);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+
+ /* ignore */
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_DONE:
+ /* After we find out the objectGUID for the entry, modify the local
+ * password database as required */
+
talloc_free(ares);
+
+ /* if it is not an entry of type person this is an error */
+ /* TODO: remove this when sambaPassword will be in schema */
+ if (ac->remote == NULL) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "entry just modified (%s) not found!",
+ ldb_dn_get_linearized(req->op.search.base));
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (!ldb_msg_check_string_attribute(ac->remote->message,
+ "objectClass", "person")) {
+ /* Not relevent to us */
+ return ldb_module_done(ac->req,
+ ac->remote_done->controls,
+ ac->remote_done->response,
+ ac->remote_done->error);
+ }
+
+ if (ldb_msg_find_ldb_val(ac->remote->message,
+ "objectGUID") == NULL) {
+ ldb_set_errstring(ac->module->ldb,
+ "no objectGUID found in search: "
+ "local_password module must be "
+ "configured below objectGUID "
+ "module!\n");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OBJECT_CLASS_VIOLATION);
+ }
+
+ objectGUID = samdb_result_guid(ac->remote->message,
+ "objectGUID");
+
+ local_dn = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
+ if ((local_dn == NULL) ||
+ ( ! ldb_dn_add_child_fmt(local_dn,
+ PASSWORD_GUID_ATTR "=%s",
+ GUID_string(ac, &objectGUID)))) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ ac->local_message->dn = local_dn;
+
+ ret = ldb_build_mod_req(&local_req, ac->module->ldb, ac,
+ ac->local_message,
+ NULL,
+ ac, lpdb_local_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ /* perform the local update */
+ ret = ldb_next_request(ac->module, local_req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
}
return LDB_SUCCESS;
}
-/* On a modify, we don't have the objectGUID handy, so we need to
- * search our DN for it */
-static int local_password_mod_search_self(struct ldb_handle *h) {
+/*****************************************************************************
+ * DELETE
+ ****************************************************************************/
+static int lpdb_delete_callabck(struct ldb_request *req,
+ struct ldb_reply *ares);
+static int lpdb_del_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+
+static int local_password_delete(struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct ldb_request *remote_req;
struct lpdb_context *ac;
- static const char * const attrs[] = { "objectGUID", "objectClass", NULL };
+ int ret;
- ac = talloc_get_type(h->private_data, struct lpdb_context);
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_delete\n");
- /* 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;
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.mod.message->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* If the caller is manipulating the local passwords directly,
+ * let them pass */
+ if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
+ req->op.del.dn) == 0) {
+ return ldb_next_request(module, req);
}
- 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->orig_req, NULL);
- if (ac->search_req->op.search.tree == NULL) {
- ldb_set_errstring(ac->module->ldb, "Invalid search filter");
+ /* From here, we assume we have password attributes to split off */
+ ac = lpdb_init_context(module, req);
+ if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac->search_req->op.search.attrs = attrs;
- ac->search_req->controls = NULL;
- ac->search_req->context = ac;
- ac->search_req->callback = get_self_callback;
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
- ac->step = LPDB_MOD_SEARCH_SELF;
+ ret = ldb_build_del_req(&remote_req, module->ldb, ac,
+ req->op.del.dn,
+ req->controls,
+ ac, lpdb_delete_callabck,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
- return ldb_next_request(ac->module, ac->search_req);
+ return ldb_next_request(module, remote_req);
}
-/* After we find out the objectGUID for the entry, modify the local
- * password database as required */
-static int local_password_mod_local(struct ldb_handle *h) {
+/* On a modify, we don't have the objectGUID handy, so we need to
+ * search our DN for it */
+static int lpdb_delete_callabck(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ static const char * const attrs[] = { "objectGUID", "objectClass", NULL };
+ struct ldb_request *search_req;
+ struct lpdb_context *ac;
+ int ret;
+ ac = talloc_get_type(req->context, struct lpdb_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb, "Unexpected reply type");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ac->remote_done = talloc_steal(ac, ares);
+
+ /* prepare the search operation */
+ ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
+ ac->req->op.del.dn, LDB_SCOPE_BASE,
+ "(objectclass=*)", attrs,
+ NULL,
+ ac, lpdb_del_search_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_next_request(ac->module, search_req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ return LDB_SUCCESS;
+}
+
+/* Called when we search for our own entry. Stores the one entry we
+ * expect (as it is a base search) on the context pointer */
+static int lpdb_del_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct ldb_request *local_req;
struct lpdb_context *ac;
+ struct ldb_dn *local_dn;
struct GUID objectGUID;
- ac = talloc_get_type(h->private_data, struct lpdb_context);
-
- /* if it is not an entry of type person this is an error */
- /* TODO: remove this when these things are checked in the schema */
- if (!ac->search_res) {
- ldb_asprintf_errstring(ac->module->ldb,
- "entry just modified (%s) not found!",
- ldb_dn_get_linearized(ac->remote_req->op.mod.message->dn));
- return LDB_ERR_OPERATIONS_ERROR;
- }
- if (!ldb_msg_check_string_attribute(ac->search_res->message, "objectClass", "person")) {
- /* Not relevent to us */
- return LDB_SUCCESS;
+ int ret = LDB_SUCCESS;
+
+ ac = talloc_get_type(req->context, struct lpdb_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
-
- if (ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID") == NULL) {
- ldb_set_errstring(ac->module->ldb,
- "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
-
- objectGUID = samdb_result_guid(ac->search_res->message, "objectGUID");
- ac->local_message->dn = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
- ldb_dn_add_child_fmt(ac->local_message->dn, PASSWORD_GUID_ATTR "=%s", GUID_string(ac, &objectGUID));
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (ac->remote != NULL) {
+ ldb_set_errstring(ac->module->ldb, "Too many results");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ac->remote = talloc_steal(ac, ares);
+ break;
+
+ case LDB_REPLY_REFERRAL:
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
+ /* ignore */
+ talloc_free(ares);
+ break;
- ac->step = LPDB_LOCAL;
+ case LDB_REPLY_DONE:
+ /* After we find out the objectGUID for the entry, modify the local
+ * password database as required */
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
+ talloc_free(ares);
+
+ /* if it is not an entry of type person this is NOT an error */
+ /* TODO: remove this when sambaPassword will be in schema */
+ if (ac->remote == NULL) {
+ return ldb_module_done(ac->req,
+ ac->remote_done->controls,
+ ac->remote_done->response,
+ ac->remote_done->error);
+ }
+ if (!ldb_msg_check_string_attribute(ac->remote->message,
+ "objectClass", "person")) {
+ /* Not relevent to us */
+ return ldb_module_done(ac->req,
+ ac->remote_done->controls,
+ ac->remote_done->response,
+ ac->remote_done->error);
+ }
+
+ if (ldb_msg_find_ldb_val(ac->remote->message,
+ "objectGUID") == NULL) {
+ ldb_set_errstring(ac->module->ldb,
+ "no objectGUID found in search: "
+ "local_password module must be "
+ "configured below objectGUID "
+ "module!\n");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OBJECT_CLASS_VIOLATION);
+ }
+
+ objectGUID = samdb_result_guid(ac->remote->message,
+ "objectGUID");
+
+ local_dn = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
+ if ((local_dn == NULL) ||
+ ( ! ldb_dn_add_child_fmt(local_dn,
+ PASSWORD_GUID_ATTR "=%s",
+ GUID_string(ac, &objectGUID)))) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_build_del_req(&local_req, ac->module->ldb, ac,
+ local_dn,
+ NULL,
+ ac, lpdb_local_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
- /* perform the local update */
- return ldb_next_request(ac->module, ac->local_req);
+ /* perform the local update */
+ ret = ldb_next_request(ac->module, local_req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ }
+
+ return LDB_SUCCESS;
}
-static int lpdb_local_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+/*****************************************************************************
+ * SEARCH
+ ****************************************************************************/
+
+static int lpdb_local_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+
+static int lpdb_local_search(struct lpdb_context *ac)
+{
+ struct ldb_request *local_req;
+ int ret;
+
+ ret = ldb_build_search_req(&local_req, ac->module->ldb, ac,
+ ac->current->local_dn,
+ LDB_SCOPE_BASE,
+ "(objectclass=*)",
+ ac->req->op.search.attrs,
+ NULL,
+ ac, lpdb_local_search_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(ac->module, local_req);
+}
+
+static int lpdb_local_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
- struct lpdb_local_search_context *local_context;
+ struct lpdb_context *ac;
+ struct ldb_reply *merge;
+ struct lpdb_reply *lr;
+ int ret;
+ int i;
+
+ ac = talloc_get_type(req->context, struct lpdb_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- local_context = talloc_get_type(context, struct lpdb_local_search_context);
+ lr = ac->current;
- /* we are interested only in the single reply (base search) we receive here */
+ /* we are interested only in a single reply (base search) */
switch (ares->type) {
case LDB_REPLY_ENTRY:
- {
- int i;
- if (local_context->local_res != NULL) {
- ldb_set_errstring(ldb, "Too many results to base search for password entry!");
+
+ if (lr->remote == NULL) {
+ ldb_set_errstring(ac->module->ldb,
+ "Too many results for password entry search!");
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
-
- local_context->local_res = ares;
- /* Make sure never to return the internal key attribute to the caller */
+ merge = lr->remote;
+ lr->remote = NULL;
+
+ /* steal the local results on the remote results to be
+ * returned all together */
+ talloc_steal(merge, ares->message->elements);
+
+ /* Make sure never to return the internal key attribute */
ldb_msg_remove_attr(ares->message, PASSWORD_GUID_ATTR);
- talloc_steal(local_context->remote_res->message->elements, ares->message->elements);
for (i=0; i < ares->message->num_elements; i++) {
struct ldb_message_element *el;
- el = ldb_msg_find_element(local_context->remote_res->message,
+ el = ldb_msg_find_element(merge->message,
ares->message->elements[i].name);
if (!el) {
- if (ldb_msg_add_empty(local_context->remote_res->message,
- ares->message->elements[i].name, 0, &el) != LDB_SUCCESS) {
+ ret = ldb_msg_add_empty(merge->message,
+ ares->message->elements[i].name,
+ 0, &el);
+ if (ret != LDB_SUCCESS) {
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_module_done(ac->req,
+ NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
*el = ares->message->elements[i];
}
}
- return local_context->ac->orig_req->callback(ldb,
- local_context->ac->orig_req->context,
- local_context->remote_res);
- }
- case LDB_REPLY_DONE:
- {
- /* Fire off the callback if there was no local entry, so we get the rest returned */
- if (local_context->local_res == NULL) {
- return local_context->ac->orig_req->callback(ldb,
- local_context->ac->orig_req->context,
- local_context->remote_res);
- }
- return LDB_SUCCESS;
+
+ /* free the rest */
+ talloc_free(ares);
+
+ return ldb_module_send_entry(ac->req, merge->message);
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ talloc_free(ares);
break;
- }
- default:
- {
+
+ case LDB_REPLY_DONE:
+
talloc_free(ares);
- ldb_set_errstring(ldb, "Unexpected result type in base search for password entry!");
- return LDB_ERR_OPERATIONS_ERROR;
- }
+
+ /* if this entry was not returned yet, return it now */
+ if (lr->remote) {
+ ret = ldb_module_send_entry(ac->req, ac->remote->message);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+ lr->remote = NULL;
+ }
+
+ if (lr->next->remote->type == LDB_REPLY_DONE) {
+ /* this was the last one */
+ return ldb_module_done(ac->req,
+ lr->next->remote->controls,
+ lr->next->remote->response,
+ lr->next->remote->error);
+ } else {
+ /* next one */
+ ac->current = lr->next;
+ talloc_free(lr);
+
+ ret = lpdb_local_search(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+ }
}
+
+ return LDB_SUCCESS;
}
/* For each entry returned in a remote search, do a local base search,
* based on the objectGUID we asked for as an additional attribute */
-static int lpdb_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int lpdb_remote_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
struct lpdb_context *ac;
+ struct ldb_dn *local_dn;
+ struct GUID objectGUID;
+ struct lpdb_reply *lr;
+ int ret;
- ac = talloc_get_type(context, struct lpdb_context);
+ ac = talloc_get_type(req->context, struct lpdb_context);
- if (ares->type == LDB_REPLY_ENTRY) {
- struct ldb_request *req;
- struct lpdb_local_search_context *local_context;
- struct GUID objectGUID;
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
/* No point searching further if it's not a 'person' entry */
if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
@@ -538,13 +898,14 @@ static int lpdb_remote_search_callback(struct ldb_context *ldb, void *context, s
ldb_msg_remove_attr(ares->message, "objectClass");
}
- return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
+ return ldb_module_send_entry(ac->req, ares->message);
}
if (ldb_msg_find_ldb_val(ares->message, "objectGUID") == NULL) {
ldb_set_errstring(ac->module->ldb,
"no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
objectGUID = samdb_result_guid(ares->message, "objectGUID");
@@ -557,44 +918,63 @@ static int lpdb_remote_search_callback(struct ldb_context *ldb, void *context, s
ldb_msg_remove_attr(ares->message, "objectClass");
}
- req = talloc_zero(ac, struct ldb_request);
- if (!req) {
- return LDB_ERR_OPERATIONS_ERROR;
+ local_dn = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
+ if ((local_dn == NULL) ||
+ (! ldb_dn_add_child_fmt(local_dn,
+ PASSWORD_GUID_ATTR "=%s",
+ GUID_string(ac, &objectGUID)))) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ lr = talloc_zero(ac, struct lpdb_reply);
+ if (lr == NULL) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
+ lr->local_dn = talloc_steal(lr, local_dn);
+ lr->remote = talloc_steal(lr, ares);
- local_context = talloc(ac, struct lpdb_local_search_context);
- if (!local_context) {
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ac->list) {
+ ac->current->next = lr;
+ } else {
+ ac->list = lr;
}
- local_context->ac = ac;
- local_context->remote_res = ares;
- local_context->local_res = NULL;
+ ac->current= lr;
+
+ break;
- req->op.search.base = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
- if ( ! ldb_dn_add_child_fmt(req->op.search.base, PASSWORD_GUID_ATTR "=%s", GUID_string(ac, &objectGUID))) {
- return LDB_ERR_OPERATIONS_ERROR;
+ case LDB_REPLY_REFERRAL:
+
+ return ldb_module_send_referral(ac->req, ares->referral);
+
+ case LDB_REPLY_DONE:
+
+ if (ac->list == NULL) {
+ /* found nothing */
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- req->operation = LDB_SEARCH;
- req->op.search.scope = LDB_SCOPE_BASE;
- req->op.search.tree = ldb_parse_tree(req, NULL);
- if (req->op.search.tree == NULL) {
- ldb_set_errstring(ac->module->ldb, "Out of Memory");
- return LDB_ERR_OPERATIONS_ERROR;
+
+ lr = talloc_zero(ac, struct lpdb_reply);
+ if (lr == NULL) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- req->op.search.attrs = ac->orig_req->op.search.attrs;
- req->controls = NULL;
- req->context = ac;
- req->callback = get_self_callback;
+ lr->remote = talloc_steal(lr, ares);
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req);
-
- req->context = local_context;
- req->callback = lpdb_local_search_callback;
+ ac->current->next = lr;
- return ldb_next_request(ac->module, req);
- } else {
- return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
+ /* rewind current and start local searches */
+ ac->current= ac->list;
+
+ ret = lpdb_local_search(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
}
+
+ return LDB_SUCCESS;
}
/* Search for passwords and other attributes. The passwords are
@@ -603,7 +983,7 @@ static int lpdb_remote_search_callback(struct ldb_context *ldb, void *context, s
static int local_password_search(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_handle *h;
+ struct ldb_request *remote_req;
struct lpdb_context *ac;
int i;
int ret;
@@ -615,6 +995,8 @@ static int local_password_search(struct ldb_module *module, struct ldb_request *
return ldb_next_request(module, req);
}
+ search_attrs = NULL;
+
/* If the caller is searching for the local passwords directly, let them pass */
if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
req->op.search.base) == 0) {
@@ -634,32 +1016,15 @@ static int local_password_search(struct ldb_module *module, struct ldb_request *
}
}
- h = lpdb_init_handle(req, module, LPDB_SEARCH);
- if (!h) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ac = talloc_get_type(h->private_data, struct lpdb_context);
-
- ac->orig_req = req;
-
- ac->remote_req = talloc(ac, struct ldb_request);
- if (ac->remote_req == NULL) {
+ ac = lpdb_init_context(module, req);
+ if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* Remote search is for all attributes: if the remote LDAP server has these attributes, then it overrides the local database */
- *(ac->remote_req) = *(ac->orig_req);
-
- /* Return our own handle do deal with this call */
- ac->remote_req->handle = h;
-
- ac->remote_req->context = ac;
- ac->remote_req->callback = lpdb_remote_search_callback;
-
if (req->op.search.attrs && !ldb_attr_in_list(req->op.search.attrs, "*")) {
if (!ldb_attr_in_list(req->op.search.attrs, "objectGUID")) {
- search_attrs = ldb_attr_list_copy_add(req, req->op.search.attrs, "objectGUID");
+ search_attrs = ldb_attr_list_copy_add(ac, req->op.search.attrs, "objectGUID");
ac->added_objectGUID = true;
if (!search_attrs) {
return LDB_ERR_OPERATIONS_ERROR;
@@ -668,7 +1033,7 @@ static int local_password_search(struct ldb_module *module, struct ldb_request *
search_attrs = req->op.search.attrs;
}
if (!ldb_attr_in_list(search_attrs, "objectClass")) {
- search_attrs = ldb_attr_list_copy_add(req, search_attrs, "objectClass");
+ search_attrs = ldb_attr_list_copy_add(ac, search_attrs, "objectClass");
ac->added_objectClass = true;
if (!search_attrs) {
return LDB_ERR_OPERATIONS_ERROR;
@@ -678,175 +1043,26 @@ static int local_password_search(struct ldb_module *module, struct ldb_request *
search_attrs = req->op.search.attrs;
}
- ac->remote_req->op.search.attrs = search_attrs;
-
- ldb_set_timeout_from_prev_req(module->ldb, ac->orig_req, ac->remote_req);
-
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
-
- ac->step = LPDB_SEARCH_REMOTE;
-
- /* perform the search */
- ret = ldb_next_request(module, ac->remote_req);
-
- if (ret == LDB_SUCCESS) {
- req->handle = ac->remote_req->handle;
- }
-
- return ret;
-}
-
-static int lpdb_wait(struct ldb_handle *handle) {
- struct lpdb_context *ac;
- int ret;
-
- if (!handle || !handle->private_data) {
+ ret = ldb_build_search_req_ex(&remote_req, module->ldb, ac,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ search_attrs,
+ req->controls,
+ ac, lpdb_remote_search_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
return LDB_ERR_OPERATIONS_ERROR;
}
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
- }
-
- handle->state = LDB_ASYNC_PENDING;
- handle->status = LDB_SUCCESS;
-
- ac = talloc_get_type(handle->private_data, struct lpdb_context);
-
- switch (ac->step) {
- case LPDB_ADD_REMOTE:
- ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->remote_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->remote_req->handle->status;
- goto done;
- }
-
- if (ac->remote_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* original request done, go on */
- return local_password_add_local(handle);
-
- case LPDB_MOD_REMOTE:
- ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->remote_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->remote_req->handle->status;
- goto done;
- }
-
- if (ac->remote_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* original request done, go on */
- return local_password_mod_search_self(handle);
-
- case LPDB_MOD_SEARCH_SELF:
- ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->search_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->search_req->handle->status;
- goto done;
- }
-
- if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* original request done, go on */
- return local_password_mod_local(handle);
-
- case LPDB_LOCAL:
- ret = ldb_wait(ac->local_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->local_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->local_req->handle->status;
- goto done;
- }
-
- if (ac->local_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- break;
-
- case LPDB_SEARCH_REMOTE:
- ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->remote_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->remote_req->handle->status;
- goto done;
- }
-
- if (ac->remote_req->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 lpdb_wait_all(struct ldb_handle *handle) {
-
- int ret;
-
- while (handle->state != LDB_ASYNC_DONE) {
- ret = lpdb_wait(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
-
- return handle->status;
-}
-
-static int local_password_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- if (type == LDB_WAIT_ALL) {
- return lpdb_wait_all(handle);
- } else {
- return lpdb_wait(handle);
- }
+ /* perform the search */
+ return ldb_next_request(module, remote_req);
}
_PUBLIC_ const struct ldb_module_ops ldb_local_password_module_ops = {
.name = "local_password",
.add = local_password_add,
.modify = local_password_modify,
- .search = local_password_search,
- .wait = local_password_wait
+ .del = local_password_delete,
+ .search = local_password_search
};
diff --git a/source4/dsdb/samdb/ldb_modules/naming_fsmo.c b/source4/dsdb/samdb/ldb_modules/naming_fsmo.c
index 084540f68d..d90c2547a6 100644
--- a/source4/dsdb/samdb/ldb_modules/naming_fsmo.c
+++ b/source4/dsdb/samdb/ldb_modules/naming_fsmo.c
@@ -29,7 +29,7 @@
#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
-#include "lib/util/dlinklist.h"
+#include "../lib/util/dlinklist.h"
static int naming_fsmo_init(struct ldb_module *module)
{
@@ -64,10 +64,9 @@ static int naming_fsmo_init(struct ldb_module *module)
}
module->private_data = naming_fsmo;
- ret = ldb_search(module->ldb, naming_dn,
- LDB_SCOPE_BASE,
- NULL, naming_attrs,
- &naming_res);
+ ret = ldb_search(module->ldb, mem_ctx, &naming_res,
+ naming_dn, LDB_SCOPE_BASE,
+ naming_attrs, NULL);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING,
"naming_fsmo_init: no partitions dn present: (skip loading of naming contexts details)\n");
@@ -81,7 +80,6 @@ static int naming_fsmo_init(struct ldb_module *module)
talloc_free(mem_ctx);
return ret;
}
- talloc_steal(mem_ctx, naming_res);
if (naming_res->count == 0) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING,
"naming_fsmo_init: no cross-ref container present: (skip loading of naming contexts details)\n");
diff --git a/source4/dsdb/samdb/ldb_modules/normalise.c b/source4/dsdb/samdb/ldb_modules/normalise.c
index 3306fd3c33..70513bd644 100644
--- a/source4/dsdb/samdb/ldb_modules/normalise.c
+++ b/source4/dsdb/samdb/ldb_modules/normalise.c
@@ -45,6 +45,14 @@
CN=Admins,CN=Users,DC=samba,DC=example,DC=com
*/
+
+struct norm_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ const struct dsdb_schema *schema;
+};
+
static int fix_dn(struct ldb_dn *dn)
{
int i, ret;
@@ -69,93 +77,117 @@ static int fix_dn(struct ldb_dn *dn)
return LDB_SUCCESS;
}
-static int normalise_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int normalize_search_callback(struct ldb_request *req, struct ldb_reply *ares)
{
- const struct dsdb_schema *schema = dsdb_get_schema(ldb);
- struct ldb_request *orig_req = talloc_get_type(context, struct ldb_request);
- TALLOC_CTX *mem_ctx;
+ struct ldb_message *msg;
+ struct norm_context *ac;
int i, j, ret;
- /* Only entries are interesting, and we handle the case of the parent seperatly */
- if (ares->type != LDB_REPLY_ENTRY) {
- return orig_req->callback(ldb, orig_req->context, ares);
- }
+ ac = talloc_get_type(req->context, struct norm_context);
- if (!schema) {
- return orig_req->callback(ldb, orig_req->context, ares);
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
-
- mem_ctx = talloc_new(ares);
- if (!mem_ctx) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- /* OK, we have one of *many* search results passing by here,
- * but we should get them one at a time */
+ /* Only entries are interesting, and we handle the case of the parent seperatly */
- ret = fix_dn(ares->message->dn);
- if (ret != LDB_SUCCESS) {
- talloc_free(mem_ctx);
- return ret;
- }
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
- for (i = 0; i < ares->message->num_elements; i++) {
- const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, ares->message->elements[i].name);
- if (!attribute) {
- continue;
- }
- /* Look to see if this attributeSyntax is a DN */
- if (!((strcmp(attribute->attributeSyntax_oid, "2.5.5.1") == 0) ||
- (strcmp(attribute->attributeSyntax_oid, "2.5.5.7") == 0))) {
- continue;
+ /* OK, we have one of *many* search results passing by here,
+ * but we should get them one at a time */
+ msg = ares->message;
+
+ ret = fix_dn(msg->dn);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- for (j = 0; j < ares->message->elements[i].num_values; j++) {
- const char *dn_str;
- struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, ldb, &ares->message->elements[i].values[j]);
- if (!dn) {
- talloc_free(mem_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(ac->schema, msg->elements[i].name);
+ if (!attribute) {
+ continue;
}
- ret = fix_dn(dn);
- if (ret != LDB_SUCCESS) {
- talloc_free(mem_ctx);
- return ret;
+ /* Look to see if this attributeSyntax is a DN */
+ if (!((strcmp(attribute->attributeSyntax_oid, "2.5.5.1") == 0) ||
+ (strcmp(attribute->attributeSyntax_oid, "2.5.5.7") == 0))) {
+ continue;
+ }
+ for (j = 0; j < msg->elements[i].num_values; j++) {
+ const char *dn_str;
+ struct ldb_dn *dn = ldb_dn_new(ac, ac->module->ldb, (const char *)msg->elements[i].values[j].data);
+ if (!dn) {
+ return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+ }
+ ret = fix_dn(dn);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ dn_str = talloc_steal(msg->elements[i].values, ldb_dn_get_linearized(dn));
+ msg->elements[i].values[j] = data_blob_string_const(dn_str);
+ talloc_free(dn);
}
- dn_str = talloc_steal(ares->message->elements[i].values, ldb_dn_get_linearized(dn));
- ares->message->elements[i].values[j] = data_blob_string_const(dn_str);
- talloc_free(dn);
}
+
+ return ldb_module_send_entry(ac->req, msg);
+
+ case LDB_REPLY_REFERRAL:
+
+ return ldb_module_send_referral(ac->req, ares->referral);
+
+ case LDB_REPLY_DONE:
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- talloc_free(mem_ctx);
- return orig_req->callback(ldb, orig_req->context, ares);
+
+ return LDB_SUCCESS;
}
/* search */
static int normalise_search(struct ldb_module *module, struct ldb_request *req)
{
+ struct ldb_request *down_req;
+ struct norm_context *ac;
int ret;
- struct ldb_request *down_req = talloc(req, struct ldb_request);
- if (!down_req) {
- ldb_oom(module->ldb);
+
+ ac = talloc(req, struct norm_context);
+ if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
- *down_req = *req;
- down_req->context = req;
- down_req->callback = normalise_search_callback;
- ret = ldb_next_request(module, down_req);
+ ac->module = module;
+ ac->req = req;
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ /* if schema not yet present just skip over */
+ ac->schema = dsdb_get_schema(ac->module->ldb);
+ if (ac->schema == NULL) {
+ talloc_free(ac);
+ return ldb_next_request(module, req);
}
- return ret;
+
+ ret = ldb_build_search_req_ex(&down_req, module->ldb, ac,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ req->op.search.attrs,
+ req->controls,
+ ac, normalize_search_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_next_request(module, down_req);
}
+
_PUBLIC_ const struct ldb_module_ops ldb_normalise_module_ops = {
.name = "normalise",
.search = normalise_search,
diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c
index b048a8d8e1..7d00851792 100644
--- a/source4/dsdb/samdb/ldb_modules/objectclass.c
+++ b/source4/dsdb/samdb/ldb_modules/objectclass.c
@@ -1,7 +1,7 @@
/*
ldb database library
- Copyright (C) Simo Sorce 2006
+ Copyright (C) Simo Sorce 2006-2008
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007
This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@
#include "ldb/include/ldb_errors.h"
#include "ldb/include/ldb_private.h"
#include "dsdb/samdb/samdb.h"
-#include "lib/util/dlinklist.h"
+#include "../lib/util/dlinklist.h"
#include "librpc/ndr/libndr.h"
#include "librpc/gen_ndr/ndr_security.h"
#include "libcli/security/security.h"
@@ -47,21 +47,12 @@
struct oc_context {
- enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD,
- OC_SEARCH_ADD_PARENT, OC_DO_ADD,
- OC_SEARCH_RENAME_PARENT, OC_DO_RENAME} step;
-
struct ldb_module *module;
- struct ldb_request *orig_req;
-
- struct ldb_request *down_req;
+ struct ldb_request *req;
- struct ldb_request *search_req;
struct ldb_reply *search_res;
- struct ldb_request *add_req;
- struct ldb_request *mod_req;
- struct ldb_request *rename_req;
+ int (*step_fn)(struct oc_context *);
};
struct class_list {
@@ -69,46 +60,31 @@ struct class_list {
const struct dsdb_class *objectclass;
};
-static int objectclass_do_add(struct ldb_handle *h);
-
-static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
+static struct oc_context *oc_init_context(struct ldb_module *module,
+ struct ldb_request *req)
{
struct oc_context *ac;
- struct ldb_handle *h;
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- return NULL;
- }
-
- h->module = module;
-
- ac = talloc_zero(h, struct oc_context);
+ ac = talloc_zero(req, struct oc_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "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;
+ ac->req = req;
- return h;
+ return ac;
}
+static int objectclass_do_add(struct oc_context *ac);
+
/* Sort objectClasses into correct order, and validate that all
* objectClasses specified actually exist in the schema
*/
static int objectclass_sort(struct ldb_module *module,
const struct dsdb_schema *schema,
- struct ldb_message *msg, /* so that when we create new elements, we put it on the right parent */
TALLOC_CTX *mem_ctx,
struct ldb_message_element *objectclass_element,
struct class_list **sorted_out)
@@ -117,6 +93,7 @@ static int objectclass_sort(struct ldb_module *module,
int layer;
struct class_list *sorted = NULL, *parent_class = NULL,
*subclass = NULL, *unsorted = NULL, *current, *poss_subclass, *poss_parent, *new_parent;
+
/* DESIGN:
*
* We work on 4 different 'bins' (implemented here as linked lists):
@@ -150,8 +127,7 @@ static int objectclass_sort(struct ldb_module *module,
for (i=0; i < objectclass_element->num_values; i++) {
current = talloc(mem_ctx, struct class_list);
if (!current) {
- ldb_set_errstring(module->ldb, "objectclass: out of memory allocating objectclass list");
- talloc_free(mem_ctx);
+ ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
current->objectclass = dsdb_class_by_lDAPDisplayName(schema, (const char *)objectclass_element->values[i].data);
@@ -258,7 +234,7 @@ static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx,
struct auth_session_info *session_info
= ldb_get_opaque(module->ldb, "sessionInfo");
struct security_descriptor *sd;
- struct dom_sid *domain_sid = samdb_domain_sid(module->ldb);
+ const struct dom_sid *domain_sid = samdb_domain_sid(module->ldb);
if (!objectclass->defaultSecurityDescriptor || !domain_sid) {
return NULL;
@@ -292,28 +268,77 @@ static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx,
}
-static int get_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares)
{
struct oc_context *ac;
+ int ret;
- ac = talloc_get_type(context, struct oc_context);
+ ac = talloc_get_type(req->context, struct oc_context);
- /* we are interested only in the single reply (base search) we receive here */
- if (ares->type == LDB_REPLY_ENTRY) {
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS &&
+ ares->error != LDB_ERR_NO_SUCH_OBJECT) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
if (ac->search_res != NULL) {
- ldb_set_errstring(ldb, "Too many results");
+ ldb_set_errstring(ac->module->ldb, "Too many results");
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- ac->search_res = talloc_move(ac, &ares);
- } else {
+ ac->search_res = talloc_steal(ac, ares);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_DONE:
talloc_free(ares);
+ ret = ac->step_fn(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ break;
}
return LDB_SUCCESS;
}
+static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct oc_context *ac;
+
+ ac = talloc_get_type(req->context, struct oc_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+}
+
/* Fix up the DN to be in the standard form, taking particular care to match the parent DN
This should mean that if the parent is:
@@ -357,22 +382,27 @@ static int fix_attributes(struct ldb_context *ldb, const struct dsdb_schema *sch
int i;
for (i=0; i < msg->num_elements; i++) {
const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, msg->elements[i].name);
+ /* Add in a very special case for 'clearTextPassword',
+ * which is used for internal processing only, and is
+ * not presented in the schema */
if (!attribute) {
- ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
- return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
+ if (strcasecmp(msg->elements[i].name, "clearTextPassword") != 0) {
+ ldb_asprintf_errstring(ldb, "attribute %s is not a valid attribute in schema", msg->elements[i].name);
+ return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
+ }
+ } else {
+ msg->elements[i].name = attribute->lDAPDisplayName;
}
- msg->elements[i].name = attribute->lDAPDisplayName;
}
return LDB_SUCCESS;
}
+static int objectclass_do_add(struct oc_context *ac);
+
static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
{
-
- static const char * const attrs[] = { NULL };
-
- struct ldb_handle *h;
+ struct ldb_request *search_req;
struct oc_context *ac;
struct ldb_dn *parent_dn;
int ret;
@@ -384,61 +414,56 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
- /* Need to object to this, but cn=rootdse doesn't hae an objectClass... */
+ /* Need to object to this, but cn=rootdse doesn't have an objectClass... */
if (ldb_msg_find_element(req->op.add.message,
"objectClass") == NULL) {
return ldb_next_request(module, req);
}
- h = oc_init_handle(req, module);
- if (!h) {
+ ac = oc_init_context(module, req);
+ if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct oc_context);
-
- /* return or own handle to deal with this call */
- req->handle = h;
/* If there isn't a parent, just go on to the add processing */
- if (ldb_dn_get_comp_num(ac->orig_req->op.add.message->dn) == 1) {
- return objectclass_do_add(h);
+ if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) {
+ return objectclass_do_add(ac);
}
- parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.add.message->dn);
+ /* get copy of parent DN */
+ parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn);
if (parent_dn == NULL) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_build_search_req(&ac->search_req, module->ldb,
+ ret = ldb_build_search_req(&search_req, module->ldb,
ac, parent_dn, LDB_SCOPE_BASE,
- "(objectClass=*)",
- attrs, NULL,
- ac, get_search_callback);
+ "(objectClass=*)", NULL,
+ NULL,
+ ac, get_search_callback,
+ req);
if (ret != LDB_SUCCESS) {
return ret;
}
+ talloc_steal(search_req, parent_dn);
- talloc_steal(ac->search_req, parent_dn);
-
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
-
- ac->step = OC_SEARCH_ADD_PARENT;
+ ac->step_fn = objectclass_do_add;
- return ldb_next_request(ac->module, ac->search_req);
+ return ldb_next_request(ac->module, search_req);
}
-static int objectclass_do_add(struct ldb_handle *h)
+static int objectclass_do_add(struct oc_context *ac)
{
const struct dsdb_schema *schema;
- struct oc_context *ac;
+ struct ldb_request *add_req;
+ char *value;
struct ldb_message_element *objectclass_element;
struct ldb_message *msg;
TALLOC_CTX *mem_ctx;
struct class_list *sorted, *current;
int ret;
-
- ac = talloc_get_type(h->private_data, struct oc_context);
+
schema = dsdb_get_schema(ac->module->ldb);
mem_ctx = talloc_new(ac);
@@ -446,41 +471,34 @@ static int objectclass_do_add(struct ldb_handle *h)
return LDB_ERR_OPERATIONS_ERROR;
}
- ac->add_req = talloc(ac, struct ldb_request);
- if (ac->add_req == NULL) {
- talloc_free(mem_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *ac->add_req = *ac->orig_req;
+ msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
- ac->add_req->op.add.message = msg = ldb_msg_copy_shallow(ac->add_req, ac->orig_req->op.add.message);
-
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->add_req);
-
/* Check we have a valid parent */
if (ac->search_res == NULL) {
- if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb), ac->orig_req->op.add.message->dn) == 0) {
+ if (ldb_dn_compare(ldb_get_root_basedn(ac->module->ldb),
+ msg->dn) == 0) {
/* Allow the tree to be started */
/* but don't keep any error string, it's meaningless */
ldb_set_errstring(ac->module->ldb, NULL);
} else {
ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot add %s, parent does not exist!",
- ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
+ ldb_dn_get_linearized(msg->dn));
+ talloc_free(mem_ctx);
return LDB_ERR_UNWILLING_TO_PERFORM;
}
} else {
/* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
ret = fix_dn(msg,
- ac->orig_req->op.add.message->dn,
+ ac->req->op.add.message->dn,
ac->search_res->message->dn,
&msg->dn);
if (ret != LDB_SUCCESS) {
ldb_asprintf_errstring(ac->module->ldb, "Could not munge DN %s into normal form",
- ldb_dn_get_linearized(ac->orig_req->op.add.message->dn));
+ ldb_dn_get_linearized(ac->req->op.add.message->dn));
+ talloc_free(mem_ctx);
return ret;
}
@@ -505,7 +523,7 @@ static int objectclass_do_add(struct ldb_handle *h)
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted);
+ ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
if (ret != LDB_SUCCESS) {
talloc_free(mem_ctx);
return ret;
@@ -524,7 +542,13 @@ static int objectclass_do_add(struct ldb_handle *h)
/* Move from the linked list back into an ldb msg */
for (current = sorted; current; current = current->next) {
- ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
+ value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
+ if (value == NULL) {
+ ldb_oom(ac->module->ldb);
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_string(msg, "objectClass", value);
if (ret != LDB_SUCCESS) {
ldb_set_errstring(ac->module->ldb,
"objectclass: could not re-add sorted "
@@ -537,8 +561,13 @@ static int objectclass_do_add(struct ldb_handle *h)
struct ldb_message_element *el;
int32_t systemFlags = 0;
if (!ldb_msg_find_element(msg, "objectCategory")) {
- ldb_msg_add_string(msg, "objectCategory",
- current->objectclass->defaultObjectCategory);
+ value = talloc_strdup(msg, current->objectclass->defaultObjectCategory);
+ if (value == NULL) {
+ ldb_oom(ac->module->ldb);
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ldb_msg_add_string(msg, "objectCategory", value);
}
if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) {
ldb_msg_add_string(msg, "showInAdvancedViewOnly",
@@ -597,20 +626,33 @@ static int objectclass_do_add(struct ldb_handle *h)
return ret;
}
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
-
- ac->step = OC_DO_ADD;
+ ret = ldb_build_add_req(&add_req, ac->module->ldb, ac,
+ msg,
+ ac->req->controls,
+ ac, oc_op_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
/* perform the add */
- return ldb_next_request(ac->module, ac->add_req);
+ return ldb_next_request(ac->module, add_req);
}
+static int oc_modify_callback(struct ldb_request *req,
+ struct ldb_reply *ares);
+static int objectclass_do_mod(struct oc_context *ac);
+
static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_message_element *objectclass_element;
struct ldb_message *msg;
const struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
+ struct class_list *sorted, *current;
+ struct ldb_request *down_req;
+ struct oc_context *ac;
+ TALLOC_CTX *mem_ctx;
+ char *value;
int ret;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
@@ -626,23 +668,19 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
}
objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
+ ac = oc_init_context(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
/* 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 with just fixing the attribute case */
if (!objectclass_element) {
- struct ldb_request *down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
- ldb_set_errstring(module->ldb, "Out of memory!");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *down_req = *req; /* copy the request */
-
- down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
-
- if (down_req->op.mod.message == NULL) {
+ msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
+ if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -651,15 +689,17 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
return ret;
}
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ ret = ldb_build_mod_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, oc_op_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return ret;
+
+ /* go on with the call chain */
+ return ldb_next_request(module, down_req);
}
switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
@@ -668,41 +708,28 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
return LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED;
}
break;
+
case LDB_FLAG_MOD_REPLACE:
- {
- struct ldb_request *down_req;
- struct class_list *sorted, *current;
- TALLOC_CTX *mem_ctx;
- mem_ctx = talloc_new(req);
+ mem_ctx = talloc_new(ac);
if (mem_ctx == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* prepare the first operation */
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
- ldb_set_errstring(module->ldb, "Out of memory!");
- talloc_free(mem_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *down_req = *req; /* copy the request */
-
- down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
-
- if (down_req->op.mod.message == NULL) {
+ msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
+ if (msg == NULL) {
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
-
+
ret = fix_attributes(module->ldb, schema, msg);
if (ret != LDB_SUCCESS) {
talloc_free(mem_ctx);
return ret;
}
- ret = objectclass_sort(module, schema, msg, mem_ctx, objectclass_element, &sorted);
+ ret = objectclass_sort(module, schema, mem_ctx, objectclass_element, &sorted);
if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
return ret;
}
@@ -719,9 +746,21 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
/* Move from the linked list back into an ldb msg */
for (current = sorted; current; current = current->next) {
- ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
+ /* copy the value as this string is on the schema
+ * context and we can't rely on it not changing
+ * before the operation is over */
+ value = talloc_strdup(msg,
+ current->objectclass->lDAPDisplayName);
+ if (value == NULL) {
+ ldb_oom(module->ldb);
+ talloc_free(mem_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_string(msg, "objectClass", value);
if (ret != LDB_SUCCESS) {
- ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
+ ldb_set_errstring(module->ldb,
+ "objectclass: could not re-add sorted "
+ "objectclass to modify msg");
talloc_free(mem_ctx);
return ret;
}
@@ -731,130 +770,121 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req
ret = ldb_msg_sanity_check(module->ldb, msg);
if (ret != LDB_SUCCESS) {
- talloc_free(mem_ctx);
return ret;
}
-
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+
+ ret = ldb_build_mod_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, oc_op_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return ret;
- }
+
+ /* go on with the call chain */
+ return ldb_next_request(module, down_req);
}
/* This isn't the default branch of the switch, but a 'in any
* other case'. When a delete isn't for all objectClasses for
* example
*/
- {
- struct ldb_handle *h;
- struct oc_context *ac;
-
- h = oc_init_handle(req, module);
- if (!h) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ac = talloc_get_type(h->private_data, struct oc_context);
-
- /* return or own handle to deal with this call */
- req->handle = h;
-
- /* prepare the first operation */
- ac->down_req = talloc(ac, struct ldb_request);
- if (ac->down_req == NULL) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *(ac->down_req) = *req; /* copy the request */
-
- ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
-
- if (ac->down_req->op.mod.message == NULL) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = fix_attributes(ac->module->ldb, schema, msg);
- if (ret != LDB_SUCCESS) {
- ldb_oom(ac->module->ldb);
- return ret;
- }
- ac->down_req->context = NULL;
- ac->down_req->callback = NULL;
- ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
-
- ac->step = OC_DO_REQ;
+ msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
+ if (msg == NULL) {
+ ldb_oom(module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- return ldb_next_request(module, ac->down_req);
+ ret = fix_attributes(module->ldb, schema, msg);
+ if (ret != LDB_SUCCESS) {
+ ldb_oom(ac->module->ldb);
+ return ret;
}
+
+ ret = ldb_build_mod_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, oc_modify_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return ldb_next_request(module, down_req);
}
-static int objectclass_search_self(struct ldb_handle *h)
+static int oc_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
{
- int ret;
- struct oc_context *ac;
static const char * const attrs[] = { "objectClass", NULL };
+ struct ldb_request *search_req;
+ struct oc_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct oc_context);
- ac = talloc_get_type(h->private_data, struct oc_context);
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- ret = ldb_build_search_req(&ac->search_req, ac->module->ldb,
- ac, ac->orig_req->op.mod.message->dn, LDB_SCOPE_BASE,
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
+ ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
"(objectClass=*)",
attrs, NULL,
- ac, get_search_callback);
-
+ ac, get_search_callback,
+ ac->req);
if (ret != LDB_SUCCESS) {
- return ret;
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
+ ac->step_fn = objectclass_do_mod;
- ac->step = OC_SEARCH_SELF;
-
- return ldb_next_request(ac->module, ac->search_req);
+ ret = ldb_next_request(ac->module, search_req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ return LDB_SUCCESS;
}
-static int objectclass_do_mod(struct ldb_handle *h) {
+static int objectclass_do_mod(struct oc_context *ac)
+{
const struct dsdb_schema *schema;
- struct oc_context *ac;
+ struct ldb_request *mod_req;
+ char *value;
struct ldb_message_element *objectclass_element;
struct ldb_message *msg;
TALLOC_CTX *mem_ctx;
struct class_list *sorted, *current;
int ret;
-
- ac = talloc_get_type(h->private_data, struct oc_context);
- schema = dsdb_get_schema(ac->module->ldb);
- mem_ctx = talloc_new(ac);
- if (mem_ctx == NULL) {
+ if (ac->search_res == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
+ schema = dsdb_get_schema(ac->module->ldb);
- ac->mod_req = talloc(ac, struct ldb_request);
- if (ac->mod_req == NULL) {
- talloc_free(mem_ctx);
+ mem_ctx = talloc_new(ac);
+ if (mem_ctx == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac->mod_req->operation = LDB_MODIFY;
- ac->mod_req->controls = NULL;
- ac->mod_req->context = ac;
- ac->mod_req->callback = NULL;
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
-
/* use a new message structure */
- ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
+ msg = ldb_msg_new(ac);
if (msg == NULL) {
- ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
+ ldb_set_errstring(ac->module->ldb,
+ "objectclass: could not create new modify msg");
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -869,9 +899,9 @@ static int objectclass_do_mod(struct ldb_handle *h) {
}
/* modify dn */
- msg->dn = ac->orig_req->op.mod.message->dn;
+ msg->dn = ac->req->op.mod.message->dn;
- ret = objectclass_sort(ac->module, schema, msg, mem_ctx, objectclass_element, &sorted);
+ ret = objectclass_sort(ac->module, schema, mem_ctx, objectclass_element, &sorted);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -889,7 +919,12 @@ static int objectclass_do_mod(struct ldb_handle *h) {
/* Move from the linked list back into an ldb msg */
for (current = sorted; current; current = current->next) {
- ret = ldb_msg_add_string(msg, "objectClass", current->objectclass->lDAPDisplayName);
+ value = talloc_strdup(msg, current->objectclass->lDAPDisplayName);
+ if (value == NULL) {
+ ldb_oom(ac->module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ret = ldb_msg_add_string(msg, "objectClass", value);
if (ret != LDB_SUCCESS) {
ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
talloc_free(mem_ctx);
@@ -903,33 +938,38 @@ static int objectclass_do_mod(struct ldb_handle *h) {
return ret;
}
-
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
-
- ac->step = OC_DO_MOD;
+ ret = ldb_build_mod_req(&mod_req, ac->module->ldb, ac,
+ msg,
+ ac->req->controls,
+ ac, oc_op_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
talloc_free(mem_ctx);
- /* perform the search */
- return ldb_next_request(ac->module, ac->mod_req);
+ /* perform the modify */
+ return ldb_next_request(ac->module, mod_req);
}
+static int objectclass_do_rename(struct oc_context *ac);
+
static int objectclass_rename(struct ldb_module *module, struct ldb_request *req)
{
-
static const char * const attrs[] = { NULL };
- struct ldb_handle *h;
+ struct ldb_request *search_req;
struct oc_context *ac;
struct ldb_dn *parent_dn;
int ret;
-
+
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_rename\n");
if (ldb_dn_is_special(req->op.rename.newdn)) { /* do not manipulate our control entries */
return ldb_next_request(module, req);
}
-
+
/* Firstly ensure we are not trying to rename it to be a child of itself */
if ((ldb_dn_compare_base(req->op.rename.olddn, req->op.rename.newdn) == 0)
&& (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) != 0)) {
@@ -938,65 +978,50 @@ static int objectclass_rename(struct ldb_module *module, struct ldb_request *req
return LDB_ERR_UNWILLING_TO_PERFORM;
}
- h = oc_init_handle(req, module);
- if (!h) {
+ ac = oc_init_context(module, req);
+ if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct oc_context);
-
- /* return or own handle to deal with this call */
- req->handle = h;
- parent_dn = ldb_dn_get_parent(ac, ac->orig_req->op.rename.newdn);
+ parent_dn = ldb_dn_get_parent(ac, req->op.rename.newdn);
if (parent_dn == NULL) {
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_build_search_req(&ac->search_req, module->ldb,
+ ret = ldb_build_search_req(&search_req, module->ldb,
ac, parent_dn, LDB_SCOPE_BASE,
"(objectClass=*)",
attrs, NULL,
- ac, get_search_callback);
+ ac, get_search_callback,
+ req);
if (ret != LDB_SUCCESS) {
return ret;
}
- talloc_steal(ac->search_req, parent_dn);
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
- ac->step = OC_SEARCH_RENAME_PARENT;
+ ac->step_fn = objectclass_do_rename;
- return ldb_next_request(ac->module, ac->search_req);
+ return ldb_next_request(ac->module, search_req);
}
-static int objectclass_do_rename(struct ldb_handle *h)
+static int objectclass_do_rename(struct oc_context *ac)
{
- struct oc_context *ac;
+ struct ldb_request *rename_req;
+ struct ldb_dn *fixed_dn;
int ret;
-
- ac = talloc_get_type(h->private_data, struct oc_context);
- ac->rename_req = talloc(ac, struct ldb_request);
- if (ac->rename_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *ac->rename_req = *ac->orig_req;
-
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->rename_req);
-
/* Check we have a valid parent */
if (ac->search_res == NULL) {
ldb_asprintf_errstring(ac->module->ldb, "objectclass: Cannot rename %s, parent does not exist!",
- ldb_dn_get_linearized(ac->orig_req->op.rename.newdn));
+ ldb_dn_get_linearized(ac->req->op.rename.newdn));
return LDB_ERR_UNWILLING_TO_PERFORM;
}
- /* Fix up the DN to be in the standard form, taking particular care to match the parent DN */
- ret = fix_dn(ac->rename_req,
- ac->orig_req->op.rename.newdn,
- ac->search_res->message->dn,
- &ac->rename_req->op.rename.newdn);
-
+ /* Fix up the DN to be in the standard form,
+ * taking particular care to match the parent DN */
+ ret = fix_dn(ac,
+ ac->req->op.rename.newdn,
+ ac->search_res->message->dn,
+ &fixed_dn);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -1005,197 +1030,17 @@ static int objectclass_do_rename(struct ldb_handle *h)
* by reading the allowedChildClasses and
* allowedChildClasssesEffective attributes */
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
-
- ac->step = OC_DO_RENAME;
-
- /* perform the rename */
- return ldb_next_request(ac->module, ac->rename_req);
-}
-
-static int oc_wait(struct ldb_handle *handle) {
- struct oc_context *ac;
- int ret;
-
- if (!handle || !handle->private_data) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
- }
-
- handle->state = LDB_ASYNC_PENDING;
- handle->status = LDB_SUCCESS;
-
- ac = talloc_get_type(handle->private_data, struct oc_context);
-
- switch (ac->step) {
- case OC_DO_REQ:
- ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->down_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req->handle->status;
- goto done;
- }
-
- if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* mods done, go on */
- return objectclass_search_self(handle);
-
- case OC_SEARCH_SELF:
- ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->search_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->search_req->handle->status;
- goto done;
- }
-
- if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* self search done, go on */
- return objectclass_do_mod(handle);
-
- case OC_DO_MOD:
- ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->mod_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->mod_req->handle->status;
- goto done;
- }
-
- if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- break;
-
- case OC_SEARCH_ADD_PARENT:
- ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
- handle->status = ret;
- goto done;
- }
- if (ac->search_req->handle->status != LDB_SUCCESS
- && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
- handle->status = ac->search_req->handle->status;
- goto done;
- }
-
- if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* parent search done, go on */
- return objectclass_do_add(handle);
-
- case OC_DO_ADD:
- ret = ldb_wait(ac->add_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->add_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->add_req->handle->status;
- goto done;
- }
-
- if (ac->add_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- break;
-
- case OC_SEARCH_RENAME_PARENT:
- ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
- handle->status = ret;
- goto done;
- }
- if (ac->search_req->handle->status != LDB_SUCCESS && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
- handle->status = ac->search_req->handle->status;
- goto done;
- }
-
- if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* parent search done, go on */
- return objectclass_do_rename(handle);
-
- case OC_DO_RENAME:
- ret = ldb_wait(ac->rename_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->rename_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->rename_req->handle->status;
- goto done;
- }
-
- if (ac->rename_req->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 oc_wait_all(struct ldb_handle *handle) {
-
- int ret;
-
- while (handle->state != LDB_ASYNC_DONE) {
- ret = oc_wait(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ ret = ldb_build_rename_req(&rename_req, ac->module->ldb, ac,
+ ac->req->op.rename.olddn, fixed_dn,
+ ac->req->controls,
+ ac, oc_op_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return handle->status;
-}
-
-static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- if (type == LDB_WAIT_ALL) {
- return oc_wait_all(handle);
- } else {
- return oc_wait(handle);
- }
+ /* perform the rename */
+ return ldb_next_request(ac->module, rename_req);
}
_PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
@@ -1203,5 +1048,4 @@ _PUBLIC_ const struct ldb_module_ops ldb_objectclass_module_ops = {
.add = objectclass_add,
.modify = objectclass_modify,
.rename = objectclass_rename,
- .wait = objectclass_wait
};
diff --git a/source4/dsdb/samdb/ldb_modules/objectguid.c b/source4/dsdb/samdb/ldb_modules/objectguid.c
index f62839389d..3d725686e7 100644
--- a/source4/dsdb/samdb/ldb_modules/objectguid.c
+++ b/source4/dsdb/samdb/ldb_modules/objectguid.c
@@ -1,9 +1,9 @@
/*
ldb database library
- Copyright (C) Simo Sorce 2004-2006
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Simo Sorce 2004-2008
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
@@ -103,6 +103,36 @@ static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_
return 0;
}
+struct og_context {
+ struct ldb_module *module;
+ struct ldb_request *req;
+};
+
+static int og_op_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct og_context *ac;
+
+ ac = talloc_get_type(req->context, struct og_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+}
+
/* add_record: add objectGUID attribute */
static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
{
@@ -115,6 +145,7 @@ static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
enum ndr_err_code ndr_err;
int ret;
time_t t = time(NULL);
+ struct og_context *ac;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
@@ -127,15 +158,15 @@ static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
+ ac = talloc(req, struct og_context);
+ if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
- *down_req = *req;
+ ac->module = module;
+ ac->req = req;
/* we have to copy the message as the caller might have it as a const */
- down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
+ msg = ldb_msg_copy_shallow(ac, req->op.add.message);
if (msg == NULL) {
talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
@@ -149,44 +180,41 @@ static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
&guid,
(ndr_push_flags_fn_t)ndr_push_GUID);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
ret = ldb_msg_add_value(msg, "objectGUID", &v, NULL);
if (ret) {
- talloc_free(down_req);
return ret;
}
if (add_time_element(msg, "whenCreated", t) != 0 ||
add_time_element(msg, "whenChanged", t) != 0) {
- talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
/* Get a sequence number from the backend */
+ /* FIXME: ldb_sequence_number is a semi-async call,
+ * make sure this function is split and a callback is used */
ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
if (ret == LDB_SUCCESS) {
if (add_uint64_element(msg, "uSNCreated", seq_num) != 0 ||
add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
- talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
}
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ ret = ldb_build_add_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, og_op_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return ret;
+ /* go on with the call chain */
+ return ldb_next_request(module, down_req);
}
/* modify_record: update timestamps */
@@ -197,6 +225,7 @@ static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
int ret;
time_t t = time(NULL);
uint64_t seq_num;
+ struct og_context *ac;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
@@ -205,22 +234,20 @@ static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
+ ac = talloc(req, struct og_context);
+ if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
- *down_req = *req;
+ ac->module = module;
+ ac->req = req;
/* we have to copy the message as the caller might have it as a const */
- down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
+ msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
if (msg == NULL) {
- talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
if (add_time_element(msg, "whenChanged", t) != 0) {
- talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -228,23 +255,21 @@ static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
if (ret == LDB_SUCCESS) {
if (add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
- talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
}
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ ret = ldb_build_mod_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, og_op_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return ret;
+ /* go on with the call chain */
+ return ldb_next_request(module, down_req);
}
_PUBLIC_ const struct ldb_module_ops ldb_objectguid_module_ops = {
diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c
index 9cae6ab7b5..2a321e29c5 100644
--- a/source4/dsdb/samdb/ldb_modules/partition.c
+++ b/source4/dsdb/samdb/ldb_modules/partition.c
@@ -1,4 +1,3 @@
-
/*
Partitions ldb module
@@ -43,61 +42,95 @@ struct partition_private_data {
struct ldb_dn **replicate;
};
+struct part_request {
+ struct ldb_module *module;
+ struct ldb_request *req;
+};
+
struct partition_context {
struct ldb_module *module;
- struct ldb_request *orig_req;
+ struct ldb_request *req;
+ bool got_success;
- struct ldb_request **down_req;
+ struct part_request *part_req;
int num_requests;
int finished_requests;
};
-static struct partition_context *partition_init_handle(struct ldb_request *req, struct ldb_module *module)
+static struct partition_context *partition_init_ctx(struct ldb_module *module, struct ldb_request *req)
{
struct partition_context *ac;
- struct ldb_handle *h;
-
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- return NULL;
- }
-
- h->module = module;
- ac = talloc_zero(h, struct partition_context);
+ ac = talloc_zero(req, struct partition_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
- talloc_free(h);
return NULL;
}
- h->private_data = ac;
-
ac->module = module;
- ac->orig_req = req;
-
- req->handle = h;
+ ac->req = req;
return ac;
}
-static struct ldb_module *make_module_for_next_request(TALLOC_CTX *mem_ctx,
- struct ldb_context *ldb,
- struct ldb_module *module)
+#define PARTITION_FIND_OP(module, op) do { \
+ struct ldb_context *ldbctx = module->ldb; \
+ while (module && module->ops->op == NULL) module = module->next; \
+ if (module == NULL) { \
+ ldb_asprintf_errstring(ldbctx, \
+ "Unable to find backend operation for " #op ); \
+ return LDB_ERR_OPERATIONS_ERROR; \
+ } \
+} while (0)
+
+/*
+ * helper functions to call the next module in chain
+ * */
+
+static int partition_request(struct ldb_module *module, struct ldb_request *request)
{
- struct ldb_module *current;
- static const struct ldb_module_ops ops; /* zero */
- current = talloc_zero(mem_ctx, struct ldb_module);
- if (current == NULL) {
- return module;
+ int ret;
+ switch (request->operation) {
+ case LDB_SEARCH:
+ PARTITION_FIND_OP(module, search);
+ ret = module->ops->search(module, request);
+ break;
+ case LDB_ADD:
+ PARTITION_FIND_OP(module, add);
+ ret = module->ops->add(module, request);
+ break;
+ case LDB_MODIFY:
+ PARTITION_FIND_OP(module, modify);
+ ret = module->ops->modify(module, request);
+ break;
+ case LDB_DELETE:
+ PARTITION_FIND_OP(module, del);
+ ret = module->ops->del(module, request);
+ break;
+ case LDB_RENAME:
+ PARTITION_FIND_OP(module, rename);
+ ret = module->ops->rename(module, request);
+ break;
+ case LDB_EXTENDED:
+ PARTITION_FIND_OP(module, extended);
+ ret = module->ops->extended(module, request);
+ break;
+ default:
+ PARTITION_FIND_OP(module, request);
+ ret = module->ops->request(module, request);
+ break;
}
-
- current->ldb = ldb;
- current->ops = &ops;
- current->prev = NULL;
- current->next = module;
- return current;
+ if (ret == LDB_SUCCESS) {
+ return ret;
+ }
+ if (!ldb_errstring(module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(module->ldb,
+ "error in module %s: %s (%d)",
+ module->ops->name,
+ ldb_strerror(ret), ret);
+ }
+ return ret;
}
static struct dsdb_control_current_partition *find_partition(struct partition_private_data *data,
@@ -120,127 +153,206 @@ static struct dsdb_control_current_partition *find_partition(struct partition_pr
/**
* fire the caller's callback for every entry, but only send 'done' once.
*/
-static int partition_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int partition_req_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
struct partition_context *ac;
+ struct ldb_module *module;
+ struct ldb_request *nreq;
+ int ret;
- ac = talloc_get_type(context, struct partition_context);
+ ac = talloc_get_type(req->context, struct partition_context);
- if (ares->type == LDB_REPLY_ENTRY) {
- return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
- } else {
- ac->finished_requests++;
- if (ac->finished_requests == ac->num_requests) {
- return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
- } else {
- talloc_free(ares);
- return LDB_SUCCESS;
- }
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
-}
-/**
- * only fire the 'last' callback, and only for START-TLS for now
- */
-static int partition_other_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
-{
- struct partition_context *ac;
+ if (ares->error != LDB_SUCCESS && !ac->got_success) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- ac = talloc_get_type(context, struct partition_context);
+ switch (ares->type) {
+ case LDB_REPLY_REFERRAL:
+ /* ignore referrals for now */
+ break;
- if (!ac->orig_req->callback) {
- talloc_free(ares);
- return LDB_SUCCESS;
- }
+ case LDB_REPLY_ENTRY:
+ if (ac->req->operation != LDB_SEARCH) {
+ ldb_set_errstring(ac->module->ldb,
+ "partition_req_callback:"
+ " Unsupported reply type for this request");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ return ldb_module_send_entry(ac->req, ares->message);
+
+ case LDB_REPLY_DONE:
+ if (ares->error == LDB_SUCCESS) {
+ ac->got_success = true;
+ }
+ if (ac->req->operation == LDB_EXTENDED) {
+ /* FIXME: check for ares->response, replmd does not fill it ! */
+ if (ares->response) {
+ if (strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID) != 0) {
+ ldb_set_errstring(ac->module->ldb,
+ "partition_req_callback:"
+ " Unknown extended reply, "
+ "only supports START_TLS");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ }
+ }
- if (!ares
- || (ares->type == LDB_REPLY_EXTENDED
- && strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID))) {
ac->finished_requests++;
if (ac->finished_requests == ac->num_requests) {
- return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
+ /* this was the last one, call callback */
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response,
+ ac->got_success?LDB_SUCCESS:ares->error);
+ }
+
+ /* not the last, now call the next one */
+ module = ac->part_req[ac->finished_requests].module;
+ nreq = ac->part_req[ac->finished_requests].req;
+
+ ret = partition_request(module, nreq);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- talloc_free(ares);
- return LDB_SUCCESS;
+
+ break;
}
- ldb_set_errstring(ldb, "partition_other_callback: Unknown reply type, only supports START_TLS");
+
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ return LDB_SUCCESS;
}
-
-static int partition_send_request(struct partition_context *ac,
+static int partition_prep_request(struct partition_context *ac,
struct dsdb_control_current_partition *partition)
{
int ret;
- struct ldb_module *backend;
struct ldb_request *req;
- if (partition) {
- backend = make_module_for_next_request(ac, ac->module->ldb, partition->module);
- } else {
- backend = ac->module;
- }
-
- ac->down_req = talloc_realloc(ac, ac->down_req,
- struct ldb_request *, ac->num_requests + 1);
- if (!ac->down_req) {
+ ac->part_req = talloc_realloc(ac, ac->part_req,
+ struct part_request,
+ ac->num_requests + 1);
+ if (ac->part_req == NULL) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- req = ac->down_req[ac->num_requests] = talloc(ac, struct ldb_request);
- if (req == NULL) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+
+ switch (ac->req->operation) {
+ case LDB_SEARCH:
+ ret = ldb_build_search_req_ex(&req, ac->module->ldb,
+ ac->part_req,
+ ac->req->op.search.base,
+ ac->req->op.search.scope,
+ ac->req->op.search.tree,
+ ac->req->op.search.attrs,
+ ac->req->controls,
+ ac, partition_req_callback,
+ ac->req);
+ break;
+ case LDB_ADD:
+ ret = ldb_build_add_req(&req, ac->module->ldb, ac->part_req,
+ ac->req->op.add.message,
+ ac->req->controls,
+ ac, partition_req_callback,
+ ac->req);
+ break;
+ case LDB_MODIFY:
+ ret = ldb_build_mod_req(&req, ac->module->ldb, ac->part_req,
+ ac->req->op.mod.message,
+ ac->req->controls,
+ ac, partition_req_callback,
+ ac->req);
+ break;
+ case LDB_DELETE:
+ ret = ldb_build_del_req(&req, ac->module->ldb, ac->part_req,
+ ac->req->op.del.dn,
+ ac->req->controls,
+ ac, partition_req_callback,
+ ac->req);
+ break;
+ case LDB_RENAME:
+ ret = ldb_build_rename_req(&req, ac->module->ldb, ac->part_req,
+ ac->req->op.rename.olddn,
+ ac->req->op.rename.newdn,
+ ac->req->controls,
+ ac, partition_req_callback,
+ ac->req);
+ break;
+ case LDB_EXTENDED:
+ ret = ldb_build_extended_req(&req, ac->module->ldb,
+ ac->part_req,
+ ac->req->op.extended.oid,
+ ac->req->op.extended.data,
+ ac->req->controls,
+ ac, partition_req_callback,
+ ac->req);
+ break;
+ default:
+ ldb_set_errstring(ac->module->ldb,
+ "Unsupported request type!");
+ ret = LDB_ERR_UNWILLING_TO_PERFORM;
}
-
- *req = *ac->orig_req; /* copy the request */
- if (req->controls) {
- req->controls
- = talloc_memdup(req,
- ac->orig_req->controls, talloc_get_size(ac->orig_req->controls));
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ac->part_req[ac->num_requests].req = req;
+
+ if (ac->req->controls) {
+ req->controls = talloc_memdup(req, ac->req->controls,
+ talloc_get_size(ac->req->controls));
if (req->controls == NULL) {
ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
}
- if (req->operation == LDB_SEARCH) {
- /* If the search is for 'more' than this partition,
- * then change the basedn, so a remote LDAP server
- * doesn't object */
- if (partition) {
- if (ldb_dn_compare_base(partition->dn, req->op.search.base) != 0) {
- req->op.search.base = partition->dn;
- }
- } else {
- req->op.search.base = NULL;
- }
- req->callback = partition_search_callback;
- req->context = ac;
- } else {
- req->callback = partition_other_callback;
- req->context = ac;
- }
-
if (partition) {
- ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition);
+ ac->part_req[ac->num_requests].module = partition->module;
+
+ ret = ldb_request_add_control(req,
+ DSDB_CONTROL_CURRENT_PARTITION_OID,
+ false, partition);
if (ret != LDB_SUCCESS) {
return ret;
}
- }
- /* Spray off search requests the backend */
- ret = ldb_next_request(backend, req);
- if (ret != LDB_SUCCESS) {
- return ret;
+ if (req->operation == LDB_SEARCH) {
+ /* If the search is for 'more' than this partition,
+ * then change the basedn, so a remote LDAP server
+ * doesn't object */
+ if (ldb_dn_compare_base(partition->dn,
+ req->op.search.base) != 0) {
+ req->op.search.base = partition->dn;
+ }
+ }
+
+ } else {
+ /* make sure you put the NEXT module here, or
+ * partition_request() will simply loop forever on itself */
+ ac->part_req[ac->num_requests].module = ac->module->next;
}
ac->num_requests++;
+
return LDB_SUCCESS;
}
+static int partition_call_first(struct partition_context *ac)
+{
+ return partition_request(ac->part_req[0].module, ac->part_req[0].req);
+}
+
/**
* Send a request down to all the partitions
*/
@@ -251,17 +363,19 @@ static int partition_send_all(struct ldb_module *module,
int i;
struct partition_private_data *data = talloc_get_type(module->private_data,
struct partition_private_data);
- int ret = partition_send_request(ac, NULL);
+ int ret = partition_prep_request(ac, NULL);
if (ret != LDB_SUCCESS) {
return ret;
}
for (i=0; data && data->partitions && data->partitions[i]; i++) {
- ret = partition_send_request(ac, data->partitions[i]);
+ ret = partition_prep_request(ac, data->partitions[i]);
if (ret != LDB_SUCCESS) {
return ret;
}
}
- return LDB_SUCCESS;
+
+ /* fire the first one */
+ return partition_call_first(ac);
}
/**
@@ -270,21 +384,23 @@ static int partition_send_all(struct ldb_module *module,
*/
static int partition_replicate(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
{
+ struct partition_context *ac;
unsigned i;
int ret;
struct dsdb_control_current_partition *partition;
- struct ldb_module *backend;
struct partition_private_data *data = talloc_get_type(module->private_data,
struct partition_private_data);
+ if (!data || !data->partitions) {
+ return ldb_next_request(module, req);
+ }
if (req->operation != LDB_SEARCH) {
/* Is this a special DN, we need to replicate to every backend? */
for (i=0; data->replicate && data->replicate[i]; i++) {
if (ldb_dn_compare(data->replicate[i],
dn) == 0) {
- struct partition_context *ac;
- ac = partition_init_handle(req, module);
+ ac = partition_init_ctx(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -310,18 +426,19 @@ static int partition_replicate(struct ldb_module *module, struct ldb_request *re
return ldb_next_request(module, req);
}
- backend = make_module_for_next_request(req, module->ldb, partition->module);
- if (!backend) {
+ ac = partition_init_ctx(module, req);
+ if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition);
+ /* we need to add a control but we never touch the original request */
+ ret = partition_prep_request(ac, partition);
if (ret != LDB_SUCCESS) {
return ret;
}
- /* issue request */
- return ldb_next_request(backend, req);
+ /* fire the first one */
+ return partition_call_first(ac);
}
/* search */
@@ -336,6 +453,7 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
/* (later) consider if we should be searching multiple
* partitions (for 'invisible' partition behaviour */
+
struct ldb_control *search_control = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
struct ldb_control *domain_scope_control = ldb_request_get_control(req, LDB_CONTROL_DOMAIN_SCOPE_OID);
@@ -350,6 +468,14 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_OPERATIONS_ERROR;
}
+ /*
+ * for now pass down the LDB_CONTROL_SEARCH_OPTIONS_OID control
+ * down as uncritical to make windows 2008 dcpromo happy.
+ */
+ if (search_control) {
+ search_control->critical = 0;
+ }
+
/* TODO:
Generate referrals (look for a partition under this DN) if we don't have the above control specified
*/
@@ -366,7 +492,7 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_OPERATIONS_ERROR;
}
}
- ac = partition_init_handle(req, module);
+ ac = partition_init_ctx(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -376,13 +502,41 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
return partition_send_all(module, ac, req);
}
for (i=0; data && data->partitions && data->partitions[i]; i++) {
- /* Find all partitions under the search base */
- if (ldb_dn_compare_base(req->op.search.base, data->partitions[i]->dn) == 0) {
- ret = partition_send_request(ac, data->partitions[i]);
+ bool match = false, stop = false;
+ /* Find all partitions under the search base
+
+ we match if:
+
+ 1) the DN we are looking for exactly matches the partition
+ or
+ 2) the DN we are looking for is a parent of the partition and it isn't
+ a scope base search
+ or
+ 3) the DN we are looking for is a child of the partition
+ */
+ if (ldb_dn_compare(data->partitions[i]->dn, req->op.search.base) == 0) {
+ match = true;
+ if (req->op.search.scope == LDB_SCOPE_BASE) {
+ stop = true;
+ }
+ }
+ if (!match &&
+ (ldb_dn_compare_base(req->op.search.base, data->partitions[i]->dn) == 0 &&
+ req->op.search.scope != LDB_SCOPE_BASE)) {
+ match = true;
+ }
+ if (!match &&
+ ldb_dn_compare_base(data->partitions[i]->dn, req->op.search.base) == 0) {
+ match = true;
+ stop = true; /* note that this relies on partition ordering */
+ }
+ if (match) {
+ ret = partition_prep_request(ac, data->partitions[i]);
if (ret != LDB_SUCCESS) {
return ret;
}
}
+ if (stop) break;
}
/* Perhaps we didn't match any partitions. Try the main partition, only */
@@ -390,8 +544,10 @@ static int partition_search(struct ldb_module *module, struct ldb_request *req)
talloc_free(ac);
return ldb_next_request(module, req);
}
-
- return LDB_SUCCESS;
+
+ /* fire the first one */
+ return partition_call_first(ac);
+
} else {
/* Handle this like all other requests */
if (search_control && (search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {
@@ -429,14 +585,13 @@ static int partition_delete(struct ldb_module *module, struct ldb_request *req)
/* rename */
static int partition_rename(struct ldb_module *module, struct ldb_request *req)
{
- int i, matched = -1;
/* Find backend */
struct dsdb_control_current_partition *backend, *backend2;
struct partition_private_data *data = talloc_get_type(module->private_data,
struct partition_private_data);
- /* Skip the lot if 'data' isn't here yet (initialistion) */
+ /* Skip the lot if 'data' isn't here yet (initialization) */
if (!data) {
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -459,22 +614,6 @@ static int partition_rename(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
}
- for (i=0; data && data->partitions && data->partitions[i]; i++) {
- if (ldb_dn_compare_base(req->op.rename.olddn, data->partitions[i]->dn) == 0) {
- matched = i;
- }
- }
-
- if (matched > 0) {
- ldb_asprintf_errstring(module->ldb,
- "Cannot rename from %s to %s, subtree rename would cross partition %s: %s",
- ldb_dn_get_linearized(req->op.rename.olddn),
- ldb_dn_get_linearized(req->op.rename.newdn),
- ldb_dn_get_linearized(data->partitions[matched]->dn),
- ldb_strerror(LDB_ERR_AFFECTS_MULTIPLE_DSAS));
- return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
- }
-
return partition_replicate(module, req, req->op.rename.olddn);
}
@@ -486,24 +625,26 @@ static int partition_start_trans(struct ldb_module *module)
struct partition_private_data);
/* Look at base DN */
/* Figure out which partition it is under */
- /* Skip the lot if 'data' isn't here yet (initialistion) */
+ /* Skip the lot if 'data' isn't here yet (initialization) */
ret = ldb_next_start_trans(module);
if (ret != LDB_SUCCESS) {
return ret;
}
for (i=0; data && data->partitions && data->partitions[i]; i++) {
- struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
+ struct ldb_module *next = data->partitions[i]->module;
+ PARTITION_FIND_OP(next, start_transaction);
- ret = ldb_next_start_trans(next);
- talloc_free(next);
+ ret = next->ops->start_transaction(next);
if (ret != LDB_SUCCESS) {
/* Back it out, if it fails on one */
for (i--; i >= 0; i--) {
- next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
- ldb_next_del_trans(next);
- talloc_free(next);
+ next = data->partitions[i]->module;
+ PARTITION_FIND_OP(next, del_transaction);
+
+ next->ops->del_transaction(next);
}
+ ldb_next_del_trans(module);
return ret;
}
}
@@ -513,7 +654,7 @@ static int partition_start_trans(struct ldb_module *module)
/* end a transaction */
static int partition_end_trans(struct ldb_module *module)
{
- int i, ret, ret2 = LDB_SUCCESS;
+ int i, ret;
struct partition_private_data *data = talloc_get_type(module->private_data,
struct partition_private_data);
ret = ldb_next_end_trans(module);
@@ -525,24 +666,24 @@ static int partition_end_trans(struct ldb_module *module)
/* Figure out which partition it is under */
/* Skip the lot if 'data' isn't here yet (initialistion) */
for (i=0; data && data->partitions && data->partitions[i]; i++) {
- struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
-
- ret = ldb_next_end_trans(next);
- talloc_free(next);
+ struct ldb_module *next = data->partitions[i]->module;
+ PARTITION_FIND_OP(next, end_transaction);
+
+ ret = next->ops->end_transaction(next);
if (ret != LDB_SUCCESS) {
- ret2 = ret;
- }
- }
+ /* Back it out, if it fails on one */
+ for (i--; i >= 0; i--) {
+ next = data->partitions[i]->module;
+ PARTITION_FIND_OP(next, del_transaction);
- if (ret != LDB_SUCCESS) {
- /* Back it out, if it fails on one */
- for (i=0; data && data->partitions && data->partitions[i]; i++) {
- struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
- ldb_next_del_trans(next);
- talloc_free(next);
+ next->ops->del_transaction(next);
+ }
+ ldb_next_del_trans(module);
+ return ret;
}
}
- return ret;
+
+ return LDB_SUCCESS;
}
/* delete a transaction */
@@ -560,10 +701,10 @@ static int partition_del_trans(struct ldb_module *module)
/* Figure out which partition it is under */
/* Skip the lot if 'data' isn't here yet (initialistion) */
for (i=0; data && data->partitions && data->partitions[i]; i++) {
- struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
-
- ret = ldb_next_del_trans(next);
- talloc_free(next);
+ struct ldb_module *next = data->partitions[i]->module;
+ PARTITION_FIND_OP(next, del_transaction);
+
+ ret = next->ops->del_transaction(next);
if (ret != LDB_SUCCESS) {
ret2 = ret;
}
@@ -571,6 +712,8 @@ static int partition_del_trans(struct ldb_module *module)
return ret2;
}
+
+/* FIXME: This function is still semi-async */
static int partition_sequence_number(struct ldb_module *module, struct ldb_request *req)
{
int i, ret;
@@ -579,105 +722,241 @@ static int partition_sequence_number(struct ldb_module *module, struct ldb_reque
uint64_t timestamp = 0;
struct partition_private_data *data = talloc_get_type(module->private_data,
struct partition_private_data);
+ struct ldb_seqnum_request *seq;
+ struct ldb_seqnum_result *seqr;
+ struct ldb_request *treq;
+ struct ldb_seqnum_request *tseq;
+ struct ldb_seqnum_result *tseqr;
+ struct ldb_extended *ext;
+ struct ldb_result *res;
+
+ seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
- switch (req->op.seq_num.type) {
+ switch (seq->type) {
case LDB_SEQ_NEXT:
case LDB_SEQ_HIGHEST_SEQ:
- ret = ldb_next_request(module, req);
+ res = talloc_zero(req, struct ldb_result);
+ if (res == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ tseq = talloc_zero(res, struct ldb_seqnum_request);
+ if (tseq == NULL) {
+ talloc_free(res);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ tseq->type = seq->type;
+
+ ret = ldb_build_extended_req(&treq, module->ldb, res,
+ LDB_EXTENDED_SEQUENCE_NUMBER,
+ tseq,
+ NULL,
+ res,
+ ldb_extended_default_callback,
+ NULL);
+ ret = ldb_next_request(module, treq);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
+ }
if (ret != LDB_SUCCESS) {
+ talloc_free(res);
return ret;
}
- if (req->op.seq_num.flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
- timestamp_sequence = req->op.seq_num.seq_num;
+ seqr = talloc_get_type(res->extended->data,
+ struct ldb_seqnum_result);
+ if (seqr->flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
+ timestamp_sequence = seqr->seq_num;
} else {
- seq_number = seq_number + req->op.seq_num.seq_num;
+ seq_number += seqr->seq_num;
}
+ talloc_free(res);
- /* Look at base DN */
- /* Figure out which partition it is under */
/* Skip the lot if 'data' isn't here yet (initialistion) */
for (i=0; data && data->partitions && data->partitions[i]; i++) {
- struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
-
- ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, data->partitions[i]);
+
+ res = talloc_zero(req, struct ldb_result);
+ if (res == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ tseq = talloc_zero(res, struct ldb_seqnum_request);
+ if (tseq == NULL) {
+ talloc_free(res);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ tseq->type = seq->type;
+
+ ret = ldb_build_extended_req(&treq, module->ldb, res,
+ LDB_EXTENDED_SEQUENCE_NUMBER,
+ tseq,
+ NULL,
+ res,
+ ldb_extended_default_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return ret;
+ }
+
+ ret = ldb_request_add_control(treq,
+ DSDB_CONTROL_CURRENT_PARTITION_OID,
+ false, data->partitions[i]);
if (ret != LDB_SUCCESS) {
+ talloc_free(res);
return ret;
}
- ret = ldb_next_request(next, req);
- talloc_free(next);
+ ret = partition_request(data->partitions[i]->module, treq);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return ret;
+ }
+ ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
if (ret != LDB_SUCCESS) {
+ talloc_free(res);
return ret;
}
- if (req->op.seq_num.flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
- timestamp_sequence = MAX(timestamp_sequence, req->op.seq_num.seq_num);
+ tseqr = talloc_get_type(res->extended->data,
+ struct ldb_seqnum_result);
+ if (tseqr->flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
+ timestamp_sequence = MAX(timestamp_sequence,
+ tseqr->seq_num);
} else {
- seq_number = seq_number + req->op.seq_num.seq_num;
+ seq_number += tseqr->seq_num;
}
+ talloc_free(res);
}
- /* fall though */
+ /* fall through */
case LDB_SEQ_HIGHEST_TIMESTAMP:
- {
- struct ldb_request *date_req = talloc(req, struct ldb_request);
- if (!date_req) {
+
+ res = talloc_zero(req, struct ldb_result);
+ if (res == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- *date_req = *req;
- date_req->op.seq_num.flags = LDB_SEQ_HIGHEST_TIMESTAMP;
- ret = ldb_next_request(module, date_req);
+ tseq = talloc_zero(res, struct ldb_seqnum_request);
+ if (tseq == NULL) {
+ talloc_free(res);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ tseq->type = LDB_SEQ_HIGHEST_TIMESTAMP;
+
+ ret = ldb_build_extended_req(&treq, module->ldb, res,
+ LDB_EXTENDED_SEQUENCE_NUMBER,
+ tseq,
+ NULL,
+ res,
+ ldb_extended_default_callback,
+ NULL);
if (ret != LDB_SUCCESS) {
+ talloc_free(res);
return ret;
}
- timestamp = date_req->op.seq_num.seq_num;
-
- /* Look at base DN */
- /* Figure out which partition it is under */
+
+ ret = ldb_next_request(module, treq);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return ret;
+ }
+ ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return ret;
+ }
+
+ tseqr = talloc_get_type(res->extended->data,
+ struct ldb_seqnum_result);
+ timestamp = tseqr->seq_num;
+
+ talloc_free(res);
+
/* Skip the lot if 'data' isn't here yet (initialistion) */
for (i=0; data && data->partitions && data->partitions[i]; i++) {
- struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
-
- ret = ldb_next_request(next, date_req);
- talloc_free(next);
+
+ res = talloc_zero(req, struct ldb_result);
+ if (res == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ tseq = talloc_zero(res, struct ldb_seqnum_request);
+ if (tseq == NULL) {
+ talloc_free(res);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ tseq->type = LDB_SEQ_HIGHEST_TIMESTAMP;
+
+ ret = ldb_build_extended_req(&treq, module->ldb, res,
+ LDB_EXTENDED_SEQUENCE_NUMBER,
+ tseq,
+ NULL,
+ res,
+ ldb_extended_default_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return ret;
+ }
+
+ ret = partition_request(data->partitions[i]->module, treq);
if (ret != LDB_SUCCESS) {
+ talloc_free(res);
return ret;
}
- timestamp = MAX(timestamp, date_req->op.seq_num.seq_num);
+ ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ return ret;
+ }
+
+ tseqr = talloc_get_type(res->extended->data,
+ struct ldb_seqnum_result);
+ timestamp = MAX(timestamp, tseqr->seq_num);
+
+ talloc_free(res);
}
+
break;
}
+
+ ext = talloc_zero(req, struct ldb_extended);
+ if (!ext) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ seqr = talloc_zero(ext, struct ldb_seqnum_result);
+ if (seqr == NULL) {
+ talloc_free(ext);
+ return LDB_ERR_OPERATIONS_ERROR;
}
+ ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
+ ext->data = seqr;
- switch (req->op.seq_num.flags) {
+ switch (seq->type) {
case LDB_SEQ_NEXT:
case LDB_SEQ_HIGHEST_SEQ:
-
- req->op.seq_num.flags = 0;
/* Has someone above set a timebase sequence? */
if (timestamp_sequence) {
- req->op.seq_num.seq_num = (((unsigned long long)timestamp << 24) | (seq_number & 0xFFFFFF));
+ seqr->seq_num = (((unsigned long long)timestamp << 24) | (seq_number & 0xFFFFFF));
} else {
- req->op.seq_num.seq_num = seq_number;
+ seqr->seq_num = seq_number;
}
- if (timestamp_sequence > req->op.seq_num.seq_num) {
- req->op.seq_num.seq_num = timestamp_sequence;
- req->op.seq_num.flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
+ if (timestamp_sequence > seqr->seq_num) {
+ seqr->seq_num = timestamp_sequence;
+ seqr->flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
}
- req->op.seq_num.flags |= LDB_SEQ_GLOBAL_SEQUENCE;
+ seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
break;
case LDB_SEQ_HIGHEST_TIMESTAMP:
- req->op.seq_num.seq_num = timestamp;
+ seqr->seq_num = timestamp;
break;
}
- switch (req->op.seq_num.flags) {
- case LDB_SEQ_NEXT:
- req->op.seq_num.seq_num++;
+ if (seq->type == LDB_SEQ_NEXT) {
+ seqr->seq_num++;
}
- return LDB_SUCCESS;
+
+ /* send request done */
+ return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
}
static int partition_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
@@ -705,7 +984,6 @@ static int partition_extended_schema_update_now(struct ldb_module *module, struc
struct partition_private_data *data;
struct ldb_dn *schema_dn;
struct partition_context *ac;
- struct ldb_module *backend;
int ret;
schema_dn = talloc_get_type(req->op.extended.data, struct ldb_dn);
@@ -724,30 +1002,37 @@ static int partition_extended_schema_update_now(struct ldb_module *module, struc
return ldb_next_request(module, req);
}
- ac = partition_init_handle(req, module);
+ ac = partition_init_ctx(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- backend = make_module_for_next_request(req, module->ldb, partition->module);
- if (!backend) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_request_add_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID, false, partition);
+ /* we need to add a control but we never touch the original request */
+ ret = partition_prep_request(ac, partition);
if (ret != LDB_SUCCESS) {
return ret;
}
- return ldb_next_request(backend, req);
+ /* fire the first one */
+ return partition_call_first(ac);
}
/* extended */
static int partition_extended(struct ldb_module *module, struct ldb_request *req)
{
+ struct partition_private_data *data;
struct partition_context *ac;
+ data = talloc_get_type(module->private_data, struct partition_private_data);
+ if (!data || !data->partitions) {
+ return ldb_next_request(module, req);
+ }
+
+ if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
+ return partition_sequence_number(module, req);
+ }
+
if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
return partition_extended_replicated_objects(module, req);
}
@@ -762,27 +1047,23 @@ static int partition_extended(struct ldb_module *module, struct ldb_request *req
* we need to send it to all partitions
*/
- ac = partition_init_handle(req, module);
+ ac = partition_init_ctx(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
+
return partition_send_all(module, ac, req);
}
-static int sort_compare(void *void1,
- void *void2, void *opaque)
+static int partition_sort_compare(const void *v1, const void *v2)
{
- struct dsdb_control_current_partition **pp1 =
- (struct dsdb_control_current_partition **)void1;
- struct dsdb_control_current_partition **pp2 =
- (struct dsdb_control_current_partition **)void2;
- struct dsdb_control_current_partition *partition1 = talloc_get_type(*pp1,
- struct dsdb_control_current_partition);
- struct dsdb_control_current_partition *partition2 = talloc_get_type(*pp2,
- struct dsdb_control_current_partition);
-
- return ldb_dn_compare(partition1->dn, partition2->dn);
+ struct dsdb_control_current_partition *p1;
+ struct dsdb_control_current_partition *p2;
+
+ p1 = *((struct dsdb_control_current_partition **)v1);
+ p2 = *((struct dsdb_control_current_partition **)v2);
+
+ return ldb_dn_compare(p1->dn, p2->dn);
}
static int partition_init(struct ldb_module *module)
@@ -807,15 +1088,13 @@ static int partition_init(struct ldb_module *module)
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_search(module->ldb, ldb_dn_new(mem_ctx, module->ldb, "@PARTITION"),
- LDB_SCOPE_BASE,
- NULL, attrs,
- &res);
+ ret = ldb_search(module->ldb, mem_ctx, &res,
+ ldb_dn_new(mem_ctx, module->ldb, "@PARTITION"),
+ LDB_SCOPE_BASE, attrs, NULL);
if (ret != LDB_SUCCESS) {
talloc_free(mem_ctx);
return ret;
}
- talloc_steal(mem_ctx, res);
if (res->count == 0) {
talloc_free(mem_ctx);
return ldb_next_init(module);
@@ -890,8 +1169,8 @@ static int partition_init(struct ldb_module *module)
data->partitions[i] = NULL;
/* sort these into order, most to least specific */
- ldb_qsort(data->partitions, partition_attributes->num_values, sizeof(*data->partitions),
- module->ldb, sort_compare);
+ qsort(data->partitions, partition_attributes->num_values,
+ sizeof(*data->partitions), partition_sort_compare);
for (i=0; data->partitions[i]; i++) {
struct ldb_request *req;
@@ -904,8 +1183,19 @@ static int partition_init(struct ldb_module *module)
req->operation = LDB_REQ_REGISTER_PARTITION;
req->op.reg_partition.dn = data->partitions[i]->dn;
+ req->callback = ldb_op_default_callback;
+
+ ldb_set_timeout(module->ldb, req, 0);
+
+ req->handle = ldb_handle_new(req, module->ldb);
+ if (req->handle == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
ret = ldb_request(module->ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
if (ret != LDB_SUCCESS) {
ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
talloc_free(mem_ctx);
@@ -923,7 +1213,7 @@ static int partition_init(struct ldb_module *module)
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
-
+
for (i=0; i < replicate_attributes->num_values; i++) {
data->replicate[i] = ldb_dn_from_ldb_val(data->replicate, module->ldb, &replicate_attributes->values[i]);
if (!ldb_dn_validate(data->replicate[i])) {
@@ -1014,74 +1304,22 @@ static int partition_init(struct ldb_module *module)
}
}
- talloc_free(mem_ctx);
- return ldb_next_init(module);
-}
-
-static int partition_wait_none(struct ldb_handle *handle) {
- struct partition_context *ac;
- int ret;
- int i;
-
- if (!handle || !handle->private_data) {
+ ret = ldb_mod_register_control(module, LDB_CONTROL_DOMAIN_SCOPE_OID);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "partition: Unable to register control with rootdse!\n");
return LDB_ERR_OPERATIONS_ERROR;
}
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
- }
-
- handle->state = LDB_ASYNC_PENDING;
- handle->status = LDB_SUCCESS;
-
- ac = talloc_get_type(handle->private_data, struct partition_context);
-
- for (i=0; i < ac->num_requests; i++) {
- ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req[i]->handle->status;
- goto done;
- }
-
- if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
- }
-
- ret = LDB_SUCCESS;
-
-done:
- handle->state = LDB_ASYNC_DONE;
- return ret;
-}
-
-
-static int partition_wait_all(struct ldb_handle *handle) {
-
- int ret;
-
- while (handle->state != LDB_ASYNC_DONE) {
- ret = partition_wait_none(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ ret = ldb_mod_register_control(module, LDB_CONTROL_SEARCH_OPTIONS_OID);
+ if (ret != LDB_SUCCESS) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "partition: Unable to register control with rootdse!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return handle->status;
-}
-
-static int partition_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- if (type == LDB_WAIT_ALL) {
- return partition_wait_all(handle);
- } else {
- return partition_wait_none(handle);
- }
+ talloc_free(mem_ctx);
+ return ldb_next_init(module);
}
_PUBLIC_ const struct ldb_module_ops ldb_partition_module_ops = {
@@ -1093,9 +1331,7 @@ _PUBLIC_ const struct ldb_module_ops ldb_partition_module_ops = {
.del = partition_delete,
.rename = partition_rename,
.extended = partition_extended,
- .sequence_number = partition_sequence_number,
.start_transaction = partition_start_trans,
.end_transaction = partition_end_trans,
.del_transaction = partition_del_trans,
- .wait = partition_wait
};
diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c
index 69783aefa8..5ed7f1fbad 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -1,7 +1,7 @@
/*
ldb database module
- Copyright (C) Simo Sorce 2004-2006
+ Copyright (C) Simo Sorce 2004-2008
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
Copyright (C) Andrew Tridgell 2004
Copyright (C) Stefan Metzmacher 2007
@@ -48,7 +48,7 @@
#include "dsdb/samdb/ldb_modules/password_modules.h"
#include "librpc/ndr/libndr.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
-#include "lib/crypto/crypto.h"
+#include "../lib/crypto/crypto.h"
#include "param/param.h"
/* If we have decided there is reason to work on this request, then
@@ -73,23 +73,16 @@
struct ph_context {
- enum ph_type {PH_ADD, PH_MOD} type;
- enum ph_step {PH_ADD_SEARCH_DOM, PH_ADD_DO_ADD, PH_MOD_DO_REQ, PH_MOD_SEARCH_SELF, PH_MOD_SEARCH_DOM, PH_MOD_DO_MOD} step;
-
struct ldb_module *module;
- struct ldb_request *orig_req;
+ struct ldb_request *req;
struct ldb_request *dom_req;
struct ldb_reply *dom_res;
- struct ldb_request *down_req;
-
- struct ldb_request *search_req;
struct ldb_reply *search_res;
- struct ldb_request *mod_req;
-
struct dom_sid *domain_sid;
+ struct domain_data *domain;
};
struct domain_data {
@@ -116,7 +109,8 @@ struct setup_password_fields_io {
/* new credentials */
struct {
- const char *cleartext;
+ const struct ldb_val *cleartext_utf8;
+ const struct ldb_val *cleartext_utf16;
struct samr_Password *nt_hash;
struct samr_Password *lm_hash;
} n;
@@ -151,6 +145,9 @@ struct setup_password_fields_io {
} g;
};
+/* Get the NT hash, and fill it in as an entry in the password history,
+ and specify it into io->g.nt_hash */
+
static int setup_nt_fields(struct setup_password_fields_io *io)
{
uint32_t i;
@@ -188,6 +185,9 @@ static int setup_nt_fields(struct setup_password_fields_io *io)
return LDB_SUCCESS;
}
+/* Get the LANMAN hash, and fill it in as an entry in the password history,
+ and specify it into io->g.lm_hash */
+
static int setup_lm_fields(struct setup_password_fields_io *io)
{
uint32_t i;
@@ -227,6 +227,10 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
Principal *salt_principal;
krb5_salt salt;
krb5_keyblock key;
+ krb5_data cleartext_data;
+
+ cleartext_data.data = io->n.cleartext_utf8->data;
+ cleartext_data.length = io->n.cleartext_utf8->length;
/* Many, many thanks to lukeh@padl.com for this
* algorithm, described in his Nov 10 2004 mail to
@@ -321,11 +325,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
* create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
* the salt and the cleartext password
*/
- krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
- ENCTYPE_AES256_CTS_HMAC_SHA1_96,
- io->n.cleartext,
- salt,
- &key);
+ krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ cleartext_data,
+ salt,
+ &key);
if (krb5_ret) {
ldb_asprintf_errstring(io->ac->module->ldb,
"setup_kerberos_keys: "
@@ -346,11 +350,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
* create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
* the salt and the cleartext password
*/
- krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
- ENCTYPE_AES128_CTS_HMAC_SHA1_96,
- io->n.cleartext,
- salt,
- &key);
+ krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ cleartext_data,
+ salt,
+ &key);
if (krb5_ret) {
ldb_asprintf_errstring(io->ac->module->ldb,
"setup_kerberos_keys: "
@@ -371,11 +375,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
* create ENCTYPE_DES_CBC_MD5 key out of
* the salt and the cleartext password
*/
- krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
- ENCTYPE_DES_CBC_MD5,
- io->n.cleartext,
- salt,
- &key);
+ krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
+ ENCTYPE_DES_CBC_MD5,
+ cleartext_data,
+ salt,
+ &key);
if (krb5_ret) {
ldb_asprintf_errstring(io->ac->module->ldb,
"setup_kerberos_keys: "
@@ -396,11 +400,11 @@ static int setup_kerberos_keys(struct setup_password_fields_io *io)
* create ENCTYPE_DES_CBC_CRC key out of
* the salt and the cleartext password
*/
- krb5_ret = krb5_string_to_key_salt(io->smb_krb5_context->krb5_context,
- ENCTYPE_DES_CBC_CRC,
- io->n.cleartext,
- salt,
- &key);
+ krb5_ret = krb5_string_to_key_data_salt(io->smb_krb5_context->krb5_context,
+ ENCTYPE_DES_CBC_CRC,
+ cleartext_data,
+ salt,
+ &key);
if (krb5_ret) {
ldb_asprintf_errstring(io->ac->module->ldb,
"setup_kerberos_keys: "
@@ -478,12 +482,11 @@ static int setup_primary_kerberos(struct setup_password_fields_io *io,
if (old_scp) {
DATA_BLOB blob;
- blob = strhex_to_data_blob(old_scp->data);
+ blob = strhex_to_data_blob(io->ac, old_scp->data);
if (!blob.data) {
ldb_oom(io->ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- talloc_steal(io->ac, blob.data);
/* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
ndr_err = ndr_pull_struct_blob(&blob, io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")), &_old_pkb,
@@ -592,12 +595,11 @@ static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
if (old_scp) {
DATA_BLOB blob;
- blob = strhex_to_data_blob(old_scp->data);
+ blob = strhex_to_data_blob(io->ac, old_scp->data);
if (!blob.data) {
ldb_oom(io->ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- talloc_steal(io->ac, blob.data);
/* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
ndr_err = ndr_pull_struct_blob(&blob, io->ac,
@@ -655,7 +657,6 @@ static int setup_primary_wdigest(struct setup_password_fields_io *io,
DATA_BLOB dns_domain;
DATA_BLOB dns_domain_l;
DATA_BLOB dns_domain_u;
- DATA_BLOB cleartext;
DATA_BLOB digest;
DATA_BLOB delim;
DATA_BLOB backslash;
@@ -936,8 +937,6 @@ static int setup_primary_wdigest(struct setup_password_fields_io *io,
dns_domain_l = data_blob_string_const(io->domain->dns_domain);
dns_domain_u = data_blob_string_const(io->domain->realm);
- cleartext = data_blob_string_const(io->n.cleartext);
-
digest = data_blob_string_const("Digest");
delim = data_blob_string_const(":");
@@ -963,7 +962,7 @@ static int setup_primary_wdigest(struct setup_password_fields_io *io,
MD5Update(&md5, wdigest[i].realm->data, wdigest[i].realm->length);
}
MD5Update(&md5, delim.data, delim.length);
- MD5Update(&md5, cleartext.data, cleartext.length);
+ MD5Update(&md5, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length);
MD5Final(pdb->hashes[i].hash, &md5);
}
@@ -1018,7 +1017,7 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)
ZERO_STRUCT(zero16);
ZERO_STRUCT(names);
- if (!io->n.cleartext) {
+ if (!io->n.cleartext_utf8) {
/*
* when we don't have a cleartext password
* we can't setup a supplementalCredential value
@@ -1200,7 +1199,7 @@ static int setup_supplemental_field(struct setup_password_fields_io *io)
if (pc) {
*nc = "CLEARTEXT";
- pcb.cleartext = io->n.cleartext;
+ pcb.cleartext = *io->n.cleartext_utf16;
ndr_err = ndr_push_struct_blob(&pcb_blob, io->ac,
lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
@@ -1292,58 +1291,97 @@ static int setup_password_fields(struct setup_password_fields_io *io)
{
bool ok;
int ret;
-
+ ssize_t converted_pw_len;
+
/*
* refuse the change if someone want to change the cleartext
* and supply his own hashes at the same time...
*/
- if (io->n.cleartext && (io->n.nt_hash || io->n.lm_hash)) {
+ if ((io->n.cleartext_utf8 || io->n.cleartext_utf16) && (io->n.nt_hash || io->n.lm_hash)) {
ldb_asprintf_errstring(io->ac->module->ldb,
"setup_password_fields: "
"it's only allowed to set the cleartext password or the password hashes");
return LDB_ERR_UNWILLING_TO_PERFORM;
}
-
- if (io->n.cleartext) {
- struct samr_Password *hash;
-
- hash = talloc(io->ac, struct samr_Password);
- if (!hash) {
+
+ if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
+ ldb_asprintf_errstring(io->ac->module->ldb,
+ "setup_password_fields: "
+ "it's only allowed to set the cleartext password as userPassword or clearTextPasssword, not both at once");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
+ if (io->n.cleartext_utf8) {
+ char **cleartext_utf16_str;
+ struct ldb_val *cleartext_utf16_blob;
+ io->n.cleartext_utf16 = cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
+ if (!io->n.cleartext_utf16) {
ldb_oom(io->ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
-
- /* compute the new nt hash */
- ok = E_md4hash(io->n.cleartext, hash->hash);
- if (ok) {
- io->n.nt_hash = hash;
- } else {
+ converted_pw_len = convert_string_talloc(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
+ CH_UTF8, CH_UTF16, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
+ (void **)&cleartext_utf16_str);
+ if (converted_pw_len == -1) {
ldb_asprintf_errstring(io->ac->module->ldb,
"setup_password_fields: "
- "failed to generate nthash from cleartext password");
+ "failed to generate UTF16 password from cleartext UTF8 password");
return LDB_ERR_OPERATIONS_ERROR;
}
+ *cleartext_utf16_blob = data_blob_const(cleartext_utf16_str, converted_pw_len);
+ } else if (io->n.cleartext_utf16) {
+ char *cleartext_utf8_str;
+ struct ldb_val *cleartext_utf8_blob;
+ io->n.cleartext_utf8 = cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
+ if (!io->n.cleartext_utf8) {
+ ldb_oom(io->ac->module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ converted_pw_len = convert_string_talloc(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
+ CH_UTF16, CH_UTF8, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length,
+ (void **)&cleartext_utf8_str);
+ if (converted_pw_len == -1) {
+ /* We can't bail out entirely, as these unconvertable passwords are frustratingly valid */
+ io->n.cleartext_utf8 = NULL;
+ talloc_free(cleartext_utf8_blob);
+ }
+ *cleartext_utf8_blob = data_blob_const(cleartext_utf8_str, converted_pw_len);
}
-
- if (io->n.cleartext) {
- struct samr_Password *hash;
-
- hash = talloc(io->ac, struct samr_Password);
- if (!hash) {
+ if (io->n.cleartext_utf16) {
+ struct samr_Password *nt_hash;
+ nt_hash = talloc(io->ac, struct samr_Password);
+ if (!nt_hash) {
ldb_oom(io->ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
+ io->n.nt_hash = nt_hash;
- /* compute the new lm hash */
- ok = E_deshash(io->n.cleartext, hash->hash);
- if (ok) {
- io->n.lm_hash = hash;
- } else {
- talloc_free(hash->hash);
- }
+ /* compute the new nt hash */
+ mdfour(nt_hash->hash, io->n.cleartext_utf16->data, io->n.cleartext_utf16->length);
}
- if (io->n.cleartext) {
+ if (io->n.cleartext_utf8) {
+ struct samr_Password *lm_hash;
+ char *cleartext_unix;
+ converted_pw_len = convert_string_talloc(io->ac, lp_iconv_convenience(ldb_get_opaque(io->ac->module->ldb, "loadparm")),
+ CH_UTF8, CH_UNIX, io->n.cleartext_utf8->data, io->n.cleartext_utf8->length,
+ (void **)&cleartext_unix);
+ if (converted_pw_len != -1) {
+ lm_hash = talloc(io->ac, struct samr_Password);
+ if (!lm_hash) {
+ ldb_oom(io->ac->module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* compute the new lm hash. */
+ ok = E_deshash((char *)cleartext_unix, lm_hash->hash);
+ if (ok) {
+ io->n.lm_hash = lm_hash;
+ } else {
+ talloc_free(lm_hash->hash);
+ }
+ }
+
ret = setup_kerberos_keys(io);
if (ret != 0) {
return ret;
@@ -1378,170 +1416,196 @@ static int setup_password_fields(struct setup_password_fields_io *io)
return LDB_SUCCESS;
}
-static struct ldb_handle *ph_init_handle(struct ldb_request *req, struct ldb_module *module, enum ph_type type)
+static struct ph_context *ph_init_context(struct ldb_module *module,
+ struct ldb_request *req)
{
struct ph_context *ac;
- struct ldb_handle *h;
-
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- return NULL;
- }
- h->module = module;
-
- ac = talloc_zero(h, struct ph_context);
+ ac = talloc_zero(req, struct ph_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
- talloc_free(h);
return NULL;
}
- h->private_data = (void *)ac;
-
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
-
- ac->type = type;
ac->module = module;
- ac->orig_req = req;
+ ac->req = req;
- return h;
+ return ac;
}
-static int get_domain_data_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
{
struct ph_context *ac;
- ac = talloc_get_type(context, struct ph_context);
-
- /* we are interested only in the single reply (base search) we receive here */
- if (ares->type == LDB_REPLY_ENTRY) {
- if (ac->dom_res != NULL) {
- ldb_set_errstring(ldb, "Too many results");
- talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ac->dom_res = talloc_steal(ac, ares);
- } else {
- talloc_free(ares);
- }
-
- return LDB_SUCCESS;
-}
-
-static int build_domain_data_request(struct ph_context *ac)
-{
- /* attrs[] is returned from this function in
- ac->dom_req->op.search.attrs, so it must be static, as
- otherwise the compiler can put it on the stack */
- static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
- char *filter;
+ ac = talloc_get_type(req->context, struct ph_context);
- ac->dom_req = talloc_zero(ac, struct ldb_request);
- if (ac->dom_req == NULL) {
- ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
- return LDB_ERR_OPERATIONS_ERROR;
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- ac->dom_req->operation = LDB_SEARCH;
- ac->dom_req->op.search.base = ldb_get_default_basedn(ac->module->ldb);
- ac->dom_req->op.search.scope = LDB_SCOPE_SUBTREE;
-
- filter = talloc_asprintf(ac->dom_req,
- "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
- ldap_encode_ndr_dom_sid(ac->dom_req, ac->domain_sid));
- if (filter == NULL) {
- ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
- talloc_free(ac->dom_req);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- ac->dom_req->op.search.tree = ldb_parse_tree(ac->dom_req, filter);
- if (ac->dom_req->op.search.tree == NULL) {
- ldb_set_errstring(ac->module->ldb, "Invalid search filter");
- talloc_free(ac->dom_req);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- ac->dom_req->op.search.attrs = attrs;
- ac->dom_req->controls = NULL;
- ac->dom_req->context = ac;
- ac->dom_req->callback = get_domain_data_callback;
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->dom_req);
- return LDB_SUCCESS;
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
-static struct domain_data *get_domain_data(struct ldb_module *module, void *ctx, struct ldb_reply *res)
+static int password_hash_add_do_add(struct ph_context *ac);
+static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
+static int password_hash_mod_search_self(struct ph_context *ac);
+static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
+static int password_hash_mod_do_mod(struct ph_context *ac);
+
+static int get_domain_data_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
struct domain_data *data;
- const char *tmp;
struct ph_context *ac;
+ int ret;
+ char *tmp;
char *p;
- ac = talloc_get_type(ctx, struct ph_context);
+ ac = talloc_get_type(req->context, struct ph_context);
- data = talloc_zero(ac, struct domain_data);
- if (data == NULL) {
- return NULL;
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
-
- if (res == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Could not find this user's domain: %s!\n", dom_sid_string(data, ac->domain_sid));
- talloc_free(data);
- return NULL;
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- data->pwdProperties= samdb_result_uint(res->message, "pwdProperties", 0);
- data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
- data->pwdHistoryLength = samdb_result_uint(res->message, "pwdHistoryLength", 0);
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ if (ac->domain != NULL) {
+ ldb_set_errstring(ac->module->ldb, "Too many results");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ data = talloc_zero(ac, struct domain_data);
+ if (data == NULL) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
- /* For a domain DN, this puts things in dotted notation */
- /* For builtin domains, this will give details for the host,
- * but that doesn't really matter, as it's just used for salt
- * and kerberos principals, which don't exist here */
+ data->pwdProperties = samdb_result_uint(ares->message, "pwdProperties", 0);
+ data->store_cleartext = data->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
+ data->pwdHistoryLength = samdb_result_uint(ares->message, "pwdHistoryLength", 0);
- tmp = ldb_dn_canonical_string(ctx, res->message->dn);
- if (!tmp) {
- return NULL;
- }
-
- /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
- p = strchr(tmp, '/');
- if (p) {
- p[0] = '\0';
- }
+ /* For a domain DN, this puts things in dotted notation */
+ /* For builtin domains, this will give details for the host,
+ * but that doesn't really matter, as it's just used for salt
+ * and kerberos principals, which don't exist here */
+
+ tmp = ldb_dn_canonical_string(data, ares->message->dn);
+ if (!tmp) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* But it puts a trailing (or just before 'builtin') / on things, so kill that */
+ p = strchr(tmp, '/');
+ if (p) {
+ p[0] = '\0';
+ }
- if (tmp != NULL) {
data->dns_domain = strlower_talloc(data, tmp);
if (data->dns_domain == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
- return NULL;
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
data->realm = strupper_talloc(data, tmp);
if (data->realm == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
- return NULL;
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
+ /* FIXME: NetbIOS name is *always* the first domain component ?? -SSS */
p = strchr(tmp, '.');
if (p) {
p[0] = '\0';
}
data->netbios_domain = strupper_talloc(data, tmp);
if (data->netbios_domain == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
- return NULL;
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ talloc_free(tmp);
+ ac->domain = data;
+ break;
+
+ case LDB_REPLY_DONE:
+
+ /* call the next step */
+ switch (ac->req->operation) {
+ case LDB_ADD:
+ ret = password_hash_add_do_add(ac);
+ break;
+
+ case LDB_MODIFY:
+ ret = password_hash_mod_do_mod(ac);
+ break;
+
+ default:
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ break;
}
- return data;
+ talloc_free(ares);
+ return LDB_SUCCESS;
+}
+
+static int build_domain_data_request(struct ph_context *ac)
+{
+ /* attrs[] is returned from this function in
+ ac->dom_req->op.search.attrs, so it must be static, as
+ otherwise the compiler can put it on the stack */
+ static const char * const attrs[] = { "pwdProperties", "pwdHistoryLength", NULL };
+ char *filter;
+
+ filter = talloc_asprintf(ac,
+ "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
+ ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
+ if (filter == NULL) {
+ ldb_oom(ac->module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return ldb_build_search_req(&ac->dom_req, ac->module->ldb, ac,
+ ldb_get_default_basedn(ac->module->ldb),
+ LDB_SCOPE_SUBTREE,
+ filter, attrs,
+ NULL,
+ ac, get_domain_data_callback,
+ ac->req);
}
static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_handle *h;
struct ph_context *ac;
struct ldb_message_element *sambaAttr;
+ struct ldb_message_element *clearTextPasswordAttr;
struct ldb_message_element *ntAttr;
struct ldb_message_element *lmAttr;
int ret;
@@ -1558,7 +1622,7 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
- /* nobody must touch this fields */
+ /* nobody must touch these fields */
if (ldb_msg_find_element(req->op.add.message, "ntPwdHistory")) {
return LDB_ERR_UNWILLING_TO_PERFORM;
}
@@ -1573,6 +1637,7 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
* or LM hashes, then we don't need to make any changes. */
sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
+ clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
@@ -1593,6 +1658,10 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
ldb_set_errstring(module->ldb, "mupltiple values for userPassword not allowed!\n");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
+ if (clearTextPasswordAttr && clearTextPasswordAttr->num_values > 1) {
+ ldb_set_errstring(module->ldb, "mupltiple values for clearTextPassword not allowed!\n");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
if (ntAttr && (ntAttr->num_values > 1)) {
ldb_set_errstring(module->ldb, "mupltiple values for unicodePwd not allowed!\n");
@@ -1608,6 +1677,11 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_CONSTRAINT_VIOLATION;
}
+ if (clearTextPasswordAttr && clearTextPasswordAttr->num_values == 0) {
+ ldb_set_errstring(module->ldb, "clearTextPassword must have a value!\n");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
if (ntAttr && (ntAttr->num_values == 0)) {
ldb_set_errstring(module->ldb, "unicodePwd must have a value!\n");
return LDB_ERR_CONSTRAINT_VIOLATION;
@@ -1617,16 +1691,16 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_CONSTRAINT_VIOLATION;
}
- h = ph_init_handle(req, module, PH_ADD);
- if (!h) {
+ ac = ph_init_context(module, req);
+ if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct ph_context);
/* get user domain data */
ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
if (ac->domain_sid == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "can't handle entry with missing objectSid!\n");
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -1635,51 +1709,33 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
return ret;
}
- ac->step = PH_ADD_SEARCH_DOM;
-
- req->handle = h;
-
return ldb_next_request(module, ac->dom_req);
}
-static int password_hash_add_do_add(struct ldb_handle *h) {
+static int password_hash_add_do_add(struct ph_context *ac) {
- struct ph_context *ac;
- struct domain_data *domain;
+ struct ldb_request *down_req;
struct smb_krb5_context *smb_krb5_context;
struct ldb_message *msg;
struct setup_password_fields_io io;
int ret;
- ac = talloc_get_type(h->private_data, struct ph_context);
-
- domain = get_domain_data(ac->module, ac, ac->dom_res);
- if (domain == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ac->down_req = talloc(ac, struct ldb_request);
- if (ac->down_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *(ac->down_req) = *(ac->orig_req);
- ac->down_req->op.add.message = msg = ldb_msg_copy_shallow(ac->down_req, ac->orig_req->op.add.message);
- if (ac->down_req->op.add.message == NULL) {
+ msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
+ if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* Some operations below require kerberos contexts */
- if (smb_krb5_init_context(ac->down_req,
- ldb_get_opaque(h->module->ldb, "EventContext"),
- (struct loadparm_context *)ldb_get_opaque(h->module->ldb, "loadparm"),
+ if (smb_krb5_init_context(ac,
+ ldb_get_event_context(ac->module->ldb),
+ (struct loadparm_context *)ldb_get_opaque(ac->module->ldb, "loadparm"),
&smb_krb5_context) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
ZERO_STRUCT(io);
io.ac = ac;
- io.domain = domain;
+ io.domain = ac->domain;
io.smb_krb5_context = smb_krb5_context;
io.u.user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
@@ -1687,12 +1743,14 @@ static int password_hash_add_do_add(struct ldb_handle *h) {
io.u.user_principal_name = samdb_result_string(msg, "userPrincipalName", NULL);
io.u.is_computer = ldb_msg_check_string_attribute(msg, "objectClass", "computer");
- io.n.cleartext = samdb_result_string(msg, "userPassword", NULL);
+ io.n.cleartext_utf8 = ldb_msg_find_ldb_val(msg, "userPassword");
+ io.n.cleartext_utf16 = ldb_msg_find_ldb_val(msg, "clearTextPassword");
io.n.nt_hash = samdb_result_hash(io.ac, msg, "unicodePwd");
io.n.lm_hash = samdb_result_hash(io.ac, msg, "dBCSPwd");
/* remove attributes */
- if (io.n.cleartext) ldb_msg_remove_attr(msg, "userPassword");
+ if (io.n.cleartext_utf8) ldb_msg_remove_attr(msg, "userPassword");
+ if (io.n.cleartext_utf16) ldb_msg_remove_attr(msg, "clearTextPassword");
if (io.n.nt_hash) ldb_msg_remove_attr(msg, "unicodePwd");
if (io.n.lm_hash) ldb_msg_remove_attr(msg, "dBCSPwd");
ldb_msg_remove_attr(msg, "pwdLastSet");
@@ -1756,27 +1814,28 @@ static int password_hash_add_do_add(struct ldb_handle *h) {
return ret;
}
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
-
- ac->step = PH_ADD_DO_ADD;
-
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
+ ret = ldb_build_add_req(&down_req, ac->module->ldb, ac,
+ msg,
+ ac->req->controls,
+ ac, ph_op_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
- /* perform the operation */
- return ldb_next_request(ac->module, ac->down_req);
+ return ldb_next_request(ac->module, down_req);
}
-static int password_hash_mod_search_self(struct ldb_handle *h);
-
static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_handle *h;
struct ph_context *ac;
struct ldb_message_element *sambaAttr;
+ struct ldb_message_element *clearTextAttr;
struct ldb_message_element *ntAttr;
struct ldb_message_element *lmAttr;
struct ldb_message *msg;
+ struct ldb_request *down_req;
+ int ret;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
@@ -1802,13 +1861,16 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
}
sambaAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
+ clearTextAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
- /* If no part of this touches the userPassword OR unicodePwd and/or dBCSPwd, then we don't
- * need to make any changes. For password changes/set there should
- * be a 'delete' or a 'modify' on this attribute. */
- if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
+ /* If no part of this touches the userPassword OR
+ * clearTextPassword OR unicodePwd and/or dBCSPwd, then we
+ * don't need to make any changes. For password changes/set
+ * there should be a 'delete' or a 'modify' on this
+ * attribute. */
+ if ((!sambaAttr) && (!clearTextAttr) && (!ntAttr) && (!lmAttr)) {
return ldb_next_request(module, req);
}
@@ -1817,6 +1879,9 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
if (sambaAttr && (sambaAttr->num_values > 1)) {
return LDB_ERR_CONSTRAINT_VIOLATION;
}
+ if (clearTextAttr && (clearTextAttr->num_values > 1)) {
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
if (ntAttr && (ntAttr->num_values > 1)) {
return LDB_ERR_CONSTRAINT_VIOLATION;
}
@@ -1824,83 +1889,144 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
return LDB_ERR_CONSTRAINT_VIOLATION;
}
- h = ph_init_handle(req, module, PH_MOD);
- if (!h) {
+ ac = ph_init_context(module, req);
+ if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct ph_context);
- /* return or own handle to deal with this call */
- req->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, "Out of memory!");
+ /* use a new message structure so that we can modify it */
+ msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
+ if (msg == NULL) {
+ ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- *(ac->down_req) = *req; /* copy the request */
-
- /* use a new message structure so that we can modify it */
- ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
-
- /* - remove any imodification to the password from the first commit
+ /* - remove any modification to the password from the first commit
* we will make the real modification later */
if (sambaAttr) ldb_msg_remove_attr(msg, "userPassword");
+ if (clearTextAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
- /* if there was nothing else to be modify skip to next step */
+ /* if there was nothing else to be modified skip to next step */
if (msg->num_elements == 0) {
- talloc_free(ac->down_req);
- ac->down_req = NULL;
- return password_hash_mod_search_self(h);
+ return password_hash_mod_search_self(ac);
}
-
- ac->down_req->context = NULL;
- ac->down_req->callback = NULL;
- ac->step = PH_MOD_DO_REQ;
+ ret = ldb_build_mod_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, ph_modify_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ return ldb_next_request(module, down_req);
+}
+
+static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ph_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct ph_context);
- ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- return ldb_next_request(module, ac->down_req);
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = password_hash_mod_search_self(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
}
-static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
{
struct ph_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct ph_context);
- ac = talloc_get_type(context, struct ph_context);
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ /* we are interested only in the single reply (base search) */
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
- /* 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, "Too many results");
+ ldb_set_errstring(ac->module->ldb, "Too many results");
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
/* if it is not an entry of type person this is an error */
- /* TODO: remove this when userPassword will be in schema */
+ /* TODO: remove this when sambaPassword will be in schema */
if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
- ldb_set_errstring(ldb, "Object class violation");
+ ldb_set_errstring(ac->module->ldb, "Object class violation");
talloc_free(ares);
- return LDB_ERR_OBJECT_CLASS_VIOLATION;
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OBJECT_CLASS_VIOLATION);
}
ac->search_res = talloc_steal(ac, ares);
- } else {
- talloc_free(ares);
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+
+ /* get object domain sid */
+ ac->domain_sid = samdb_result_sid_prefix(ac,
+ ac->search_res->message,
+ "objectSid");
+ if (ac->domain_sid == NULL) {
+ ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR,
+ "can't handle entry without objectSid!\n");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ /* get user domain data */
+ ret = build_domain_data_request(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,ret);
+ }
+
+ return ldb_next_request(ac->module, ac->dom_req);
+
+ case LDB_REPLY_REFERRAL:
+ /*ignore anything else for now */
+ break;
}
+ talloc_free(ares);
return LDB_SUCCESS;
}
-static int password_hash_mod_search_self(struct ldb_handle *h) {
+static int password_hash_mod_search_self(struct ph_context *ac) {
- struct ph_context *ac;
static const char * const attrs[] = { "userAccountControl", "lmPwdHistory",
"ntPwdHistory",
"objectSid", "msDS-KeyVersionNumber",
@@ -1909,64 +2035,28 @@ static int password_hash_mod_search_self(struct ldb_handle *h) {
"dBCSPwd", "unicodePwd",
"supplementalCredentials",
NULL };
-
- ac = talloc_get_type(h->private_data, struct ph_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->search_req, NULL);
- if (ac->search_req->op.search.tree == NULL) {
- ldb_set_errstring(ac->module->ldb, "Invalid search filter");
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ac->search_req->op.search.attrs = attrs;
- ac->search_req->controls = NULL;
- ac->search_req->context = ac;
- ac->search_req->callback = get_self_callback;
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
-
- ac->step = PH_MOD_SEARCH_SELF;
-
- return ldb_next_request(ac->module, ac->search_req);
-}
-
-static int password_hash_mod_search_dom(struct ldb_handle *h) {
-
- struct ph_context *ac;
+ struct ldb_request *search_req;
int ret;
- ac = talloc_get_type(h->private_data, struct ph_context);
+ ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
+ ac->req->op.mod.message->dn,
+ LDB_SCOPE_BASE,
+ "(objectclass=*)",
+ attrs,
+ NULL,
+ ac, ph_mod_search_callback,
+ ac->req);
- /* get object domain sid */
- ac->domain_sid = samdb_result_sid_prefix(ac, ac->search_res->message, "objectSid");
- if (ac->domain_sid == NULL) {
- ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* get user domain data */
- ret = build_domain_data_request(ac);
if (ret != LDB_SUCCESS) {
return ret;
}
- ac->step = PH_MOD_SEARCH_DOM;
-
- return ldb_next_request(ac->module, ac->dom_req);
+ return ldb_next_request(ac->module, search_req);
}
-static int password_hash_mod_do_mod(struct ldb_handle *h) {
+static int password_hash_mod_do_mod(struct ph_context *ac) {
- struct ph_context *ac;
- struct domain_data *domain;
+ struct ldb_request *mod_req;
struct smb_krb5_context *smb_krb5_context;
struct ldb_message *msg;
struct ldb_message *orig_msg;
@@ -1974,43 +2064,29 @@ static int password_hash_mod_do_mod(struct ldb_handle *h) {
struct setup_password_fields_io io;
int ret;
- ac = talloc_get_type(h->private_data, struct ph_context);
-
- domain = get_domain_data(ac->module, ac, ac->dom_res);
- if (domain == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ac->mod_req = talloc(ac, struct ldb_request);
- if (ac->mod_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *(ac->mod_req) = *(ac->orig_req);
-
/* use a new message structure so that we can modify it */
- ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
+ msg = ldb_msg_new(ac);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* modify dn */
- msg->dn = ac->orig_req->op.mod.message->dn;
+ msg->dn = ac->req->op.mod.message->dn;
/* Some operations below require kerberos contexts */
- if (smb_krb5_init_context(ac->mod_req,
- ldb_get_opaque(h->module->ldb, "EventContext"),
- (struct loadparm_context *)ldb_get_opaque(h->module->ldb, "loadparm"),
+ if (smb_krb5_init_context(ac,
+ ldb_get_event_context(ac->module->ldb),
+ (struct loadparm_context *)ldb_get_opaque(ac->module->ldb, "loadparm"),
&smb_krb5_context) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
- orig_msg = discard_const(ac->orig_req->op.mod.message);
+ orig_msg = discard_const(ac->req->op.mod.message);
searched_msg = ac->search_res->message;
ZERO_STRUCT(io);
io.ac = ac;
- io.domain = domain;
+ io.domain = ac->domain;
io.smb_krb5_context = smb_krb5_context;
io.u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0);
@@ -2018,7 +2094,8 @@ static int password_hash_mod_do_mod(struct ldb_handle *h) {
io.u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL);
io.u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer");
- io.n.cleartext = samdb_result_string(orig_msg, "userPassword", NULL);
+ io.n.cleartext_utf8 = ldb_msg_find_ldb_val(orig_msg, "userPassword");
+ io.n.cleartext_utf16 = ldb_msg_find_ldb_val(orig_msg, "clearTextPassword");
io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd");
io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd");
@@ -2093,189 +2170,20 @@ static int password_hash_mod_do_mod(struct ldb_handle *h) {
return ret;
}
- h->state = LDB_ASYNC_INIT;
- h->status = LDB_SUCCESS;
-
- ac->step = PH_MOD_DO_MOD;
-
- ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
-
- /* perform the search */
- return ldb_next_request(ac->module, ac->mod_req);
-}
-
-static int ph_wait(struct ldb_handle *handle) {
- struct ph_context *ac;
- int ret;
-
- if (!handle || !handle->private_data) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
- }
-
- handle->state = LDB_ASYNC_PENDING;
- handle->status = LDB_SUCCESS;
-
- ac = talloc_get_type(handle->private_data, struct ph_context);
-
- switch (ac->step) {
- case PH_ADD_SEARCH_DOM:
- ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->dom_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->dom_req->handle->status;
- goto done;
- }
-
- if (ac->dom_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* domain search done, go on */
- return password_hash_add_do_add(handle);
-
- case PH_ADD_DO_ADD:
- ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->down_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req->handle->status;
- goto done;
- }
-
- if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- break;
-
- case PH_MOD_DO_REQ:
- ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->down_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req->handle->status;
- goto done;
- }
-
- if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* non-password mods done, go on */
- return password_hash_mod_search_self(handle);
-
- case PH_MOD_SEARCH_SELF:
- ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->search_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->search_req->handle->status;
- goto done;
- }
-
- if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- if (ac->search_res == NULL) {
- return LDB_ERR_NO_SUCH_OBJECT;
- }
-
- /* self search done, go on */
- return password_hash_mod_search_dom(handle);
-
- case PH_MOD_SEARCH_DOM:
- ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->dom_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->dom_req->handle->status;
- goto done;
- }
-
- if (ac->dom_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- /* domain search done, go on */
- return password_hash_mod_do_mod(handle);
-
- case PH_MOD_DO_MOD:
- ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->mod_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->mod_req->handle->status;
- goto done;
- }
-
- if (ac->mod_req->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 ph_wait_all(struct ldb_handle *handle) {
-
- int ret;
-
- while (handle->state != LDB_ASYNC_DONE) {
- ret = ph_wait(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ ret = ldb_build_mod_req(&mod_req, ac->module->ldb, ac,
+ msg,
+ ac->req->controls,
+ ac, ph_op_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return handle->status;
-}
-
-static int password_hash_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- if (type == LDB_WAIT_ALL) {
- return ph_wait_all(handle);
- } else {
- return ph_wait(handle);
- }
+ return ldb_next_request(ac->module, mod_req);
}
_PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = {
.name = "password_hash",
.add = password_hash_add,
.modify = password_hash_modify,
- .wait = password_hash_wait
};
diff --git a/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c b/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c
index 09d56d77c9..198b667358 100644
--- a/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c
+++ b/source4/dsdb/samdb/ldb_modules/pdc_fsmo.c
@@ -28,7 +28,7 @@
#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
-#include "lib/util/dlinklist.h"
+#include "../lib/util/dlinklist.h"
static int pdc_fsmo_init(struct ldb_module *module)
{
@@ -63,10 +63,9 @@ static int pdc_fsmo_init(struct ldb_module *module)
}
module->private_data = pdc_fsmo;
- ret = ldb_search(module->ldb, pdc_dn,
- LDB_SCOPE_BASE,
- NULL, pdc_attrs,
- &pdc_res);
+ ret = ldb_search(module->ldb, mem_ctx, &pdc_res,
+ pdc_dn, LDB_SCOPE_BASE,
+ pdc_attrs, NULL);
if (ret == LDB_ERR_NO_SUCH_OBJECT) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING,
"pdc_fsmo_init: no domain object present: (skip loading of domain details)\n");
@@ -79,7 +78,6 @@ static int pdc_fsmo_init(struct ldb_module *module)
talloc_free(mem_ctx);
return ret;
}
- talloc_steal(mem_ctx, pdc_res);
if (pdc_res->count == 0) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING,
"pdc_fsmo_init: no domain object present: (skip loading of domain details)\n");
diff --git a/source4/dsdb/samdb/ldb_modules/proxy.c b/source4/dsdb/samdb/ldb_modules/proxy.c
index 0d065425ca..2ff42297b7 100644
--- a/source4/dsdb/samdb/ldb_modules/proxy.c
+++ b/source4/dsdb/samdb/ldb_modules/proxy.c
@@ -50,6 +50,14 @@ struct proxy_data {
const char **newstr;
};
+struct proxy_ctx {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+#ifdef DEBUG_PROXY
+ int count;
+#endif
+};
/*
load the @PROXYINFO record
@@ -62,18 +70,17 @@ static int load_proxy_info(struct ldb_module *module)
int ret;
const char *olddn, *newdn, *url, *username, *password, *oldstr, *newstr;
struct cli_credentials *creds;
-
/* see if we have already loaded it */
if (proxy->upstream != NULL) {
- return 0;
+ return LDB_SUCCESS;
}
dn = ldb_dn_new(proxy, module->ldb, "@PROXYINFO");
if (dn == NULL) {
goto failed;
}
- ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
+ ret = ldb_search(module->ldb, proxy, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
talloc_free(dn);
if (ret != LDB_SUCCESS || res->count != 1) {
ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find @PROXYINFO\n");
@@ -105,7 +112,7 @@ static int load_proxy_info(struct ldb_module *module)
goto failed;
}
- proxy->upstream = ldb_init(proxy);
+ proxy->upstream = ldb_init(proxy, ldb_get_event_context(ldb));
if (proxy->upstream == NULL) {
ldb_oom(module->ldb);
goto failed;
@@ -145,7 +152,7 @@ static int load_proxy_info(struct ldb_module *module)
talloc_free(res);
- return 0;
+ return LDB_SUCCESS;
failed:
talloc_free(res);
@@ -153,7 +160,7 @@ failed:
talloc_free(proxy->newdn);
talloc_free(proxy->upstream);
proxy->upstream = NULL;
- return -1;
+ return LDB_ERR_OPERATIONS_ERROR;
}
@@ -180,10 +187,10 @@ static void proxy_convert_blob(TALLOC_CTX *mem_ctx, struct ldb_val *v,
/*
convert a returned value
*/
-static void proxy_convert_value(struct ldb_module *module, struct ldb_message *msg, struct ldb_val *v)
+static void proxy_convert_value(struct proxy_data *proxy, struct ldb_message *msg, struct ldb_val *v)
{
- struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
int i;
+
for (i=0;proxy->oldstr[i];i++) {
char *p = strcasestr((char *)v->data, proxy->oldstr[i]);
if (p == NULL) continue;
@@ -195,20 +202,21 @@ static void proxy_convert_value(struct ldb_module *module, struct ldb_message *m
/*
convert a returned value
*/
-static struct ldb_parse_tree *proxy_convert_tree(struct ldb_module *module,
+static struct ldb_parse_tree *proxy_convert_tree(TALLOC_CTX *mem_ctx,
+ struct proxy_data *proxy,
struct ldb_parse_tree *tree)
{
- struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
int i;
- char *expression = ldb_filter_from_tree(module, tree);
+ char *expression = ldb_filter_from_tree(mem_ctx, tree);
+
for (i=0;proxy->newstr[i];i++) {
struct ldb_val v;
char *p = strcasestr(expression, proxy->newstr[i]);
if (p == NULL) continue;
v.data = (uint8_t *)expression;
v.length = strlen(expression)+1;
- proxy_convert_blob(module, &v, proxy->newstr[i], proxy->oldstr[i]);
- return ldb_parse_tree(module, (const char *)v.data);
+ proxy_convert_blob(mem_ctx, &v, proxy->newstr[i], proxy->oldstr[i]);
+ return ldb_parse_tree(mem_ctx, (const char *)v.data);
}
return tree;
}
@@ -218,13 +226,14 @@ static struct ldb_parse_tree *proxy_convert_tree(struct ldb_module *module,
/*
convert a returned record
*/
-static void proxy_convert_record(struct ldb_module *module, struct ldb_message *msg)
+static void proxy_convert_record(struct ldb_context *ldb,
+ struct proxy_data *proxy,
+ struct ldb_message *msg)
{
- struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
int attr, v;
-
+
/* fix the message DN */
- if (ldb_dn_compare_base(module->ldb, proxy->olddn, msg->dn) == 0) {
+ if (ldb_dn_compare_base(proxy->olddn, msg->dn) == 0) {
ldb_dn_remove_base_components(msg->dn, ldb_dn_get_comp_num(proxy->olddn));
ldb_dn_add_base(msg->dn, proxy->newdn);
}
@@ -232,21 +241,71 @@ static void proxy_convert_record(struct ldb_module *module, struct ldb_message *
/* fix any attributes */
for (attr=0;attr<msg->num_elements;attr++) {
for (v=0;v<msg->elements[attr].num_values;v++) {
- proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
+ proxy_convert_value(proxy, msg, &msg->elements[attr].values[v]);
}
}
/* fix any DN components */
for (attr=0;attr<msg->num_elements;attr++) {
for (v=0;v<msg->elements[attr].num_values;v++) {
- proxy_convert_value(module, msg, &msg->elements[attr].values[v]);
+ proxy_convert_value(proxy, msg, &msg->elements[attr].values[v]);
}
}
}
+static int proxy_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct proxy_data *proxy;
+ struct proxy_ctx *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct proxy_ctx);
+ proxy = talloc_get_type(ac->module->private_data, struct proxy_data);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ /* Only entries are interesting, and we only want the olddn */
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+#ifdef DEBUG_PROXY
+ ac->count++;
+#endif
+ proxy_convert_record(ac->module->ldb, proxy, ares->message);
+ ret = ldb_module_send_entry(ac->req, ares->message);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+
+ /* ignore remote referrals */
+ break;
+
+ case LDB_REPLY_DONE:
+
+#ifdef DEBUG_PROXY
+ printf("# record %d\n", ac->count+1);
+#endif
+
+ return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
+ }
+
+ talloc_free(ares);
+ return ret;
+}
+
/* search */
static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *req)
{
+ struct proxy_ctx *ac;
+ struct ldb_parse_tree *newtree;
struct proxy_data *proxy = talloc_get_type(module->private_data, struct proxy_data);
struct ldb_request *newreq;
struct ldb_dn *base;
@@ -258,56 +317,59 @@ static int proxy_search_bytree(struct ldb_module *module, struct ldb_request *re
goto passthru;
}
- if (load_proxy_info(module) != 0) {
- return -1;
+ if (load_proxy_info(module) != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
/* see if the dn is within olddn */
- if (ldb_dn_compare_base(module->ldb, proxy->newdn, req->op.search.base) != 0) {
+ if (ldb_dn_compare_base(proxy->newdn, req->op.search.base) != 0) {
goto passthru;
}
- newreq = talloc(module, struct ldb_request);
- if (newreq == NULL) {
- return -1;
+ ac = talloc(req, struct proxy_ctx);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- newreq->op.search.tree = proxy_convert_tree(module, req->op.search.tree);
+ ac->module = module;
+ ac->req = req;
+#ifdef DEBUG_PROXY
+ ac->count = 0;
+#endif
+
+ newtree = proxy_convert_tree(ac, proxy, req->op.search.tree);
/* convert the basedn of this search */
- base = ldb_dn_copy(proxy, req->op.search.base);
+ base = ldb_dn_copy(ac, req->op.search.base);
if (base == NULL) {
- talloc_free(newreq);
goto failed;
}
ldb_dn_remove_base_components(base, ldb_dn_get_comp_num(proxy->newdn));
ldb_dn_add_base(base, proxy->olddn);
ldb_debug(module->ldb, LDB_DEBUG_FATAL, "proxying: '%s' with dn '%s' \n",
- ldb_filter_from_tree(proxy, newreq->op.search.tree), ldb_dn_get_linearized(newreq->op.search.base));
+ ldb_filter_from_tree(ac, newreq->op.search.tree), ldb_dn_get_linearized(newreq->op.search.base));
for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
ldb_debug(module->ldb, LDB_DEBUG_FATAL, "attr: '%s'\n", req->op.search.attrs[i]);
}
- newreq->op.search.base = base;
- newreq->op.search.scope = req->op.search.scope;
- newreq->op.search.attrs = req->op.search.attrs;
- newreq->op.search.res = req->op.search.res;
- newreq->controls = req->controls;
+ ret = ldb_build_search_req_ex(&newreq, module->ldb, ac,
+ base, req->op.search.scope,
+ newtree, req->op.search.attrs,
+ req->controls,
+ ac, proxy_search_callback,
+ req);
+
+ /* FIXME: warning, need a real event system hooked up for this to work properly,
+ * for now this makes the module *not* ASYNC */
ret = ldb_request(proxy->upstream, newreq);
if (ret != LDB_SUCCESS) {
ldb_set_errstring(module->ldb, ldb_errstring(proxy->upstream));
- talloc_free(newreq);
- return -1;
}
-
- for (i = 0; i < newreq->op.search.res->count; i++) {
- printf("# record %d\n", i+1);
-
- proxy_convert_record(module, newreq->op.search.res->msgs[i]);
+ ret = ldb_wait(newreq->handle, LDB_WAIT_ALL);
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(module->ldb, ldb_errstring(proxy->upstream));
}
-
- talloc_free(newreq);
return ret;
failed:
diff --git a/source4/dsdb/samdb/ldb_modules/ranged_results.c b/source4/dsdb/samdb/ldb_modules/ranged_results.c
index c6ebea1044..b8e43a7e88 100644
--- a/source4/dsdb/samdb/ldb_modules/ranged_results.c
+++ b/source4/dsdb/samdb/ldb_modules/ranged_results.c
@@ -32,57 +32,89 @@
#include "ldb_includes.h"
struct rr_context {
- struct ldb_request *orig_req;
- struct ldb_request *down_req;
+ struct ldb_module *module;
+ struct ldb_request *req;
};
-static int rr_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static struct rr_context *rr_init_context(struct ldb_module *module,
+ struct ldb_request *req)
{
- struct rr_context *rr_context = talloc_get_type(context, struct rr_context);
- struct ldb_request *orig_req = rr_context->orig_req;
+ struct rr_context *ac;
+
+ ac = talloc_zero(req, struct rr_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ return ac;
+}
+
+static int rr_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct rr_context *ac;
int i, j;
-
- if (ares->type != LDB_REPLY_ENTRY) {
- return rr_context->orig_req->callback(ldb, rr_context->orig_req->context, ares);
+
+ ac = talloc_get_type(req->context, struct rr_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ return ldb_module_send_referral(ac->req, ares->referral);
}
+ if (ares->type == LDB_REPLY_DONE) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ /* LDB_REPLY_ENTRY */
+
/* Find those that are range requests from the attribute list */
- for (i = 0; orig_req->op.search.attrs[i]; i++) {
+ for (i = 0; ac->req->op.search.attrs[i]; i++) {
char *p, *new_attr;
const char *end_str;
unsigned int start, end, orig_num_values;
struct ldb_message_element *el;
struct ldb_val *orig_values;
- p = strchr(orig_req->op.search.attrs[i], ';');
+ p = strchr(ac->req->op.search.attrs[i], ';');
if (!p) {
continue;
}
if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
continue;
}
- if (sscanf(p, ";range=%u-%u", &start, &end) == 2) {
- } else if (sscanf(p, ";range=%u-*", &start) == 1) {
- end = (unsigned int)-1;
- } else {
- continue;
+ if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
+ if (sscanf(p, ";range=%u-*", &start) == 1) {
+ end = (unsigned int)-1;
+ } else {
+ continue;
+ }
}
- new_attr = talloc_strndup(orig_req,
- orig_req->op.search.attrs[i],
- (unsigned int)(p-orig_req->op.search.attrs[i]));
+ new_attr = talloc_strndup(ac->req,
+ ac->req->op.search.attrs[i],
+ (size_t)(p - ac->req->op.search.attrs[i]));
if (!new_attr) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
el = ldb_msg_find_element(ares->message, new_attr);
talloc_free(new_attr);
if (!el) {
continue;
}
- if (start > end) {
- ldb_asprintf_errstring(ldb, "range request error: start must not be greater than end");
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
if (end >= (el->num_values - 1)) {
/* Need to leave the requested attribute in
* there (so add an empty one to match) */
@@ -91,11 +123,12 @@ static int rr_search_callback(struct ldb_context *ldb, void *context, struct ldb
} else {
end_str = talloc_asprintf(el, "%u", end);
if (!end_str) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
}
- /* If start is greater then where we noe find the end to be */
+ /* If start is greater then where we are find the end to be */
if (start > end) {
el->num_values = 0;
el->values = NULL;
@@ -104,16 +137,19 @@ static int rr_search_callback(struct ldb_context *ldb, void *context, struct ldb
orig_num_values = el->num_values;
if ((start + end < start) || (start + end < end)) {
- ldb_asprintf_errstring(ldb, "range request error: start or end would overflow!");
- return LDB_ERR_UNWILLING_TO_PERFORM;
+ ldb_asprintf_errstring(ac->module->ldb,
+ "range request error: start or end would overflow!");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_UNWILLING_TO_PERFORM);
}
el->num_values = 0;
el->values = talloc_array(el, struct ldb_val, (end - start) + 1);
if (!el->values) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
for (j=start; j <= end; j++) {
el->values[el->num_values] = orig_values[j];
@@ -122,13 +158,13 @@ static int rr_search_callback(struct ldb_context *ldb, void *context, struct ldb
}
el->name = talloc_asprintf(el, "%s;range=%u-%s", el->name, start, end_str);
if (!el->name) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ ldb_oom(ac->module->ldb);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
}
- return rr_context->orig_req->callback(ldb, rr_context->orig_req->context, ares);
-
+ return ldb_module_send_entry(ac->req, ares->message);
}
/* search */
@@ -137,8 +173,10 @@ static int rr_search(struct ldb_module *module, struct ldb_request *req)
int i;
unsigned int start, end;
const char **new_attrs = NULL;
- struct rr_context *context;
bool found_rr = false;
+ struct ldb_request *down_req;
+ struct rr_context *ac;
+ int ret;
/* Strip the range request from the attribute */
for (i = 0; req->op.search.attrs && req->op.search.attrs[i]; i++) {
@@ -146,19 +184,21 @@ static int rr_search(struct ldb_module *module, struct ldb_request *req)
new_attrs = talloc_realloc(req, new_attrs, const char *, i+2);
new_attrs[i] = req->op.search.attrs[i];
new_attrs[i+1] = NULL;
- p = strchr(req->op.search.attrs[i], ';');
+ p = strchr(new_attrs[i], ';');
if (!p) {
continue;
}
if (strncasecmp(p, ";range=", strlen(";range=")) != 0) {
continue;
}
- if (sscanf(p, ";range=%u-%u", &start, &end) == 2) {
- } else if (sscanf(p, ";range=%u-*", &start) == 1) {
- end = (unsigned int)-1;
- } else {
- ldb_asprintf_errstring(module->ldb, "range request error: range requst malformed");
- return LDB_ERR_UNWILLING_TO_PERFORM;
+ end = (unsigned int)-1;
+ if (sscanf(p, ";range=%u-*", &start) != 1) {
+ if (sscanf(p, ";range=%u-%u", &start, &end) != 2) {
+ ldb_asprintf_errstring(module->ldb,
+ "range request error: "
+ "range request malformed");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
}
if (start > end) {
ldb_asprintf_errstring(module->ldb, "range request error: start must not be greater than end");
@@ -166,9 +206,8 @@ static int rr_search(struct ldb_module *module, struct ldb_request *req)
}
found_rr = true;
- new_attrs[i] = talloc_strndup(new_attrs,
- req->op.search.attrs[i],
- (unsigned int)(p-req->op.search.attrs[i]));
+ new_attrs[i] = talloc_strndup(new_attrs, new_attrs[i],
+ (size_t)(p - new_attrs[i]));
if (!new_attrs[i]) {
ldb_oom(module->ldb);
@@ -177,27 +216,27 @@ static int rr_search(struct ldb_module *module, struct ldb_request *req)
}
if (found_rr) {
- int ret;
- context = talloc(req, struct rr_context);
- context->orig_req = req;
- context->down_req = talloc(context, struct ldb_request);
- *context->down_req = *req;
-
- context->down_req->op.search.attrs = new_attrs;
-
- context->down_req->callback = rr_search_callback;
- context->down_req->context = context;
-
- ret = ldb_next_request(module, context->down_req);
-
- /* We don't need to implement our own 'wait' function, so pass the handle along */
- if (ret == LDB_SUCCESS) {
- req->handle = context->down_req->handle;
+ ac = rr_init_context(module, req);
+ if (!ac) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_search_req_ex(&down_req, module->ldb, ac,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ new_attrs,
+ req->controls,
+ ac, rr_search_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return ret;
+ return ldb_next_request(module, down_req);
}
/* No change, just run the original request as if we were never here */
+ talloc_free(new_attrs);
return ldb_next_request(module, req);
}
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index dd5faf837a..f30748c85c 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -1,7 +1,7 @@
/*
ldb database library
- Copyright (C) Simo Sorce 2004-2006
+ Copyright (C) Simo Sorce 2004-2008
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
Copyright (C) Andrew Tridgell 2005
Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
@@ -51,68 +51,34 @@
struct replmd_replicated_request {
struct ldb_module *module;
- struct ldb_handle *handle;
- struct ldb_request *orig_req;
+ struct ldb_request *req;
const struct dsdb_schema *schema;
struct dsdb_extended_replicated_objects *objs;
+ /* the controls we pass down */
+ struct ldb_control **controls;
+
uint32_t index_current;
- struct {
- TALLOC_CTX *mem_ctx;
- struct ldb_request *search_req;
- struct ldb_message *search_msg;
- int search_ret;
- struct ldb_request *change_req;
- int change_ret;
- } sub;
+ struct ldb_message *search_msg;
};
-static struct replmd_replicated_request *replmd_replicated_init_handle(struct ldb_module *module,
- struct ldb_request *req,
- struct dsdb_extended_replicated_objects *objs)
+static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
+ struct ldb_request *req)
{
- struct replmd_replicated_request *ar;
- struct ldb_handle *h;
- const struct dsdb_schema *schema;
-
- schema = dsdb_get_schema(module->ldb);
- if (!schema) {
- ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "replmd_replicated_init_handle: no loaded schema found\n");
- return NULL;
- }
+ struct replmd_replicated_request *ac;
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- return NULL;
- }
-
- h->module = module;
- h->state = LDB_ASYNC_PENDING;
- h->status = LDB_SUCCESS;
-
- ar = talloc_zero(h, struct replmd_replicated_request);
- if (ar == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- talloc_free(h);
+ ac = talloc_zero(req, struct replmd_replicated_request);
+ if (ac == NULL) {
+ ldb_oom(module->ldb);
return NULL;
}
- h->private_data = ar;
-
- ar->module = module;
- ar->handle = h;
- ar->orig_req = req;
- ar->schema = schema;
- ar->objs = objs;
-
- req->handle = h;
-
- return ar;
+ ac->module = module;
+ ac->req = req;
+ return ac;
}
/*
@@ -124,16 +90,16 @@ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
char *s;
if (ldb_msg_find_element(msg, attr) != NULL) {
- return 0;
+ return LDB_SUCCESS;
}
s = ldb_timestring(msg, t);
if (s == NULL) {
- return -1;
+ return LDB_ERR_OPERATIONS_ERROR;
}
- if (ldb_msg_add_string(msg, attr, s) != 0) {
- return -1;
+ if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
el = ldb_msg_find_element(msg, attr);
@@ -141,7 +107,7 @@ static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
is ignored */
el->flags = LDB_FLAG_MOD_REPLACE;
- return 0;
+ return LDB_SUCCESS;
}
/*
@@ -152,11 +118,11 @@ static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_
struct ldb_message_element *el;
if (ldb_msg_find_element(msg, attr) != NULL) {
- return 0;
+ return LDB_SUCCESS;
}
- if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != 0) {
- return -1;
+ if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
el = ldb_msg_find_element(msg, attr);
@@ -164,7 +130,7 @@ static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_
is ignored */
el->flags = LDB_FLAG_MOD_REPLACE;
- return 0;
+ return LDB_SUCCESS;
}
static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
@@ -236,34 +202,37 @@ static void replmd_ldb_message_sort(struct ldb_message *msg,
discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
}
-static int replmd_prepare_originating(struct ldb_module *module, struct ldb_request *req,
- struct ldb_dn *dn, const char *fn_name,
- int (*fn)(struct ldb_module *,
- struct ldb_request *,
- const struct dsdb_schema *))
+static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
{
- const struct dsdb_schema *schema;
-
- /* do not manipulate our control entries */
- if (ldb_dn_is_special(dn)) {
- return ldb_next_request(module, req);
+ struct replmd_replicated_request *ac;
+
+ ac = talloc_get_type(req->context, struct replmd_replicated_request);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- schema = dsdb_get_schema(module->ldb);
- if (!schema) {
- ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "%s: no dsdb_schema loaded",
- fn_name);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb,
+ "invalid ldb_reply_type in callback");
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- return fn(module, req, schema);
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
}
-static int replmd_add_originating(struct ldb_module *module,
- struct ldb_request *req,
- const struct dsdb_schema *schema)
+static int replmd_add(struct ldb_module *module, struct ldb_request *req)
{
+ struct replmd_replicated_request *ac;
+ const struct dsdb_schema *schema;
enum ndr_err_code ndr_err;
struct ldb_request *down_req;
struct ldb_message *msg;
@@ -280,11 +249,30 @@ static int replmd_add_originating(struct ldb_module *module,
int ret;
uint32_t i, ni=0;
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "replmd_add_originating\n");
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "replmd_add\n");
+
+ schema = dsdb_get_schema(module->ldb);
+ if (!schema) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
+ "replmd_modify: no dsdb_schema loaded");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ ac = replmd_ctx_init(module, req);
+ if (!ac) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->schema = schema;
- if (ldb_msg_find_element(req->op.add.message, "objectGUID")) {
+ if (ldb_msg_find_element(req->op.add.message, "objectGUID") != NULL) {
ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
- "replmd_add_originating: it's not allowed to add an object with objectGUID\n");
+ "replmd_add: it's not allowed to add an object with objectGUID\n");
return LDB_ERR_UNWILLING_TO_PERFORM;
}
@@ -301,22 +289,13 @@ static int replmd_add_originating(struct ldb_module *module,
our_invocation_id = samdb_ntds_invocation_id(module->ldb);
if (!our_invocation_id) {
ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
- "replmd_add_originating: unable to find invocationId\n");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* create a copy of the request */
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
- ldb_oom(module->ldb);
+ "replmd_add: unable to find invocationId\n");
return LDB_ERR_OPERATIONS_ERROR;
}
- *down_req = *req;
/* we have to copy the message as the caller might have it as a const */
- down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
+ msg = ldb_msg_copy_shallow(ac, req->op.add.message);
if (msg == NULL) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -325,7 +304,6 @@ static int replmd_add_originating(struct ldb_module *module,
unix_to_nt_time(&now, t);
time_str = ldb_timestring(msg, t);
if (!time_str) {
- talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -343,7 +321,6 @@ static int replmd_add_originating(struct ldb_module *module,
*/
ret = ldb_msg_add_string(msg, "whenCreated", time_str);
if (ret != LDB_SUCCESS) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -356,7 +333,6 @@ static int replmd_add_originating(struct ldb_module *module,
struct replPropertyMetaData1,
nmd.ctr.ctr1.count);
if (!nmd.ctr.ctr1.array) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -371,9 +347,8 @@ static int replmd_add_originating(struct ldb_module *module,
sa = dsdb_attribute_by_lDAPDisplayName(schema, e->name);
if (!sa) {
ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
- "replmd_add_originating: attribute '%s' not defined in schema\n",
+ "replmd_add: attribute '%s' not defined in schema\n",
e->name);
- talloc_free(down_req);
return LDB_ERR_NO_SUCH_ATTRIBUTE;
}
@@ -419,7 +394,6 @@ static int replmd_add_originating(struct ldb_module *module,
&nmd,
(ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -429,31 +403,26 @@ static int replmd_add_originating(struct ldb_module *module,
*/
ret = ldb_msg_add_value(msg, "objectGUID", &guid_value, NULL);
if (ret != LDB_SUCCESS) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ret = ldb_msg_add_string(msg, "whenChanged", time_str);
if (ret != LDB_SUCCESS) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ret = samdb_msg_add_uint64(module->ldb, msg, msg, "uSNCreated", seq_num);
if (ret != LDB_SUCCESS) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ret = samdb_msg_add_uint64(module->ldb, msg, msg, "uSNChanged", seq_num);
if (ret != LDB_SUCCESS) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
if (ret != LDB_SUCCESS) {
- talloc_free(down_req);
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -463,49 +432,54 @@ static int replmd_add_originating(struct ldb_module *module,
*/
replmd_ldb_message_sort(msg, schema);
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ ret = ldb_build_add_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, replmd_op_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return ret;
-}
-
-static int replmd_add(struct ldb_module *module, struct ldb_request *req)
-{
- return replmd_prepare_originating(module, req, req->op.add.message->dn,
- "replmd_add", replmd_add_originating);
+ /* go on with the call chain */
+ return ldb_next_request(module, down_req);
}
-static int replmd_modify_originating(struct ldb_module *module,
- struct ldb_request *req,
- const struct dsdb_schema *schema)
+static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
{
+ struct replmd_replicated_request *ac;
+ const struct dsdb_schema *schema;
struct ldb_request *down_req;
struct ldb_message *msg;
int ret;
time_t t = time(NULL);
uint64_t seq_num;
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "replmd_modify_originating\n");
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.mod.message->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
+
+ schema = dsdb_get_schema(module->ldb);
+ if (!schema) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
+ "replmd_modify: no dsdb_schema loaded");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
+ ac = replmd_ctx_init(module, req);
+ if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- *down_req = *req;
+ ac->schema = schema;
/* we have to copy the message as the caller might have it as a const */
- down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
+ msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
if (msg == NULL) {
- talloc_free(down_req);
+ talloc_free(ac);
return LDB_ERR_OPERATIONS_ERROR;
}
@@ -521,16 +495,16 @@ static int replmd_modify_originating(struct ldb_module *module,
* - calculate the new replPropertyMetaData attribute
*/
- if (add_time_element(msg, "whenChanged", t) != 0) {
- talloc_free(down_req);
+ if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
+ talloc_free(ac);
return LDB_ERR_OPERATIONS_ERROR;
}
/* Get a sequence number from the backend */
ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
if (ret == LDB_SUCCESS) {
- if (add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
- talloc_free(down_req);
+ if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
+ talloc_free(ac);
return LDB_ERR_OPERATIONS_ERROR;
}
}
@@ -540,96 +514,71 @@ static int replmd_modify_originating(struct ldb_module *module,
* - replace the old object with the newly constructed one
*/
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
- }
-
- return ret;
-}
-
-static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
-{
- return replmd_prepare_originating(module, req, req->op.mod.message->dn,
- "replmd_modify", replmd_modify_originating);
-}
-
-static int replmd_replicated_request_reply_helper(struct replmd_replicated_request *ar, int ret)
-{
- struct ldb_reply *ares = NULL;
-
- ar->handle->status = ret;
- ar->handle->state = LDB_ASYNC_DONE;
-
- if (!ar->orig_req->callback) {
- return LDB_SUCCESS;
- }
-
- /* we're done and need to report the success to the caller */
- ares = talloc_zero(ar, struct ldb_reply);
- if (!ares) {
- ar->handle->status = LDB_ERR_OPERATIONS_ERROR;
- ar->handle->state = LDB_ASYNC_DONE;
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = ldb_build_mod_req(&down_req, module->ldb, ac,
+ msg,
+ req->controls,
+ ac, replmd_op_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
+ talloc_steal(down_req, msg);
- ares->type = LDB_REPLY_EXTENDED;
- ares->response = NULL;
-
- return ar->orig_req->callback(ar->module->ldb, ar->orig_req->context, ares);
-}
-
-static int replmd_replicated_request_done(struct replmd_replicated_request *ar)
-{
- return replmd_replicated_request_reply_helper(ar, LDB_SUCCESS);
+ /* go on with the call chain */
+ return ldb_next_request(module, down_req);
}
static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
{
- return replmd_replicated_request_reply_helper(ar, ret);
+ return ret;
}
static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
{
int ret = LDB_ERR_OTHER;
/* TODO: do some error mapping */
- return replmd_replicated_request_reply_helper(ar, ret);
+ return ret;
}
static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
-static int replmd_replicated_apply_add_callback(struct ldb_context *ldb,
- void *private_data,
+static int replmd_replicated_apply_add_callback(struct ldb_request *req,
struct ldb_reply *ares)
{
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- struct replmd_replicated_request *ar = talloc_get_type(private_data,
+ struct replmd_replicated_request *ar = talloc_get_type(req->context,
struct replmd_replicated_request);
+ int ret;
+
- ar->sub.change_ret = ldb_wait(ar->sub.search_req->handle, LDB_WAIT_ALL);
- if (ar->sub.change_ret != LDB_SUCCESS) {
- return replmd_replicated_request_error(ar, ar->sub.change_ret);
+ if (!ares) {
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, ares->controls,
+ ares->response, ares->error);
}
- talloc_free(ar->sub.mem_ctx);
- ZERO_STRUCT(ar->sub);
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ar->module->ldb, "Invalid reply type\n!");
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ talloc_free(ares);
ar->index_current++;
- return replmd_replicated_apply_next(ar);
-#else
+ ret = replmd_replicated_apply_next(ar);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, NULL, NULL, ret);
+ }
+
return LDB_SUCCESS;
-#endif
}
static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
{
+ struct ldb_request *change_req;
enum ndr_err_code ndr_err;
struct ldb_message *msg;
struct replPropertyMetaDataBlob *md;
@@ -696,39 +645,17 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
replmd_ldb_message_sort(msg, ar->schema);
- ret = ldb_build_add_req(&ar->sub.change_req,
+ ret = ldb_build_add_req(&change_req,
ar->module->ldb,
- ar->sub.mem_ctx,
+ ar,
msg,
- NULL,
+ ar->controls,
ar,
- replmd_replicated_apply_add_callback);
+ replmd_replicated_apply_add_callback,
+ ar->req);
if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- return ldb_next_request(ar->module, ar->sub.change_req);
-#else
- ret = ldb_next_request(ar->module, ar->sub.change_req);
- if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(ar->module->ldb, "Failed to add replicated object %s: %s", ldb_dn_get_linearized(ar->sub.change_req->op.add.message->dn),
- ldb_errstring(ar->module->ldb));
- return replmd_replicated_request_error(ar, ret);
- }
-
- ar->sub.change_ret = ldb_wait(ar->sub.change_req->handle, LDB_WAIT_ALL);
- if (ar->sub.change_ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(ar->module->ldb, "Failed while waiting on add replicated object %s: %s", ldb_dn_get_linearized(ar->sub.change_req->op.add.message->dn),
- ldb_errstring(ar->module->ldb));
- return replmd_replicated_request_error(ar, ar->sub.change_ret);
- }
-
- talloc_free(ar->sub.mem_ctx);
- ZERO_STRUCT(ar->sub);
-
- ar->index_current++;
-
- return LDB_SUCCESS;
-#endif
+ return ldb_next_request(ar->module, change_req);
}
static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1,
@@ -752,35 +679,42 @@ static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMeta
return m1->originating_usn - m2->originating_usn;
}
-static int replmd_replicated_apply_merge_callback(struct ldb_context *ldb,
- void *private_data,
+static int replmd_replicated_apply_merge_callback(struct ldb_request *req,
struct ldb_reply *ares)
{
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- struct replmd_replicated_request *ar = talloc_get_type(private_data,
+ struct replmd_replicated_request *ar = talloc_get_type(req->context,
struct replmd_replicated_request);
+ int ret;
- ret = ldb_next_request(ar->module, ar->sub.change_req);
- if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
-
- ar->sub.change_ret = ldb_wait(ar->sub.search_req->handle, LDB_WAIT_ALL);
- if (ar->sub.change_ret != LDB_SUCCESS) {
- return replmd_replicated_request_error(ar, ar->sub.change_ret);
+ if (!ares) {
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, ares->controls,
+ ares->response, ares->error);
}
- talloc_free(ar->sub.mem_ctx);
- ZERO_STRUCT(ar->sub);
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ar->module->ldb, "Invalid reply type\n!");
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ talloc_free(ares);
ar->index_current++;
+ ret = replmd_replicated_apply_next(ar);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, NULL, NULL, ret);
+ }
+
return LDB_SUCCESS;
-#else
- return LDB_SUCCESS;
-#endif
}
static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
{
+ struct ldb_request *change_req;
enum ndr_err_code ndr_err;
struct ldb_message *msg;
struct replPropertyMetaDataBlob *rmd;
@@ -801,11 +735,11 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
/*
* TODO: add rename conflict handling
*/
- if (ldb_dn_compare(msg->dn, ar->sub.search_msg->dn) != 0) {
+ if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
ldb_debug_set(ar->module->ldb, LDB_DEBUG_FATAL, "replmd_replicated_apply_merge[%u]: rename not supported",
ar->index_current);
ldb_debug(ar->module->ldb, LDB_DEBUG_FATAL, "%s => %s\n",
- ldb_dn_get_linearized(ar->sub.search_msg->dn),
+ ldb_dn_get_linearized(ar->search_msg->dn),
ldb_dn_get_linearized(msg->dn));
return replmd_replicated_request_werror(ar, WERR_NOT_SUPPORTED);
}
@@ -816,9 +750,9 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
}
/* find existing meta data */
- omd_value = ldb_msg_find_ldb_val(ar->sub.search_msg, "replPropertyMetaData");
+ omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
if (omd_value) {
- ndr_err = ndr_pull_struct_blob(omd_value, ar->sub.mem_ctx,
+ ndr_err = ndr_pull_struct_blob(omd_value, ar,
lp_iconv_convenience(ldb_get_opaque(ar->module->ldb, "loadparm")), &omd,
(ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
@@ -834,7 +768,7 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
ZERO_STRUCT(nmd);
nmd.version = 1;
nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
- nmd.ctr.ctr1.array = talloc_array(ar->sub.mem_ctx,
+ nmd.ctr.ctr1.array = talloc_array(ar,
struct replPropertyMetaData1,
nmd.ctr.ctr1.count);
if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
@@ -917,14 +851,16 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
if (msg->num_elements == 0) {
ldb_debug(ar->module->ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
ar->index_current);
- goto next_object;
+
+ ar->index_current++;
+ return replmd_replicated_apply_next(ar);
}
ldb_debug(ar->module->ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
ar->index_current, msg->num_elements);
/*
- * when we now that we'll modify the record, add the whenChanged, uSNChanged
+ * when we know that we'll modify the record, add the whenChanged, uSNChanged
* and replPopertyMetaData attributes
*/
ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
@@ -947,150 +883,123 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
}
- ret = ldb_build_mod_req(&ar->sub.change_req,
+ ret = ldb_build_mod_req(&change_req,
ar->module->ldb,
- ar->sub.mem_ctx,
+ ar,
msg,
- NULL,
+ ar->controls,
ar,
- replmd_replicated_apply_merge_callback);
- if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
-
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- return ldb_next_request(ar->module, ar->sub.change_req);
-#else
- ret = ldb_next_request(ar->module, ar->sub.change_req);
+ replmd_replicated_apply_merge_callback,
+ ar->req);
if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
- ar->sub.change_ret = ldb_wait(ar->sub.change_req->handle, LDB_WAIT_ALL);
- if (ar->sub.change_ret != LDB_SUCCESS) {
- return replmd_replicated_request_error(ar, ar->sub.change_ret);
- }
-
-next_object:
- talloc_free(ar->sub.mem_ctx);
- ZERO_STRUCT(ar->sub);
-
- ar->index_current++;
-
- return LDB_SUCCESS;
-#endif
+ return ldb_next_request(ar->module, change_req);
}
-static int replmd_replicated_apply_search_callback(struct ldb_context *ldb,
- void *private_data,
+static int replmd_replicated_apply_search_callback(struct ldb_request *req,
struct ldb_reply *ares)
{
- struct replmd_replicated_request *ar = talloc_get_type(private_data,
+ struct replmd_replicated_request *ar = talloc_get_type(req->context,
struct replmd_replicated_request);
- bool is_done = false;
+ int ret;
+
+ if (!ares) {
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS &&
+ ares->error != LDB_ERR_NO_SUCH_OBJECT) {
+ return ldb_module_done(ar->req, ares->controls,
+ ares->response, ares->error);
+ }
switch (ares->type) {
case LDB_REPLY_ENTRY:
- ar->sub.search_msg = talloc_steal(ar->sub.mem_ctx, ares->message);
+ ar->search_msg = talloc_steal(ar, ares->message);
break;
+
case LDB_REPLY_REFERRAL:
/* we ignore referrals */
break;
- case LDB_REPLY_EXTENDED:
- case LDB_REPLY_DONE:
- is_done = true;
- }
- talloc_free(ares);
-
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- if (is_done) {
- ar->sub.search_ret = ldb_wait(ar->sub.search_req->handle, LDB_WAIT_ALL);
- if (ar->sub.search_ret != LDB_SUCCESS) {
- return replmd_replicated_request_error(ar, ar->sub.search_ret);
+ case LDB_REPLY_DONE:
+ if (ar->search_msg != NULL) {
+ ret = replmd_replicated_apply_merge(ar);
+ } else {
+ ret = replmd_replicated_apply_add(ar);
}
- if (ar->sub.search_msg) {
- return replmd_replicated_apply_merge(ar);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, NULL, NULL, ret);
}
- return replmd_replicated_apply_add(ar);
}
-#endif
+
+ talloc_free(ares);
return LDB_SUCCESS;
}
-static int replmd_replicated_apply_search(struct replmd_replicated_request *ar)
+static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
+
+static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
{
int ret;
char *tmp_str;
char *filter;
+ struct ldb_request *search_req;
+
+ if (ar->index_current >= ar->objs->num_objects) {
+ /* done with it, go to the last op */
+ return replmd_replicated_uptodate_vector(ar);
+ }
+
+ ar->search_msg = NULL;
- tmp_str = ldb_binary_encode(ar->sub.mem_ctx, ar->objs->objects[ar->index_current].guid_value);
+ tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
- filter = talloc_asprintf(ar->sub.mem_ctx, "(objectGUID=%s)", tmp_str);
+ filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
talloc_free(tmp_str);
- ret = ldb_build_search_req(&ar->sub.search_req,
+ ret = ldb_build_search_req(&search_req,
ar->module->ldb,
- ar->sub.mem_ctx,
+ ar,
ar->objs->partition_dn,
LDB_SCOPE_SUBTREE,
filter,
NULL,
NULL,
ar,
- replmd_replicated_apply_search_callback);
- if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
-
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- return ldb_next_request(ar->module, ar->sub.search_req);
-#else
- ret = ldb_next_request(ar->module, ar->sub.search_req);
+ replmd_replicated_apply_search_callback,
+ ar->req);
if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
- ar->sub.search_ret = ldb_wait(ar->sub.search_req->handle, LDB_WAIT_ALL);
- if (ar->sub.search_ret != LDB_SUCCESS && ar->sub.search_ret != LDB_ERR_NO_SUCH_OBJECT) {
- return replmd_replicated_request_error(ar, ar->sub.search_ret);
- }
- if (ar->sub.search_msg) {
- return replmd_replicated_apply_merge(ar);
- }
-
- return replmd_replicated_apply_add(ar);
-#endif
-}
-
-static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
-{
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- if (ar->index_current >= ar->objs->num_objects) {
- return replmd_replicated_uptodate_vector(ar);
- }
-#endif
-
- ar->sub.mem_ctx = talloc_new(ar);
- if (!ar->sub.mem_ctx) return replmd_replicated_request_werror(ar, WERR_NOMEM);
-
- return replmd_replicated_apply_search(ar);
+ return ldb_next_request(ar->module, search_req);
}
-static int replmd_replicated_uptodate_modify_callback(struct ldb_context *ldb,
- void *private_data,
+static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
struct ldb_reply *ares)
{
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- struct replmd_replicated_request *ar = talloc_get_type(private_data,
+ struct replmd_replicated_request *ar = talloc_get_type(req->context,
struct replmd_replicated_request);
- ar->sub.change_ret = ldb_wait(ar->sub.search_req->handle, LDB_WAIT_ALL);
- if (ar->sub.change_ret != LDB_SUCCESS) {
- return replmd_replicated_request_error(ar, ar->sub.change_ret);
+ if (!ares) {
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, ares->controls,
+ ares->response, ares->error);
}
- talloc_free(ar->sub.mem_ctx);
- ZERO_STRUCT(ar->sub);
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ar->module->ldb, "Invalid reply type\n!");
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
- return replmd_replicated_request_done(ar);
-#else
- return LDB_SUCCESS;
-#endif
+ talloc_free(ares);
+
+ return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
}
static int replmd_drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
@@ -1101,6 +1010,7 @@ static int replmd_drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplic
static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
{
+ struct ldb_request *change_req;
enum ndr_err_code ndr_err;
struct ldb_message *msg;
struct replUpToDateVectorBlob ouv;
@@ -1142,9 +1052,9 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
/*
* first create the new replUpToDateVector
*/
- ouv_value = ldb_msg_find_ldb_val(ar->sub.search_msg, "replUpToDateVector");
+ ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
if (ouv_value) {
- ndr_err = ndr_pull_struct_blob(ouv_value, ar->sub.mem_ctx,
+ ndr_err = ndr_pull_struct_blob(ouv_value, ar,
lp_iconv_convenience(ldb_get_opaque(ar->module->ldb, "loadparm")), &ouv,
(ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
@@ -1165,7 +1075,7 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
*/
nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
if (ruv) nuv.ctr.ctr2.count += ruv->count;
- nuv.ctr.ctr2.cursors = talloc_array(ar->sub.mem_ctx,
+ nuv.ctr.ctr2.cursors = talloc_array(ar,
struct drsuapi_DsReplicaCursor2,
nuv.ctr.ctr2.count);
if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
@@ -1266,9 +1176,9 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
/*
* create the change ldb_message
*/
- msg = ldb_msg_new(ar->sub.mem_ctx);
+ msg = ldb_msg_new(ar);
if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
- msg->dn = ar->sub.search_msg->dn;
+ msg->dn = ar->search_msg->dn;
ndr_err = ndr_push_struct_blob(&nuv_value, msg,
lp_iconv_convenience(ldb_get_opaque(ar->module->ldb, "loadparm")),
@@ -1301,12 +1211,12 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
* first see if we already have a repsFrom value for the current source dsa
* if so we'll later replace this value
*/
- orf_el = ldb_msg_find_element(ar->sub.search_msg, "repsFrom");
+ orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
if (orf_el) {
for (i=0; i < orf_el->num_values; i++) {
struct repsFromToBlob *trf;
- trf = talloc(ar->sub.mem_ctx, struct repsFromToBlob);
+ trf = talloc(ar, struct repsFromToBlob);
if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ar->module->ldb, "loadparm")), trf,
@@ -1375,72 +1285,62 @@ static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *a
nrf_el->flags = LDB_FLAG_MOD_REPLACE;
/* prepare the ldb_modify() request */
- ret = ldb_build_mod_req(&ar->sub.change_req,
+ ret = ldb_build_mod_req(&change_req,
ar->module->ldb,
- ar->sub.mem_ctx,
+ ar,
msg,
- NULL,
+ ar->controls,
ar,
- replmd_replicated_uptodate_modify_callback);
- if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
-
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- return ldb_next_request(ar->module, ar->sub.change_req);
-#else
- ret = ldb_next_request(ar->module, ar->sub.change_req);
+ replmd_replicated_uptodate_modify_callback,
+ ar->req);
if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
- ar->sub.change_ret = ldb_wait(ar->sub.search_req->handle, LDB_WAIT_ALL);
- if (ar->sub.change_ret != LDB_SUCCESS) {
- return replmd_replicated_request_error(ar, ar->sub.change_ret);
- }
-
- talloc_free(ar->sub.mem_ctx);
- ZERO_STRUCT(ar->sub);
-
- return replmd_replicated_request_done(ar);
-#endif
+ return ldb_next_request(ar->module, change_req);
}
-static int replmd_replicated_uptodate_search_callback(struct ldb_context *ldb,
- void *private_data,
+static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
struct ldb_reply *ares)
{
- struct replmd_replicated_request *ar = talloc_get_type(private_data,
+ struct replmd_replicated_request *ar = talloc_get_type(req->context,
struct replmd_replicated_request);
- bool is_done = false;
+ int ret;
+
+ if (!ares) {
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS &&
+ ares->error != LDB_ERR_NO_SUCH_OBJECT) {
+ return ldb_module_done(ar->req, ares->controls,
+ ares->response, ares->error);
+ }
switch (ares->type) {
case LDB_REPLY_ENTRY:
- ar->sub.search_msg = talloc_steal(ar->sub.mem_ctx, ares->message);
+ ar->search_msg = talloc_steal(ar, ares->message);
break;
+
case LDB_REPLY_REFERRAL:
/* we ignore referrals */
break;
- case LDB_REPLY_EXTENDED:
- case LDB_REPLY_DONE:
- is_done = true;
- }
-
- talloc_free(ares);
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- if (is_done) {
- ar->sub.search_ret = ldb_wait(ar->sub.search_req->handle, LDB_WAIT_ALL);
- if (ar->sub.search_ret != LDB_SUCCESS) {
- return replmd_replicated_request_error(ar, ar->sub.search_ret);
+ case LDB_REPLY_DONE:
+ if (ar->search_msg == NULL) {
+ ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
+ } else {
+ ret = replmd_replicated_uptodate_modify(ar);
}
- if (!ar->sub.search_msg) {
- return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, NULL, NULL, ret);
}
-
- return replmd_replicated_uptodate_modify(ar);
}
-#endif
+
+ talloc_free(ares);
return LDB_SUCCESS;
}
-static int replmd_replicated_uptodate_search(struct replmd_replicated_request *ar)
+
+static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
{
int ret;
static const char *attrs[] = {
@@ -1448,49 +1348,32 @@ static int replmd_replicated_uptodate_search(struct replmd_replicated_request *a
"repsFrom",
NULL
};
+ struct ldb_request *search_req;
- ret = ldb_build_search_req(&ar->sub.search_req,
+ ar->search_msg = NULL;
+
+ ret = ldb_build_search_req(&search_req,
ar->module->ldb,
- ar->sub.mem_ctx,
+ ar,
ar->objs->partition_dn,
LDB_SCOPE_BASE,
"(objectClass=*)",
attrs,
NULL,
ar,
- replmd_replicated_uptodate_search_callback);
+ replmd_replicated_uptodate_search_callback,
+ ar->req);
if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- return ldb_next_request(ar->module, ar->sub.search_req);
-#else
- ret = ldb_next_request(ar->module, ar->sub.search_req);
- if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
-
- ar->sub.search_ret = ldb_wait(ar->sub.search_req->handle, LDB_WAIT_ALL);
- if (ar->sub.search_ret != LDB_SUCCESS) {
- return replmd_replicated_request_error(ar, ar->sub.search_ret);
- }
- if (!ar->sub.search_msg) {
- return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
- }
-
- return replmd_replicated_uptodate_modify(ar);
-#endif
-}
-
-static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
-{
- ar->sub.mem_ctx = talloc_new(ar);
- if (!ar->sub.mem_ctx) return replmd_replicated_request_werror(ar, WERR_NOMEM);
-
- return replmd_replicated_uptodate_search(ar);
+ return ldb_next_request(ar->module, search_req);
}
static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
{
struct dsdb_extended_replicated_objects *objs;
struct replmd_replicated_request *ar;
+ struct ldb_control **ctrls;
+ int ret;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
@@ -1506,25 +1389,35 @@ static int replmd_extended_replicated_objects(struct ldb_module *module, struct
return LDB_ERR_PROTOCOL_ERROR;
}
- ar = replmd_replicated_init_handle(module, req, objs);
- if (!ar) {
+ ar = replmd_ctx_init(module, req);
+ if (!ar)
return LDB_ERR_OPERATIONS_ERROR;
+
+ ar->objs = objs;
+ ar->schema = dsdb_get_schema(module->ldb);
+ if (!ar->schema) {
+ ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
+ talloc_free(ar);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
}
-#ifdef REPLMD_FULL_ASYNC /* TODO: activate this code when ldb support full async code */
- return replmd_replicated_apply_next(ar);
-#else
- while (ar->index_current < ar->objs->num_objects &&
- req->handle->state != LDB_ASYNC_DONE) {
- replmd_replicated_apply_next(ar);
+ ctrls = req->controls;
+
+ if (req->controls) {
+ req->controls = talloc_memdup(ar, req->controls,
+ talloc_get_size(req->controls));
+ if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
}
- if (req->handle->state != LDB_ASYNC_DONE) {
- replmd_replicated_uptodate_vector(ar);
+ ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return LDB_SUCCESS;
-#endif
+ ar->controls = req->controls;
+ req->controls = ctrls;
+
+ return replmd_replicated_apply_next(ar);
}
static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
@@ -1536,53 +1429,9 @@ static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
-static int replmd_wait_none(struct ldb_handle *handle) {
- struct replmd_replicated_request *ar;
-
- if (!handle || !handle->private_data) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ar = talloc_get_type(handle->private_data, struct replmd_replicated_request);
- if (!ar) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* we do only sync calls */
- if (handle->state != LDB_ASYNC_DONE) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- return handle->status;
-}
-
-static int replmd_wait_all(struct ldb_handle *handle) {
-
- int ret;
-
- while (handle->state != LDB_ASYNC_DONE) {
- ret = replmd_wait_none(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
-
- return handle->status;
-}
-
-static int replmd_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- if (type == LDB_WAIT_ALL) {
- return replmd_wait_all(handle);
- } else {
- return replmd_wait_none(handle);
- }
-}
-
_PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
.name = "repl_meta_data",
.add = replmd_add,
.modify = replmd_modify,
.extended = replmd_extended,
- .wait = replmd_wait
};
diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c
index ebc90d4cf3..b38e182cf7 100644
--- a/source4/dsdb/samdb/ldb_modules/rootdse.c
+++ b/source4/dsdb/samdb/ldb_modules/rootdse.c
@@ -4,7 +4,7 @@
rootDSE ldb module
Copyright (C) Andrew Tridgell 2005
- Copyright (C) Simo Sorce 2005
+ Copyright (C) Simo Sorce 2005-2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -221,40 +221,77 @@ failed:
struct rootdse_context {
struct ldb_module *module;
- void *up_context;
- int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
-
- const char * const * attrs;
+ struct ldb_request *req;
};
-static int rootdse_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static struct rootdse_context *rootdse_init_context(struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct rootdse_context *ac;
+
+ ac = talloc_zero(req, struct rootdse_context);
+ if (ac == NULL) {
+ ldb_set_errstring(module->ldb, "Out of Memory");
+ return NULL;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ return ac;
+}
+
+static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares)
{
struct rootdse_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct rootdse_context);
- ac = talloc_get_type(context, struct rootdse_context);
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- if (ares->type == LDB_REPLY_ENTRY) {
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
/*
* if the client explicit asks for the 'netlogon' attribute
* the reply_entry needs to be skipped
*/
- if (ac->attrs && ldb_attr_in_list(ac->attrs, "netlogon")) {
+ if (ac->req->op.search.attrs &&
+ ldb_attr_in_list(ac->req->op.search.attrs, "netlogon")) {
talloc_free(ares);
return LDB_SUCCESS;
}
/* for each record returned post-process to add any dynamic
attributes that have been asked for */
- if (rootdse_add_dynamic(ac->module, ares->message, ac->attrs) != LDB_SUCCESS) {
- goto error;
+ ret = rootdse_add_dynamic(ac->module, ares->message,
+ ac->req->op.search.attrs);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ares);
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- }
- return ac->up_callback(ldb, ac->up_context, ares);
+ return ldb_module_send_entry(ac->req, ares->message);
+
+ case LDB_REPLY_REFERRAL:
+ /* should we allow the backend to return referrals in this case
+ * ?? */
+ break;
+
+ case LDB_REPLY_DONE:
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
-error:
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ return LDB_SUCCESS;
}
static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
@@ -270,48 +307,25 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
- ac = talloc(req, struct rootdse_context);
+ ac = rootdse_init_context(module, req);
if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac->module = module;
- ac->up_context = req->context;
- ac->up_callback = req->callback;
- ac->attrs = req->op.search.attrs;
-
- down_req = talloc_zero(req, struct ldb_request);
- if (down_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- down_req->operation = req->operation;
/* in our db we store the rootDSE with a DN of @ROOTDSE */
- down_req->op.search.base = ldb_dn_new(down_req, module->ldb, "@ROOTDSE");
- down_req->op.search.scope = LDB_SCOPE_BASE;
- down_req->op.search.tree = ldb_parse_tree(down_req, NULL);
- if (down_req->op.search.base == NULL || down_req->op.search.tree == NULL) {
- ldb_oom(module->ldb);
- talloc_free(down_req);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- down_req->op.search.attrs = req->op.search.attrs;
- down_req->controls = req->controls;
-
- down_req->context = ac;
- down_req->callback = rootdse_callback;
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
- /* perform the search */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ ret = ldb_build_search_req(&down_req, module->ldb, ac,
+ ldb_dn_new(ac, module->ldb, "@ROOTDSE"),
+ LDB_SCOPE_BASE,
+ NULL,
+ req->op.search.attrs,
+ NULL,/* for now skip the controls from the client */
+ ac, rootdse_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- return ret;
+ return ldb_next_request(module, down_req);
}
static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
@@ -332,9 +346,9 @@ static int rootdse_register_control(struct ldb_module *module, struct ldb_reques
priv->num_controls += 1;
priv->controls = list;
- return LDB_SUCCESS;
+ return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
}
-
+
static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req)
{
struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
@@ -353,9 +367,9 @@ static int rootdse_register_partition(struct ldb_module *module, struct ldb_requ
priv->num_partitions += 1;
priv->partitions = list;
- return LDB_SUCCESS;
+ return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
}
-
+
static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
{
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c
index bd491bd011..95a16b5527 100644
--- a/source4/dsdb/samdb/ldb_modules/samldb.c
+++ b/source4/dsdb/samdb/ldb_modules/samldb.c
@@ -1,8 +1,8 @@
-/*
+/*
SAM ldb module
- Copyright (C) Simo Sorce 2004
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Simo Sorce 2004-2008
* NOTICE: this module is NOT released under the GNU LGPL license as
* other ldb code. This module is release under the GNU GPL v3 or
@@ -12,12 +12,12 @@
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -37,728 +37,1266 @@
#include "lib/ldb/include/ldb_errors.h"
#include "lib/ldb/include/ldb.h"
#include "lib/ldb/include/ldb_private.h"
+#include "lib/events/events.h"
#include "dsdb/samdb/samdb.h"
#include "libcli/security/security.h"
#include "librpc/gen_ndr/ndr_security.h"
-#include "util/util_ldb.h"
+#include "../lib/util/util_ldb.h"
+#include "ldb_wrap.h"
+
+struct samldb_ctx;
+
+typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
+
+struct samldb_step {
+ struct samldb_step *next;
+ samldb_step_fn_t fn;
+};
+
+struct samldb_ctx {
+ struct ldb_module *module;
+ struct ldb_request *req;
-int samldb_notice_sid(struct ldb_module *module,
- TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
+ /* the resulting message */
+ struct ldb_message *msg;
+
+ /* used to apply templates */
+ const char *type;
+
+ /* used to find parent domain */
+ struct ldb_dn *check_dn;
+ struct ldb_dn *domain_dn;
+ struct dom_sid *domain_sid;
+ uint32_t next_rid;
+
+ /* generic storage, remember to zero it before use */
+ struct ldb_reply *ares;
+
+ /* holds the entry SID */
+ struct dom_sid *sid;
+
+ /* all the async steps necessary to complete the operation */
+ struct samldb_step *steps;
+ struct samldb_step *curstep;
+};
-static bool samldb_msg_add_sid(struct ldb_module *module, struct ldb_message *msg, const char *name, const struct dom_sid *sid)
+static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
+ struct ldb_request *req)
{
- struct ldb_val v;
- enum ndr_err_code ndr_err;
+ struct samldb_ctx *ac;
- ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
- (ndr_push_flags_fn_t)ndr_push_dom_sid);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- return false;
+ ac = talloc_zero(req, struct samldb_ctx);
+ if (ac == NULL) {
+ ldb_oom(module->ldb);
+ return NULL;
}
- return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
+
+ ac->module = module;
+ ac->req = req;
+
+ return ac;
}
-/*
- allocate a new id, attempting to do it atomically
- return 0 on failure, the id on success
-*/
-static int samldb_set_next_rid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
- struct ldb_dn *dn, uint32_t old_id, uint32_t new_id)
+static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
{
- struct ldb_message msg;
- int ret;
- struct ldb_val vals[2];
- struct ldb_message_element els[2];
+ struct samldb_step *step;
- if (new_id == 0) {
- /* out of IDs ! */
- ldb_set_errstring(ldb, "Are we out of valid IDs ?\n");
+ step = talloc_zero(ac, struct samldb_step);
+ if (step == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* we do a delete and add as a single operation. That prevents
- a race, in case we are not actually on a transaction db */
- ZERO_STRUCT(msg);
- msg.dn = ldb_dn_copy(mem_ctx, dn);
- if (!msg.dn) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ac->steps == NULL) {
+ ac->steps = step;
+ ac->curstep = step;
+ } else {
+ ac->curstep->next = step;
+ ac->curstep = step;
}
- msg.num_elements = 2;
- msg.elements = els;
- els[0].num_values = 1;
- els[0].values = &vals[0];
- els[0].flags = LDB_FLAG_MOD_DELETE;
- els[0].name = talloc_strdup(mem_ctx, "nextRid");
- if (!els[0].name) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ step->fn = fn;
- els[1].num_values = 1;
- els[1].values = &vals[1];
- els[1].flags = LDB_FLAG_MOD_ADD;
- els[1].name = els[0].name;
+ return LDB_SUCCESS;
+}
- vals[0].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", old_id);
- if (!vals[0].data) {
- ldb_oom(ldb);
+static int samldb_first_step(struct samldb_ctx *ac)
+{
+ if (ac->steps == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- vals[0].length = strlen((char *)vals[0].data);
- vals[1].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", new_id);
- if (!vals[1].data) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ ac->curstep = ac->steps;
+ return ac->curstep->fn(ac);
+}
+
+static int samldb_next_step(struct samldb_ctx *ac)
+{
+ if (ac->curstep->next) {
+ ac->curstep = ac->curstep->next;
+ return ac->curstep->fn(ac);
}
- vals[1].length = strlen((char *)vals[1].data);
- ret = ldb_modify(ldb, &msg);
- return ret;
+ /* it is an error if the last step does not properly
+ * return to the upper module by itself */
+ return LDB_ERR_OPERATIONS_ERROR;
}
-/*
- allocate a new id, attempting to do it atomically
- return 0 on failure, the id on success
-*/
-static int samldb_find_next_rid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
- struct ldb_dn *dn, uint32_t *old_rid)
+static int samldb_search_template_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
- const char * const attrs[2] = { "nextRid", NULL };
- struct ldb_result *res = NULL;
+ struct samldb_ctx *ac;
int ret;
- const char *str;
- ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, "nextRid=*", attrs, &res);
- if (ret != LDB_SUCCESS) {
- return ret;
+ ac = talloc_get_type(req->context, struct samldb_ctx);
+
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
}
- if (res->count != 1) {
- talloc_free(res);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- str = ldb_msg_find_attr_as_string(res->msgs[0], "nextRid", NULL);
- if (str == NULL) {
- ldb_asprintf_errstring(module->ldb,
- "attribute nextRid not found in %s\n",
- ldb_dn_get_linearized(dn));
- talloc_free(res);
- return LDB_ERR_OPERATIONS_ERROR;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ /* save entry */
+ if (ac->ares != NULL) {
+ /* one too many! */
+ ldb_set_errstring(ac->module->ldb,
+ "Invalid number of results while searching "
+ "for template objects");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ ac->ares = talloc_steal(ac, ares);
+ ret = LDB_SUCCESS;
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ talloc_free(ares);
+ ret = LDB_SUCCESS;
+ break;
+
+ case LDB_REPLY_DONE:
+
+ talloc_free(ares);
+ ret = samldb_next_step(ac);
+ break;
+ }
+
+done:
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- *old_rid = strtol(str, NULL, 0);
- talloc_free(res);
return LDB_SUCCESS;
}
-static int samldb_allocate_next_rid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
- struct ldb_dn *dn, const struct dom_sid *dom_sid,
- struct dom_sid **new_sid)
+static int samldb_search_template(struct samldb_ctx *ac)
{
- struct dom_sid *obj_sid;
- uint32_t old_rid;
+ struct event_context *ev;
+ struct loadparm_context *lparm_ctx;
+ struct ldb_context *templates_ldb;
+ char *templates_ldb_path;
+ struct ldb_request *req;
+ struct ldb_dn *basedn;
+ void *opaque;
int ret;
-
- ret = samldb_find_next_rid(module, mem_ctx, dn, &old_rid);
- if (ret) {
- return ret;
+
+ opaque = ldb_get_opaque(ac->module->ldb, "loadparm");
+ lparm_ctx = talloc_get_type(opaque, struct loadparm_context);
+ if (lparm_ctx == NULL) {
+ ldb_set_errstring(ac->module->ldb,
+ "Unable to find loadparm context\n");
+ return LDB_ERR_OPERATIONS_ERROR;
}
-
- /* return the new object sid */
- obj_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid);
-
- *new_sid = dom_sid_add_rid(mem_ctx, dom_sid, old_rid + 1);
- if (!*new_sid) {
+
+ opaque = ldb_get_opaque(ac->module->ldb, "templates_ldb");
+ templates_ldb = talloc_get_type(opaque, struct ldb_context);
+
+ /* make sure we have the templates ldb */
+ if (!templates_ldb) {
+ templates_ldb_path = samdb_relative_path(ac->module->ldb, ac,
+ "templates.ldb");
+ if (!templates_ldb_path) {
+ ldb_set_errstring(ac->module->ldb,
+ "samldb_init_template: ERROR: Failed "
+ "to contruct path for template db");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ev = ldb_get_event_context(ac->module->ldb);
+
+ templates_ldb = ldb_wrap_connect(ac->module->ldb, ev,
+ lparm_ctx, templates_ldb_path,
+ NULL, NULL, 0, NULL);
+ talloc_free(templates_ldb_path);
+
+ if (!templates_ldb) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (!talloc_reference(templates_ldb, ev)) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_set_opaque(ac->module->ldb,
+ "templates_ldb", templates_ldb);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ /* search template */
+ basedn = ldb_dn_new_fmt(ac, templates_ldb,
+ "cn=Template%s,cn=Templates", ac->type);
+ if (basedn == NULL) {
+ ldb_set_errstring(ac->module->ldb,
+ "samldb_init_template: ERROR: Failed "
+ "to contruct DN for template");
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = samldb_notice_sid(module, mem_ctx, *new_sid);
- if (ret != 0) {
- /* gah, there are conflicting sids.
- * This is a critical situation it means that someone messed up with
- * the DB and nextRid is not returning free RIDs, report an error
- * and refuse to create any user until the problem is fixed */
- ldb_asprintf_errstring(module->ldb,
- "Critical Error: unconsistent DB, unable to retireve an unique RID to generate a new SID: %s",
- ldb_errstring(module->ldb));
+ /* pull the template record */
+ ret = ldb_build_search_req(&req, templates_ldb, ac,
+ basedn, LDB_SCOPE_BASE,
+ "(distinguishedName=*)", NULL,
+ NULL,
+ ac, samldb_search_template_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
return ret;
}
- return ret;
+
+ talloc_steal(req, basedn);
+ ac->ares = NULL;
+
+ return ldb_request(templates_ldb, req);
}
-/* search the domain related to the provided dn
- allocate a new RID for the domain
- return the new sid string
-*/
-static int samldb_get_new_sid(struct ldb_module *module,
- TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
- struct ldb_dn *dom_dn,
- struct dom_sid **sid)
+static int samldb_apply_template(struct samldb_ctx *ac)
+{
+ struct ldb_message_element *el;
+ struct ldb_message *msg;
+ int i, j;
+ int ret;
+
+ msg = ac->ares->message;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ el = &msg->elements[i];
+ /* some elements should not be copied */
+ if (ldb_attr_cmp(el->name, "cn") == 0 ||
+ ldb_attr_cmp(el->name, "name") == 0 ||
+ ldb_attr_cmp(el->name, "objectClass") == 0 ||
+ ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
+ ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
+ ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
+ ldb_attr_cmp(el->name, "objectGUID") == 0) {
+ continue;
+ }
+ for (j = 0; j < el->num_values; j++) {
+ ret = samdb_find_or_add_attribute(
+ ac->module->ldb, ac->msg, el->name,
+ (char *)el->values[j].data);
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(ac->module->ldb,
+ "Failed adding template attribute\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+ }
+
+ return samldb_next_step(ac);
+}
+
+static int samldb_get_parent_domain(struct samldb_ctx *ac);
+
+static int samldb_get_parent_domain_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
- const char * const attrs[2] = { "objectSid", NULL };
- struct ldb_result *res = NULL;
+ struct samldb_ctx *ac;
+ const char *nextRid;
int ret;
- struct dom_sid *dom_sid;
- /* get the domain component part of the provided dn */
+ ac = talloc_get_type(req->context, struct samldb_ctx);
+
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ /* save entry */
+ if (ac->domain_dn != NULL) {
+ /* one too many! */
+ ldb_set_errstring(ac->module->ldb,
+ "Invalid number of results while searching "
+ "for domain object");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+
+ nextRid = ldb_msg_find_attr_as_string(ares->message,
+ "nextRid", NULL);
+ if (nextRid == NULL) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "attribute nextRid not found in %s\n",
+ ldb_dn_get_linearized(ares->message->dn));
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;;
+ }
+
+ ac->next_rid = strtol(nextRid, NULL, 0);
+
+ ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
+ "objectSid");
+ if (ac->domain_sid == NULL) {
+ ldb_set_errstring(ac->module->ldb,
+ "error retrieving parent domain domain sid!\n");
+ ret = LDB_ERR_CONSTRAINT_VIOLATION;
+ break;
+ }
+ ac->domain_dn = talloc_steal(ac, ares->message->dn);
+
+ talloc_free(ares);
+ ret = LDB_SUCCESS;
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ talloc_free(ares);
+ ret = LDB_SUCCESS;
+ break;
- /* find the domain sid */
+ case LDB_REPLY_DONE:
- ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res);
+ talloc_free(ares);
+ if (ac->domain_dn == NULL) {
+ /* search again */
+ ret = samldb_get_parent_domain(ac);
+ } else {
+ /* found, go on */
+ ret = samldb_next_step(ac);
+ }
+ break;
+ }
+
+done:
if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(module->ldb,
- "samldb_get_new_sid: error retrieving domain sid from %s: %s!\n",
- ldb_dn_get_linearized(dom_dn),
- ldb_errstring(module->ldb));
- talloc_free(res);
- return ret;
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- if (res->count != 1) {
- ldb_asprintf_errstring(module->ldb,
- "samldb_get_new_sid: error retrieving domain sid from %s: not found!\n",
- ldb_dn_get_linearized(dom_dn));
- talloc_free(res);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ return LDB_SUCCESS;
+}
+
+/* Find a domain object in the parents of a particular DN. */
+static int samldb_get_parent_domain(struct samldb_ctx *ac)
+{
+ static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
+ struct ldb_request *req;
+ struct ldb_dn *dn;
+ int ret;
+
+ if (ac->check_dn == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- dom_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
- if (dom_sid == NULL) {
- ldb_set_errstring(module->ldb, "samldb_get_new_sid: error parsing domain sid!\n");
- talloc_free(res);
+ dn = ldb_dn_get_parent(ac, ac->check_dn);
+ if (dn == NULL) {
+ ldb_set_errstring(ac->module->ldb,
+ "Unable to find parent domain object");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
- /* allocate a new Rid for the domain */
- ret = samldb_allocate_next_rid(module, mem_ctx, dom_dn, dom_sid, sid);
- if (ret != 0) {
- ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to increment nextRid of %s: %s\n", ldb_dn_get_linearized(dom_dn), ldb_errstring(module->ldb));
- talloc_free(res);
+ ac->check_dn = dn;
+
+ ret = ldb_build_search_req(&req, ac->module->ldb, ac,
+ dn, LDB_SCOPE_BASE,
+ "(|(objectClass=domain)"
+ "(objectClass=builtinDomain)"
+ "(objectClass=samba4LocalDomain))",
+ attrs,
+ NULL,
+ ac, samldb_get_parent_domain_callback,
+ ac->req);
+
+ if (ret != LDB_SUCCESS) {
return ret;
}
- talloc_free(res);
+ return ldb_next_request(ac->module, req);
+}
+
+static int samldb_generate_samAccountName(struct ldb_message *msg)
+{
+ char *name;
+
+ /* Format: $000000-000000000000 */
- return ret;
+ name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
+ (unsigned int)generate_random(),
+ (unsigned int)generate_random(),
+ (unsigned int)generate_random());
+ if (name == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ return ldb_msg_add_steal_string(msg, "samAccountName", name);
}
-/* If we are adding new users/groups, we need to update the nextRid
- * attribute to be 'above' all incoming users RIDs. This tries to
- * avoid clashes in future */
+static int samldb_check_samAccountName_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct samldb_ctx *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct samldb_ctx);
-int samldb_notice_sid(struct ldb_module *module,
- TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+ /* if we get an entry it means this samAccountName
+ * already exists */
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ talloc_free(ares);
+ ret = LDB_SUCCESS;
+ break;
+
+ case LDB_REPLY_DONE:
+
+ /* not found, go on */
+ talloc_free(ares);
+ ret = samldb_next_step(ac);
+ break;
+ }
+
+done:
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int samldb_check_samAccountName(struct samldb_ctx *ac)
{
+ struct ldb_request *req;
+ const char *name;
+ char *filter;
int ret;
- struct ldb_dn *dom_dn;
- struct dom_sid *dom_sid;
- const char *attrs[] = { NULL };
- struct ldb_result *dom_res;
- struct ldb_result *res;
- uint32_t old_rid;
-
- /* find if this SID already exists */
- ret = ldb_search_exp_fmt(module->ldb, mem_ctx, &res,
- NULL, LDB_SCOPE_SUBTREE, attrs,
- "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid));
- if (ret == LDB_SUCCESS) {
- if (res->count > 0) {
- talloc_free(res);
- ldb_asprintf_errstring(module->ldb,
- "Attempt to add record with SID %s rejected,"
- " because this SID is already in the database",
- dom_sid_string(mem_ctx, sid));
- /* We have a duplicate SID, we must reject the add */
- return LDB_ERR_CONSTRAINT_VIOLATION;
+
+ if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
+ ret = samldb_generate_samAccountName(ac->msg);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- talloc_free(res);
- } else {
- ldb_asprintf_errstring(module->ldb,
- "samldb_notice_sid: error searching to see if sid %s is in use: %s\n",
- dom_sid_string(mem_ctx, sid),
- ldb_errstring(module->ldb));
- return ret;
}
- dom_sid = dom_sid_dup(mem_ctx, sid);
- if (!dom_sid) {
+ name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
+ if (name == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ filter = talloc_asprintf(ac, "samAccountName=%s", name);
+ if (filter == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* get the domain component part of the provided SID */
- dom_sid->num_auths--;
-
- /* find the domain DN */
- ret = ldb_search_exp_fmt(module->ldb, mem_ctx, &dom_res,
- NULL, LDB_SCOPE_SUBTREE, attrs,
- "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))",
- ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
- if (ret == LDB_SUCCESS) {
- if (dom_res->count == 0) {
- talloc_free(dom_res);
- /* This isn't an operation on a domain we know about, so nothing to update */
- return LDB_SUCCESS;
- }
- if (dom_res->count > 1) {
- talloc_free(dom_res);
- ldb_asprintf_errstring(module->ldb,
- "samldb_notice_sid: error retrieving domain from sid: duplicate (found %d) domain: %s!\n",
- dom_res->count, dom_sid_string(dom_res, dom_sid));
- return LDB_ERR_OPERATIONS_ERROR;
- }
- } else {
- ldb_asprintf_errstring(module->ldb,
- "samldb_notice_sid: error retrieving domain from sid: %s: %s\n",
- dom_sid_string(dom_res, dom_sid),
- ldb_errstring(module->ldb));
+ ret = ldb_build_search_req(&req, ac->module->ldb, ac,
+ ac->domain_dn, LDB_SCOPE_SUBTREE,
+ filter, NULL,
+ NULL,
+ ac, samldb_check_samAccountName_callback,
+ ac->req);
+ talloc_free(filter);
+ if (ret != LDB_SUCCESS) {
return ret;
}
+ ac->ares = NULL;
+ return ldb_next_request(ac->module, req);
+}
- dom_dn = dom_res->msgs[0]->dn;
+static int samldb_check_samAccountType(struct samldb_ctx *ac)
+{
+ unsigned int account_type;
+ unsigned int group_type;
+ unsigned int uac;
+ int ret;
- ret = samldb_find_next_rid(module, mem_ctx,
- dom_dn, &old_rid);
- if (ret) {
- talloc_free(dom_res);
- return ret;
+ /* make sure sAMAccountType is not specified */
+ if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "sAMAccountType must not be specified");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
}
- if (old_rid <= sid->sub_auths[sid->num_auths - 1]) {
- ret = samldb_set_next_rid(module->ldb, mem_ctx, dom_dn, old_rid,
- sid->sub_auths[sid->num_auths - 1] + 1);
+ if (strcmp("user", ac->type) == 0) {
+ uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
+ if (uac == 0) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "userAccountControl invalid");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ } else {
+ account_type = samdb_uf2atype(uac);
+ ret = samdb_msg_add_uint(ac->module->ldb,
+ ac->msg, ac->msg,
+ "sAMAccountType",
+ account_type);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+ } else
+ if (strcmp("group", ac->type) == 0) {
+
+ group_type = samdb_result_uint(ac->msg, "groupType", 0);
+ if (group_type == 0) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "groupType invalid");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ } else {
+ account_type = samdb_gtype2atype(group_type);
+ ret = samdb_msg_add_uint(ac->module->ldb,
+ ac->msg, ac->msg,
+ "sAMAccountType",
+ account_type);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
}
- talloc_free(dom_res);
- return ret;
+
+ return samldb_next_step(ac);
}
-static int samldb_handle_sid(struct ldb_module *module,
- TALLOC_CTX *mem_ctx, struct ldb_message *msg2,
- struct ldb_dn *parent_dn)
+static int samldb_get_sid_domain_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
+ struct samldb_ctx *ac;
+ const char *nextRid;
int ret;
-
- struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg2, "objectSid");
- if (sid == NULL) {
- ret = samldb_get_new_sid(module, msg2, msg2->dn, parent_dn, &sid);
- if (ret != 0) {
- return ret;
+
+ ac = talloc_get_type(req->context, struct samldb_ctx);
+
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ /* save entry */
+ if (ac->next_rid != 0) {
+ /* one too many! */
+ ldb_set_errstring(ac->module->ldb,
+ "Invalid number of results while searching "
+ "for domain object");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
}
- if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
- talloc_free(sid);
- return LDB_ERR_OPERATIONS_ERROR;
+ nextRid = ldb_msg_find_attr_as_string(ares->message,
+ "nextRid", NULL);
+ if (nextRid == NULL) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "attribute nextRid not found in %s\n",
+ ldb_dn_get_linearized(ares->message->dn));
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
}
- talloc_free(sid);
+
+ ac->next_rid = strtol(nextRid, NULL, 0);
+
+ ac->domain_dn = talloc_steal(ac, ares->message->dn);
+
+ talloc_free(ares);
ret = LDB_SUCCESS;
- } else {
- ret = samldb_notice_sid(module, msg2, sid);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ talloc_free(ares);
+ ret = LDB_SUCCESS;
+ break;
+
+ case LDB_REPLY_DONE:
+
+ if (ac->next_rid == 0) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "Unable to get nextRid from domain entry\n");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+
+ /* found, go on */
+ ret = samldb_next_step(ac);
+ break;
+ }
+
+done:
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- return ret;
+
+ return LDB_SUCCESS;
}
-static int samldb_generate_samAccountName(struct ldb_module *module, TALLOC_CTX *mem_ctx,
- struct ldb_dn *dom_dn, char **name)
+/* Find a domain object in the parents of a particular DN. */
+static int samldb_get_sid_domain(struct samldb_ctx *ac)
{
- const char *attrs[] = { NULL };
- struct ldb_result *res;
+ static const char * const attrs[2] = { "nextRid", NULL };
+ struct ldb_request *req;
+ char *filter;
int ret;
-
- /* Format: $000000-000000000000 */
-
- do {
- *name = talloc_asprintf(mem_ctx, "$%.6X-%.6X%.6X", (unsigned int)generate_random(), (unsigned int)generate_random(), (unsigned int)generate_random());
- /* TODO: Figure out exactly what this is meant to conflict with */
- ret = ldb_search_exp_fmt(module->ldb,
- mem_ctx, &res, dom_dn, LDB_SCOPE_SUBTREE, attrs,
- "samAccountName=%s",
- ldb_binary_encode_string(mem_ctx, *name));
- if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(module->ldb, "samldb: Failure searching to determine if samAccountName %s is unique: %s",
- *name, ldb_errstring(module->ldb));
- return ret;
- }
- if (res->count == 0) {
- talloc_free(res);
- /* Great. There are no conflicting users/groups/etc */
- return LDB_SUCCESS;
- } else {
- talloc_free(*name);
- /* gah, there is a conflicting name, lets move around the loop again... */
- }
- } while (1);
+ if (ac->sid == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->domain_sid = dom_sid_dup(ac, ac->sid);
+ if (!ac->domain_sid) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ /* get the domain component part of the provided SID */
+ ac->domain_sid->num_auths--;
+
+ filter = talloc_asprintf(ac, "(&(objectSid=%s)"
+ "(|(objectClass=domain)"
+ "(objectClass=builtinDomain)"
+ "(objectClass=samba4LocalDomain)))",
+ ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
+ if (filter == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_search_req(&req, ac->module->ldb, ac,
+ ldb_get_default_basedn(ac->module->ldb),
+ LDB_SCOPE_SUBTREE,
+ filter, attrs,
+ NULL,
+ ac, samldb_get_sid_domain_callback,
+ ac->req);
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ac->next_rid = 0;
+ return ldb_next_request(ac->module, req);
}
-static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_message *msg,
- struct ldb_message **ret_msg)
+static bool samldb_msg_add_sid(struct ldb_message *msg,
+ const char *name,
+ const struct dom_sid *sid)
{
- int ret;
- unsigned int group_type;
- char *name;
- struct ldb_message *msg2;
- struct ldb_dn *dom_dn;
- const char *rdn_name;
- TALLOC_CTX *mem_ctx = talloc_new(msg);
- const char *errstr;
- if (!mem_ctx) {
+ struct ldb_val v;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
+ (ndr_push_flags_fn_t)ndr_push_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
+}
+
+static int samldb_new_sid(struct samldb_ctx *ac)
+{
+
+ if (ac->domain_sid == NULL || ac->next_rid == 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* build the new msg */
- msg2 = ldb_msg_copy(mem_ctx, msg);
- if (!msg2) {
- ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
- talloc_free(mem_ctx);
+ ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
+ if (ac->sid == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = samdb_copy_template(module->ldb, msg2,
- "group",
- &errstr);
- if (ret != 0) {
-
- talloc_free(mem_ctx);
- return ret;
+ if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- rdn_name = ldb_dn_get_rdn_name(msg2->dn);
+ return samldb_next_step(ac);
+}
- if (strcasecmp(rdn_name, "cn") != 0) {
- ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad RDN (%s) for group!\n", rdn_name);
- talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+static int samldb_check_sid_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct samldb_ctx *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct samldb_ctx);
+
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- ret = samdb_search_for_parent_domain(module->ldb, mem_ctx, msg2->dn, &dom_dn, &errstr);
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+ /* if we get an entry it means an object with the
+ * requested sid exists */
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_CONSTRAINT_VIOLATION);
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_DONE:
+
+ /* not found, go on */
+ talloc_free(ares);
+ ret = samldb_next_step(ac);
+ break;
+ }
+
+done:
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int samldb_check_sid(struct samldb_ctx *ac)
+{
+ const char *const attrs[2] = { "objectSid", NULL };
+ struct ldb_request *req;
+ char *filter;
+ int ret;
+
+ if (ac->sid == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ filter = talloc_asprintf(ac, "(objectSid=%s)",
+ ldap_encode_ndr_dom_sid(ac, ac->sid));
+ if (filter == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_search_req(&req, ac->module->ldb, ac,
+ ldb_get_default_basedn(ac->module->ldb),
+ LDB_SCOPE_SUBTREE,
+ filter, attrs,
+ NULL,
+ ac, samldb_check_sid_callback,
+ ac->req);
+
if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(module->ldb,
- "samldb_fill_group_object: %s", errstr);
return ret;
}
- /* Generate a random name, if no samAccountName was supplied */
- if (ldb_msg_find_element(msg2, "samAccountName") == NULL) {
- ret = samldb_generate_samAccountName(module, mem_ctx, dom_dn, &name);
- if (ret != LDB_SUCCESS) {
- talloc_free(mem_ctx);
- return ret;
- }
- ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name);
- if (ret) {
- talloc_free(mem_ctx);
- return ret;
- }
+ return ldb_next_request(ac->module, req);
+}
+
+static int samldb_notice_sid_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct samldb_ctx *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct samldb_ctx);
+
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
}
-
- if (ldb_msg_find_element(msg2, "sAMAccountType") != NULL) {
- ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified");
- talloc_free(mem_ctx);
- return LDB_ERR_UNWILLING_TO_PERFORM;
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- group_type = samdb_result_uint(msg2, "groupType", 0);
- if (group_type == 0) {
- ldb_asprintf_errstring(module->ldb, "groupType invalid");
- talloc_free(mem_ctx);
- return LDB_ERR_UNWILLING_TO_PERFORM;
- } else {
- unsigned int account_type = samdb_gtype2atype(group_type);
- ret = samdb_msg_add_uint(module->ldb, msg2, msg2,
- "sAMAccountType",
- account_type);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb,
+ "Invalid reply type!\n");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
}
- /* Manage SID allocation, conflicts etc */
- ret = samldb_handle_sid(module, mem_ctx, msg2, dom_dn);
+ ret = samldb_next_step(ac);
- if (ret == LDB_SUCCESS) {
- talloc_steal(msg, msg2);
- *ret_msg = msg2;
+done:
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- talloc_free(mem_ctx);
- return ret;
+
+ return LDB_SUCCESS;
}
-static int samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg)
+/* If we are adding new users/groups, we need to update the nextRid
+ * attribute to be 'above' the new/incoming RID. Attempt to do it
+ *atomically. */
+static int samldb_notice_sid(struct samldb_ctx *ac)
{
+ uint32_t old_id, new_id;
+ struct ldb_request *req;
+ struct ldb_message *msg;
+ struct ldb_message_element *els;
+ struct ldb_val *vals;
int ret;
- char *name;
- struct ldb_message *msg2;
- struct ldb_dn *dom_dn;
- const char *rdn_name;
- TALLOC_CTX *mem_ctx = talloc_new(msg);
- const char *errstr;
- unsigned int user_account_control;
- if (!mem_ctx) {
+
+ old_id = ac->next_rid;
+ new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
+
+ if (old_id >= new_id) {
+ /* no need to update the domain nextRid attribute */
+ return samldb_next_step(ac);
+ }
+
+ /* we do a delete and add as a single operation. That prevents
+ a race, in case we are not actually on a transaction db */
+ msg = talloc_zero(ac, struct ldb_message);
+ if (msg == NULL) {
+ ldb_oom(ac->module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ els = talloc_array(msg, struct ldb_message_element, 2);
+ if (els == NULL) {
+ ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
+ vals = talloc_array(msg, struct ldb_val, 2);
+ if (vals == NULL) {
+ ldb_oom(ac->module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ msg->dn = ac->domain_dn;
+ msg->num_elements = 2;
+ msg->elements = els;
- /* build the new msg */
- msg2 = ldb_msg_copy(mem_ctx, msg);
- if (!msg2) {
- ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: ldb_msg_copy failed!\n");
- talloc_free(mem_ctx);
+ els[0].num_values = 1;
+ els[0].values = &vals[0];
+ els[0].flags = LDB_FLAG_MOD_DELETE;
+ els[0].name = talloc_strdup(msg, "nextRid");
+ if (!els[0].name) {
+ ldb_oom(ac->module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = samdb_copy_template(module->ldb, msg2,
- "user",
- &errstr);
- if (ret) {
- ldb_asprintf_errstring(module->ldb,
- "samldb_fill_user_or_computer_object: Error copying user template: %s\n",
- errstr);
- talloc_free(mem_ctx);
+ els[1].num_values = 1;
+ els[1].values = &vals[1];
+ els[1].flags = LDB_FLAG_MOD_ADD;
+ els[1].name = els[0].name;
+
+ vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
+ if (!vals[0].data) {
+ ldb_oom(ac->module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ vals[0].length = strlen((char *)vals[0].data);
+
+ vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
+ if (!vals[1].data) {
+ ldb_oom(ac->module->ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ vals[1].length = strlen((char *)vals[1].data);
+
+ ret = ldb_build_mod_req(&req, ac->module->ldb, ac,
+ msg, NULL,
+ ac, samldb_notice_sid_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
return ret;
}
- rdn_name = ldb_dn_get_rdn_name(msg2->dn);
+ return ldb_next_request(ac->module, req);
+}
- if (strcasecmp(rdn_name, "cn") != 0) {
- ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for user/computer, should be CN=!\n", rdn_name);
- talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+static int samldb_add_entry_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct samldb_ctx *ac;
+
+ ac = talloc_get_type(req->context, struct samldb_ctx);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb,
+ "Invalid reply type!\n");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- ret = samdb_search_for_parent_domain(module->ldb, mem_ctx, msg2->dn, &dom_dn, &errstr);
+ /* we exit the samldb module here */
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+}
+
+static int samldb_add_entry(struct samldb_ctx *ac)
+{
+ struct ldb_request *req;
+ int ret;
+
+ ret = ldb_build_add_req(&req, ac->module->ldb, ac,
+ ac->msg,
+ ac->req->controls,
+ ac, samldb_add_entry_callback,
+ ac->req);
if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(module->ldb,
- "samldb_fill_user_or_computer_object: %s", errstr);
return ret;
}
- if (ldb_msg_find_element(msg2, "samAccountName") == NULL) {
- ret = samldb_generate_samAccountName(module, mem_ctx, dom_dn, &name);
- if (ret != LDB_SUCCESS) {
- talloc_free(mem_ctx);
- return ret;
- }
- ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name);
- if (ret) {
- talloc_free(mem_ctx);
- return ret;
- }
+ return ldb_next_request(ac->module, req);
+}
+
+static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
+{
+ int ret;
+
+ /* first look for the template */
+ ac->type = type;
+ ret = samldb_add_step(ac, samldb_search_template);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* then apply it */
+ ret = samldb_add_step(ac, samldb_apply_template);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* search for a parent domain objet */
+ ac->check_dn = ac->req->op.add.message->dn;
+ ret = samldb_add_step(ac, samldb_get_parent_domain);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* check if we have a valid samAccountName */
+ ret = samldb_add_step(ac, samldb_check_samAccountName);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* check account_type/group_type */
+ ret = samldb_add_step(ac, samldb_check_samAccountType);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* check if we have a valid SID */
+ ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
+ if ( ! ac->sid) {
+ ret = samldb_add_step(ac, samldb_new_sid);
+ if (ret != LDB_SUCCESS) return ret;
+ } else {
+ ret = samldb_add_step(ac, samldb_get_sid_domain);
+ if (ret != LDB_SUCCESS) return ret;
}
- if (ldb_msg_find_element(msg2, "sAMAccountType") != NULL) {
- ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified");
- talloc_free(mem_ctx);
- return LDB_ERR_UNWILLING_TO_PERFORM;
+ ret = samldb_add_step(ac, samldb_check_sid);
+ if (ret != LDB_SUCCESS) return ret;
+
+ ret = samldb_add_step(ac, samldb_notice_sid);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* finally proceed with adding the entry */
+ ret = samldb_add_step(ac, samldb_add_entry);
+ if (ret != LDB_SUCCESS) return ret;
+
+ return samldb_first_step(ac);
+
+ /* TODO: userAccountControl, badPwdCount, codePage,
+ * countryCode, badPasswordTime, lastLogoff, lastLogon,
+ * pwdLastSet, primaryGroupID, accountExpires, logonCount */
+
+}
+
+static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct samldb_ctx *ac;
+ const char *nextRid;
+ const char *name;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct samldb_ctx);
+
+ if (!ares) {
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
}
- user_account_control = samdb_result_uint(msg2, "userAccountControl", 0);
- if (user_account_control == 0) {
- ldb_asprintf_errstring(module->ldb, "userAccountControl invalid");
- talloc_free(mem_ctx);
- return LDB_ERR_UNWILLING_TO_PERFORM;
- } else {
- unsigned int account_type = samdb_uf2atype(user_account_control);
- ret = samdb_msg_add_uint(module->ldb, msg2, msg2,
- "sAMAccountType",
- account_type);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- /* Manage SID allocation, conflicts etc */
- ret = samldb_handle_sid(module, mem_ctx, msg2, dom_dn);
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ /* save entry */
+ if (ac->next_rid != 0) {
+ /* one too many! */
+ ldb_set_errstring(ac->module->ldb,
+ "Invalid number of results while searching "
+ "for domain object");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
- /* TODO: userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */
+ nextRid = ldb_msg_find_attr_as_string(ares->message,
+ "nextRid", NULL);
+ if (nextRid == NULL) {
+ ldb_asprintf_errstring(ac->module->ldb,
+ "attribute nextRid not found in %s\n",
+ ldb_dn_get_linearized(ares->message->dn));
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ break;
+ }
+
+ ac->next_rid = strtol(nextRid, NULL, 0);
+
+ ac->domain_dn = talloc_steal(ac, ares->message->dn);
+
+ name = samdb_result_string(ares->message, "name", NULL);
+ ldb_debug(ac->module->ldb, LDB_DEBUG_TRACE,
+ "NOTE (strange but valid): Adding foreign SID "
+ "record with SID %s, but this domain (%s) is "
+ "not foreign in the database",
+ dom_sid_string(ares, ac->sid), name);
- if (ret == 0) {
- *ret_msg = msg2;
- talloc_steal(msg, msg2);
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_DONE:
+
+ /* if this is a fake foreign SID, notice the SID */
+ if (ac->domain_dn) {
+ ret = samldb_notice_sid(ac);
+ break;
+ }
+
+ /* found, go on */
+ ret = samldb_next_step(ac);
+ break;
+ }
+
+done:
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
}
- talloc_free(mem_ctx);
- return ret;
+
+ return LDB_SUCCESS;
}
-
-static int samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg,
- struct ldb_message **ret_msg)
+
+/* Find a domain object in the parents of a particular DN. */
+static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
{
- struct ldb_message *msg2;
- const char *rdn_name;
- struct dom_sid *dom_sid;
- struct dom_sid *sid;
- const char *dom_attrs[] = { "name", NULL };
- struct ldb_message **dom_msgs;
- const char *errstr;
+ static const char * const attrs[3] = { "nextRid", "name", NULL };
+ struct ldb_request *req;
+ char *filter;
int ret;
- TALLOC_CTX *mem_ctx = talloc_new(msg);
- if (!mem_ctx) {
+ if (ac->sid == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* build the new msg */
- msg2 = ldb_msg_copy(mem_ctx, msg);
- if (!msg2) {
- ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: ldb_msg_copy failed!\n");
- talloc_free(mem_ctx);
+ ac->domain_sid = dom_sid_dup(ac, ac->sid);
+ if (!ac->domain_sid) {
return LDB_ERR_OPERATIONS_ERROR;
}
+ /* get the domain component part of the provided SID */
+ ac->domain_sid->num_auths--;
- ret = samdb_copy_template(module->ldb, msg2,
- "ForeignSecurityPrincipal",
- &errstr);
- if (ret != 0) {
- ldb_asprintf_errstring(module->ldb,
- "samldb_fill_foreignSecurityPrincipal_object: "
- "Error copying template: %s",
- errstr);
- talloc_free(mem_ctx);
- return ret;
+ filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
+ ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
+ if (filter == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- rdn_name = ldb_dn_get_rdn_name(msg2->dn);
+ ret = ldb_build_search_req(&req, ac->module->ldb, ac,
+ ldb_get_default_basedn(ac->module->ldb),
+ LDB_SCOPE_SUBTREE,
+ filter, attrs,
+ NULL,
+ ac, samldb_foreign_notice_sid_callback,
+ ac->req);
- if (strcasecmp(rdn_name, "cn") != 0) {
- ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for ForeignSecurityPrincipal, should be CN=!", rdn_name);
- talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- sid = samdb_result_dom_sid(msg2, msg, "objectSid");
- if (!sid) {
- /* Slightly different for the foreign sids. We don't want
- * domain SIDs ending up there, it would cause all sorts of
- * pain */
-
- sid = dom_sid_parse_talloc(msg2, (const char *)ldb_dn_get_rdn_val(msg2->dn)->data);
- if (!sid) {
- ldb_set_errstring(module->ldb, "No valid found SID in ForeignSecurityPrincipal CN!");
- talloc_free(mem_ctx);
- return LDB_ERR_CONSTRAINT_VIOLATION;
- }
+ ac->next_rid = 0;
+ return ldb_next_request(ac->module, req);
+}
- if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
- talloc_free(sid);
- return LDB_ERR_OPERATIONS_ERROR;
- }
+static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
+{
+ int ret;
- dom_sid = dom_sid_dup(mem_ctx, sid);
- if (!dom_sid) {
- talloc_free(mem_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
+ ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
+ if (ac->sid == NULL) {
+ ac->sid = dom_sid_parse_talloc(ac->msg,
+ (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
+ if (!ac->sid) {
+ ldb_set_errstring(ac->module->ldb,
+ "No valid found SID in "
+ "ForeignSecurityPrincipal CN!");
+ talloc_free(ac);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
}
- /* get the domain component part of the provided SID */
- dom_sid->num_auths--;
-
- /* find the domain DN */
-
- ret = gendb_search(module->ldb,
- mem_ctx, NULL, &dom_msgs, dom_attrs,
- "(&(objectSid=%s)(objectclass=domain))",
- ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
- if (ret >= 1) {
- /* We don't really like the idea of foreign sids that are not foreign, but it happens */
- const char *name = samdb_result_string(dom_msgs[0], "name", NULL);
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "NOTE (strange but valid): Adding foreign SID record with SID %s, but this domian (%s) is already in the database",
- dom_sid_string(mem_ctx, sid), name);
- } else if (ret == -1) {
- ldb_asprintf_errstring(module->ldb,
- "samldb_fill_foreignSecurityPrincipal_object: error searching for a domain with this sid: %s\n",
- dom_sid_string(mem_ctx, dom_sid));
- talloc_free(dom_msgs);
+ if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
+ talloc_free(ac);
return LDB_ERR_OPERATIONS_ERROR;
}
}
- /* This isn't an operation on a domain we know about, so just
- * check for the SID, looking for duplicates via the common
- * code */
- ret = samldb_notice_sid(module, msg2, sid);
- if (ret == 0) {
- talloc_steal(msg, msg2);
- *ret_msg = msg2;
- }
-
- return ret;
+ /* first look for the template */
+ ac->type = "foreignSecurityPrincipal";
+ ret = samldb_add_step(ac, samldb_search_template);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* then apply it */
+ ret = samldb_add_step(ac, samldb_apply_template);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* check we do not already have this SID */
+ ret = samldb_add_step(ac, samldb_check_sid);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* check if we need to notice this SID */
+ ret = samldb_add_step(ac, samldb_foreign_notice_sid);
+ if (ret != LDB_SUCCESS) return ret;
+
+ /* finally proceed with adding the entry */
+ ret = samldb_add_step(ac, samldb_add_entry);
+ if (ret != LDB_SUCCESS) return ret;
+
+ return samldb_first_step(ac);
}
-/* add_record */
+static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
+{
+ const char *rdn_name;
-/*
- * FIXME
- *
- * Actually this module is not async at all as it does a number of sync searches
- * in the process. It still to be decided how to deal with it properly so it is
- * left SYNC for now until we think of a good solution.
- */
+ rdn_name = ldb_dn_get_rdn_name(dn);
+
+ if (strcasecmp(rdn_name, "cn") != 0) {
+ ldb_asprintf_errstring(module->ldb,
+ "Bad RDN (%s=) for samldb object, "
+ "should be CN=!\n", rdn_name);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ return LDB_SUCCESS;
+}
+
+/* add_record */
static int samldb_add(struct ldb_module *module, struct ldb_request *req)
{
- const struct ldb_message *msg = req->op.add.message;
- struct ldb_message *msg2 = NULL;
- struct ldb_request *down_req;
+ struct samldb_ctx *ac;
int ret;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
- if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
+ /* do not manipulate our control entries */
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
return ldb_next_request(module, req);
}
- /* is user or computer? */
- if ((samdb_find_attribute(module->ldb, msg, "objectclass", "user") != NULL) ||
- (samdb_find_attribute(module->ldb, msg, "objectclass", "computer") != NULL)) {
- /* add all relevant missing objects */
- ret = samldb_fill_user_or_computer_object(module, msg, &msg2);
- if (ret) {
- return ret;
- }
+ ac = samldb_ctx_init(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- /* is group? add all relevant missing objects */
- if ( ! msg2 ) {
- if (samdb_find_attribute(module->ldb, msg, "objectclass", "group") != NULL) {
- ret = samldb_fill_group_object(module, msg, &msg2);
- if (ret) {
- return ret;
- }
- }
+ /* build the new msg */
+ ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
+ if (!ac->msg) {
+ talloc_free(ac);
+ ldb_debug(ac->module->ldb, LDB_DEBUG_FATAL,
+ "samldb_add: ldb_msg_copy failed!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
}
- /* perhaps a foreignSecurityPrincipal? */
- if ( ! msg2 ) {
- if (samdb_find_attribute(module->ldb, msg, "objectclass", "foreignSecurityPrincipal") != NULL) {
- ret = samldb_fill_foreignSecurityPrincipal_object(module, msg, &msg2);
- if (ret) {
- return ret;
- }
+ if (samdb_find_attribute(module->ldb, ac->msg,
+ "objectclass", "computer") != NULL) {
+
+ /* make sure the computer object also has the 'user'
+ * objectclass so it will be handled by the next call */
+ ret = samdb_find_or_add_value(module->ldb, ac->msg,
+ "objectclass", "user");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ac);
+ return ret;
}
}
- if (msg2 == NULL) {
- return ldb_next_request(module, req);
- }
+ if (samdb_find_attribute(module->ldb, ac->msg,
+ "objectclass", "user") != NULL) {
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ac);
+ return ret;
+ }
+
+ return samldb_fill_object(ac, "user");
}
- *down_req = *req;
-
- down_req->op.add.message = talloc_steal(down_req, msg2);
+ if (samdb_find_attribute(module->ldb, ac->msg,
+ "objectclass", "group") != NULL) {
+
+ ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ac);
+ return ret;
+ }
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
+ return samldb_fill_object(ac, "group");
+ }
- /* go on with the call chain */
- ret = ldb_next_request(module, down_req);
+ /* perhaps a foreignSecurityPrincipal? */
+ if (samdb_find_attribute(module->ldb, ac->msg,
+ "objectclass",
+ "foreignSecurityPrincipal") != NULL) {
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ac);
+ return ret;
+ }
+
+ return samldb_fill_foreignSecurityPrincipal_object(ac);
}
- return ret;
+ talloc_free(ac);
+
+ /* nothing matched, go on */
+ return ldb_next_request(module, req);
}
/* modify */
@@ -777,6 +1315,8 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_UNWILLING_TO_PERFORM;
}
+ /* TODO: do not modify original request, create a new one */
+
el = ldb_msg_find_element(req->op.mod.message, "groupType");
if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
diff --git a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c
index 968b19c038..0266654811 100644
--- a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c
+++ b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c
@@ -29,7 +29,7 @@
#include "librpc/gen_ndr/ndr_misc.h"
#include "librpc/gen_ndr/ndr_drsuapi.h"
#include "librpc/gen_ndr/ndr_drsblobs.h"
-#include "lib/util/dlinklist.h"
+#include "../lib/util/dlinklist.h"
#include "param/param.h"
static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
@@ -62,8 +62,10 @@ struct schema_fsmo_private_data {
};
struct schema_fsmo_search_data {
- struct schema_fsmo_private_data *module_context;
- struct ldb_request *orig_req;
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ const struct dsdb_schema *schema;
};
static int schema_fsmo_init(struct ldb_module *module)
@@ -152,6 +154,16 @@ static int schema_fsmo_add(struct ldb_module *module, struct ldb_request *req)
uint32_t id32;
WERROR status;
+ /* special objects should always go through */
+ if (ldb_dn_is_special(req->op.add.message->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /* replicated update should always go through */
+ if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
+ return ldb_next_request(module, req);
+ }
+
schema = dsdb_get_schema(module->ldb);
if (!schema) {
return ldb_next_request(module, req);
@@ -307,7 +319,7 @@ static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message
}
}
}
- return 0;
+ return LDB_SUCCESS;
}
@@ -315,41 +327,54 @@ static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message
/* Add objectClasses, attributeTypes and dITContentRules from the
schema object (they are not stored in the database)
*/
-static int schema_fsmo_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int schema_fsmo_search_callback(struct ldb_request *req, struct ldb_reply *ares)
{
- const struct dsdb_schema *schema = dsdb_get_schema(ldb);
- struct schema_fsmo_search_data *search_data = talloc_get_type(context, struct schema_fsmo_search_data);
- struct ldb_request *orig_req = search_data->orig_req;
- TALLOC_CTX *mem_ctx;
+ struct schema_fsmo_search_data *ac;
+ struct schema_fsmo_private_data *mc;
int i, ret;
- /* Only entries are interesting, and we handle the case of the parent seperatly */
- if (ares->type != LDB_REPLY_ENTRY) {
- return orig_req->callback(ldb, orig_req->context, ares);
- }
+ ac = talloc_get_type(req->context, struct schema_fsmo_search_data);
+ mc = talloc_get_type(ac->module->private_data, struct schema_fsmo_private_data);
- if (ldb_dn_compare(ares->message->dn, search_data->module_context->aggregate_dn) != 0) {
- talloc_free(mem_ctx);
- return orig_req->callback(ldb, orig_req->context, ares);
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
-
- mem_ctx = talloc_new(ares);
- if (!mem_ctx) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
+ /* Only entries are interesting, and we handle the case of the parent seperatly */
- for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
- if (ldb_attr_in_list(orig_req->op.search.attrs, generated_attrs[i].attr)) {
- ret = generated_attrs[i].fn(ldb, ares->message, schema);
- if (ret != LDB_SUCCESS) {
- return ret;
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+ if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) != 0) {
+ return ldb_module_send_entry(ac->req, ares->message);
+ }
+
+ for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
+ if (ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
+ ret = generated_attrs[i].fn(ac->module->ldb, ares->message, ac->schema);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
}
}
+
+ return ldb_module_send_entry(ac->req, ares->message);
+
+ case LDB_REPLY_REFERRAL:
+
+ return ldb_module_send_referral(ac->req, ares->referral);
+
+ case LDB_REPLY_DONE:
+
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- talloc_free(mem_ctx);
- return orig_req->callback(ldb, orig_req->context, ares);
+ return LDB_SUCCESS;
}
/* search */
@@ -380,27 +405,24 @@ static int schema_fsmo_search(struct ldb_module *module, struct ldb_request *req
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- down_req = talloc(req, struct ldb_request);
- if (!down_req) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- *down_req = *req;
- search_context->orig_req = req;
- search_context->module_context = talloc_get_type(module->private_data, struct schema_fsmo_private_data);
- down_req->context = search_context;
- down_req->callback = schema_fsmo_search_callback;
+ search_context->module = module;
+ search_context->req = req;
+ search_context->schema = schema;
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ ret = ldb_build_search_req_ex(&down_req, module->ldb, search_context,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ req->op.search.attrs,
+ req->controls,
+ search_context, schema_fsmo_search_callback,
+ req);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return ret;
+
+ return ldb_next_request(module, down_req);
}
diff --git a/source4/dsdb/samdb/ldb_modules/show_deleted.c b/source4/dsdb/samdb/ldb_modules/show_deleted.c
index 361cf226dc..0e3b46debe 100644
--- a/source4/dsdb/samdb/ldb_modules/show_deleted.c
+++ b/source4/dsdb/samdb/ldb_modules/show_deleted.c
@@ -27,7 +27,7 @@
*
* Component: ldb deleted objects control module
*
- * Description: this module hides deleted objects, and returns them if the control is there
+ * Description: this module hides deleted objects, and returns them if the right control is there
*
* Author: Stefan Metzmacher
*/
@@ -42,36 +42,38 @@
struct show_deleted_search_request {
struct ldb_module *module;
- void *up_context;
- int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
-
- bool remove_from_msg;
+ struct ldb_request *req;
};
-static int show_deleted_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int show_deleted_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
struct show_deleted_search_request *ar;
- ar = talloc_get_type(context, struct show_deleted_search_request);
+ ar = talloc_get_type(req->context, struct show_deleted_search_request);
- if (ares->type == LDB_REPLY_ENTRY) {
- bool isDeleted;
+ if (!ares) {
+ return ldb_module_done(ar->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ar->req, ares->controls,
+ ares->response, ares->error);
+ }
- isDeleted = ldb_msg_find_attr_as_bool(ares->message, "isDeleted", false);
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
- if (isDeleted) {
- goto skip_deleted;
- }
+ return ldb_module_send_entry(ar->req, ares->message);
- if (ar->remove_from_msg) {
- ldb_msg_remove_attr(ares->message, "isDeleted");
- }
- }
+ case LDB_REPLY_REFERRAL:
+ return ldb_module_send_referral(ar->req, ares->referral);
- return ar->up_callback(ldb, ar->up_context, ares);
+ case LDB_REPLY_DONE:
+ return ldb_module_done(ar->req, ares->controls,
+ ares->response, LDB_SUCCESS);
-skip_deleted:
- talloc_free(ares);
+ }
return LDB_SUCCESS;
}
@@ -81,116 +83,68 @@ static int show_deleted_search(struct ldb_module *module, struct ldb_request *re
struct ldb_control **saved_controls;
struct show_deleted_search_request *ar;
struct ldb_request *down_req;
- char **new_attrs;
- uint32_t num_attrs = 0;
- uint32_t i;
+ char *old_filter;
+ char *new_filter;
int ret;
- /* check if there's a show deleted control */
- control = ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID);
-
- /* copy the request for modification */
- down_req = talloc(req, struct ldb_request);
- if (down_req == NULL) {
- ldb_oom(module->ldb);
+ ar = talloc_zero(req, struct show_deleted_search_request);
+ if (ar == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
+ ar->module = module;
+ ar->req = req;
- /* copy the request */
- *down_req = *req;
+ /* check if there's a show deleted control */
+ control = ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID);
- /* if a control is there remove if from the modified request */
- if (control && !save_controls(control, down_req, &saved_controls)) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
+ if ( ! control) {
+ old_filter = ldb_filter_from_tree(ar, req->op.search.tree);
+ new_filter = talloc_asprintf(ar, "(&(!(isDeleted=TRUE))%s)",
+ old_filter);
- /* if we had a control, then just go on to the next request as we have nothing to hide */
- if (control) {
- goto next_request;
- }
+ ret = ldb_build_search_req(&down_req, module->ldb, ar,
+ req->op.search.base,
+ req->op.search.scope,
+ new_filter,
+ req->op.search.attrs,
+ req->controls,
+ ar, show_deleted_search_callback,
+ req);
- ar = talloc(down_req, struct show_deleted_search_request);
- if (ar == NULL) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ar->module = module;
- ar->up_context = req->context;
- ar->up_callback = req->callback;
- ar->remove_from_msg = true;
-
- /* check if attrs only is specified, in that case check wether we need to modify them */
- if (down_req->op.search.attrs) {
- for (i=0; (down_req->op.search.attrs && down_req->op.search.attrs[i]); i++) {
- num_attrs++;
- if (strcasecmp(down_req->op.search.attrs[i], "*") == 0) {
- ar->remove_from_msg = false;
- } else if (strcasecmp(down_req->op.search.attrs[i], "isDeleted") == 0) {
- ar->remove_from_msg = false;
- }
- }
} else {
- ar->remove_from_msg = false;
+ ret = ldb_build_search_req_ex(&down_req, module->ldb, ar,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ req->op.search.attrs,
+ req->controls,
+ ar, show_deleted_search_callback,
+ req);
}
-
- if (ar->remove_from_msg) {
- new_attrs = talloc_array(down_req, char *, num_attrs + 2);
- if (!new_attrs) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- for (i=0; i < num_attrs; i++) {
- new_attrs[i] = discard_const_p(char, down_req->op.search.attrs[i]);
- }
- new_attrs[i] = talloc_strdup(new_attrs, "isDeleted");
- if (!new_attrs[i]) {
- ldb_oom(module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- new_attrs[i+1] = NULL;
- down_req->op.search.attrs = (const char * const *)new_attrs;
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
- down_req->context = ar;
- down_req->callback = show_deleted_search_callback;
- ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
-
-next_request:
- /* perform the search */
- ret = ldb_next_request(module, down_req);
-
- /* do not free down_req as the call results may be linked to it,
- * it will be freed when the upper level request get freed */
- if (ret == LDB_SUCCESS) {
- req->handle = down_req->handle;
+ /* if a control is there remove if from the modified request */
+ if (control && !save_controls(control, down_req, &saved_controls)) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return ret;
+ /* perform the search */
+ return ldb_next_request(module, down_req);
}
static int show_deleted_init(struct ldb_module *module)
{
- struct ldb_request *req;
int ret;
- req = talloc(module, struct ldb_request);
- if (req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_REQ_REGISTER_CONTROL;
- req->op.reg_control.oid = LDB_CONTROL_SHOW_DELETED_OID;
- req->controls = NULL;
-
- ret = ldb_request(module->ldb, req);
+ ret = ldb_mod_register_control(module, LDB_CONTROL_SHOW_DELETED_OID);
if (ret != LDB_SUCCESS) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "show_deleted: Unable to register control with rootdse!\n");
- talloc_free(req);
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR,
+ "extended_dn: Unable to register control with rootdse!\n");
return LDB_ERR_OPERATIONS_ERROR;
}
- talloc_free(req);
return ldb_next_init(module);
}
diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c
index 8f92995145..c353914e2c 100644
--- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c
+++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c
@@ -36,6 +36,11 @@
#include "librpc/ndr/libndr.h"
#include "dsdb/samdb/samdb.h"
+struct entryuuid_private {
+ struct ldb_context *ldb;
+ struct ldb_dn **base_dns;
+};
+
static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
{
struct GUID guid;
@@ -598,10 +603,18 @@ static int nsuniqueid_init(struct ldb_module *module)
return ldb_next_init(module);
}
-static int get_seq(struct ldb_context *ldb, void *context,
- struct ldb_reply *ares)
+static int get_seq_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
- unsigned long long *seq = (unsigned long long *)context;
+ unsigned long long *seq = (unsigned long long *)req->context;
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_request_done(req, ares->error);
+ }
+
if (ares->type == LDB_REPLY_ENTRY) {
struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
if (el) {
@@ -609,6 +622,11 @@ static int get_seq(struct ldb_context *ldb, void *context,
}
}
+ if (ares->type == LDB_REPLY_DONE) {
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ talloc_free(ares);
return LDB_SUCCESS;
}
@@ -617,7 +635,7 @@ static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_reque
int ret;
struct map_private *map_private;
struct entryuuid_private *entryuuid_private;
- unsigned long long seq = 0;
+ unsigned long long seq_num = 0;
struct ldb_request *search_req;
const struct ldb_control *partition_ctrl;
@@ -627,6 +645,12 @@ static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_reque
"contextCSN", NULL
};
+ struct ldb_seqnum_request *seq;
+ struct ldb_seqnum_result *seqr;
+ struct ldb_extended *ext;
+
+ seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
+
map_private = talloc_get_type(module->private_data, struct map_private);
entryuuid_private = talloc_get_type(map_private->caller_private, struct entryuuid_private);
@@ -635,7 +659,7 @@ static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_reque
partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
if (!partition_ctrl) {
ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
- "instancetype_add: no current partition control found");
+ "entryuuid_sequence_number: no current partition control found");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
@@ -643,74 +667,79 @@ static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_reque
struct dsdb_control_current_partition);
SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
- search_req = talloc(req, struct ldb_request);
- if (search_req == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = ldb_build_search_req(&search_req, module->ldb, req,
+ partition->dn, LDB_SCOPE_BASE,
+ NULL, contextCSN_attr, NULL,
+ &seq_num, get_seq_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
-
- /* Finally, we have it. This saves searching over more
- * partitions than we expose to the client, such as a cn=samba
- * configuration partition */
- search_req->operation = LDB_SEARCH;
- search_req->op.search.base = partition->dn;
- search_req->op.search.scope = LDB_SCOPE_BASE;
-
- search_req->op.search.tree = ldb_parse_tree(search_req, "objectClass=*");
- if (search_req->op.search.tree == NULL) {
- ldb_set_errstring(module->ldb, "Unable to parse search expression");
- talloc_free(search_req);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- search_req->op.search.attrs = contextCSN_attr;
- search_req->controls = NULL;
- search_req->context = &seq;
- search_req->callback = get_seq;
- ldb_set_timeout(module->ldb, search_req, 0); /* use default timeout */
-
ret = ldb_next_request(module, search_req);
-
+
if (ret == LDB_SUCCESS) {
ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
}
-
+
talloc_free(search_req);
if (ret != LDB_SUCCESS) {
return ret;
}
- switch (req->op.seq_num.type) {
+ ext = talloc_zero(req, struct ldb_extended);
+ if (!ext) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ seqr = talloc_zero(req, struct ldb_seqnum_result);
+ if (seqr == NULL) {
+ talloc_free(ext);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
+ ext->data = seqr;
+
+ switch (seq->type) {
case LDB_SEQ_HIGHEST_SEQ:
- req->op.seq_num.seq_num = seq;
+ seqr->seq_num = seq_num;
break;
case LDB_SEQ_NEXT:
- req->op.seq_num.seq_num = seq;
- req->op.seq_num.seq_num++;
+ seqr->seq_num = seq_num;
+ seqr->seq_num++;
break;
case LDB_SEQ_HIGHEST_TIMESTAMP:
{
- req->op.seq_num.seq_num = (seq >> 24);
+ seqr->seq_num = (seq_num >> 24);
break;
}
}
- req->op.seq_num.flags = 0;
- req->op.seq_num.flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
- req->op.seq_num.flags |= LDB_SEQ_GLOBAL_SEQUENCE;
- return LDB_SUCCESS;
+ seqr->flags = 0;
+ seqr->flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
+ seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
+
+ /* send request done */
+ return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
+}
+
+static int entryuuid_extended(struct ldb_module *module, struct ldb_request *req)
+{
+ if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
+ return entryuuid_sequence_number(module, req);
+ }
+
+ return ldb_next_request(module, req);
}
_PUBLIC_ const struct ldb_module_ops ldb_entryuuid_module_ops = {
.name = "entryuuid",
.init_context = entryuuid_init,
- .sequence_number = entryuuid_sequence_number,
+ .extended = entryuuid_extended,
LDB_MAP_OPS
};
_PUBLIC_ const struct ldb_module_ops ldb_nsuniqueid_module_ops = {
.name = "nsuniqueid",
.init_context = nsuniqueid_init,
- .sequence_number = entryuuid_sequence_number,
+ .extended = entryuuid_extended,
LDB_MAP_OPS
};
diff --git a/source4/dsdb/samdb/ldb_modules/subtree_delete.c b/source4/dsdb/samdb/ldb_modules/subtree_delete.c
index 9c332d2969..10e2dc25ce 100644
--- a/source4/dsdb/samdb/ldb_modules/subtree_delete.c
+++ b/source4/dsdb/samdb/ldb_modules/subtree_delete.c
@@ -3,6 +3,7 @@
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2007
Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+ Copyright (C) Simo Sorce <idra@samba.org> 2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,104 +32,88 @@
#include "ldb_includes.h"
struct subtree_delete_context {
- enum sd_step {SD_SEARCH, SD_DO_DEL} 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 *req;
int num_children;
};
-static struct subtree_delete_context *subtree_delete_init_handle(struct ldb_request *req,
- struct ldb_module *module)
+static struct subtree_delete_context *subdel_ctx_init(struct ldb_module *module,
+ struct ldb_request *req)
{
struct subtree_delete_context *ac;
- struct ldb_handle *h;
-
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- return NULL;
- }
-
- h->module = module;
- ac = talloc_zero(h, struct subtree_delete_context);
+ ac = talloc_zero(req, struct subtree_delete_context);
if (ac == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- talloc_free(h);
+ ldb_oom(module->ldb);
return NULL;
}
- h->private_data = ac;
-
ac->module = module;
- ac->handle = h;
- ac->orig_req = req;
-
- req->handle = h;
+ ac->req = req;
return ac;
}
-static int subtree_delete_check_for_children(struct subtree_delete_context *ac)
+static int subtree_delete_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
{
- if (ac->num_children > 0) {
- ldb_asprintf_errstring(ac->module->ldb, "Cannot delete %s, not a leaf node (has %d children)\n",
- ldb_dn_get_linearized(ac->orig_req->op.del.dn), ac->num_children);
- return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF;
- } else {
- struct ldb_request *req = talloc(ac, struct ldb_request);
- if (!req) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- *req = *ac->orig_req;
-
- /* Ensure any (io) errors during the search for
- * children don't propgate back in the error string */
- ldb_set_errstring(ac->module->ldb, NULL);
+ struct subtree_delete_context *ac;
+ int ret;
- ac->down_req = req;
- ac->step = SD_DO_DEL;
- return ldb_next_request(ac->module, req);
- }
-}
+ ac = talloc_get_type(req->context, struct subtree_delete_context);
-static int subtree_delete_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
-{
- struct subtree_delete_context *ac = talloc_get_type(context, struct subtree_delete_context);
- TALLOC_CTX *mem_ctx = talloc_new(ac);
-
- if (!mem_ctx) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
}
- /* OK, we have one of *many* search results here:
- We should also get the entry we tried to rename. This
- callback handles this and everything below it.
- */
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
- /* Only entries are interesting, and we handle the case of the parent seperatly */
- if (ares->type == LDB_REPLY_ENTRY
- && ldb_dn_compare(ares->message->dn, ac->orig_req->op.del.dn) != 0) {
- /* And it is an actual entry: now object bitterly that we are not a leaf node */
+ talloc_free(ares);
ac->num_children++;
+ break;
+
+ case LDB_REPLY_REFERRAL:
+
+ /* ignore */
+ talloc_free(ares);
+ break;
+
+ case LDB_REPLY_DONE:
+
+ if (ac->num_children > 0) {
+ talloc_free(ares);
+ ldb_asprintf_errstring(ac->module->ldb,
+ "Cannot delete %s, not a leaf node "
+ "(has %d children)\n",
+ ldb_dn_get_linearized(ac->req->op.del.dn),
+ ac->num_children);
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_NOT_ALLOWED_ON_NON_LEAF);
+ }
+
+ /* ok no children, let the original request through */
+ ret = ldb_next_request(ac->module, ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ /* free our own context we are not going to be called back */
+ talloc_free(ac);
}
- talloc_free(ares);
return LDB_SUCCESS;
}
-/* rename */
static int subtree_delete(struct ldb_module *module, struct ldb_request *req)
{
- const char *attrs[] = { NULL };
- struct ldb_request *new_req;
+ static const char * const attrs[2] = { "distinguishedName", NULL };
+ struct ldb_request *search_req;
struct subtree_delete_context *ac;
int ret;
if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
@@ -142,119 +127,28 @@ static int subtree_delete(struct ldb_module *module, struct ldb_request *req)
- return an error if there are any
*/
- ac = subtree_delete_init_handle(req, module);
+ ac = subdel_ctx_init(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_build_search_req(&new_req, module->ldb, req,
- req->op.del.dn,
- LDB_SCOPE_SUBTREE,
- "(objectClass=*)",
- attrs,
+ /* we do not really need to find all descendents,
+ * if there is even one single direct child, that's
+ * enough to bail out */
+ ret = ldb_build_search_req(&search_req, module->ldb, ac,
+ req->op.del.dn, LDB_SCOPE_ONELEVEL,
+ "(objectClass=*)", attrs,
req->controls,
- ac,
- subtree_delete_search_callback);
-
+ ac, subtree_delete_search_callback,
+ req);
if (ret != LDB_SUCCESS) {
return ret;
}
- ret = ldb_set_timeout_from_prev_req(module->ldb, req, new_req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ac->search_req = new_req;
- if (req == NULL) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- return ldb_next_request(module, new_req);
-}
-
-
-static int subtree_delete_wait_none(struct ldb_handle *handle) {
- struct subtree_delete_context *ac;
- int ret = LDB_ERR_OPERATIONS_ERROR;
- if (!handle || !handle->private_data) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
- }
-
- handle->state = LDB_ASYNC_PENDING;
- handle->status = LDB_SUCCESS;
-
- ac = talloc_get_type(handle->private_data, struct subtree_delete_context);
-
- switch (ac->step) {
- case SD_SEARCH:
- ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) {
- handle->status = ret;
- goto done;
- }
- if (ac->search_req->handle->status != LDB_SUCCESS
- && ac->search_req->handle->status != LDB_ERR_NO_SUCH_OBJECT) {
- handle->status = ac->search_req->handle->status;
- goto done;
- }
-
- return subtree_delete_check_for_children(ac);
-
- case SD_DO_DEL:
- ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->down_req->handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req->handle->status;
- goto done;
- }
-
- if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
-
- break;
- }
-done:
- handle->state = LDB_ASYNC_DONE;
- return ret;
-}
-
-static int subtree_delete_wait_all(struct ldb_handle *handle) {
-
- int ret;
-
- while (handle->state != LDB_ASYNC_DONE) {
- ret = subtree_delete_wait_none(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
-
- return handle->status;
-}
-
-static int subtree_delete_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- if (type == LDB_WAIT_ALL) {
- return subtree_delete_wait_all(handle);
- } else {
- return subtree_delete_wait_none(handle);
- }
+ return ldb_next_request(module, search_req);
}
const struct ldb_module_ops ldb_subtree_delete_module_ops = {
.name = "subtree_delete",
.del = subtree_delete,
- .wait = subtree_delete_wait,
};
diff --git a/source4/dsdb/samdb/ldb_modules/subtree_rename.c b/source4/dsdb/samdb/ldb_modules/subtree_rename.c
index fd1388d416..d3ceb8ad97 100644
--- a/source4/dsdb/samdb/ldb_modules/subtree_rename.c
+++ b/source4/dsdb/samdb/ldb_modules/subtree_rename.c
@@ -30,137 +30,182 @@
#include "ldb_includes.h"
+struct subren_msg_store {
+ struct subren_msg_store *next;
+ struct ldb_dn *olddn;
+ struct ldb_dn *newdn;
+};
+
struct subtree_rename_context {
struct ldb_module *module;
- struct ldb_handle *handle;
- struct ldb_request *orig_req;
-
- struct ldb_request **down_req;
- int num_requests;
- int finished_requests;
+ struct ldb_request *req;
- int num_children;
+ struct subren_msg_store *list;
+ struct subren_msg_store *current;
};
-static struct subtree_rename_context *subtree_rename_init_handle(struct ldb_request *req,
- struct ldb_module *module)
+static struct subtree_rename_context *subren_ctx_init(struct ldb_module *module,
+ struct ldb_request *req)
{
struct subtree_rename_context *ac;
- struct ldb_handle *h;
- h = talloc_zero(req, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
+ ac = talloc_zero(req, struct subtree_rename_context);
+ if (ac == NULL) {
+ ldb_oom(module->ldb);
return NULL;
}
- h->module = module;
+ ac->module = module;
+ ac->req = req;
- ac = talloc_zero(h, struct subtree_rename_context);
- if (ac == NULL) {
- ldb_set_errstring(module->ldb, "Out of Memory");
- talloc_free(h);
- return NULL;
+ return ac;
+}
+
+static int subtree_rename_next_request(struct subtree_rename_context *ac);
+
+static int subtree_rename_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct subtree_rename_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct subtree_rename_context);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- h->private_data = ac;
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
- ac->module = module;
- ac->handle = h;
- ac->orig_req = req;
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb, "Invalid reply type!\n");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
- req->handle = h;
+ if (ac->current == NULL) {
+ /* this was the last one */
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+ }
- return ac;
-}
+ ret = subtree_rename_next_request(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ talloc_free(ares);
+ return LDB_SUCCESS;
+}
-static int subtree_rename_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int subtree_rename_next_request(struct subtree_rename_context *ac)
{
struct ldb_request *req;
- struct subtree_rename_context *ac = talloc_get_type(context, struct subtree_rename_context);
- TALLOC_CTX *mem_ctx = talloc_new(ac);
-
- if (!mem_ctx) {
- ldb_oom(ac->module->ldb);
+ int ret;
+
+ if (ac->current == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* OK, we have one of *many* search results here:
-
- We should also get the entry we tried to rename. This
- callback handles this and everything below it.
- */
-
- /* Only entries are interesting, and we handle the case of the parent seperatly */
- if (ares->type == LDB_REPLY_ENTRY
- && ldb_dn_compare(ares->message->dn, ac->orig_req->op.rename.olddn) != 0) {
- /* And it is an actual entry: now create a rename from it */
- int ret;
-
- struct ldb_dn *newdn = ldb_dn_copy(mem_ctx, ares->message->dn);
- if (!newdn) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+
+ ret = ldb_build_rename_req(&req, ac->module->ldb, ac->current,
+ ac->current->olddn,
+ ac->current->newdn,
+ ac->req->controls,
+ ac, subtree_rename_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ac->current = ac->current->next;
+
+ return ldb_next_request(ac->module, req);
+}
+
+static int subtree_rename_search_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct subren_msg_store *store;
+ struct subtree_rename_context *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct subtree_rename_context);
+
+ if (!ares || !ac->current) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+ if (ldb_dn_compare(ares->message->dn, ac->list->olddn) == 0) {
+ /* this was already stored by the
+ * subtree_rename_search() */
+ talloc_free(ares);
+ return LDB_SUCCESS;
}
-
- ldb_dn_remove_base_components(newdn, ldb_dn_get_comp_num(ac->orig_req->op.rename.olddn));
- if (!ldb_dn_add_base(newdn, ac->orig_req->op.rename.newdn)) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
+ store = talloc_zero(ac, struct subren_msg_store);
+ if (store == NULL) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
+ ac->current->next = store;
+ ac->current = store;
- ret = ldb_build_rename_req(&req, ldb, mem_ctx,
- ares->message->dn,
- newdn,
- NULL,
- NULL,
- NULL);
-
- if (ret != LDB_SUCCESS) {
- return ret;
+ /* the first list element contains the base for the rename */
+ store->olddn = talloc_steal(store, ares->message->dn);
+ store->newdn = ldb_dn_copy(store, store->olddn);
+
+ if ( ! ldb_dn_remove_base_components(store->newdn,
+ ldb_dn_get_comp_num(ac->list->olddn))) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- ret = ldb_set_timeout_from_prev_req(ldb, ac->orig_req, req);
-
- if (ret != LDB_SUCCESS) {
- return ret;
+ if ( ! ldb_dn_add_base(store->newdn, ac->list->newdn)) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
}
- talloc_steal(req, newdn);
+ break;
- talloc_steal(req, ares->message->dn);
-
- talloc_free(ares);
-
- } else if (ares->type == LDB_REPLY_DONE) {
- req = talloc(mem_ctx, struct ldb_request);
- *req = *ac->orig_req;
- talloc_free(ares);
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ break;
- } else {
- talloc_free(ares);
- return LDB_SUCCESS;
- }
-
- 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;
+ case LDB_REPLY_DONE:
+
+ /* rewind ac->current */
+ ac->current = ac->list;
+
+ /* All dns set up, start with the first one */
+ ret = subtree_rename_next_request(ac);
+
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+ break;
}
- ac->down_req[ac->num_requests] = req;
- ac->num_requests++;
-
- return ldb_next_request(ac->module, req);
-
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
}
/* rename */
static int subtree_rename(struct ldb_module *module, struct ldb_request *req)
{
- const char *attrs[] = { NULL };
- struct ldb_request *new_req;
+ static const char *attrs[2] = { "distinguishedName", NULL };
+ struct ldb_request *search_req;
struct subtree_rename_context *ac;
int ret;
if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
@@ -176,110 +221,37 @@ static int subtree_rename(struct ldb_module *module, struct ldb_request *req)
- Regain our sainity
*/
- ac = subtree_rename_init_handle(req, module);
+ ac = subren_ctx_init(module, req);
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_build_search_req(&new_req, module->ldb, req,
+ /* add this entry as the first to do */
+ ac->current = talloc_zero(ac, struct subren_msg_store);
+ if (ac->current == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ac->current->olddn = req->op.rename.olddn;
+ ac->current->newdn = req->op.rename.newdn;
+ ac->list = ac->current;
+
+ ret = ldb_build_search_req(&search_req, module->ldb, ac,
req->op.rename.olddn,
LDB_SCOPE_SUBTREE,
"(objectClass=*)",
attrs,
- req->controls,
+ NULL,
ac,
- subtree_rename_search_callback);
-
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_set_timeout_from_prev_req(module->ldb, req, new_req);
-
+ subtree_rename_search_callback,
+ req);
if (ret != LDB_SUCCESS) {
return ret;
}
- 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] = new_req;
- if (req == NULL) {
- ldb_oom(ac->module->ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ac->num_requests++;
- return ldb_next_request(module, new_req);
-}
-
-
-static int subtree_rename_wait_none(struct ldb_handle *handle) {
- struct subtree_rename_context *ac;
- int i, ret = LDB_ERR_OPERATIONS_ERROR;
- if (!handle || !handle->private_data) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
- }
-
- handle->state = LDB_ASYNC_PENDING;
- handle->status = LDB_SUCCESS;
-
- ac = talloc_get_type(handle->private_data, struct subtree_rename_context);
-
- for (i=0; i < ac->num_requests; i++) {
- ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
-
- if (ret != LDB_SUCCESS) {
- handle->status = ret;
- goto done;
- }
- if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req[i]->handle->status;
- goto done;
- }
-
- if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
- return LDB_SUCCESS;
- }
- }
-
-done:
- handle->state = LDB_ASYNC_DONE;
- return ret;
-
-}
-
-static int subtree_rename_wait_all(struct ldb_handle *handle) {
-
- int ret;
-
- while (handle->state != LDB_ASYNC_DONE) {
- ret = subtree_rename_wait_none(handle);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
-
- return handle->status;
-}
-
-static int subtree_rename_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- if (type == LDB_WAIT_ALL) {
- return subtree_rename_wait_all(handle);
- } else {
- return subtree_rename_wait_none(handle);
- }
+ return ldb_next_request(module, search_req);
}
const struct ldb_module_ops ldb_subtree_rename_module_ops = {
.name = "subtree_rename",
.rename = subtree_rename,
- .wait = subtree_rename_wait,
};
diff --git a/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py b/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py
index 428e6b4d4b..1fc531902d 100644
--- a/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py
+++ b/source4/dsdb/samdb/ldb_modules/tests/samba3sam.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2005-2007
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2005-2008
# Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
#
# This is a Python port of the original in testprogs/ejs/samba3sam.js
@@ -23,19 +23,26 @@
"""Tests for the samba3sam LDB module, which maps Samba3 LDAP to AD LDAP."""
import os
-import sys
-import samba
import ldb
from ldb import SCOPE_DEFAULT, SCOPE_BASE, SCOPE_SUBTREE
from samba import Ldb, substitute_var
-from samba.tests import LdbTestCase, TestCaseInTempDir
+from samba.tests import LdbTestCase, TestCaseInTempDir, cmdline_loadparm
+import samba.dcerpc.security
+import samba.security
+import samba.ndr
+
+datadir = os.path.join(os.path.dirname(__file__),
+ "../../../../../testdata/samba3")
+
+def read_datafile(filename):
+ return open(os.path.join(datadir, filename), 'r').read()
+
+def ldb_debug(l, text):
+ print text
-datadir = os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3")
class MapBaseTestCase(TestCaseInTempDir):
- def setup_data(self, obj, ldif):
- self.assertTrue(ldif is not None)
- obj.db.add_ldif(substitute_var(ldif, obj.substvars))
+ """Base test case for mapping tests."""
def setup_modules(self, ldb, s3, s4):
ldb.add({"dn": "@MAP=samba3sam",
@@ -46,40 +53,53 @@ class MapBaseTestCase(TestCaseInTempDir):
"@LIST": "rootdse,paged_results,server_sort,extended_dn,asq,samldb,password_hash,operational,objectguid,rdn_name,samba3sam,partition"})
ldb.add({"dn": "@PARTITION",
- "partition": [s4.basedn + ":" + s4.url, s3.basedn + ":" + s3.url],
+ "partition": ["%s:%s" % (s4.basedn, s4.url),
+ "%s:%s" % (s3.basedn, s3.url)],
"replicateEntries": ["@ATTRIBUTES", "@INDEXLIST"]})
def setUp(self):
super(MapBaseTestCase, self).setUp()
def make_dn(basedn, rdn):
- return rdn + ",sambaDomainName=TESTS," + basedn
+ return "%s,sambaDomainName=TESTS,%s" % (rdn, basedn)
def make_s4dn(basedn, rdn):
- return rdn + "," + basedn
+ return "%s,%s" % (rdn, basedn)
self.ldbfile = os.path.join(self.tempdir, "test.ldb")
self.ldburl = "tdb://" + self.ldbfile
tempdir = self.tempdir
- print tempdir
class Target:
- """Simple helper class that contains data for a specific SAM connection."""
+ """Simple helper class that contains data for a specific SAM
+ connection."""
def __init__(self, file, basedn, dn):
self.file = os.path.join(tempdir, file)
self.url = "tdb://" + self.file
self.basedn = basedn
self.substvars = {"BASEDN": self.basedn}
- self.db = Ldb()
+ self.db = Ldb(lp=cmdline_loadparm)
self._dn = dn
def dn(self, rdn):
- return self._dn(rdn, self.basedn)
+ return self._dn(self.basedn, rdn)
def connect(self):
return self.db.connect(self.url)
+ def setup_data(self, path):
+ self.add_ldif(read_datafile(path))
+
+ def subst(self, text):
+ return substitute_var(text, self.substvars)
+
+ def add_ldif(self, ldif):
+ self.db.add_ldif(self.subst(ldif))
+
+ def modify_ldif(self, ldif):
+ self.db.modify_ldif(self.subst(ldif))
+
self.samba4 = Target("samba4.ldb", "dc=vernstok,dc=nl", make_s4dn)
self.samba3 = Target("samba3.ldb", "cn=Samba3Sam", make_dn)
self.templates = Target("templates.ldb", "cn=templates", None)
@@ -95,56 +115,70 @@ class MapBaseTestCase(TestCaseInTempDir):
os.unlink(self.samba4.file)
super(MapBaseTestCase, self).tearDown()
+ def assertSidEquals(self, text, ndr_sid):
+ sid_obj1 = samba.ndr.ndr_unpack(samba.dcerpc.security.dom_sid,
+ str(ndr_sid[0]))
+ sid_obj2 = samba.security.Sid(text)
+ # For now, this is the only way we can compare these since the
+ # classes are in different places. Should reconcile that at some point.
+ self.assertEquals(sid_obj1.sid_rev_num, sid_obj2.sid_rev_num)
+ self.assertEquals(sid_obj1.num_auths, sid_obj2.num_auths)
+ # FIXME: self.assertEquals(sid_obj1.id_auth, sid_obj2.id_auth)
+ # FIXME: self.assertEquals(sid_obj1.sub_auths[:sid_obj1.num_auths],
+ # sid_obj2.sub_auths[:sid_obj2.num_auths])
+
class Samba3SamTestCase(MapBaseTestCase):
+
def setUp(self):
super(Samba3SamTestCase, self).setUp()
- ldb = Ldb(self.ldburl)
- self.setup_data(self.samba3, open(os.path.join(datadir, "samba3.ldif"), 'r').read())
- self.setup_data(self.templates, open(os.path.join(datadir, "provision_samba3sam_templates.ldif"), 'r').read())
- ldif = open(os.path.join(datadir, "provision_samba3sam.ldif"), 'r').read()
- ldb.add_ldif(substitute_var(ldif, self.samba4.substvars))
+ ldb = Ldb(self.ldburl, lp=cmdline_loadparm)
+ self.samba3.setup_data("samba3.ldif")
+ self.templates.setup_data("provision_samba3sam_templates.ldif")
+ ldif = read_datafile("provision_samba3sam.ldif")
+ ldb.add_ldif(self.samba4.subst(ldif))
self.setup_modules(ldb, self.samba3, self.samba4)
- self.ldb = Ldb(self.ldburl)
+ del ldb
+ self.ldb = Ldb(self.ldburl, lp=cmdline_loadparm)
- def test_s3sam_search(self):
- print "Looking up by non-mapped attribute"
+ def test_search_non_mapped(self):
+ """Looking up by non-mapped attribute"""
msg = self.ldb.search(expression="(cn=Administrator)")
self.assertEquals(len(msg), 1)
self.assertEquals(msg[0]["cn"], "Administrator")
- print "Looking up by mapped attribute"
+ def test_search_non_mapped(self):
+ """Looking up by mapped attribute"""
msg = self.ldb.search(expression="(name=Backup Operators)")
self.assertEquals(len(msg), 1)
self.assertEquals(msg[0]["name"], "Backup Operators")
- print "Looking up by old name of renamed attribute"
+ def test_old_name_of_renamed(self):
+ """Looking up by old name of renamed attribute"""
msg = self.ldb.search(expression="(displayName=Backup Operators)")
self.assertEquals(len(msg), 0)
- print "Looking up mapped entry containing SID"
+ def test_mapped_containing_sid(self):
+ """Looking up mapped entry containing SID"""
msg = self.ldb.search(expression="(cn=Replicator)")
self.assertEquals(len(msg), 1)
- print msg[0].dn
- self.assertEquals(str(msg[0].dn), "cn=Replicator,ou=Groups,dc=vernstok,dc=nl")
- self.assertEquals(msg[0]["objectSid"], "S-1-5-21-4231626423-2410014848-2360679739-552")
-
- print "Checking mapping of objectClass"
+ self.assertEquals(str(msg[0].dn),
+ "cn=Replicator,ou=Groups,dc=vernstok,dc=nl")
+ self.assertTrue("objectSid" in msg[0])
+ self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
+ msg[0]["objectSid"])
oc = set(msg[0]["objectClass"])
- self.assertTrue(oc is not None)
- for i in oc:
- self.assertEquals(oc[i] == "posixGroup" or oc[i], "group")
+ self.assertEquals(oc, set(["group"]))
- print "Looking up by objectClass"
+ def test_search_by_objclass(self):
+ """Looking up by objectClass"""
msg = self.ldb.search(expression="(|(objectClass=user)(cn=Administrator))")
- self.assertEquals(len(msg), 2)
- for i in range(len(msg)):
- self.assertEquals((str(msg[i].dn), "unixName=Administrator,ou=Users,dc=vernstok,dc=nl") or
- (str(msg[i].dn) == "unixName=nobody,ou=Users,dc=vernstok,dc=nl"))
-
+ self.assertEquals(set([str(m.dn) for m in msg]),
+ set(["unixName=Administrator,ou=Users,dc=vernstok,dc=nl",
+ "unixName=nobody,ou=Users,dc=vernstok,dc=nl"]))
def test_s3sam_modify(self):
- print "Adding a record that will be fallbacked"
+ # Adding a record that will be fallbacked
self.ldb.add({"dn": "cn=Foo",
"foo": "bar",
"blah": "Blie",
@@ -152,33 +186,36 @@ class Samba3SamTestCase(MapBaseTestCase):
"showInAdvancedViewOnly": "TRUE"}
)
- print "Checking for existence of record (local)"
- # TODO: This record must be searched in the local database, which is currently only supported for base searches
+ # Checking for existence of record (local)
+ # TODO: This record must be searched in the local database, which is
+ # currently only supported for base searches
# msg = ldb.search(expression="(cn=Foo)", ['foo','blah','cn','showInAdvancedViewOnly')]
# TODO: Actually, this version should work as well but doesn't...
#
#
- msg = self.ldb.search(expression="(cn=Foo)", base="cn=Foo", scope=SCOPE_BASE, attrs=['foo','blah','cn','showInAdvancedViewOnly'])
+ msg = self.ldb.search(expression="(cn=Foo)", base="cn=Foo",
+ scope=SCOPE_BASE,
+ attrs=['foo','blah','cn','showInAdvancedViewOnly'])
self.assertEquals(len(msg), 1)
self.assertEquals(msg[0]["showInAdvancedViewOnly"], "TRUE")
self.assertEquals(msg[0]["foo"], "bar")
self.assertEquals(msg[0]["blah"], "Blie")
- print "Adding record that will be mapped"
+ # Adding record that will be mapped
self.ldb.add({"dn": "cn=Niemand,cn=Users,dc=vernstok,dc=nl",
"objectClass": "user",
"unixName": "bin",
"sambaUnicodePwd": "geheim",
"cn": "Niemand"})
- print "Checking for existence of record (remote)"
+ # Checking for existence of record (remote)
msg = self.ldb.search(expression="(unixName=bin)",
attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
self.assertEquals(len(msg), 1)
self.assertEquals(msg[0]["cn"], "Niemand")
self.assertEquals(msg[0]["sambaUnicodePwd"], "geheim")
- print "Checking for existence of record (local && remote)"
+ # Checking for existence of record (local && remote)
msg = self.ldb.search(expression="(&(unixName=bin)(sambaUnicodePwd=geheim))",
attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
self.assertEquals(len(msg), 1) # TODO: should check with more records
@@ -186,21 +223,23 @@ class Samba3SamTestCase(MapBaseTestCase):
self.assertEquals(msg[0]["unixName"], "bin")
self.assertEquals(msg[0]["sambaUnicodePwd"], "geheim")
- print "Checking for existence of record (local || remote)"
+ # Checking for existence of record (local || remote)
msg = self.ldb.search(expression="(|(unixName=bin)(sambaUnicodePwd=geheim))",
attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
- print "got " + len(msg) + " replies"
+ #print "got %d replies" % len(msg)
self.assertEquals(len(msg), 1) # TODO: should check with more records
self.assertEquals(msg[0]["cn"], "Niemand")
- self.assertEquals(msg[0]["unixName"] == "bin" or msg[0]["sambaUnicodePwd"], "geheim")
+ self.assertEquals(msg[0]["unixName"], "bin")
+ self.assertEquals(msg[0]["sambaUnicodePwd"], "geheim")
- print "Checking for data in destination database"
- msg = s3.db.search("(cn=Niemand)")
+ # Checking for data in destination database
+ msg = self.samba3.db.search(expression="(cn=Niemand)")
self.assertTrue(len(msg) >= 1)
- self.assertEquals(msg[0]["sambaSID"], "S-1-5-21-4231626423-2410014848-2360679739-2001")
+ self.assertEquals(msg[0]["sambaSID"],
+ "S-1-5-21-4231626423-2410014848-2360679739-2001")
self.assertEquals(msg[0]["displayName"], "Niemand")
- print "Adding attribute..."
+ # Adding attribute...
self.ldb.modify_ldif("""
dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
changetype: modify
@@ -208,13 +247,13 @@ add: description
description: Blah
""")
- print "Checking whether changes are still there..."
+ # Checking whether changes are still there...
msg = self.ldb.search(expression="(cn=Niemand)")
self.assertTrue(len(msg) >= 1)
self.assertEquals(msg[0]["cn"], "Niemand")
self.assertEquals(msg[0]["description"], "Blah")
- print "Modifying attribute..."
+ # Modifying attribute...
self.ldb.modify_ldif("""
dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
changetype: modify
@@ -222,64 +261,66 @@ replace: description
description: Blie
""")
- print "Checking whether changes are still there..."
+ # Checking whether changes are still there...
msg = self.ldb.search(expression="(cn=Niemand)")
self.assertTrue(len(msg) >= 1)
self.assertEquals(msg[0]["description"], "Blie")
- print "Deleting attribute..."
+ # Deleting attribute...
self.ldb.modify_ldif("""
dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
changetype: modify
delete: description
""")
- print "Checking whether changes are no longer there..."
+ # Checking whether changes are no longer there...
msg = self.ldb.search(expression="(cn=Niemand)")
self.assertTrue(len(msg) >= 1)
- self.assertTrue(not "description" in res[0])
+ self.assertTrue(not "description" in msg[0])
- print "Renaming record..."
- self.ldb.rename("cn=Niemand,cn=Users,dc=vernstok,dc=nl", "cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
+ # Renaming record...
+ self.ldb.rename("cn=Niemand,cn=Users,dc=vernstok,dc=nl",
+ "cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
- print "Checking whether DN has changed..."
+ # Checking whether DN has changed...
msg = self.ldb.search(expression="(cn=Niemand2)")
self.assertEquals(len(msg), 1)
- self.assertEquals(str(msg[0].dn), "cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
+ self.assertEquals(str(msg[0].dn),
+ "cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
- print "Deleting record..."
+ # Deleting record...
self.ldb.delete("cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
- print "Checking whether record is gone..."
+ # Checking whether record is gone...
msg = self.ldb.search(expression="(cn=Niemand2)")
self.assertEquals(len(msg), 0)
-
class MapTestCase(MapBaseTestCase):
+
def setUp(self):
super(MapTestCase, self).setUp()
- ldb = Ldb(self.ldburl)
- self.setup_data(self.templates, open(os.path.join(datadir, "provision_samba3sam_templates.ldif"), 'r').read())
- ldif = open(os.path.join(datadir, "provision_samba3sam.ldif"), 'r').read()
- ldb.add_ldif(substitute_var(ldif, self.samba4.substvars))
+ ldb = Ldb(self.ldburl, lp=cmdline_loadparm)
+ self.templates.setup_data("provision_samba3sam_templates.ldif")
+ ldif = read_datafile("provision_samba3sam.ldif")
+ ldb.add_ldif(self.samba4.subst(ldif))
self.setup_modules(ldb, self.samba3, self.samba4)
- self.ldb = Ldb(self.ldburl)
+ del ldb
+ self.ldb = Ldb(self.ldburl, lp=cmdline_loadparm)
def test_map_search(self):
- print "Running search tests on mapped data"
- ldif = """
-dn: """ + "sambaDomainName=TESTS,""" + self.samba3.basedn + """
-objectclass: sambaDomain
-objectclass: top
-sambaSID: S-1-5-21-4231626423-2410014848-2360679739
-sambaNextRid: 2000
-sambaDomainName: TESTS"""
- self.samba3.db.add_ldif(substitute_var(ldif, self.samba3.substvars))
-
- print "Add a set of split records"
- ldif = """
-dn: """ + self.samba4.dn("cn=X") + """
+ """Running search tests on mapped data."""
+ self.samba3.db.add({
+ "dn": "sambaDomainName=TESTS," + self.samba3.basedn,
+ "objectclass": ["sambaDomain", "top"],
+ "sambaSID": "S-1-5-21-4231626423-2410014848-2360679739",
+ "sambaNextRid": "2000",
+ "sambaDomainName": "TESTS"
+ })
+
+ # Add a set of split records
+ self.ldb.add_ldif("""
+dn: """+ self.samba4.dn("cn=X") + """
objectClass: user
cn: X
codePage: x
@@ -291,127 +332,128 @@ description: x
objectSid: S-1-5-21-4231626423-2410014848-2360679739-552
primaryGroupID: 1-5-21-4231626423-2410014848-2360679739-512
-dn: """ + self.samba4.dn("cn=Y") + """
-objectClass: top
-cn: Y
-codePage: x
-revision: x
-dnsHostName: y
-nextRid: y
-lastLogon: y
-description: x
-
-dn: """ + self.samba4.dn("cn=Z") + """
-objectClass: top
-cn: Z
-codePage: x
-revision: y
-dnsHostName: z
-nextRid: y
-lastLogon: z
-description: y
-"""
-
- self.ldb.add_ldif(substitute_var(ldif, self.samba4.substvars))
-
- print "Add a set of remote records"
-
- ldif = """
-dn: """ + self.samba3.dn("cn=A") + """
-objectClass: posixAccount
-cn: A
-sambaNextRid: x
-sambaBadPasswordCount: x
-sambaLogonTime: x
-description: x
-sambaSID: S-1-5-21-4231626423-2410014848-2360679739-552
-sambaPrimaryGroupSID: S-1-5-21-4231626423-2410014848-2360679739-512
-
-dn: """ + self.samba3.dn("cn=B") + """
-objectClass: top
-cn:B
-sambaNextRid: x
-sambaBadPasswordCount: x
-sambaLogonTime: y
-description: x
+""")
-dn: """ + self.samba3.dn("cn=C") + """
-objectClass: top
-cn: C
-sambaNextRid: x
-sambaBadPasswordCount: y
-sambaLogonTime: z
-description: y
-"""
- self.samba3.add_ldif(substitute_var(ldif, self.samba3.substvars))
+ self.ldb.add({
+ "dn": self.samba4.dn("cn=Y"),
+ "objectClass": "top",
+ "cn": "Y",
+ "codePage": "x",
+ "revision": "x",
+ "dnsHostName": "y",
+ "nextRid": "y",
+ "lastLogon": "y",
+ "description": "x"})
- print "Testing search by DN"
+ self.ldb.add({
+ "dn": self.samba4.dn("cn=Z"),
+ "objectClass": "top",
+ "cn": "Z",
+ "codePage": "x",
+ "revision": "y",
+ "dnsHostName": "z",
+ "nextRid": "y",
+ "lastLogon": "z",
+ "description": "y"})
+
+ # Add a set of remote records
+
+ self.samba3.db.add({
+ "dn": self.samba3.dn("cn=A"),
+ "objectClass": "posixAccount",
+ "cn": "A",
+ "sambaNextRid": "x",
+ "sambaBadPasswordCount": "x",
+ "sambaLogonTime": "x",
+ "description": "x",
+ "sambaSID": "S-1-5-21-4231626423-2410014848-2360679739-552",
+ "sambaPrimaryGroupSID": "S-1-5-21-4231626423-2410014848-2360679739-512"})
+
+ self.samba3.db.add({
+ "dn": self.samba3.dn("cn=B"),
+ "objectClass": "top",
+ "cn": "B",
+ "sambaNextRid": "x",
+ "sambaBadPasswordCount": "x",
+ "sambaLogonTime": "y",
+ "description": "x"})
+
+ self.samba3.db.add({
+ "dn": self.samba3.dn("cn=C"),
+ "objectClass": "top",
+ "cn": "C",
+ "sambaNextRid": "x",
+ "sambaBadPasswordCount": "y",
+ "sambaLogonTime": "z",
+ "description": "y"})
+
+ # Testing search by DN
# Search remote record by local DN
dn = self.samba4.dn("cn=A")
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
+ res = self.ldb.search(dn, scope=SCOPE_BASE,
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 1)
- self.assertEquals(str(str(res[0].dn)), dn)
+ self.assertEquals(str(res[0].dn), dn)
self.assertTrue(not "dnsHostName" in res[0])
self.assertEquals(res[0]["lastLogon"], "x")
# Search remote record by remote DN
dn = self.samba3.dn("cn=A")
- attrs = ["dnsHostName", "lastLogon", "sambaLogonTime"]
- res = self.samba3.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
+ res = self.samba3.db.search(dn, scope=SCOPE_BASE,
+ attrs=["dnsHostName", "lastLogon", "sambaLogonTime"])
self.assertEquals(len(res), 1)
- self.assertEquals(str(str(res[0].dn)), dn)
+ self.assertEquals(str(res[0].dn), dn)
self.assertTrue(not "dnsHostName" in res[0])
self.assertTrue(not "lastLogon" in res[0])
self.assertEquals(res[0]["sambaLogonTime"], "x")
# Search split record by local DN
dn = self.samba4.dn("cn=X")
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
+ res = self.ldb.search(dn, scope=SCOPE_BASE,
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 1)
- self.assertEquals(str(str(res[0].dn)), dn)
+ self.assertEquals(str(res[0].dn), dn)
self.assertEquals(res[0]["dnsHostName"], "x")
self.assertEquals(res[0]["lastLogon"], "x")
# Search split record by remote DN
dn = self.samba3.dn("cn=X")
- attrs = ["dnsHostName", "lastLogon", "sambaLogonTime"]
- res = self.samba3.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
+ res = self.samba3.db.search(dn, scope=SCOPE_BASE,
+ attrs=["dnsHostName", "lastLogon", "sambaLogonTime"])
self.assertEquals(len(res), 1)
- self.assertEquals(str(str(res[0].dn)), dn)
+ self.assertEquals(str(res[0].dn), dn)
self.assertTrue(not "dnsHostName" in res[0])
self.assertTrue(not "lastLogon" in res[0])
self.assertEquals(res[0]["sambaLogonTime"], "x")
- print "Testing search by attribute"
+ # Testing search by attribute
# Search by ignored attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(revision=x)", scope=SCOPE_DEFAULT, attrs=attrs)
+ res = self.ldb.search(expression="(revision=x)", scope=SCOPE_DEFAULT,
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 2)
- self.assertEquals(str(str(res[0].dn)), self.samba4.dn("cn=Y"))
+ self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
self.assertEquals(res[0]["dnsHostName"], "y")
self.assertEquals(res[0]["lastLogon"], "y")
- self.assertEquals(str(str(res[1].dn)), self.samba4.dn("cn=X"))
+ self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
self.assertEquals(res[1]["dnsHostName"], "x")
self.assertEquals(res[1]["lastLogon"], "x")
# Search by kept attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(description=y)", scope=SCOPE_DEFAULT, attrs=attrs)
+ res = self.ldb.search(expression="(description=y)",
+ scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 2)
- self.assertEquals(str(str(res[0].dn)), self.samba4.dn("cn=Z"))
+ self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Z"))
self.assertEquals(res[0]["dnsHostName"], "z")
self.assertEquals(res[0]["lastLogon"], "z")
- self.assertEquals(str(str(res[1].dn)), self.samba4.dn("cn=C"))
+ self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C"))
self.assertTrue(not "dnsHostName" in res[1])
self.assertEquals(res[1]["lastLogon"], "z")
# Search by renamed attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(badPwdCount=x)", scope=SCOPE_DEFAULT, attrs=attrs)
+ res = self.ldb.search(expression="(badPwdCount=x)", scope=SCOPE_DEFAULT,
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 2)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
self.assertTrue(not "dnsHostName" in res[0])
@@ -421,27 +463,30 @@ description: y
self.assertEquals(res[1]["lastLogon"], "x")
# Search by converted attribute
- attrs = ["dnsHostName", "lastLogon", "objectSid"]
# TODO:
# Using the SID directly in the parse tree leads to conversion
# errors, letting the search fail with no results.
#res = self.ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-552)", scope=SCOPE_DEFAULT, attrs)
- res = self.ldb.search(expression="(objectSid=*)", attrs=attrs)
+ res = self.ldb.search(expression="(objectSid=*)", base=None, scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon", "objectSid"])
self.assertEquals(len(res), 3)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
self.assertEquals(res[0]["dnsHostName"], "x")
self.assertEquals(res[0]["lastLogon"], "x")
- self.assertEquals(res[0]["objectSid"], "S-1-5-21-4231626423-2410014848-2360679739-552")
+ self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
+ res[0]["objectSid"])
+ self.assertTrue("objectSid" in res[0])
self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
self.assertTrue(not "dnsHostName" in res[1])
self.assertEquals(res[1]["lastLogon"], "x")
- self.assertEquals(res[1]["objectSid"], "S-1-5-21-4231626423-2410014848-2360679739-552")
+ self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
+ res[1]["objectSid"])
+ self.assertTrue("objectSid" in res[1])
# Search by generated attribute
# In most cases, this even works when the mapping is missing
# a `convert_operator' by enumerating the remote db.
- attrs = ["dnsHostName", "lastLogon", "primaryGroupID"]
- res = self.ldb.search(expression="(primaryGroupID=512)", attrs=attrs)
+ res = self.ldb.search(expression="(primaryGroupID=512)",
+ attrs=["dnsHostName", "lastLogon", "primaryGroupID"])
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
self.assertTrue(not "dnsHostName" in res[0])
@@ -463,8 +508,8 @@ description: y
#
# Search by remote name of renamed attribute */
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(sambaBadPasswordCount=*)", attrs=attrs)
+ res = self.ldb.search(expression="(sambaBadPasswordCount=*)",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 0)
# Search by objectClass
@@ -474,39 +519,34 @@ description: y
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
self.assertEquals(res[0]["dnsHostName"], "x")
self.assertEquals(res[0]["lastLogon"], "x")
- self.assertTrue(res[0]["objectClass"] is not None)
self.assertEquals(res[0]["objectClass"][0], "user")
self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
self.assertTrue(not "dnsHostName" in res[1])
self.assertEquals(res[1]["lastLogon"], "x")
- self.assertTrue(res[1]["objectClass"] is not None)
self.assertEquals(res[1]["objectClass"][0], "user")
# Prove that the objectClass is actually used for the search
- res = self.ldb.search(expression="(|(objectClass=user)(badPwdCount=x))", attrs=attrs)
+ res = self.ldb.search(expression="(|(objectClass=user)(badPwdCount=x))",
+ attrs=attrs)
self.assertEquals(len(res), 3)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
self.assertTrue(not "dnsHostName" in res[0])
self.assertEquals(res[0]["lastLogon"], "y")
- self.assertTrue(res[0]["objectClass"] is not None)
- for oc in set(res[0]["objectClass"]):
- self.assertEquals(oc, "user")
+ self.assertEquals(set(res[0]["objectClass"]), set(["top"]))
self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
self.assertEquals(res[1]["dnsHostName"], "x")
self.assertEquals(res[1]["lastLogon"], "x")
- self.assertTrue(res[1]["objectClass"] is not None)
self.assertEquals(res[1]["objectClass"][0], "user")
self.assertEquals(str(res[2].dn), self.samba4.dn("cn=A"))
self.assertTrue(not "dnsHostName" in res[2])
self.assertEquals(res[2]["lastLogon"], "x")
- self.assertTrue(res[2]["objectClass"] is not None)
self.assertEquals(res[2]["objectClass"][0], "user")
- print "Testing search by parse tree"
+ # Testing search by parse tree
# Search by conjunction of local attributes
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(&(codePage=x)(revision=x))", attrs=attrs)
+ res = self.ldb.search(expression="(&(codePage=x)(revision=x))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 2)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
self.assertEquals(res[0]["dnsHostName"], "y")
@@ -516,8 +556,8 @@ description: y
self.assertEquals(res[1]["lastLogon"], "x")
# Search by conjunction of remote attributes
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(&(lastLogon=x)(description=x))", attrs=attrs)
+ res = self.ldb.search(expression="(&(lastLogon=x)(description=x))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 2)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
self.assertEquals(res[0]["dnsHostName"], "x")
@@ -527,8 +567,8 @@ description: y
self.assertEquals(res[1]["lastLogon"], "x")
# Search by conjunction of local and remote attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(&(codePage=x)(description=x))", attrs=attrs)
+ res = self.ldb.search(expression="(&(codePage=x)(description=x))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 2)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
self.assertEquals(res[0]["dnsHostName"], "y")
@@ -539,14 +579,16 @@ description: y
# Search by conjunction of local and remote attribute w/o match
attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(&(codePage=x)(nextRid=x))", attrs=attrs)
+ res = self.ldb.search(expression="(&(codePage=x)(nextRid=x))",
+ attrs=attrs)
self.assertEquals(len(res), 0)
- res = self.ldb.search(expression="(&(revision=x)(lastLogon=z))", attrs=attrs)
+ res = self.ldb.search(expression="(&(revision=x)(lastLogon=z))",
+ attrs=attrs)
self.assertEquals(len(res), 0)
# Search by disjunction of local attributes
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(|(revision=x)(dnsHostName=x))", attrs=attrs)
+ res = self.ldb.search(expression="(|(revision=x)(dnsHostName=x))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 2)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
self.assertEquals(res[0]["dnsHostName"], "y")
@@ -556,41 +598,41 @@ description: y
self.assertEquals(res[1]["lastLogon"], "x")
# Search by disjunction of remote attributes
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(|(badPwdCount=x)(lastLogon=x))", attrs=attrs)
+ res = self.ldb.search(expression="(|(badPwdCount=x)(lastLogon=x))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 3)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertTrue("dnsHostName" in res[0])
+ self.assertFalse("dnsHostName" in res[0])
self.assertEquals(res[0]["lastLogon"], "y")
self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
self.assertEquals(res[1]["dnsHostName"], "x")
self.assertEquals(res[1]["lastLogon"], "x")
self.assertEquals(str(res[2].dn), self.samba4.dn("cn=A"))
- self.assertTrue("dnsHostName" in res[2])
+ self.assertFalse("dnsHostName" in res[2])
self.assertEquals(res[2]["lastLogon"], "x")
# Search by disjunction of local and remote attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(|(revision=x)(lastLogon=y))", attrs=attrs)
+ res = self.ldb.search(expression="(|(revision=x)(lastLogon=y))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 3)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
self.assertEquals(res[0]["dnsHostName"], "y")
self.assertEquals(res[0]["lastLogon"], "y")
self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
- self.assertTrue("dnsHostName" in res[1])
+ self.assertFalse("dnsHostName" in res[1])
self.assertEquals(res[1]["lastLogon"], "y")
self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X"))
self.assertEquals(res[2]["dnsHostName"], "x")
self.assertEquals(res[2]["lastLogon"], "x")
# Search by disjunction of local and remote attribute w/o match
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(|(codePage=y)(nextRid=z))", attrs=attrs)
+ res = self.ldb.search(expression="(|(codePage=y)(nextRid=z))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 0)
# Search by negated local attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(!(revision=x))", attrs=attrs)
+ res = self.ldb.search(expression="(!(revision=x))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 5)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
self.assertTrue(not "dnsHostName" in res[0])
@@ -606,8 +648,8 @@ description: y
self.assertEquals(res[3]["lastLogon"], "z")
# Search by negated remote attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(!(description=x))", attrs=attrs)
+ res = self.ldb.search(expression="(!(description=x))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 3)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Z"))
self.assertEquals(res[0]["dnsHostName"], "z")
@@ -617,8 +659,8 @@ description: y
self.assertEquals(res[1]["lastLogon"], "z")
# Search by negated conjunction of local attributes
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(!(&(codePage=x)(revision=x)))", attrs=attrs)
+ res = self.ldb.search(expression="(!(&(codePage=x)(revision=x)))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 5)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
self.assertTrue(not "dnsHostName" in res[0])
@@ -634,8 +676,8 @@ description: y
self.assertEquals(res[3]["lastLogon"], "z")
# Search by negated conjunction of remote attributes
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(!(&(lastLogon=x)(description=x)))", attrs=attrs)
+ res = self.ldb.search(expression="(!(&(lastLogon=x)(description=x)))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 5)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
self.assertEquals(res[0]["dnsHostName"], "y")
@@ -651,8 +693,8 @@ description: y
self.assertEquals(res[3]["lastLogon"], "z")
# Search by negated conjunction of local and remote attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(!(&(codePage=x)(description=x)))", attrs=attrs)
+ res = self.ldb.search(expression="(!(&(codePage=x)(description=x)))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 5)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
self.assertTrue(not "dnsHostName" in res[0])
@@ -668,8 +710,8 @@ description: y
self.assertEquals(res[3]["lastLogon"], "z")
# Search by negated disjunction of local attributes
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(!(|(revision=x)(dnsHostName=x)))", attrs=attrs)
+ res = self.ldb.search(expression="(!(|(revision=x)(dnsHostName=x)))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
self.assertTrue(not "dnsHostName" in res[0])
self.assertEquals(res[0]["lastLogon"], "y")
@@ -684,8 +726,8 @@ description: y
self.assertEquals(res[3]["lastLogon"], "z")
# Search by negated disjunction of remote attributes
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(!(|(badPwdCount=x)(lastLogon=x)))", attrs=attrs)
+ res = self.ldb.search(expression="(!(|(badPwdCount=x)(lastLogon=x)))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 4)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
self.assertEquals(res[0]["dnsHostName"], "y")
@@ -698,8 +740,8 @@ description: y
self.assertEquals(res[2]["lastLogon"], "z")
# Search by negated disjunction of local and remote attribute
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(!(|(revision=x)(lastLogon=y)))", attrs=attrs)
+ res = self.ldb.search(expression="(!(|(revision=x)(lastLogon=y)))",
+ attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 4)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
self.assertTrue(not "dnsHostName" in res[0])
@@ -711,9 +753,8 @@ description: y
self.assertTrue(not "dnsHostName" in res[2])
self.assertEquals(res[2]["lastLogon"], "z")
- print "Search by complex parse tree"
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", attrs=attrs)
+ # Search by complex parse tree
+ res = self.ldb.search(expression="(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", attrs=["dnsHostName", "lastLogon"])
self.assertEquals(len(res), 6)
self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
self.assertTrue(not "dnsHostName" in res[0])
@@ -754,10 +795,12 @@ description: y
self.assertEquals(res[0]["revision"], "1")
self.assertEquals(res[0]["description"], "test")
# Check it's not in the local db
- res = self.samba4.db.search(expression="(cn=test)", scope=SCOPE_DEFAULT, attrs=attrs)
+ res = self.samba4.db.search(expression="(cn=test)",
+ scope=SCOPE_DEFAULT, attrs=attrs)
self.assertEquals(len(res), 0)
# Check it's not in the remote db
- res = self.samba3.db.search(expression="(cn=test)", scope=SCOPE_DEFAULT, attrs=attrs)
+ res = self.samba3.db.search(expression="(cn=test)",
+ scope=SCOPE_DEFAULT, attrs=attrs)
self.assertEquals(len(res), 0)
# Modify local record
@@ -805,8 +848,8 @@ description: foo
"sambaBadPasswordCount": "3",
"sambaNextRid": "1001"})
# Check it's there
- attrs = ["description", "sambaBadPasswordCount", "sambaNextRid"]
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
+ res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
+ attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn2)
self.assertEquals(res[0]["description"], "foo")
@@ -814,7 +857,7 @@ description: foo
self.assertEquals(res[0]["sambaNextRid"], "1001")
# Check in mapped db
attrs = ["description", "badPwdCount", "nextRid"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
+ res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs, expression="")
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn)
self.assertEquals(res[0]["description"], "foo")
@@ -834,16 +877,16 @@ badPwdCount: 4
"""
self.ldb.modify_ldif(ldif)
# Check in mapped db
- attrs = ["description", "badPwdCount", "nextRid"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
+ res = self.ldb.search(dn, scope=SCOPE_BASE,
+ attrs=["description", "badPwdCount", "nextRid"])
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn)
self.assertEquals(res[0]["description"], "test")
self.assertEquals(res[0]["badPwdCount"], "4")
self.assertEquals(res[0]["nextRid"], "1001")
# Check in remote db
- attrs = ["description", "sambaBadPasswordCount", "sambaNextRid"]
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
+ res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
+ attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn2)
self.assertEquals(res[0]["description"], "test")
@@ -855,8 +898,8 @@ badPwdCount: 4
self.ldb.rename(dn, dn2)
# Check in mapped db
dn = dn2
- attrs = ["description", "badPwdCount", "nextRid"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
+ res = self.ldb.search(dn, scope=SCOPE_BASE,
+ attrs=["description", "badPwdCount", "nextRid"])
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn)
self.assertEquals(res[0]["description"], "test")
@@ -864,8 +907,8 @@ badPwdCount: 4
self.assertEquals(res[0]["nextRid"], "1001")
# Check in remote db
dn2 = self.samba3.dn("cn=toast")
- attrs = ["description", "sambaBadPasswordCount", "sambaNextRid"]
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
+ res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
+ attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn2)
self.assertEquals(res[0]["description"], "test")
@@ -874,7 +917,7 @@ badPwdCount: 4
# Delete remote record
self.ldb.delete(dn)
- # Check in mapped db
+ # Check in mapped db that it's removed
res = self.ldb.search(dn, scope=SCOPE_BASE)
self.assertEquals(len(res), 0)
# Check in remote db
@@ -899,6 +942,7 @@ add: revision
revision: 1
replace: description
description: test
+
"""
self.ldb.modify_ldif(ldif)
# Check in mapped db
@@ -954,7 +998,8 @@ description: test
self.assertTrue(not "nextRid" in res[0])
self.assertEquals(res[0]["revision"], "1")
# Check in remote db
- attrs = ["description", "sambaBadPasswordCount", "sambaNextRid", "revision"]
+ attrs = ["description", "sambaBadPasswordCount", "sambaNextRid",
+ "revision"]
res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn2)
@@ -992,7 +1037,8 @@ revision: 2
self.assertTrue(not "nextRid" in res[0])
self.assertEquals(res[0]["revision"], "2")
# Check in remote db
- attrs = ["description", "sambaBadPasswordCount", "sambaNextRid", "revision"]
+ attrs = ["description", "sambaBadPasswordCount", "sambaNextRid",
+ "revision"]
res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn2)
@@ -1024,8 +1070,9 @@ revision: 2
self.assertEquals(res[0]["revision"], "2")
# Check in remote db
dn2 = self.samba3.dn("cn=toast")
- attrs = ["description", "sambaBadPasswordCount", "sambaNextRid", "revision"]
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
+ res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
+ attrs=["description", "sambaBadPasswordCount", "sambaNextRid",
+ "revision"])
self.assertEquals(len(res), 1)
self.assertEquals(str(res[0].dn), dn2)
self.assertEquals(res[0]["description"], "test")
diff --git a/source4/dsdb/samdb/ldb_modules/update_keytab.c b/source4/dsdb/samdb/ldb_modules/update_keytab.c
index b36c2c9b71..8eb49b5792 100644
--- a/source4/dsdb/samdb/ldb_modules/update_keytab.c
+++ b/source4/dsdb/samdb/ldb_modules/update_keytab.c
@@ -43,6 +43,39 @@ struct update_kt_private {
struct dn_list *changed_dns;
};
+struct update_kt_ctx {
+ struct ldb_module *module;
+ struct ldb_request *req;
+
+ struct ldb_dn *dn;
+ bool delete;
+
+ struct ldb_reply *op_reply;
+ bool found;
+};
+
+static struct update_kt_ctx *update_kt_ctx_init(struct ldb_module *module,
+ struct ldb_request *req)
+{
+ struct update_kt_ctx *ac;
+
+ ac = talloc_zero(req, struct update_kt_ctx);
+ if (ac == NULL) {
+ ldb_oom(module->ldb);
+ return NULL;
+ }
+
+ ac->module = module;
+ ac->req = req;
+
+ return ac;
+}
+
+/* FIXME: too many semi-async searches here for my taste, direct and indirect as
+ * cli_credentials_set_secrets() performs a sync ldb search.
+ * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
+ * of async issues). -SSS
+ */
static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool delete) {
struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
struct dn_list *item;
@@ -59,8 +92,8 @@ static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool delet
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE,
- filter, attrs, &res);
+ ret = ldb_search(module->ldb, data, &res,
+ dn, LDB_SCOPE_BASE, attrs, "%s", filter);
if (ret != LDB_SUCCESS) {
talloc_free(filter);
return ret;
@@ -80,7 +113,7 @@ static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool delet
ldb_oom(module->ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
-
+
item->creds = cli_credentials_init(item);
if (!item->creds) {
DEBUG(1, ("cli_credentials_init failed!"));
@@ -90,7 +123,7 @@ static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool delet
}
cli_credentials_set_conf(item->creds, ldb_get_opaque(module->ldb, "loadparm"));
- status = cli_credentials_set_secrets(item->creds, ldb_get_opaque(module->ldb, "EventContext"), ldb_get_opaque(module->ldb, "loadparm"), module->ldb, NULL, filter);
+ status = cli_credentials_set_secrets(item->creds, ldb_get_event_context(module->ldb), ldb_get_opaque(module->ldb, "loadparm"), module->ldb, NULL, filter);
talloc_free(filter);
if (NT_STATUS_IS_OK(status)) {
if (delete) {
@@ -105,60 +138,237 @@ static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool delet
return LDB_SUCCESS;
}
+static int ukt_search_modified(struct update_kt_ctx *ac);
+
+static int update_kt_op_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct update_kt_ctx *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct update_kt_ctx);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ ldb_set_errstring(ac->module->ldb, "Invalid request type!\n");
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ac->delete) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, LDB_SUCCESS);
+ }
+
+ ac->op_reply = talloc_steal(ac, ares);
+
+ ret = ukt_search_modified(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
+ return LDB_SUCCESS;
+}
+
+static int ukt_del_op(struct update_kt_ctx *ac)
+{
+ struct ldb_request *down_req;
+ int ret;
+
+ ret = ldb_build_del_req(&down_req, ac->module->ldb, ac,
+ ac->dn,
+ ac->req->controls,
+ ac, update_kt_op_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ return ldb_next_request(ac->module, down_req);
+}
+
+static int ukt_search_modified_callback(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ struct update_kt_ctx *ac;
+ int ret;
+
+ ac = talloc_get_type(req->context, struct update_kt_ctx);
+
+ if (!ares) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, ares->controls,
+ ares->response, ares->error);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+
+ ac->found = true;
+ break;
+
+ case LDB_REPLY_REFERRAL:
+ /* ignore */
+ break;
+
+ case LDB_REPLY_DONE:
+
+ if (ac->found) {
+ /* do the dirty sync job here :/ */
+ ret = add_modified(ac->module, ac->dn, ac->delete);
+ }
+
+ if (ac->delete) {
+ ret = ukt_del_op(ac);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req,
+ NULL, NULL, ret);
+ }
+ break;
+ }
+
+ return ldb_module_done(ac->req, ac->op_reply->controls,
+ ac->op_reply->response, LDB_SUCCESS);
+ }
+
+ talloc_free(ares);
+ return LDB_SUCCESS;
+}
+
+static int ukt_search_modified(struct update_kt_ctx *ac)
+{
+ static const char * const attrs[] = { "distinguishedName", NULL };
+ struct ldb_request *search_req;
+ int ret;
+
+ ret = ldb_build_search_req(&search_req, ac->module->ldb, ac,
+ ac->dn, LDB_SCOPE_BASE,
+ "(&(objectClass=kerberosSecret)"
+ "(privateKeytab=*))", attrs,
+ NULL,
+ ac, ukt_search_modified_callback,
+ ac->req);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ return ldb_next_request(ac->module, search_req);
+}
+
+
/* add */
static int update_kt_add(struct ldb_module *module, struct ldb_request *req)
{
+ struct update_kt_ctx *ac;
+ struct ldb_request *down_req;
int ret;
- ret = ldb_next_request(module, req);
+
+ ac = update_kt_ctx_init(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->dn = req->op.add.message->dn;
+
+ ret = ldb_build_add_req(&down_req, module->ldb, ac,
+ req->op.add.message,
+ req->controls,
+ ac, update_kt_op_callback,
+ req);
if (ret != LDB_SUCCESS) {
return ret;
}
- return add_modified(module, req->op.add.message->dn, false);
+
+ return ldb_next_request(module, down_req);
}
/* modify */
static int update_kt_modify(struct ldb_module *module, struct ldb_request *req)
{
+ struct update_kt_ctx *ac;
+ struct ldb_request *down_req;
int ret;
- ret = ldb_next_request(module, req);
+
+ ac = update_kt_ctx_init(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->dn = req->op.mod.message->dn;
+
+ ret = ldb_build_mod_req(&down_req, module->ldb, ac,
+ req->op.mod.message,
+ req->controls,
+ ac, update_kt_op_callback,
+ req);
if (ret != LDB_SUCCESS) {
return ret;
}
- return add_modified(module, req->op.mod.message->dn, false);
+
+ return ldb_next_request(module, down_req);
}
/* delete */
static int update_kt_delete(struct ldb_module *module, struct ldb_request *req)
{
- int ret;
- /* Before we delete it, record the details */
- ret = add_modified(module, req->op.del.dn, true);
- if (ret != LDB_SUCCESS) {
- return ret;
+ struct update_kt_ctx *ac;
+
+ ac = update_kt_ctx_init(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return ldb_next_request(module, req);
+
+ ac->dn = req->op.del.dn;
+ ac->delete = true;
+
+ return ukt_search_modified(ac);
}
/* rename */
static int update_kt_rename(struct ldb_module *module, struct ldb_request *req)
{
+ struct update_kt_ctx *ac;
+ struct ldb_request *down_req;
int ret;
- ret = ldb_next_request(module, req);
+
+ ac = update_kt_ctx_init(module, req);
+ if (ac == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ac->dn = req->op.rename.newdn;
+
+ ret = ldb_build_rename_req(&down_req, module->ldb, ac,
+ req->op.rename.olddn,
+ req->op.rename.newdn,
+ req->controls,
+ ac, update_kt_op_callback,
+ req);
if (ret != LDB_SUCCESS) {
return ret;
}
- return add_modified(module, req->op.rename.newdn, false);
+
+ return ldb_next_request(module, down_req);
}
/* end a transaction */
static int update_kt_end_trans(struct ldb_module *module)
{
struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
-
struct dn_list *p;
+
for (p=data->changed_dns; p; p = p->next) {
int kret;
- kret = cli_credentials_update_keytab(p->creds, ldb_get_opaque(module->ldb, "EventContext"), ldb_get_opaque(module->ldb, "loadparm"));
+ kret = cli_credentials_update_keytab(p->creds, ldb_get_event_context(module->ldb), ldb_get_opaque(module->ldb, "loadparm"));
if (kret != 0) {
talloc_free(data->changed_dns);
data->changed_dns = NULL;
@@ -169,6 +379,7 @@ static int update_kt_end_trans(struct ldb_module *module)
talloc_free(data->changed_dns);
data->changed_dns = NULL;
+
return ldb_next_end_trans(module);
}
@@ -176,7 +387,7 @@ static int update_kt_end_trans(struct ldb_module *module)
static int update_kt_del_trans(struct ldb_module *module)
{
struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
-
+
talloc_free(data->changed_dns);
data->changed_dns = NULL;