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.
+ version 3 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
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
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Author: Andrew Tridgell
*/
-#include "includes.h"
-#include "ldb/include/includes.h"
+#include "ldb_includes.h"
-#include "ldb/ldb_tdb/ldb_tdb.h"
+#include "ldb_tdb.h"
/*
add one element to a message
el.name = "distinguishedName";
el.num_values = 1;
el.values = &val;
- val.data = (uint8_t *)ldb_dn_linearize(msg, msg->dn);
+ val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn);
val.length = strlen((char *)val.data);
ret = msg_add_element(msg, &el, 1);
}
for (i=0;i<msg->num_elements;i++) {
- const struct ldb_attrib_handler *h;
- h = ldb_attrib_handler(ldb, msg->elements[i].name);
- if (h->flags & LDB_ATTR_FLAG_HIDDEN) {
+ const struct ldb_schema_attribute *a;
+ a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
+ if (a->flags & LDB_ATTR_FLAG_HIDDEN) {
continue;
}
if (msg_add_element(ret, &msg->elements[i],
return ret;
}
+/*
+ search the database for a single simple dn.
+ return LDB_ERR_NO_SUCH_OBJECT on record-not-found
+ and LDB_SUCCESS on success
+*/
+static int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn)
+{
+ struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
+ TDB_DATA tdb_key, tdb_data;
+
+ if (ldb_dn_is_null(dn)) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ /* form the key */
+ tdb_key = ltdb_key(module, dn);
+ if (!tdb_key.dptr) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
+ talloc_free(tdb_key.dptr);
+ if (!tdb_data.dptr) {
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ free(tdb_data.dptr);
+ return LDB_SUCCESS;
+}
/*
search the database for a single simple dn, returning all attributes
in a single message
- return 1 on success, 0 on record-not-found and -1 on error
+ return LDB_ERR_NO_SUCH_OBJECT on record-not-found
+ and LDB_SUCCESS on success
*/
-int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg)
+int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg)
{
- struct ltdb_private *ltdb = module->private_data;
+ struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data;
int ret;
TDB_DATA tdb_key, tdb_data;
/* form the key */
tdb_key = ltdb_key(module, dn);
if (!tdb_key.dptr) {
- return -1;
+ return LDB_ERR_OPERATIONS_ERROR;
}
tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
talloc_free(tdb_key.dptr);
if (!tdb_data.dptr) {
- return 0;
+ return LDB_ERR_NO_SUCH_OBJECT;
}
-
+
msg->num_elements = 0;
msg->elements = NULL;
ret = ltdb_unpack_data(module, &tdb_data, msg);
free(tdb_data.dptr);
if (ret == -1) {
- return -1;
+ return LDB_ERR_OPERATIONS_ERROR;
}
if (!msg->dn) {
msg->dn = ldb_dn_copy(msg, dn);
}
if (!msg->dn) {
- return -1;
+ return LDB_ERR_OPERATIONS_ERROR;
}
- return 1;
-}
-
-/*
- lock the database for read - use by ltdb_search
-*/
-static int ltdb_lock_read(struct ldb_module *module)
-{
- struct ltdb_private *ltdb = module->private_data;
- return tdb_lockall_read(ltdb->tdb);
-}
-
-/*
- unlock the database after a ltdb_lock_read()
-*/
-static int ltdb_unlock_read(struct ldb_module *module)
-{
- struct ltdb_private *ltdb = module->private_data;
- return tdb_unlockall_read(ltdb->tdb);
+ return LDB_SUCCESS;
}
/*
*/
static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
{
- struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle);
- struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
- struct ldb_reply *ares = NULL;
+ struct ltdb_context *ac;
+ struct ldb_message *msg;
int ret;
+ ac = talloc_get_type(state, struct ltdb_context);
+
if (key.dsize < 4 ||
strncmp((char *)key.dptr, "DN=", 3) != 0) {
return 0;
}
- ares = talloc_zero(ac, struct ldb_reply);
- if (!ares) {
- handle->status = LDB_ERR_OPERATIONS_ERROR;
- handle->state = LDB_ASYNC_DONE;
- return -1;
- }
-
- ares->message = ldb_msg_new(ares);
- if (!ares->message) {
- handle->status = LDB_ERR_OPERATIONS_ERROR;
- handle->state = LDB_ASYNC_DONE;
- talloc_free(ares);
+ msg = ldb_msg_new(ac);
+ if (!msg) {
return -1;
}
/* unpack the record */
- ret = ltdb_unpack_data(ac->module, &data, ares->message);
+ ret = ltdb_unpack_data(ac->module, &data, msg);
if (ret == -1) {
- talloc_free(ares);
+ talloc_free(msg);
return -1;
}
- if (!ares->message->dn) {
- ares->message->dn = ldb_dn_explode(ares->message, (char *)key.dptr + 3);
- if (ares->message->dn == NULL) {
- handle->status = LDB_ERR_OPERATIONS_ERROR;
- handle->state = LDB_ASYNC_DONE;
- talloc_free(ares);
+ if (!msg->dn) {
+ msg->dn = ldb_dn_new(msg, ac->module->ldb,
+ (char *)key.dptr + 3);
+ if (msg->dn == NULL) {
+ talloc_free(msg);
return -1;
}
}
/* see if it matches the given expression */
- if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree,
- ac->base, ac->scope)) {
- talloc_free(ares);
+ if (!ldb_match_msg(ac->module->ldb, msg,
+ ac->tree, ac->base, ac->scope)) {
+ talloc_free(msg);
return 0;
}
/* filter the attributes that the user wants */
- ret = ltdb_filter_attrs(ares->message, ac->attrs);
+ ret = ltdb_filter_attrs(msg, ac->attrs);
if (ret == -1) {
- handle->status = LDB_ERR_OPERATIONS_ERROR;
- handle->state = LDB_ASYNC_DONE;
- talloc_free(ares);
+ talloc_free(msg);
return -1;
}
- ares->type = LDB_REPLY_ENTRY;
- handle->state = LDB_ASYNC_PENDING;
- handle->status = ac->callback(ac->module->ldb, ac->context, ares);
-
- if (handle->status != LDB_SUCCESS) {
- /* don't try to free ares here, the callback is in charge of that */
+ ret = ldb_module_send_entry(ac->req, msg, NULL);
+ if (ret != LDB_SUCCESS) {
+ ac->callback_failed = true;
+ /* the callback failed, abort the operation */
return -1;
}
search the database with a LDAP-like expression.
this is the "full search" non-indexed variant
*/
-static int ltdb_search_full(struct ldb_handle *handle)
+static int ltdb_search_full(struct ltdb_context *ctx)
{
- struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
- struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
+ struct ltdb_private *ltdb = talloc_get_type(ctx->module->private_data, struct ltdb_private);
int ret;
- ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
+ if (ltdb->in_transaction != 0) {
+ ret = tdb_traverse(ltdb->tdb, search_func, ctx);
+ } else {
+ ret = tdb_traverse_read(ltdb->tdb, search_func, ctx);
+ }
if (ret == -1) {
- handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return LDB_ERR_OPERATIONS_ERROR;
}
- handle->state = LDB_ASYNC_DONE;
return LDB_SUCCESS;
}
search the database with a LDAP-like expression.
choses a search method
*/
-int ltdb_search(struct ldb_module *module, struct ldb_request *req)
+int ltdb_search(struct ltdb_context *ctx)
{
+ struct ldb_module *module = ctx->module;
+ struct ldb_request *req = ctx->req;
struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
- struct ltdb_context *ltdb_ac;
- struct ldb_reply *ares;
int ret;
- if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) &&
- (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
- return LDB_ERR_OPERATIONS_ERROR;
+ req->handle->state = LDB_ASYNC_PENDING;
if (ltdb_lock_read(module) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
return LDB_ERR_OPERATIONS_ERROR;
}
- req->handle = init_ltdb_handle(ltdb, module, req);
- if (req->handle == NULL) {
- ltdb_unlock_read(module);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
+ if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) {
+
+ /* Check what we should do with a NULL dn */
+ switch (req->op.search.scope) {
+ case LDB_SCOPE_BASE:
+ ldb_asprintf_errstring(module->ldb,
+ "NULL Base DN invalid for a base search");
+ ret = LDB_ERR_INVALID_DN_SYNTAX;
+ break;
+ case LDB_SCOPE_ONELEVEL:
+ ldb_asprintf_errstring(module->ldb,
+ "NULL Base DN invalid for a one-level search");
+ ret = LDB_ERR_INVALID_DN_SYNTAX;
+ break;
+ case LDB_SCOPE_SUBTREE:
+ default:
+ /* We accept subtree searches from a NULL base DN, ie over the whole DB */
+ ret = LDB_SUCCESS;
+ }
+ } else if (ldb_dn_is_valid(req->op.search.base) == false) {
- ltdb_ac->tree = req->op.search.tree;
- ltdb_ac->scope = req->op.search.scope;
- ltdb_ac->base = req->op.search.base;
- ltdb_ac->attrs = req->op.search.attrs;
+ /* We don't want invalid base DNs here */
+ ldb_asprintf_errstring(module->ldb,
+ "Invalid Base DN: %s",
+ ldb_dn_get_linearized(req->op.search.base));
+ ret = LDB_ERR_INVALID_DN_SYNTAX;
- ret = ltdb_search_indexed(req->handle);
- if (ret == -1) {
- ret = ltdb_search_full(req->handle);
- }
- if (ret != LDB_SUCCESS) {
- ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
- req->handle->state = LDB_ASYNC_DONE;
- req->handle->status = ret;
+ } else if (ltdb->check_base) {
+ /* This database has been marked as 'checkBaseOnSearch', so do a spot check of the base dn */
+ ret = ltdb_search_base(module, req->op.search.base);
+
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ ldb_asprintf_errstring(module->ldb,
+ "No such Base DN: %s",
+ ldb_dn_get_linearized(req->op.search.base));
+ }
+
+ } else {
+ /* If we are not checking the base DN life is easy */
+ ret = LDB_SUCCESS;
}
- /* Finally send an LDB_REPLY_DONE packet when searching is finished */
+ ctx->tree = req->op.search.tree;
+ ctx->scope = req->op.search.scope;
+ ctx->base = req->op.search.base;
+ ctx->attrs = req->op.search.attrs;
- ares = talloc_zero(req, struct ldb_reply);
- if (!ares) {
- ltdb_unlock_read(module);
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ret == LDB_SUCCESS) {
+ ret = ltdb_search_indexed(ctx);
+ if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+ /* Not in the index, therefore OK! */
+ ret = LDB_SUCCESS;
+
+ }
+ /* Check if we got just a normal error.
+ * In that case proceed to a full search unless we got a
+ * callback error */
+ if ( ! ctx->callback_failed && ret != LDB_SUCCESS) {
+ /* Not indexed, so we need to do a full scan */
+ ret = ltdb_search_full(ctx);
+ if (ret != LDB_SUCCESS) {
+ ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
+ }
+ }
}
- req->handle->state = LDB_ASYNC_DONE;
- ares->type = LDB_REPLY_DONE;
-
- ret = req->callback(module->ldb, req->context, ares);
- req->handle->status = ret;
-
ltdb_unlock_read(module);
- return LDB_SUCCESS;
+ return ret;
}