source: vendor/current/lib/ldb-samba/ldb_wrap.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

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