📄 ldb_tdb.c
字号:
/* ldb database library Copyright (C) Andrew Tridgell 2004 Copyright (C) Stefan Metzmacher 2004 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 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 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, see <http://www.gnu.org/licenses/>.*//* * Name: ldb_tdb * * Component: ldb tdb backend * * Description: core functions for tdb backend * * Author: Andrew Tridgell * Author: Stefan Metzmacher * * Modifications: * * - description: make the module use asyncronous calls * date: Feb 2006 * Author: Simo Sorce */#include "ldb_includes.h"#include "ldb_tdb.h"/* map a tdb error code to a ldb error code*/static int ltdb_err_map(enum TDB_ERROR tdb_code){ switch (tdb_code) { case TDB_SUCCESS: return LDB_SUCCESS; case TDB_ERR_CORRUPT: case TDB_ERR_OOM: case TDB_ERR_EINVAL: return LDB_ERR_OPERATIONS_ERROR; case TDB_ERR_IO: return LDB_ERR_PROTOCOL_ERROR; case TDB_ERR_LOCK: case TDB_ERR_NOLOCK: return LDB_ERR_BUSY; case TDB_ERR_LOCK_TIMEOUT: return LDB_ERR_TIME_LIMIT_EXCEEDED; case TDB_ERR_EXISTS: return LDB_ERR_ENTRY_ALREADY_EXISTS; case TDB_ERR_NOEXIST: return LDB_ERR_NO_SUCH_OBJECT; case TDB_ERR_RDONLY: return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } return LDB_ERR_OTHER;}struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module, struct ldb_request *req){ struct ltdb_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 ltdb_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->context = req->context; ac->callback = req->callback; return h;}/* form a TDB_DATA for a record key caller frees note that the key for a record can depend on whether the dn refers to a case sensitive index record or not*/struct TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn){ struct ldb_context *ldb = module->ldb; TDB_DATA key; char *key_str = NULL; const char *dn_folded = NULL; /* most DNs are case insensitive. The exception is index DNs for case sensitive attributes there are 3 cases dealt with in this code: 1) if the dn doesn't start with @ then uppercase the attribute names and the attributes values of case insensitive attributes 2) if the dn starts with @ then leave it alone - the indexing code handles the rest */ dn_folded = ldb_dn_get_casefold(dn); if (!dn_folded) { goto failed; } key_str = talloc_strdup(ldb, "DN="); if (!key_str) { goto failed; } key_str = talloc_strdup_append_buffer(key_str, dn_folded); if (!key_str) { goto failed; } key.dptr = (uint8_t *)key_str; key.dsize = strlen(key_str) + 1; return key;failed: errno = ENOMEM; key.dptr = NULL; key.dsize = 0; return key;}/* check special dn's have valid attributes currently only @ATTRIBUTES is checked*/int ltdb_check_special_dn(struct ldb_module *module, const struct ldb_message *msg){ int i, j; if (! ldb_dn_is_special(msg->dn) || ! ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) { return 0; } /* we have @ATTRIBUTES, let's check attributes are fine */ /* should we check that we deny multivalued attributes ? */ for (i = 0; i < msg->num_elements; i++) { for (j = 0; j < msg->elements[i].num_values; j++) { if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) { ldb_set_errstring(module->ldb, "Invalid attribute value in an @ATTRIBUTES entry"); return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; } } } return 0;}/* we've made a modification to a dn - possibly reindex and update sequence number*/static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn){ int ret = LDB_SUCCESS; if (ldb_dn_is_special(dn) && (ldb_dn_check_special(dn, LTDB_INDEXLIST) || ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) { ret = ltdb_reindex(module); } if (ret == LDB_SUCCESS && !(ldb_dn_is_special(dn) && ldb_dn_check_special(dn, LTDB_BASEINFO)) ) { ret = ltdb_increase_sequence_number(module); } return ret;}/* store a record into the db*/int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); TDB_DATA tdb_key, tdb_data; int ret; tdb_key = ltdb_key(module, msg->dn); if (!tdb_key.dptr) { return LDB_ERR_OTHER; } ret = ltdb_pack_data(module, msg, &tdb_data); if (ret == -1) { talloc_free(tdb_key.dptr); return LDB_ERR_OTHER; } ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs); if (ret == -1) { ret = ltdb_err_map(tdb_error(ltdb->tdb)); goto done; } ret = ltdb_index_add(module, msg); if (ret != LDB_SUCCESS) { tdb_delete(ltdb->tdb, tdb_key); }done: talloc_free(tdb_key.dptr); talloc_free(tdb_data.dptr); return ret;}static int ltdb_add_internal(struct ldb_module *module, const struct ldb_message *msg){ int ret; ret = ltdb_check_special_dn(module, msg); if (ret != LDB_SUCCESS) { return ret; } if (ltdb_cache_load(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } ret = ltdb_store(module, msg, TDB_INSERT); if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { ldb_asprintf_errstring(module->ldb, "Entry %s already exists", ldb_dn_get_linearized(msg->dn)); return ret; } if (ret == LDB_SUCCESS) { ret = ltdb_index_one(module, msg, 1); if (ret != LDB_SUCCESS) { return ret; } ret = ltdb_modified(module, msg->dn); if (ret != LDB_SUCCESS) { return ret; } } return ret;}/* add a record to the database*/static int ltdb_add(struct ldb_module *module, struct ldb_request *req){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); struct ltdb_context *ltdb_ac; int tret, ret = LDB_SUCCESS; if (check_critical_controls(req->controls)) { return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; } req->handle = init_ltdb_handle(ltdb, module, req); if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); tret = ltdb_add_internal(module, req->op.add.message); if (tret != LDB_SUCCESS) { req->handle->status = tret; goto done; } if (ltdb_ac->callback) { ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); }done: req->handle->state = LDB_ASYNC_DONE; return ret;}/* delete a record from the database, not updating indexes (used for deleting index records)*/int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); TDB_DATA tdb_key; int ret; tdb_key = ltdb_key(module, dn); if (!tdb_key.dptr) { return LDB_ERR_OTHER; } ret = tdb_delete(ltdb->tdb, tdb_key); talloc_free(tdb_key.dptr); if (ret != 0) { ret = ltdb_err_map(tdb_error(ltdb->tdb)); } return ret;}static int ltdb_delete_internal(struct ldb_module *module, struct ldb_dn *dn){ struct ldb_message *msg; int ret; msg = talloc(module, struct ldb_message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* in case any attribute of the message was indexed, we need to fetch the old record */ ret = ltdb_search_dn1(module, dn, msg); if (ret != LDB_SUCCESS) { /* not finding the old record is an error */ goto done; } ret = ltdb_delete_noindex(module, dn); if (ret != LDB_SUCCESS) { goto done; } /* remove one level attribute */ ret = ltdb_index_one(module, msg, 0); if (ret != LDB_SUCCESS) { goto done; } /* remove any indexed attributes */ ret = ltdb_index_del(module, msg); if (ret != LDB_SUCCESS) { goto done; } ret = ltdb_modified(module, dn); if (ret != LDB_SUCCESS) { goto done; }done: talloc_free(msg); return ret;}/* delete a record from the database*/static int ltdb_delete(struct ldb_module *module, struct ldb_request *req){ struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); struct ltdb_context *ltdb_ac; int tret, ret = LDB_SUCCESS; if (check_critical_controls(req->controls)) { return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; } req->handle = NULL; if (ltdb_cache_load(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } req->handle = init_ltdb_handle(ltdb, module, req); if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); tret = ltdb_delete_internal(module, req->op.del.dn); if (tret != LDB_SUCCESS) { req->handle->status = tret; goto done; } if (ltdb_ac->callback) { ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); }done: req->handle->state = LDB_ASYNC_DONE; return ret;}/* find an element by attribute name. At the moment this does a linear search, it should be re-coded to use a binary search once all places that modify records guarantee sorted order return the index of the first matching element if found, otherwise -1*/static int find_element(const struct ldb_message *msg, const char *name){ unsigned int i; for (i=0;i<msg->num_elements;i++) { if (ldb_attr_cmp(msg->elements[i].name, name) == 0) { return i; } } return -1;}/* add an element to an existing record. Assumes a elements array that we can call re-alloc on, and assumed that we can re-use the data pointers from the passed in additional values. Use with care! returns 0 on success, -1 on failure (and sets errno)*/static int msg_add_element(struct ldb_context *ldb, struct ldb_message *msg, struct ldb_message_element *el){ struct ldb_message_element *e2; unsigned int i; e2 = talloc_realloc(msg, msg->elements, struct ldb_message_element, msg->num_elements+1); if (!e2) { errno = ENOMEM; return -1; } msg->elements = e2; e2 = &msg->elements[msg->num_elements]; e2->name = el->name; e2->flags = el->flags; e2->values = NULL; if (el->num_values != 0) { e2->values = talloc_array(msg->elements, struct ldb_val, el->num_values); if (!e2->values) { errno = ENOMEM; return -1; } } for (i=0;i<el->num_values;i++) { e2->values[i] = el->values[i]; } e2->num_values = el->num_values; msg->num_elements++; return 0;}/* delete all elements having a specified attribute name*/static int msg_delete_attribute(struct ldb_module *module, struct ldb_context *ldb, struct ldb_message *msg, const char *name){ const char *dn; unsigned int i, j; dn = ldb_dn_get_linearized(msg->dn); if (dn == NULL) { return -1; } for (i=0;i<msg->num_elements;i++) { if (ldb_attr_cmp(msg->elements[i].name, name) == 0) { for (j=0;j<msg->elements[i].num_values;j++) { ltdb_index_del_value(module, dn, &msg->elements[i], j); } talloc_free(msg->elements[i].values); if (msg->num_elements > (i+1)) { memmove(&msg->elements[i], &msg->elements[i+1], sizeof(struct ldb_message_element)* (msg->num_elements - (i+1))); } msg->num_elements--; i--; msg->elements = talloc_realloc(msg, msg->elements, struct ldb_message_element, msg->num_elements); } } return 0;}/* delete all elements matching an attribute name/value return 0 on success, -1 on failure*/static int msg_delete_element(struct ldb_module *module, struct ldb_message *msg, const char *name, const struct ldb_val *val){ struct ldb_context *ldb = module->ldb; unsigned int i; int found; struct ldb_message_element *el; const struct ldb_schema_attribute *a; found = find_element(msg, name); if (found == -1) { return -1; } el = &msg->elements[found];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -