2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2004-2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 the stupidity of the unix fcntl locking design forces us to never
24 allow a database file to be opened twice in the same process. These
25 wrappers provide convenient access to a tdb or ldb, taking advantage
26 of talloc destructors to ensure that only a single open is done
30 #include "lib/events/events.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "lib/ldb-samba/ldif_handlers.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "param/param.h"
37 #include "dlinklist.h"
40 this is used to catch debug messages from ldb
42 static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
43 const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
45 static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
46 const char *fmt, va_list ap)
57 case LDB_DEBUG_WARNING:
65 vasprintf(&s, fmt, ap);
67 DEBUG(samba_level, ("ldb: %s\n", s));
73 connecting to a ldb can be a relatively expensive operation because
74 of the schema and partition loads. We keep a list of open ldb
75 contexts here, and try to re-use when possible.
77 This means callers of ldb_wrap_connect() must use talloc_unlink() or
78 the free of a parent to destroy the context
80 static struct ldb_wrap {
81 struct ldb_wrap *next, *prev;
82 struct ldb_wrap_context {
83 /* the context is what we use to tell if two ldb
84 * connections are exactly equivalent
87 struct tevent_context *ev;
88 struct loadparm_context *lp_ctx;
89 struct auth_session_info *session_info;
90 struct cli_credentials *credentials;
93 struct ldb_context *ldb;
97 see if two database opens are equivalent
99 static bool ldb_wrap_same_context(const struct ldb_wrap_context *c1,
100 const struct ldb_wrap_context *c2)
102 return (c1->ev == c2->ev &&
103 c1->lp_ctx == c2->lp_ctx &&
104 c1->session_info == c2->session_info &&
105 c1->credentials == c2->credentials &&
106 c1->flags == c2->flags &&
107 (c1->url == c2->url || strcmp(c1->url, c2->url) == 0));
111 free a ldb_wrap structure
113 static int ldb_wrap_destructor(struct ldb_wrap *w)
115 DLIST_REMOVE(ldb_wrap_list, w);
120 wrapped connection to a ldb database
121 to close just talloc_free() the returned ldb_context
123 TODO: We need an error_string parameter
125 struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx,
126 struct tevent_context *ev,
127 struct loadparm_context *lp_ctx,
129 struct auth_session_info *session_info,
130 struct cli_credentials *credentials,
133 struct ldb_context *ldb;
135 char *real_url = NULL;
137 struct ldb_wrap_context c;
142 c.session_info = session_info;
143 c.credentials = credentials;
146 /* see if we can re-use an existing ldb */
147 for (w=ldb_wrap_list; w; w=w->next) {
148 if (ldb_wrap_same_context(&c, &w->context)) {
149 return talloc_reference(mem_ctx, w->ldb);
153 /* we want to use the existing event context if possible. This
154 relies on the fact that in smbd, everything is a child of
155 the main event_context */
160 ldb = ldb_init(mem_ctx, ev);
165 ldb_set_modules_dir(ldb,
168 lp_modulesdir(lp_ctx)));
170 if (ldb_set_opaque(ldb, "sessionInfo", session_info)) {
175 if (ldb_set_opaque(ldb, "credentials", credentials)) {
180 if (ldb_set_opaque(ldb, "loadparm", lp_ctx)) {
185 /* This must be done before we load the schema, as these
186 * handlers for objectSid and objectGUID etc must take
187 * precedence over the 'binary attribute' declaration in the
189 ret = ldb_register_samba_handlers(ldb);
195 if (lp_ctx != NULL && strcmp(lp_sam_url(lp_ctx), url) == 0) {
196 dsdb_set_global_schema(ldb);
199 ldb_set_debug(ldb, ldb_wrap_debug, NULL);
201 ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
203 real_url = private_path(ldb, lp_ctx, url);
204 if (real_url == NULL) {
209 /* allow admins to force non-sync ldb for all databases */
210 if (lp_parm_bool(lp_ctx, NULL, "ldb", "nosync", false)) {
211 flags |= LDB_FLG_NOSYNC;
215 flags |= LDB_FLG_ENABLE_TRACING;
218 /* we usually want Samba databases to be private. If we later
219 find we need one public, we will need to add a parameter to
220 ldb_wrap_connect() */
221 ldb_set_create_perms(ldb, 0600);
223 ret = ldb_connect(ldb, real_url, flags, NULL);
224 if (ret != LDB_SUCCESS) {
229 /* setup for leak detection */
230 ldb_set_opaque(ldb, "wrap_url", real_url);
232 /* add to the list of open ldb contexts */
233 w = talloc(ldb, struct ldb_wrap);
240 w->context.url = talloc_strdup(w, url);
241 if (w->context.url == NULL) {
248 DLIST_ADD(ldb_wrap_list, w);
250 DEBUG(3,("ldb_wrap open of %s\n", url));
252 talloc_set_destructor(w, ldb_wrap_destructor);
258 when we fork() we need to make sure that any open ldb contexts have
259 any open transactions cancelled
261 void ldb_wrap_fork_hook(void)