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