📄 ldb.c
字号:
/* ldb database library Copyright (C) Andrew Tridgell 2004 Copyright (C) Simo Sorce 2005-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 * * Component: ldb core API * * Description: core API routines interfacing to ldb backends * * Author: Andrew Tridgell */#include "ldb_includes.h"/* initialise a ldb context The mem_ctx is optional*/struct ldb_context *ldb_init(void *mem_ctx){ struct ldb_context *ldb = talloc_zero(mem_ctx, struct ldb_context); int ret; ret = ldb_setup_wellknown_attributes(ldb); if (ret != 0) { talloc_free(ldb); return NULL; } ldb_set_utf8_default(ldb); ldb_set_create_perms(ldb, 0666); ldb_set_modules_dir(ldb, LDB_MODULESDIR); return ldb;}static struct backends_list_entry { struct ldb_backend_ops *ops; struct backends_list_entry *prev, *next;} *ldb_backends = NULL;#ifndef STATIC_LIBLDB_BACKENDS #ifdef HAVE_LDB_LDAP#define LDAP_INIT &ldb_ldap_backend_ops, \ &ldb_ldapi_backend_ops, \ &ldb_ldaps_backend_ops,#else#define LDAP_INIT#endif#ifdef HAVE_LDB_SQLITE3#define SQLITE3_INIT &ldb_sqlite3_backend_ops,#else#define SQLITE3_INIT#endif#define STATIC_LIBLDB_BACKENDS \ LDAP_INIT \ SQLITE3_INIT \ &ldb_tdb_backend_ops, \ NULL#endifconst static struct ldb_backend_ops *builtin_backends[] = { STATIC_LIBLDB_BACKENDS};static ldb_connect_fn ldb_find_backend(const char *url){ struct backends_list_entry *backend; int i; for (i = 0; builtin_backends[i]; i++) { if (strncmp(builtin_backends[i]->name, url, strlen(builtin_backends[i]->name)) == 0) return builtin_backends[i]->connect_fn; } for (backend = ldb_backends; backend; backend = backend->next) { if (strncmp(backend->ops->name, url, strlen(backend->ops->name)) == 0) { return backend->ops->connect_fn; } } return NULL;}/* register a new ldb backend*/int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn){ struct ldb_backend_ops *backend = talloc(talloc_autofree_context(), struct ldb_backend_ops); struct backends_list_entry *entry = talloc(talloc_autofree_context(), struct backends_list_entry); if (ldb_find_backend(url_prefix)) { return LDB_SUCCESS; } /* Maybe check for duplicity here later on? */ backend->name = talloc_strdup(backend, url_prefix); backend->connect_fn = connectfn; entry->ops = backend; DLIST_ADD(ldb_backends, entry); return LDB_SUCCESS;}/* Return the ldb module form of a database. The URL can either be one of the following forms ldb://path ldapi://path flags is made up of LDB_FLG_* the options are passed uninterpreted to the backend, and are backend specific. This allows modules to get at only the backend module, for example where a module may wish to direct certain requests at a particular backend.*/int ldb_connect_backend(struct ldb_context *ldb, const char *url, const char *options[], struct ldb_module **backend_module){ int ret; char *backend; ldb_connect_fn fn; if (strchr(url, ':') != NULL) { backend = talloc_strndup(ldb, url, strchr(url, ':')-url); } else { /* Default to tdb */ backend = talloc_strdup(ldb, "tdb"); } fn = ldb_find_backend(backend); if (fn == NULL) { int (*init_fn) (void); init_fn = ldb_dso_load_symbol(ldb, backend, "init_module"); if (init_fn != NULL && init_fn() == 0) { fn = ldb_find_backend(backend); } } if (fn == NULL) { struct ldb_backend_ops *ops; char *symbol_name = talloc_asprintf(ldb, "ldb_%s_backend_ops", backend); if (symbol_name == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ops = ldb_dso_load_symbol(ldb, backend, symbol_name); if (ops != NULL) { fn = ops->connect_fn; } talloc_free(symbol_name); } talloc_free(backend); if (fn == NULL) { ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to find backend for '%s'\n", url); return LDB_ERR_OTHER; } ret = fn(ldb, url, ldb->flags, options, backend_module); if (ret != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to '%s'\n", url); return ret; } return ret;}/* try to autodetect a basedn if none specified. This fixes one of my pet hates about ldapsearch, which is that you have to get a long, complex basedn right to make any use of it.*/void ldb_set_default_dns(struct ldb_context *ldb){ TALLOC_CTX *tmp_ctx; int ret; struct ldb_result *res; struct ldb_dn *tmp_dn=NULL; static const char *attrs[] = { "rootDomainNamingContext", "configurationNamingContext", "schemaNamingContext", "defaultNamingContext", NULL }; tmp_ctx = talloc_new(ldb); ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, NULL), LDB_SCOPE_BASE, "(objectClass=*)", attrs, &res); if (ret == LDB_SUCCESS) { if (res->count == 1) { if (!ldb_get_opaque(ldb, "rootDomainNamingContext")) { tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], "rootDomainNamingContext"); ldb_set_opaque(ldb, "rootDomainNamingContext", tmp_dn); } if (!ldb_get_opaque(ldb, "configurationNamingContext")) { tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], "configurationNamingContext"); ldb_set_opaque(ldb, "configurationNamingContext", tmp_dn); } if (!ldb_get_opaque(ldb, "schemaNamingContext")) { tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], "schemaNamingContext"); ldb_set_opaque(ldb, "schemaNamingContext", tmp_dn); } if (!ldb_get_opaque(ldb, "defaultNamingContext")) { tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], "defaultNamingContext"); ldb_set_opaque(ldb, "defaultNamingContext", tmp_dn); } } talloc_free(res); } talloc_free(tmp_ctx);}struct ldb_dn *ldb_get_root_basedn(struct ldb_context *ldb){ return talloc_get_type(ldb_get_opaque(ldb, "rootDomainNamingContext"), struct ldb_dn);}struct ldb_dn *ldb_get_config_basedn(struct ldb_context *ldb){ return talloc_get_type(ldb_get_opaque(ldb, "configurationNamingContext"), struct ldb_dn);}struct ldb_dn *ldb_get_schema_basedn(struct ldb_context *ldb){ return talloc_get_type(ldb_get_opaque(ldb, "schemaNamingContext"), struct ldb_dn);}struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb){ return talloc_get_type(ldb_get_opaque(ldb, "defaultNamingContext"), struct ldb_dn);}/* connect to a database. The URL can either be one of the following forms ldb://path ldapi://path flags is made up of LDB_FLG_* the options are passed uninterpreted to the backend, and are backend specific*/int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]){ int ret; const char *url2; /* We seem to need to do this here, or else some utilities don't get ldb backends */ ldb->flags = flags; url2 = talloc_strdup(ldb, url); if (!url2) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } ret = ldb_set_opaque(ldb, "ldb_url", talloc_strdup(ldb, url2)); if (ret != LDB_SUCCESS) { return ret; } ret = ldb_connect_backend(ldb, url, options, &ldb->modules); if (ret != LDB_SUCCESS) { return ret; } if (ldb_load_modules(ldb, options) != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to load modules for %s: %s\n", url, ldb_errstring(ldb)); return LDB_ERR_OTHER; } /* TODO: get timeout from options if available there */ ldb->default_timeout = 300; /* set default to 5 minutes */ /* set the default base dn */ ldb_set_default_dns(ldb); return LDB_SUCCESS;}void ldb_set_errstring(struct ldb_context *ldb, const char *err_string){ if (ldb->err_string) { talloc_free(ldb->err_string); } ldb->err_string = talloc_strdup(ldb, err_string);}void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...){ va_list ap; char *old_string = NULL; if (ldb->err_string) { old_string = ldb->err_string; } va_start(ap, format); ldb->err_string = talloc_vasprintf(ldb, format, ap); va_end(ap); talloc_free(old_string);}void ldb_reset_err_string(struct ldb_context *ldb){ if (ldb->err_string) { talloc_free(ldb->err_string); ldb->err_string = NULL; }}#define FIRST_OP(ldb, op) do { \ module = ldb->modules; \ while (module && module->ops->op == NULL) module = module->next; \ if (module == NULL) { \ ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \ return LDB_ERR_OPERATIONS_ERROR; \ } \} while (0)/* start a transaction*/static int ldb_transaction_start_internal(struct ldb_context *ldb){ struct ldb_module *module; int status; FIRST_OP(ldb, start_transaction); ldb_reset_err_string(ldb); status = module->ops->start_transaction(module); if (status != LDB_SUCCESS) { if (ldb->err_string == NULL) { /* no error string was setup by the backend */ ldb_asprintf_errstring(ldb, "ldb transaction start: %s (%d)", ldb_strerror(status), status); } } return status;}/* commit a transaction*/static int ldb_transaction_commit_internal(struct ldb_context *ldb){ struct ldb_module *module; int status; FIRST_OP(ldb, end_transaction); ldb_reset_err_string(ldb); status = module->ops->end_transaction(module); if (status != LDB_SUCCESS) { if (ldb->err_string == NULL) { /* no error string was setup by the backend */ ldb_asprintf_errstring(ldb, "ldb transaction commit: %s (%d)", ldb_strerror(status), status); } } return status;}/* cancel a transaction*/static int ldb_transaction_cancel_internal(struct ldb_context *ldb){ struct ldb_module *module; int status; FIRST_OP(ldb, del_transaction); status = module->ops->del_transaction(module); if (status != LDB_SUCCESS) { if (ldb->err_string == NULL) { /* no error string was setup by the backend */ ldb_asprintf_errstring(ldb, "ldb transaction cancel: %s (%d)", ldb_strerror(status), status); } } return status;}int ldb_transaction_start(struct ldb_context *ldb){ /* disable autotransactions */ ldb->transaction_active++; return ldb_transaction_start_internal(ldb);}int ldb_transaction_commit(struct ldb_context *ldb){ /* renable autotransactions (when we reach 0) */ if (ldb->transaction_active > 0) ldb->transaction_active--; return ldb_transaction_commit_internal(ldb);}int ldb_transaction_cancel(struct ldb_context *ldb){ /* renable autotransactions (when we reach 0) */ if (ldb->transaction_active > 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -