From ea3c96647faef4911c6fe376f71e2b0dc63c7259 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 10 Nov 2016 18:03:26 +0100 Subject: ldb:rdn_name: add support for LDB_CONTROL_RECALCULATE_RDN_OID on ldb_modify() BUG: https://bugzilla.samba.org/show_bug.cgi?id=12399 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam --- lib/ldb/modules/rdn_name.c | 141 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) (limited to 'lib') diff --git a/lib/ldb/modules/rdn_name.c b/lib/ldb/modules/rdn_name.c index e8d5d8ae9bd..469778227ed 100644 --- a/lib/ldb/modules/rdn_name.c +++ b/lib/ldb/modules/rdn_name.c @@ -377,11 +377,20 @@ static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, down_req); } +static int rdn_recalculate_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request); + + talloc_steal(up_req, req); + return up_req->callback(up_req, ares); +} + static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; const struct ldb_val *rdn_val_p; struct ldb_message_element *e = NULL; + struct ldb_control *recalculate_rdn_control = NULL; ldb = ldb_module_get_ctx(module); @@ -390,6 +399,138 @@ static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } + recalculate_rdn_control = ldb_request_get_control(req, + LDB_CONTROL_RECALCULATE_RDN_OID); + if (recalculate_rdn_control != NULL) { + struct ldb_message *msg = NULL; + const char *rdn_name = NULL; + struct ldb_val rdn_val; + const struct ldb_schema_attribute *a = NULL; + struct ldb_request *mod_req = NULL; + int ret; + struct ldb_message_element *rdn_del = NULL; + struct ldb_message_element *name_del = NULL; + + recalculate_rdn_control->critical = false; + + msg = ldb_msg_copy_shallow(req, req->op.mod.message); + if (msg == NULL) { + return ldb_module_oom(module); + } + + /* + * The caller must pass a dummy 'name' attribute + * in order to bypass some high level checks. + * + * We just remove it and check nothing is left. + */ + ldb_msg_remove_attr(msg, "name"); + + if (msg->num_elements != 0) { + return ldb_module_operr(module); + } + + rdn_name = ldb_dn_get_rdn_name(msg->dn); + if (rdn_name == NULL) { + return ldb_module_oom(module); + } + + a = ldb_schema_attribute_by_name(ldb, rdn_name); + if (a == NULL) { + return ldb_module_operr(module); + } + + if (a->name != NULL) { + rdn_name = a->name; + } + + rdn_val_p = ldb_dn_get_rdn_val(msg->dn); + if (rdn_val_p == NULL) { + return ldb_module_oom(module); + } + rdn_val = ldb_val_dup(msg, rdn_val_p); + if (rdn_val.length == 0) { + return ldb_module_oom(module); + } + + /* + * This is a bit tricky: + * + * We want _DELETE elements (as "rdn_del" and "name_del" without + * values) first, followed by _ADD (with the real names) + * elements (with values). Then we fix up the "rdn_del" and + * "name_del" attributes. + */ + + ret = ldb_msg_add_empty(msg, "rdn_del", LDB_FLAG_MOD_DELETE, NULL); + if (ret != 0) { + return ldb_module_oom(module); + } + ret = ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_ADD, NULL); + if (ret != 0) { + return ldb_module_oom(module); + } + ret = ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL); + if (ret != 0) { + return ldb_module_oom(module); + } + + ret = ldb_msg_add_empty(msg, "name_del", LDB_FLAG_MOD_DELETE, NULL); + if (ret != 0) { + return ldb_module_oom(module); + } + ret = ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_ADD, NULL); + if (ret != 0) { + return ldb_module_oom(module); + } + ret = ldb_msg_add_value(msg, "name", &rdn_val, NULL); + if (ret != 0) { + return ldb_module_oom(module); + } + + rdn_del = ldb_msg_find_element(msg, "rdn_del"); + if (rdn_del == NULL) { + return ldb_module_operr(module); + } + rdn_del->name = talloc_strdup(msg->elements, rdn_name); + if (rdn_del->name == NULL) { + return ldb_module_oom(module); + } + name_del = ldb_msg_find_element(msg, "name_del"); + if (name_del == NULL) { + return ldb_module_operr(module); + } + name_del->name = talloc_strdup(msg->elements, "name"); + if (name_del->name == NULL) { + return ldb_module_oom(module); + } + + ret = ldb_build_mod_req(&mod_req, ldb, + req, msg, NULL, + req, rdn_recalculate_callback, + req); + if (ret != LDB_SUCCESS) { + return ldb_module_done(req, NULL, NULL, ret); + } + talloc_steal(mod_req, msg); + + ret = ldb_request_add_control(mod_req, + LDB_CONTROL_RECALCULATE_RDN_OID, + false, NULL); + if (ret != LDB_SUCCESS) { + return ldb_module_done(req, NULL, NULL, ret); + } + ret = ldb_request_add_control(mod_req, + LDB_CONTROL_PERMISSIVE_MODIFY_OID, + false, NULL); + if (ret != LDB_SUCCESS) { + return ldb_module_done(req, NULL, NULL, ret); + } + + /* go on with the call chain */ + return ldb_next_request(module, mod_req); + } + rdn_val_p = ldb_dn_get_rdn_val(req->op.mod.message->dn); if (rdn_val_p == NULL) { return LDB_ERR_OPERATIONS_ERROR; -- cgit v1.2.1