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 524673801 : static void ldb_wrap_debug(void *context, enum ldb_debug_level level,
53 : const char *fmt, va_list ap)
54 : {
55 524673801 : int samba_level = -1;
56 524673801 : switch (level) {
57 0 : case LDB_DEBUG_FATAL:
58 0 : samba_level = DBGLVL_ERR;
59 0 : break;
60 2192 : case LDB_DEBUG_ERROR:
61 2192 : samba_level = DBGLVL_WARNING;
62 2192 : break;
63 2311 : case LDB_DEBUG_WARNING:
64 2311 : samba_level = DBGLVL_NOTICE;
65 2311 : break;
66 516965202 : case LDB_DEBUG_TRACE:
67 516965202 : samba_level = DBGLVL_DEBUG + 1;
68 516965202 : break;
69 :
70 : };
71 524673801 : if (CHECK_DEBUGLVL(samba_level)) {
72 1653 : char *s = NULL;
73 7 : int ret;
74 :
75 1653 : ret = vasprintf(&s, fmt, ap);
76 1653 : if (ret == -1) {
77 0 : return;
78 : }
79 1653 : DEBUG(samba_level, ("ldb: %s\n", s));
80 1653 : 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 123617 : static int ldb_wrap_destructor(struct ldb_wrap *w)
115 : {
116 123617 : DLIST_REMOVE(ldb_wrap_list, w);
117 123617 : return 0;
118 : }
119 :
120 : /*
121 : * The casefolder for s4's LDB databases - Unicode-safe
122 : */
123 696814993 : char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n)
124 : {
125 696814993 : return strupper_talloc_n(mem_ctx, s, n);
126 : }
127 :
128 126976050 : int ldb_comparison_fold_utf8(void *ignored,
129 : const struct ldb_val *v1,
130 : const struct ldb_val *v2)
131 : {
132 253952100 : return strncasecmp_ldb((const char *)v1->data, v1->length,
133 126976050 : (const char *)v2->data, v2->length);
134 : }
135 :
136 :
137 303022 : struct ldb_context *samba_ldb_init(TALLOC_CTX *mem_ctx,
138 : struct tevent_context *ev,
139 : struct loadparm_context *lp_ctx,
140 : struct auth_session_info *session_info,
141 : struct cli_credentials *credentials)
142 : {
143 10773 : struct ldb_context *ldb;
144 10773 : int ret;
145 :
146 303022 : ldb = ldb_init(mem_ctx, ev);
147 303022 : if (ldb == NULL) {
148 0 : return NULL;
149 : }
150 :
151 303022 : ldb_set_modules_dir(ldb, modules_path(ldb, "ldb"));
152 :
153 303022 : ldb_set_debug(ldb, ldb_wrap_debug, NULL);
154 :
155 303022 : ldb_set_utf8_functions(ldb, NULL, wrap_casefold, ldb_comparison_fold_utf8);
156 :
157 303022 : if (session_info) {
158 185234 : if (ldb_set_opaque(ldb, DSDB_SESSION_INFO, session_info)) {
159 0 : talloc_free(ldb);
160 0 : return NULL;
161 : }
162 : }
163 :
164 303022 : if (credentials) {
165 821 : if (ldb_set_opaque(ldb, "credentials", credentials)) {
166 0 : talloc_free(ldb);
167 0 : return NULL;
168 : }
169 : }
170 :
171 303022 : if (ldb_set_opaque(ldb, "loadparm", lp_ctx)) {
172 0 : talloc_free(ldb);
173 0 : return NULL;
174 : }
175 :
176 : /* This must be done before we load the schema, as these
177 : * handlers for objectSid and objectGUID etc must take
178 : * precedence over the 'binary attribute' declaration in the
179 : * schema */
180 303022 : ret = ldb_register_samba_handlers(ldb);
181 303022 : if (ret != LDB_SUCCESS) {
182 0 : talloc_free(ldb);
183 0 : return NULL;
184 : }
185 :
186 : /* we usually want Samba databases to be private. If we later
187 : find we need one public, we will need to add a parameter to
188 : ldb_wrap_connect() */
189 303022 : ldb_set_create_perms(ldb, 0600);
190 :
191 303022 : return ldb;
192 : }
193 :
194 183869 : struct ldb_context *ldb_wrap_find(const char *url,
195 : struct tevent_context *ev,
196 : struct loadparm_context *lp_ctx,
197 : struct auth_session_info *session_info,
198 : struct cli_credentials *credentials,
199 : unsigned int flags)
200 : {
201 183869 : pid_t pid = getpid();
202 6871 : struct ldb_wrap *w;
203 : /* see if we can re-use an existing ldb */
204 353092 : for (w=ldb_wrap_list; w; w=w->next) {
205 251673 : if (w->context.pid == pid &&
206 142958 : w->context.ev == ev &&
207 82682 : w->context.lp_ctx == lp_ctx &&
208 82682 : w->context.session_info == session_info &&
209 82602 : w->context.credentials == credentials &&
210 82602 : w->context.flags == flags &&
211 82602 : (w->context.url == url || strcmp(w->context.url, url) == 0))
212 82450 : return w->ldb;
213 : }
214 :
215 97084 : return NULL;
216 : }
217 :
218 303010 : int samba_ldb_connect(struct ldb_context *ldb, struct loadparm_context *lp_ctx,
219 : const char *url, unsigned int flags)
220 : {
221 10761 : int ret;
222 303010 : char *real_url = NULL;
223 :
224 : /* allow admins to force non-sync ldb for all databases */
225 303010 : if (lpcfg_parm_bool(lp_ctx, NULL, "ldb", "nosync", false)) {
226 302824 : flags |= LDB_FLG_NOSYNC;
227 : }
228 :
229 303010 : if (DEBUGLVL(10)) {
230 0 : flags |= LDB_FLG_ENABLE_TRACING;
231 : }
232 :
233 303010 : real_url = lpcfg_private_path(ldb, lp_ctx, url);
234 303010 : if (real_url == NULL) {
235 0 : return LDB_ERR_OPERATIONS_ERROR;
236 : }
237 :
238 303010 : ret = ldb_connect(ldb, real_url, flags, NULL);
239 :
240 303010 : if (ret != LDB_SUCCESS) {
241 1081 : return ret;
242 : }
243 :
244 : /* setup for leak detection */
245 301927 : ldb_set_opaque(ldb, "wrap_url", real_url);
246 :
247 301927 : return LDB_SUCCESS;
248 : }
249 :
250 101399 : bool ldb_wrap_add(const char *url, struct tevent_context *ev,
251 : struct loadparm_context *lp_ctx,
252 : struct auth_session_info *session_info,
253 : struct cli_credentials *credentials,
254 : unsigned int flags,
255 : struct ldb_context *ldb)
256 : {
257 4335 : struct ldb_wrap *w;
258 4335 : struct ldb_wrap_context c;
259 :
260 : /* add to the list of open ldb contexts */
261 101399 : w = talloc(ldb, struct ldb_wrap);
262 101399 : if (w == NULL) {
263 0 : return false;
264 : }
265 :
266 101399 : c.pid = getpid();
267 101399 : c.url = url;
268 101399 : c.ev = ev;
269 101399 : c.lp_ctx = lp_ctx;
270 101399 : c.session_info = session_info;
271 101399 : c.credentials = credentials;
272 101399 : c.flags = flags;
273 :
274 101399 : w->context = c;
275 101399 : w->context.url = talloc_strdup(w, url);
276 101399 : if (w->context.url == NULL) {
277 0 : return false;
278 : }
279 :
280 101399 : if (session_info) {
281 : /* take a reference to the session_info, as it is
282 : * possible for the ldb to live longer than the
283 : * session_info. This happens when a DRS DsBind call
284 : * reuses a handle, but the original connection is
285 : * shutdown. The token for the new connection is still
286 : * valid, so we need the session_info to remain valid for
287 : * ldb modules to use
288 : */
289 101399 : if (talloc_reference(w, session_info) == NULL) {
290 0 : return false;
291 : }
292 : }
293 :
294 101399 : w->ldb = ldb;
295 :
296 101399 : DLIST_ADD(ldb_wrap_list, w);
297 :
298 101399 : talloc_set_destructor(w, ldb_wrap_destructor);
299 :
300 101399 : return true;
301 : }
302 :
303 :
304 : /*
305 : wrapped connection to a ldb database
306 : to close just talloc_free() the returned ldb_context
307 :
308 : TODO: We need an error_string parameter
309 : */
310 129197 : struct ldb_context *ldb_wrap_connect(TALLOC_CTX *mem_ctx,
311 : struct tevent_context *ev,
312 : struct loadparm_context *lp_ctx,
313 : const char *url,
314 : struct auth_session_info *session_info,
315 : struct cli_credentials *credentials,
316 : unsigned int flags)
317 : {
318 4908 : struct ldb_context *ldb;
319 4908 : int ret;
320 :
321 : /*
322 : * Unlike samdb_connect_url() do not try and cache the LDB
323 : * handle, get a new one each time. Only sam.ldb is
324 : * punitively expensive to open and helpful caches like this
325 : * cause challenges (such as if the value for 'private dir'
326 : * changes).
327 : */
328 :
329 129197 : ldb = samba_ldb_init(mem_ctx, ev, lp_ctx, session_info, credentials);
330 :
331 129197 : if (ldb == NULL)
332 0 : return NULL;
333 :
334 129197 : ret = samba_ldb_connect(ldb, lp_ctx, url, flags);
335 129197 : if (ret != LDB_SUCCESS) {
336 1063 : talloc_free(ldb);
337 1063 : return NULL;
338 : }
339 :
340 128134 : DEBUG(3,("ldb_wrap open of %s\n", url));
341 :
342 123228 : return ldb;
343 : }
344 :
345 : /*
346 : call tdb_reopen_all() in case there is a TDB open so we are
347 : not blocked from re-opening it inside ldb_tdb.
348 : */
349 16821 : void ldb_wrap_fork_hook(void)
350 : {
351 16821 : if (tdb_reopen_all(1) != 0) {
352 0 : smb_panic("tdb_reopen_all failed\n");
353 : }
354 16821 : }
355 :
356 1304329 : char *ldb_relative_path(struct ldb_context *ldb,
357 : TALLOC_CTX *mem_ctx,
358 : const char *name)
359 : {
360 45123 : const char *base_url =
361 1304329 : (const char *)ldb_get_opaque(ldb, "ldb_url");
362 45123 : char *path, *p, *full_name;
363 1304329 : if (name == NULL || base_url == NULL) {
364 0 : return NULL;
365 : }
366 1304329 : if (strncmp("tdb://", base_url, 6) == 0) {
367 49514 : base_url = base_url+6;
368 1254815 : } else if (strncmp("mdb://", base_url, 6) == 0) {
369 0 : base_url = base_url+6;
370 1254815 : } else if (strncmp("ldb://", base_url, 6) == 0) {
371 364 : base_url = base_url+6;
372 : }
373 1304329 : path = talloc_strdup(mem_ctx, base_url);
374 1304329 : if (path == NULL) {
375 0 : return NULL;
376 : }
377 1304329 : if ( (p = strrchr(path, '/')) != NULL) {
378 1304329 : p[0] = '\0';
379 1304329 : full_name = talloc_asprintf(mem_ctx, "%s/%s", path, name);
380 : } else {
381 0 : full_name = talloc_asprintf(mem_ctx, "./%s", name);
382 : }
383 1304329 : talloc_free(path);
384 1304329 : return full_name;
385 : }
|