summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2016-11-10 18:03:26 +0100
committerAndrew Bartlett <abartlet@samba.org>2016-12-01 05:54:23 +0100
commitea3c96647faef4911c6fe376f71e2b0dc63c7259 (patch)
treecff1acc47d952fb943a78119be25d28ad2bf45e6 /lib
parent25aa26178faf87efc166ec0bad8d86fb1968d7c7 (diff)
downloadsamba-ea3c96647faef4911c6fe376f71e2b0dc63c7259.tar.gz
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 <metze@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Diffstat (limited to 'lib')
-rw-r--r--lib/ldb/modules/rdn_name.c141
1 files changed, 141 insertions, 0 deletions
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;