1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-13 16:23:50 +03:00
Files
samba-mirror/source/lib/ldb/modules/rdn_name.c
Simo Sorce 0fa5d4bc22 r19489: Change ldb_msg_add_value and ldb_msg_add_empty to take a foruth argument.
This is a pointer to an element pointer. If it is not null it will be
filled with the pointer of the manipulated element.
Will avoid double searches on the elements list in some cases.
2007-10-10 14:24:38 -05:00

338 lines
8.0 KiB
C

/*
ldb database library
Copyright (C) Andrew Bartlet 2005
Copyright (C) Simo Sorce 2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: rdb_name
*
* Component: ldb rdn name module
*
* Description: keep a consistent name attribute on objects manpulations
*
* Author: Andrew Bartlet
*
* Modifications:
* - made the module async
* Simo Sorce Mar 2006
*/
#include "includes.h"
#include "ldb/include/includes.h"
static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name)
{
int i;
for (i = 0; i < msg->num_elements; i++) {
if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
return &msg->elements[i];
}
}
return NULL;
}
static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_request *down_req;
struct ldb_message *msg;
struct ldb_message_element *attribute;
struct ldb_dn_component *rdn;
int i, ret;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n");
/* do not manipulate our control entries */
if (ldb_dn_is_special(req->op.add.message->dn)) {
return ldb_next_request(module, req);
}
down_req = talloc(req, struct ldb_request);
if (down_req == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
*down_req = *req;
down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
rdn = ldb_dn_get_rdn(msg, msg->dn);
if (rdn == NULL) {
talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
/* Perhaps someone above us tried to set this? */
if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
attribute->num_values = 0;
}
if (ldb_msg_add_value(msg, "name", &rdn->value, NULL) != 0) {
talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
attribute = rdn_name_find_attribute(msg, rdn->name);
if (!attribute) {
if (ldb_msg_add_value(msg, rdn->name, &rdn->value, NULL) != 0) {
talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
} else {
const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, rdn->name);
for (i = 0; i < attribute->num_values; i++) {
if (handler->comparison_fn(module->ldb, msg, &rdn->value, &attribute->values[i]) == 0) {
/* overwrite so it matches in case */
attribute->values[i] = rdn->value;
break;
}
}
if (i == attribute->num_values) {
ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
"RDN mismatch on %s: %s",
ldb_dn_linearize(msg, msg->dn), rdn->name);
talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
}
/* 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;
}
struct rename_context {
enum {RENAME_RENAME, RENAME_MODIFY} step;
struct ldb_request *orig_req;
struct ldb_request *down_req;
struct ldb_request *mod_req;
};
static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_handle *h;
struct rename_context *ac;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n");
/* do not manipulate our control entries */
if (ldb_dn_is_special(req->op.rename.newdn)) {
return ldb_next_request(module, req);
}
h = talloc_zero(req, struct ldb_handle);
if (h == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
h->module = module;
ac = talloc_zero(h, struct rename_context);
if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
h->private_data = (void *)ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->orig_req = req;
ac->down_req = talloc(req, struct ldb_request);
if (ac->down_req == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
*(ac->down_req) = *req;
ac->step = RENAME_RENAME;
req->handle = h;
/* rename first, modify "name" if rename is ok */
return ldb_next_request(module, ac->down_req);
}
static int rdn_name_rename_do_mod(struct ldb_handle *h) {
struct rename_context *ac;
struct ldb_dn_component *rdn;
struct ldb_message *msg;
ac = talloc_get_type(h->private_data, struct rename_context);
rdn = ldb_dn_get_rdn(ac, ac->orig_req->op.rename.newdn);
if (rdn == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->mod_req = talloc_zero(ac, struct ldb_request);
ac->mod_req->operation = LDB_MODIFY;
ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
msg->dn = ldb_dn_copy(msg, ac->orig_req->op.rename.newdn);
if (msg->dn == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (ldb_msg_add_empty(msg, rdn->name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (ldb_msg_add_value(msg, rdn->name, &rdn->value, NULL) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (ldb_msg_add_value(msg, "name", &rdn->value, NULL) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
ldb_set_timeout_from_prev_req(h->module->ldb, ac->orig_req, ac->mod_req);
ac->step = RENAME_MODIFY;
/* do the mod call */
return ldb_request(h->module->ldb, ac->mod_req);
}
static int rename_wait(struct ldb_handle *handle)
{
struct rename_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 rename_context);
switch(ac->step) {
case RENAME_RENAME:
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;
}
/* rename operation done */
return rdn_name_rename_do_mod(handle);
case RENAME_MODIFY:
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 rename_wait_all(struct ldb_handle *handle) {
int ret;
while (handle->state != LDB_ASYNC_DONE) {
ret = rename_wait(handle);
if (ret != LDB_SUCCESS) {
return ret;
}
}
return handle->status;
}
static int rdn_name_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
if (type == LDB_WAIT_ALL) {
return rename_wait_all(handle);
} else {
return rename_wait(handle);
}
}
static const struct ldb_module_ops rdn_name_ops = {
.name = "rdn_name",
.add = rdn_name_add,
.rename = rdn_name_rename,
.wait = rdn_name_wait
};
int ldb_rdn_name_init(void)
{
return ldb_register_module(&rdn_name_ops);
}