lib/ldb-samba: only debug LDB_DEBUG_TRACE at level 10
[ira/third_party.git] / ldb-samba / ldb_wrap.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    LDB wrap functions
5
6    Copyright (C) Andrew Tridgell 2004-2009
7
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.
12
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.
17
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/>.
20 */
21
22 /*
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
27 */
28
29 #include "includes.h"
30 #include "lib/events/events.h"
31 #include <ldb.h>
32 #include <ldb_errors.h>
33 #include "lib/ldb-samba/ldif_handlers.h"
34 #include "ldb_wrap.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "param/param.h"
37 #include "../lib/util/dlinklist.h"
38 #include <tdb.h>
39
40 #define DBGC_CLASS DBGC_LDB
41
42 /*
43   this is used to catch debug messages from ldb
44 */
45 static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
46                            const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
47
48 static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
49                            const char *fmt, va_list ap)
50 {
51         int samba_level = -1;
52         switch (level) {
53         case LDB_DEBUG_FATAL:
54                 samba_level = 0;
55                 break;
56         case LDB_DEBUG_ERROR:
57                 samba_level = 1;
58                 break;
59         case LDB_DEBUG_WARNING:
60                 samba_level = 2;
61                 break;
62         case LDB_DEBUG_TRACE:
63                 samba_level = 10;
64                 break;
65
66         };
67         if (CHECK_DEBUGLVL(samba_level)) {
68                 char *s = NULL;
69                 vasprintf(&s, fmt, ap);
70                 if (!s) return;
71                 DEBUG(samba_level, ("ldb: %s\n", s));
72                 free(s);
73         }
74 }
75
76
77 /*
78   connecting to a ldb can be a relatively expensive operation because
79   of the schema and partition loads. We keep a list of open ldb
80   contexts here, and try to re-use when possible.
81
82   This means callers of ldb_wrap_connect() must use talloc_unlink() or
83   the free of a parent to destroy the context
84  */
85 static struct ldb_wrap {
86         struct ldb_wrap *next, *prev;
87         struct ldb_wrap_context {
88                 /* the context is what we use to tell if two ldb
89                  * connections are exactly equivalent
90                  */
91                 const char *url;
92                 struct tevent_context *ev;
93                 struct loadparm_context *lp_ctx;
94                 struct auth_session_info *session_info;
95                 struct cli_credentials *credentials;
96                 unsigned int flags;
97         } context;
98         struct ldb_context *ldb;
99 } *ldb_wrap_list;
100
101 /*
102    free a ldb_wrap structure
103  */
104 static int ldb_wrap_destructor(struct ldb_wrap *w)
105 {
106         DLIST_REMOVE(ldb_wrap_list, w);
107         return 0;
108 }
109
110 /*
111  * The casefolder for s4's LDB databases - Unicode-safe
112  */
113 char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n)
114 {
115         return strupper_talloc_n(mem_ctx, s, n);
116 }
117
118
119  struct ldb_context *samba_ldb_init(TALLOC_CTX *mem_ctx,
120                                     struct tevent_context *ev,
121                                     struct loadparm_context *lp_ctx,
122                                     struct auth_session_info *session_info,
123                                     struct cli_credentials *credentials)
124 {
125         struct ldb_context *ldb;
126         int ret;
127
128         ldb = ldb_init(mem_ctx, ev);
129         if (ldb == NULL) {
130                 return NULL;
131         }
132
133         ldb_set_modules_dir(ldb, modules_path(ldb, "ldb"));
134
135         ldb_set_debug(ldb, ldb_wrap_debug, NULL);
136
137         ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
138
139         if (session_info) {
140                 if (ldb_set_opaque(ldb, "sessionInfo", session_info)) {
141                         talloc_free(ldb);
142                         return NULL;
143                 }
144         }
145
146         if (credentials) {
147                 if (ldb_set_opaque(ldb, "credentials", credentials)) {
148                         talloc_free(ldb);
149                         return NULL;
150                 }
151         }
152
153         if (ldb_set_opaque(ldb, "loadparm", lp_ctx)) {
154                 talloc_free(ldb);
155                 return NULL;
156         }
157
158         /* This must be done before we load the schema, as these
159          * handlers for objectSid and objectGUID etc must take
160          * precedence over the 'binary attribute' declaration in the
161          * schema */
162         ret = ldb_register_samba_handlers(ldb);
163         if (ret != LDB_SUCCESS) {
164                 talloc_free(ldb);
165                 return NULL;
166         }
167
168         /* we usually want Samba databases to be private. If we later
169            find we need one public, we will need to add a parameter to
170            ldb_wrap_connect() */
171         ldb_set_create_perms(ldb, 0600);
172
173         return ldb;
174 }
175
176  struct ldb_context *ldb_wrap_find(const char *url,
177                                    struct tevent_context *ev,
178                                    struct loadparm_context *lp_ctx,
179                                    struct auth_session_info *session_info,
180                                    struct cli_credentials *credentials,
181                                    unsigned int flags)
182 {
183         struct ldb_wrap *w;
184         /* see if we can re-use an existing ldb */
185         for (w=ldb_wrap_list; w; w=w->next) {
186                 if (w->context.ev == ev &&
187                     w->context.lp_ctx == lp_ctx &&
188                     w->context.session_info == session_info &&
189                     w->context.credentials == credentials &&
190                     w->context.flags == flags &&
191                     (w->context.url == url || strcmp(w->context.url, url) == 0))
192                         return w->ldb;
193         }
194
195         return NULL;
196 }
197
198 int samba_ldb_connect(struct ldb_context *ldb, struct loadparm_context *lp_ctx,
199                       const char *url, unsigned int flags)
200 {
201         int ret;
202         char *real_url = NULL;
203
204         /* allow admins to force non-sync ldb for all databases */
205         if (lpcfg_parm_bool(lp_ctx, NULL, "ldb", "nosync", false)) {
206                 flags |= LDB_FLG_NOSYNC;
207         }
208
209         if (DEBUGLVL(10)) {
210                 flags |= LDB_FLG_ENABLE_TRACING;
211         }
212
213         real_url = lpcfg_private_path(ldb, lp_ctx, url);
214         if (real_url == NULL) {
215                 return LDB_ERR_OPERATIONS_ERROR;
216         }
217
218         ret = ldb_connect(ldb, real_url, flags, NULL);
219
220         if (ret != LDB_SUCCESS) {
221                 return ret;
222         }
223
224         /* setup for leak detection */
225         ldb_set_opaque(ldb, "wrap_url", real_url);
226
227         return LDB_SUCCESS;
228 }
229
230  bool ldb_wrap_add(const char *url, struct tevent_context *ev,
231                    struct loadparm_context *lp_ctx,
232                    struct auth_session_info *session_info,
233                    struct cli_credentials *credentials,
234                    unsigned int flags,
235                    struct ldb_context *ldb)
236 {
237         struct ldb_wrap *w;
238         struct ldb_wrap_context c;
239
240         /* add to the list of open ldb contexts */
241         w = talloc(ldb, struct ldb_wrap);
242         if (w == NULL) {
243                 return false;
244         }
245
246         c.url          = url;
247         c.ev           = ev;
248         c.lp_ctx       = lp_ctx;
249         c.session_info = session_info;
250         c.credentials  = credentials;
251         c.flags        = flags;
252
253         w->context = c;
254         w->context.url = talloc_strdup(w, url);
255         if (w->context.url == NULL) {
256                 return false;
257         }
258
259         if (session_info) {
260                 /* take a reference to the session_info, as it is
261                  * possible for the ldb to live longer than the
262                  * session_info. This happens when a DRS DsBind call
263                  * reuses a handle, but the original connection is
264                  * shutdown. The token for the new connection is still
265                  * valid, so we need the session_info to remain valid for
266                  * ldb modules to use
267                  */
268                 if (talloc_reference(w, session_info) == NULL) {
269                         return false;
270                 }
271         }
272
273         w->ldb = ldb;
274
275         DLIST_ADD(ldb_wrap_list, w);
276
277         talloc_set_destructor(w, ldb_wrap_destructor);
278
279         return true;
280 }
281
282
283 /*
284   wrapped connection to a ldb database
285   to close just talloc_free() the returned ldb_context
286
287   TODO:  We need an error_string parameter
288  */
289  struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx,
290                                       struct tevent_context *ev,
291                                       struct loadparm_context *lp_ctx,
292                                       const char *url,
293                                       struct auth_session_info *session_info,
294                                       struct cli_credentials *credentials,
295                                       unsigned int flags)
296 {
297         struct ldb_context *ldb;
298         int ret;
299
300         ldb = ldb_wrap_find(url, ev, lp_ctx, session_info, credentials, flags);
301         if (ldb != NULL)
302                 return talloc_reference(mem_ctx, ldb);
303
304         ldb = samba_ldb_init(mem_ctx, ev, lp_ctx, session_info, credentials);
305
306         if (ldb == NULL)
307                 return NULL;
308
309         ret = samba_ldb_connect(ldb, lp_ctx, url, flags);
310         if (ret != LDB_SUCCESS) {
311                 talloc_free(ldb);
312                 return NULL;
313         }
314
315         if (!ldb_wrap_add(url, ev, lp_ctx, session_info, credentials, flags, ldb)) {
316                 talloc_free(ldb);
317                 return NULL;
318         }
319
320         DEBUG(3,("ldb_wrap open of %s\n", url));
321
322         return ldb;
323 }
324
325 /*
326   when we fork() we need to make sure that any open ldb contexts have
327   any open transactions cancelled (ntdb databases doesn't need reopening,
328   as we don't use clear_if_first).
329  */
330  void ldb_wrap_fork_hook(void)
331 {
332         struct ldb_wrap *w;
333
334         for (w=ldb_wrap_list; w; w=w->next) {
335                 if (ldb_transaction_cancel_noerr(w->ldb) != LDB_SUCCESS) {
336                         smb_panic("Failed to cancel child transactions\n");
337                 }
338         }
339
340         if (tdb_reopen_all(1) != 0) {
341                 smb_panic("tdb_reopen_all failed\n");
342         }
343 }
344
345  char *ldb_relative_path(struct ldb_context *ldb,
346                          TALLOC_CTX *mem_ctx,
347                          const char *name)
348 {
349         const char *base_url =
350                 (const char *)ldb_get_opaque(ldb, "ldb_url");
351         char *path, *p, *full_name;
352         if (name == NULL) {
353                 return NULL;
354         }
355         if (strncmp("tdb://", base_url, 6) == 0) {
356                 base_url = base_url+6;
357         }
358         path = talloc_strdup(mem_ctx, base_url);
359         if (path == NULL) {
360                 return NULL;
361         }
362         if ( (p = strrchr(path, '/')) != NULL) {
363                 p[0] = '\0';
364                 full_name = talloc_asprintf(mem_ctx, "%s/%s", path, name);
365         } else {
366                 full_name = talloc_asprintf(mem_ctx, "./%s", name);
367         }
368         talloc_free(path);
369         return full_name;
370 }