883c7f3c9c9df449f89c8da49954b0bd90a5108a
[ddiss/samba.git] / lib / dbwrap / dbwrap_tdb.c
1 /*
2    Unix SMB/CIFS implementation.
3    Database interface wrapper around tdb
4    Copyright (C) Volker Lendecke 2005-2007
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "dbwrap/dbwrap.h"
22 #include "dbwrap/dbwrap_private.h"
23 #include "dbwrap/dbwrap_tdb.h"
24 #include "lib/tdb_wrap/tdb_wrap.h"
25 #include "lib/util/util_tdb.h"
26 #include "system/filesys.h"
27 #include "ccan/str/str.h"
28
29 struct db_tdb_ctx {
30         struct tdb_wrap *wtdb;
31
32         struct {
33                 dev_t dev;
34                 ino_t ino;
35         } id;
36 };
37
38 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag);
39 static NTSTATUS db_tdb_delete(struct db_record *rec);
40
41 static void db_tdb_log_key(const char *prefix, TDB_DATA key)
42 {
43         size_t len;
44         char *keystr;
45
46         if (DEBUGLEVEL < 10) {
47                 return;
48         }
49         len = key.dsize;
50         if (DEBUGLEVEL == 10) {
51                 /*
52                  * Only fully spam at debuglevel > 10
53                  */
54                 len = MIN(10, key.dsize);
55         }
56         keystr = hex_encode_talloc(talloc_tos(), (unsigned char *)(key.dptr),
57                                    len);
58         DEBUG(10, ("%s key %s\n", prefix, keystr));
59         TALLOC_FREE(keystr);
60 }
61
62 static int db_tdb_record_destr(struct db_record* data)
63 {
64         struct db_tdb_ctx *ctx =
65                 talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
66
67         db_tdb_log_key("Unlocking", data->key);
68         tdb_chainunlock(ctx->wtdb->tdb, data->key);
69         return 0;
70 }
71
72 struct tdb_fetch_locked_state {
73         TALLOC_CTX *mem_ctx;
74         struct db_record *result;
75 };
76
77 static int db_tdb_fetchlock_parse(TDB_DATA key, TDB_DATA data,
78                                   void *private_data)
79 {
80         struct tdb_fetch_locked_state *state =
81                 (struct tdb_fetch_locked_state *)private_data;
82         struct db_record *result;
83
84         result = (struct db_record *)talloc_size(
85                 state->mem_ctx,
86                 sizeof(struct db_record) + key.dsize + data.dsize);
87
88         if (result == NULL) {
89                 return 0;
90         }
91         state->result = result;
92
93         result->key.dsize = key.dsize;
94         result->key.dptr = ((uint8_t *)result) + sizeof(struct db_record);
95         memcpy(result->key.dptr, key.dptr, key.dsize);
96
97         result->value.dsize = data.dsize;
98
99         if (data.dsize > 0) {
100                 result->value.dptr = result->key.dptr+key.dsize;
101                 memcpy(result->value.dptr, data.dptr, data.dsize);
102         }
103         else {
104                 result->value.dptr = NULL;
105         }
106
107         return 0;
108 }
109
110 static struct db_record *db_tdb_fetch_locked_internal(
111         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
112 {
113         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
114                                                        struct db_tdb_ctx);
115         struct tdb_fetch_locked_state state;
116
117         state.mem_ctx = mem_ctx;
118         state.result = NULL;
119
120         if ((tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse,
121                               &state) < 0) &&
122             (tdb_error(ctx->wtdb->tdb) != TDB_ERR_NOEXIST)) {
123                 tdb_chainunlock(ctx->wtdb->tdb, key);
124                 return NULL;
125         }
126
127         if (state.result == NULL) {
128                 db_tdb_fetchlock_parse(key, tdb_null, &state);
129         }
130
131         if (state.result == NULL) {
132                 tdb_chainunlock(ctx->wtdb->tdb, key);
133                 return NULL;
134         }
135
136         talloc_set_destructor(state.result, db_tdb_record_destr);
137
138         state.result->private_data = talloc_reference(state.result, ctx);
139         state.result->store = db_tdb_store;
140         state.result->delete_rec = db_tdb_delete;
141
142         DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
143
144         return state.result;
145 }
146
147 static struct db_record *db_tdb_fetch_locked(
148         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
149 {
150         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
151                                                        struct db_tdb_ctx);
152
153         db_tdb_log_key("Locking", key);
154         if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
155                 DEBUG(3, ("tdb_chainlock failed\n"));
156                 return NULL;
157         }
158         return db_tdb_fetch_locked_internal(db, mem_ctx, key);
159 }
160
161 static struct db_record *db_tdb_fetch_locked_timeout(
162         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key,
163         unsigned int timeout)
164 {
165         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
166                                                        struct db_tdb_ctx);
167
168         db_tdb_log_key("Locking with timeout ", key);
169         if (tdb_chainlock_with_timeout(ctx->wtdb->tdb, key, timeout) != 0) {
170                 DEBUG(3, ("tdb_chainlock_with_timeout failed\n"));
171                 return NULL;
172         }
173         return db_tdb_fetch_locked_internal(db, mem_ctx, key);
174 }
175
176 static struct db_record *db_tdb_try_fetch_locked(
177         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
178 {
179         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
180                                                        struct db_tdb_ctx);
181
182         db_tdb_log_key("Trying to lock", key);
183         if (tdb_chainlock_nonblock(ctx->wtdb->tdb, key) != 0) {
184                 DEBUG(3, ("tdb_chainlock_nonblock failed\n"));
185                 return NULL;
186         }
187         return db_tdb_fetch_locked_internal(db, mem_ctx, key);
188 }
189
190
191 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
192 {
193         struct db_tdb_ctx *ctx = talloc_get_type_abort(
194                 db->private_data, struct db_tdb_ctx);
195         return tdb_exists(ctx->wtdb->tdb, key);
196 }
197
198 static int db_tdb_wipe(struct db_context *db)
199 {
200         struct db_tdb_ctx *ctx = talloc_get_type_abort(
201                 db->private_data, struct db_tdb_ctx);
202         return tdb_wipe_all(ctx->wtdb->tdb);
203 }
204
205 static int db_tdb_check(struct db_context *db)
206 {
207         struct db_tdb_ctx *ctx = talloc_get_type_abort(
208                 db->private_data, struct db_tdb_ctx);
209         return tdb_check(ctx->wtdb->tdb, NULL, NULL);
210 }
211
212 struct db_tdb_parse_state {
213         void (*parser)(TDB_DATA key, TDB_DATA data,
214                        void *private_data);
215         void *private_data;
216 };
217
218 /*
219  * tdb_parse_record expects a parser returning int, mixing up tdb and
220  * parser errors. Wrap around that by always returning 0 and have
221  * dbwrap_parse_record expect a parser returning void.
222  */
223
224 static int db_tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
225 {
226         struct db_tdb_parse_state *state =
227                 (struct db_tdb_parse_state *)private_data;
228         state->parser(key, data, state->private_data);
229         return 0;
230 }
231
232 static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
233                              void (*parser)(TDB_DATA key, TDB_DATA data,
234                                            void *private_data),
235                              void *private_data)
236 {
237         struct db_tdb_ctx *ctx = talloc_get_type_abort(
238                 db->private_data, struct db_tdb_ctx);
239         struct db_tdb_parse_state state;
240         int ret;
241
242         state.parser = parser;
243         state.private_data = private_data;
244
245         ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_parser, &state);
246
247         if (ret != 0) {
248                 return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
249         }
250         return NT_STATUS_OK;
251 }
252
253 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
254 {
255         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
256                                                        struct db_tdb_ctx);
257
258         /*
259          * This has a bug: We need to replace rec->value for correct
260          * operation, but right now brlock and locking don't use the value
261          * anymore after it was stored.
262          */
263
264         return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
265                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
266 }
267
268 static NTSTATUS db_tdb_delete(struct db_record *rec)
269 {
270         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
271                                                        struct db_tdb_ctx);
272
273         if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
274                 return NT_STATUS_OK;
275         }
276
277         if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
278                 return NT_STATUS_NOT_FOUND;
279         }
280
281         return NT_STATUS_UNSUCCESSFUL;
282 }
283
284 struct db_tdb_traverse_ctx {
285         struct db_context *db;
286         int (*f)(struct db_record *rec, void *private_data);
287         void *private_data;
288 };
289
290 static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
291                                 void *private_data)
292 {
293         struct db_tdb_traverse_ctx *ctx =
294                 (struct db_tdb_traverse_ctx *)private_data;
295         struct db_record rec;
296
297         rec.key = kbuf;
298         rec.value = dbuf;
299         rec.store = db_tdb_store;
300         rec.delete_rec = db_tdb_delete;
301         rec.private_data = ctx->db->private_data;
302         rec.db = ctx->db;
303
304         return ctx->f(&rec, ctx->private_data);
305 }
306
307 static int db_tdb_traverse(struct db_context *db,
308                            int (*f)(struct db_record *rec, void *private_data),
309                            void *private_data)
310 {
311         struct db_tdb_ctx *db_ctx =
312                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
313         struct db_tdb_traverse_ctx ctx;
314
315         ctx.db = db;
316         ctx.f = f;
317         ctx.private_data = private_data;
318         return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
319 }
320
321 static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
322 {
323         return NT_STATUS_MEDIA_WRITE_PROTECTED;
324 }
325
326 static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
327 {
328         return NT_STATUS_MEDIA_WRITE_PROTECTED;
329 }
330
331 static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
332                                 void *private_data)
333 {
334         struct db_tdb_traverse_ctx *ctx =
335                 (struct db_tdb_traverse_ctx *)private_data;
336         struct db_record rec;
337
338         rec.key = kbuf;
339         rec.value = dbuf;
340         rec.store = db_tdb_store_deny;
341         rec.delete_rec = db_tdb_delete_deny;
342         rec.private_data = ctx->db->private_data;
343         rec.db = ctx->db;
344
345         return ctx->f(&rec, ctx->private_data);
346 }
347
348 static int db_tdb_traverse_read(struct db_context *db,
349                            int (*f)(struct db_record *rec, void *private_data),
350                            void *private_data)
351 {
352         struct db_tdb_ctx *db_ctx =
353                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
354         struct db_tdb_traverse_ctx ctx;
355
356         ctx.db = db;
357         ctx.f = f;
358         ctx.private_data = private_data;
359         return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
360 }
361
362 static int db_tdb_get_seqnum(struct db_context *db)
363
364 {
365         struct db_tdb_ctx *db_ctx =
366                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
367         return tdb_get_seqnum(db_ctx->wtdb->tdb);
368 }
369
370 static int db_tdb_transaction_start(struct db_context *db)
371 {
372         struct db_tdb_ctx *db_ctx =
373                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
374         return tdb_transaction_start(db_ctx->wtdb->tdb) ? -1 : 0;
375 }
376
377 static NTSTATUS db_tdb_transaction_start_nonblock(struct db_context *db)
378 {
379         struct db_tdb_ctx *db_ctx =
380                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
381         int ret;
382
383         ret = tdb_transaction_start_nonblock(db_ctx->wtdb->tdb);
384         if (ret != 0) {
385                 return map_nt_error_from_tdb(tdb_error(db_ctx->wtdb->tdb));
386         }
387         return NT_STATUS_OK;
388 }
389
390 static int db_tdb_transaction_commit(struct db_context *db)
391 {
392         struct db_tdb_ctx *db_ctx =
393                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
394         return tdb_transaction_commit(db_ctx->wtdb->tdb) ? -1 : 0;
395 }
396
397 static int db_tdb_transaction_cancel(struct db_context *db)
398 {
399         struct db_tdb_ctx *db_ctx =
400                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
401         tdb_transaction_cancel(db_ctx->wtdb->tdb);
402         return 0;
403 }
404
405 static void db_tdb_id(struct db_context *db, const uint8_t **id, size_t *idlen)
406 {
407         struct db_tdb_ctx *db_ctx =
408                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
409         *id = (uint8_t *)&db_ctx->id;
410         *idlen = sizeof(db_ctx->id);
411 }
412
413 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
414                                struct loadparm_context *lp_ctx,
415                                const char *name,
416                                int hash_size, int tdb_flags,
417                                int open_flags, mode_t mode,
418                                enum dbwrap_lock_order lock_order)
419 {
420         struct db_context *result = NULL;
421         struct db_tdb_ctx *db_tdb;
422         struct stat st;
423
424         /* Extra paranoia. */
425         if (name && strends(name, ".ntdb")) {
426                 DEBUG(0, ("can't try to open %s with tdb!\n", name));
427                 return NULL;
428         }
429
430         result = talloc_zero(mem_ctx, struct db_context);
431         if (result == NULL) {
432                 DEBUG(0, ("talloc failed\n"));
433                 goto fail;
434         }
435
436         result->private_data = db_tdb = talloc(result, struct db_tdb_ctx);
437         if (db_tdb == NULL) {
438                 DEBUG(0, ("talloc failed\n"));
439                 goto fail;
440         }
441         result->lock_order = lock_order;
442
443         db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
444                                      open_flags, mode, lp_ctx);
445         if (db_tdb->wtdb == NULL) {
446                 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
447                 goto fail;
448         }
449
450         ZERO_STRUCT(db_tdb->id);
451
452         if (fstat(tdb_fd(db_tdb->wtdb->tdb), &st) == -1) {
453                 DEBUG(3, ("fstat failed: %s\n", strerror(errno)));
454                 goto fail;
455         }
456         db_tdb->id.dev = st.st_dev;
457         db_tdb->id.ino = st.st_ino;
458
459         result->fetch_locked = db_tdb_fetch_locked;
460         result->fetch_locked_timeout = db_tdb_fetch_locked_timeout;
461         result->try_fetch_locked = db_tdb_try_fetch_locked;
462         result->traverse = db_tdb_traverse;
463         result->traverse_read = db_tdb_traverse_read;
464         result->parse_record = db_tdb_parse;
465         result->get_seqnum = db_tdb_get_seqnum;
466         result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
467         result->transaction_start = db_tdb_transaction_start;
468         result->transaction_start_nonblock = db_tdb_transaction_start_nonblock;
469         result->transaction_commit = db_tdb_transaction_commit;
470         result->transaction_cancel = db_tdb_transaction_cancel;
471         result->exists = db_tdb_exists;
472         result->wipe = db_tdb_wipe;
473         result->id = db_tdb_id;
474         result->check = db_tdb_check;
475         result->stored_callback = NULL;
476         return result;
477
478  fail:
479         if (result != NULL) {
480                 TALLOC_FREE(result);
481         }
482         return NULL;
483 }