diff options
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c | 153 | ||||
-rw-r--r-- | source4/lib/ldb_wrap.c | 186 | ||||
-rw-r--r-- | source4/lib/tdb_wrap.c | 117 |
3 files changed, 456 insertions, 0 deletions
diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c new file mode 100644 index 0000000000..654574cd2f --- /dev/null +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb_wrap.c @@ -0,0 +1,153 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2005 + + ** 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/>. +*/ + +#include "ldb_includes.h" + +#include "ldb_tdb.h" + +/* + the purpose of this code is to work around the braindead posix locking + rules, to allow us to have a ldb open more than once while allowing + locking to work +*/ + +struct ltdb_wrap { + struct ltdb_wrap *next, *prev; + struct tdb_context *tdb; + dev_t device; + ino_t inode; +}; + +static struct ltdb_wrap *tdb_list; + +/* destroy the last connection to a tdb */ +static int ltdb_wrap_destructor(struct ltdb_wrap *w) +{ + tdb_close(w->tdb); + if (w->next) { + w->next->prev = w->prev; + } + if (w->prev) { + w->prev->next = w->next; + } + if (w == tdb_list) { + tdb_list = w->next; + } + return 0; +} + +static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4); +static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) +{ + va_list ap; + const char *name = tdb_name(tdb); + struct ldb_context *ldb = talloc_get_type(tdb_get_logging_private(tdb), struct ldb_context); + enum ldb_debug_level ldb_level; + char *message; + va_start(ap, fmt); + message = talloc_vasprintf(ldb, fmt, ap); + va_end(ap); + + switch (level) { + case TDB_DEBUG_FATAL: + ldb_level = LDB_DEBUG_FATAL; + break; + case TDB_DEBUG_ERROR: + ldb_level = LDB_DEBUG_ERROR; + break; + case TDB_DEBUG_WARNING: + ldb_level = LDB_DEBUG_WARNING; + break; + case TDB_DEBUG_TRACE: + ldb_level = LDB_DEBUG_TRACE; + break; + default: + ldb_level = LDB_DEBUG_FATAL; + } + + ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message); + talloc_free(message); +} + +/* + wrapped connection to a tdb database. The caller should _not_ free + this as it is not a talloc structure (as tdb does not use talloc + yet). It will auto-close when the caller frees the mem_ctx that is + passed to this call + */ +struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx, + const char *path, int hash_size, + int tdb_flags, + int open_flags, mode_t mode, + struct ldb_context *ldb) +{ + struct ltdb_wrap *w; + struct stat st; + struct tdb_logging_context log_ctx; + + log_ctx.log_fn = ltdb_log_fn; + log_ctx.log_private = ldb; + + if (stat(path, &st) == 0) { + for (w=tdb_list;w;w=w->next) { + if (st.st_dev == w->device && st.st_ino == w->inode) { + if (!talloc_reference(mem_ctx, w)) { + return NULL; + } + return w->tdb; + } + } + } + + w = talloc(mem_ctx, struct ltdb_wrap); + if (w == NULL) { + return NULL; + } + + w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode, &log_ctx, NULL); + if (w->tdb == NULL) { + talloc_free(w); + return NULL; + } + + if (fstat(tdb_fd(w->tdb), &st) != 0) { + tdb_close(w->tdb); + talloc_free(w); + return NULL; + } + + w->device = st.st_dev; + w->inode = st.st_ino; + + talloc_set_destructor(w, ltdb_wrap_destructor); + + w->next = tdb_list; + w->prev = NULL; + if (tdb_list) { + tdb_list->prev = w; + } + tdb_list = w; + + return w->tdb; +} + diff --git a/source4/lib/ldb_wrap.c b/source4/lib/ldb_wrap.c new file mode 100644 index 0000000000..21ca04997e --- /dev/null +++ b/source4/lib/ldb_wrap.c @@ -0,0 +1,186 @@ +/* + Unix SMB/CIFS implementation. + + LDB wrap functions + + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + the stupidity of the unix fcntl locking design forces us to never + allow a database file to be opened twice in the same process. These + wrappers provide convenient access to a tdb or ldb, taking advantage + of talloc destructors to ensure that only a single open is done +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "lib/ldb/include/ldb.h" +#include "lib/ldb/include/ldb_errors.h" +#include "lib/ldb-samba/ldif_handlers.h" +#include "ldb_wrap.h" +#include "dsdb/samdb/samdb.h" +#include "param/param.h" + +/* + this is used to catch debug messages from ldb +*/ +static void ldb_wrap_debug(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); + +static void ldb_wrap_debug(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap) +{ + int samba_level; + char *s = NULL; + switch (level) { + case LDB_DEBUG_FATAL: + samba_level = 0; + break; + case LDB_DEBUG_ERROR: + samba_level = 1; + break; + case LDB_DEBUG_WARNING: + samba_level = 2; + break; + case LDB_DEBUG_TRACE: + samba_level = 5; + break; + + }; + vasprintf(&s, fmt, ap); + if (!s) return; + DEBUG(level, ("ldb: %s\n", s)); + free(s); +} + +/* check for memory leaks on the ldb context */ +static int ldb_wrap_destructor(struct ldb_context *ldb) +{ + size_t *startup_blocks = (size_t *)ldb_get_opaque(ldb, "startup_blocks"); + if (startup_blocks && + talloc_total_blocks(ldb) > *startup_blocks + 400) { + DEBUG(0,("WARNING: probable memory leak in ldb %s - %lu blocks (startup %lu) %lu bytes\n", + (char *)ldb_get_opaque(ldb, "wrap_url"), + (unsigned long)talloc_total_blocks(ldb), + (unsigned long)*startup_blocks, + (unsigned long)talloc_total_size(ldb))); +#if 0 + talloc_report_full(ldb, stdout); + call_backtrace(); + smb_panic("probable memory leak in ldb"); +#endif + } + return 0; +} + +/* + wrapped connection to a ldb database + to close just talloc_free() the returned ldb_context + + TODO: We need an error_string parameter + */ +struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const char *url, + struct auth_session_info *session_info, + struct cli_credentials *credentials, + unsigned int flags, + const char *options[]) +{ + struct ldb_context *ldb; + int ret; + struct event_context *ev; + char *real_url = NULL; + size_t *startup_blocks; + + ldb = ldb_init(mem_ctx); + if (ldb == NULL) { + return NULL; + } + + ldb_set_modules_dir(ldb, + talloc_asprintf(ldb, "%s/ldb", lp_modulesdir(lp_ctx))); + + /* we want to use the existing event context if possible. This + relies on the fact that in smbd, everything is a child of + the main event_context */ + ev = event_context_find(ldb); + + if (ldb_set_opaque(ldb, "EventContext", ev)) { + talloc_free(ldb); + return NULL; + } + + if (ldb_set_opaque(ldb, "sessionInfo", session_info)) { + talloc_free(ldb); + return NULL; + } + + if (ldb_set_opaque(ldb, "credentials", credentials)) { + talloc_free(ldb); + return NULL; + } + + if (strcmp(lp_sam_url(lp_ctx), url) == 0) { + dsdb_set_global_schema(ldb); + } + + ret = ldb_register_samba_handlers(ldb); + if (ret == -1) { + talloc_free(ldb); + return NULL; + } + + ldb_set_debug(ldb, ldb_wrap_debug, NULL); + + ldb_set_utf8_fns(ldb, NULL, wrap_casefold); + + real_url = private_path(ldb, lp_ctx, url); + if (real_url == NULL) { + talloc_free(ldb); + return NULL; + } + + /* allow admins to force non-sync ldb for all databases */ + if (lp_parm_bool(lp_ctx, NULL, "ldb", "nosync", false)) { + flags |= LDB_FLG_NOSYNC; + } + + /* we usually want Samba databases to be private. If we later + find we need one public, we will need to add a parameter to + ldb_wrap_connect() */ + ldb_set_create_perms(ldb, 0600); + + ret = ldb_connect(ldb, real_url, flags, options); + if (ret != LDB_SUCCESS) { + talloc_free(ldb); + return NULL; + } + + /* setup for leak detection */ + ldb_set_opaque(ldb, "wrap_url", real_url); + startup_blocks = talloc(ldb, size_t); + *startup_blocks = talloc_total_blocks(ldb); + ldb_set_opaque(ldb, "startup_blocks", startup_blocks); + + talloc_set_destructor(ldb, ldb_wrap_destructor); + + return ldb; +} + + + diff --git a/source4/lib/tdb_wrap.c b/source4/lib/tdb_wrap.c new file mode 100644 index 0000000000..37095dff2c --- /dev/null +++ b/source4/lib/tdb_wrap.c @@ -0,0 +1,117 @@ +/* + Unix SMB/CIFS implementation. + TDB wrap functions + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/tdb/include/tdb.h" +#include "lib/util/dlinklist.h" +#include "tdb_wrap.h" +#include "tdb.h" + +static struct tdb_wrap *tdb_list; + +/* destroy the last connection to a tdb */ +static int tdb_wrap_destructor(struct tdb_wrap *w) +{ + tdb_close(w->tdb); + DLIST_REMOVE(tdb_list, w); + return 0; +} + +/* + Log tdb messages via DEBUG(). +*/ +static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, + const char *format, ...) PRINTF_ATTRIBUTE(3,4); + +static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, + const char *format, ...) +{ + va_list ap; + char *ptr = NULL; + int debug_level; + + va_start(ap, format); + vasprintf(&ptr, format, ap); + va_end(ap); + + switch (level) { + case TDB_DEBUG_FATAL: + debug_level = 0; + break; + case TDB_DEBUG_ERROR: + debug_level = 1; + break; + case TDB_DEBUG_WARNING: + debug_level = 2; + break; + case TDB_DEBUG_TRACE: + debug_level = 5; + break; + default: + debug_level = 0; + } + + if (ptr != NULL) { + const char *name = tdb_name(tdb); + DEBUG(debug_level, ("tdb(%s): %s", name ? name : "unnamed", ptr)); + free(ptr); + } +} + + +/* + wrapped connection to a tdb database + to close just talloc_free() the tdb_wrap pointer + */ +struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx, + const char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode) +{ + struct tdb_wrap *w; + struct tdb_logging_context log_ctx; + log_ctx.log_fn = tdb_wrap_log; + + for (w=tdb_list;w;w=w->next) { + if (strcmp(name, w->name) == 0) { + return talloc_reference(mem_ctx, w); + } + } + + w = talloc(mem_ctx, struct tdb_wrap); + if (w == NULL) { + return NULL; + } + + w->name = talloc_strdup(w, name); + + w->tdb = tdb_open_ex(name, hash_size, tdb_flags, + open_flags, mode, &log_ctx, NULL); + if (w->tdb == NULL) { + talloc_free(w); + return NULL; + } + + talloc_set_destructor(w, tdb_wrap_destructor); + + DLIST_ADD(tdb_list, w); + + return w; +} |