efdb5dbee4a4ce26212fd523308e7255479e470c
[kai/samba.git] / source3 / 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/util/tdb_wrap.h"
25 #include "lib/param/param.h"
26 #include "util_tdb.h"
27
28 struct db_tdb_ctx {
29         struct tdb_wrap *wtdb;
30 };
31
32 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag);
33 static NTSTATUS db_tdb_delete(struct db_record *rec);
34
35 static void db_tdb_log_key(const char *prefix, TDB_DATA key)
36 {
37         size_t len;
38         char *keystr;
39
40         if (DEBUGLEVEL < 10) {
41                 return;
42         }
43         len = key.dsize;
44         if (DEBUGLEVEL == 10) {
45                 /*
46                  * Only fully spam at debuglevel > 10
47                  */
48                 len = MIN(10, key.dsize);
49         }
50         keystr = hex_encode_talloc(talloc_tos(), (unsigned char *)(key.dptr),
51                                    len);
52         DEBUG(10, ("%s key %s\n", prefix, keystr));
53         TALLOC_FREE(keystr);
54 }
55
56 static int db_tdb_record_destr(struct db_record* data)
57 {
58         struct db_tdb_ctx *ctx =
59                 talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
60
61         db_tdb_log_key("Unlocking", data->key);
62         tdb_chainunlock(ctx->wtdb->tdb, data->key);
63         return 0;
64 }
65
66 struct tdb_fetch_locked_state {
67         TALLOC_CTX *mem_ctx;
68         struct db_record *result;
69 };
70
71 static int db_tdb_fetchlock_parse(TDB_DATA key, TDB_DATA data,
72                                   void *private_data)
73 {
74         struct tdb_fetch_locked_state *state =
75                 (struct tdb_fetch_locked_state *)private_data;
76         struct db_record *result;
77
78         result = (struct db_record *)talloc_size(
79                 state->mem_ctx,
80                 sizeof(struct db_record) + key.dsize + data.dsize);
81
82         if (result == NULL) {
83                 return 0;
84         }
85         state->result = result;
86
87         result->key.dsize = key.dsize;
88         result->key.dptr = ((uint8 *)result) + sizeof(struct db_record);
89         memcpy(result->key.dptr, key.dptr, key.dsize);
90
91         result->value.dsize = data.dsize;
92
93         if (data.dsize > 0) {
94                 result->value.dptr = result->key.dptr+key.dsize;
95                 memcpy(result->value.dptr, data.dptr, data.dsize);
96         }
97         else {
98                 result->value.dptr = NULL;
99         }
100
101         return 0;
102 }
103
104 static struct db_record *db_tdb_fetch_locked(struct db_context *db,
105                                      TALLOC_CTX *mem_ctx, TDB_DATA key)
106 {
107         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
108                                                        struct db_tdb_ctx);
109         struct tdb_fetch_locked_state state;
110
111         db_tdb_log_key("Locking", key);
112
113         if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
114                 DEBUG(3, ("tdb_chainlock failed\n"));
115                 return NULL;
116         }
117
118         state.mem_ctx = mem_ctx;
119         state.result = NULL;
120
121         tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse, &state);
122
123         if (state.result == NULL) {
124                 db_tdb_fetchlock_parse(key, tdb_null, &state);
125         }
126
127         if (state.result == NULL) {
128                 tdb_chainunlock(ctx->wtdb->tdb, key);
129                 return NULL;
130         }
131
132         talloc_set_destructor(state.result, db_tdb_record_destr);
133
134         state.result->private_data = talloc_reference(state.result, ctx);
135         state.result->store = db_tdb_store;
136         state.result->delete_rec = db_tdb_delete;
137
138         DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
139
140         return state.result;
141 }
142
143 struct tdb_fetch_state {
144         TALLOC_CTX *mem_ctx;
145         NTSTATUS result;
146         TDB_DATA data;
147 };
148
149 static int db_tdb_fetch_parse(TDB_DATA key, TDB_DATA data,
150                               void *private_data)
151 {
152         struct tdb_fetch_state *state =
153                 (struct tdb_fetch_state *)private_data;
154
155         if (data.dptr == NULL) {
156                 /* should not happen */
157                 state->result = NT_STATUS_INTERNAL_DB_ERROR;
158                 return -1;
159         }
160
161         state->data.dptr = (uint8 *)talloc_memdup(state->mem_ctx, data.dptr,
162                                                   data.dsize);
163         if (state->data.dptr == NULL) {
164                 state->result = NT_STATUS_NO_MEMORY;
165                 return -1;
166         }
167
168         state->data.dsize = data.dsize;
169         return 0;
170 }
171
172 static NTSTATUS db_tdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
173                              TDB_DATA key, TDB_DATA *pdata)
174 {
175         struct db_tdb_ctx *ctx = talloc_get_type_abort(
176                 db->private_data, struct db_tdb_ctx);
177
178         struct tdb_fetch_state state;
179         int ret;
180
181         state.mem_ctx = mem_ctx;
182         state.result = NT_STATUS_OK;
183         state.data = tdb_null;
184
185         ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetch_parse, &state);
186
187         if (ret != 0) {
188                 NTSTATUS status;
189
190                 if (!NT_STATUS_IS_OK(state.result)) {
191                         /* the parser has set an error code. return it */
192                         return state.result;
193                 }
194
195                 status = map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
196                 return status;
197         }
198
199         if (!NT_STATUS_IS_OK(state.result)) {
200                 return state.result;
201         }
202
203         *pdata = state.data;
204         return NT_STATUS_OK;
205 }
206
207 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
208 {
209         struct db_tdb_ctx *ctx = talloc_get_type_abort(
210                 db->private_data, struct db_tdb_ctx);
211         return tdb_exists(ctx->wtdb->tdb, key);
212 }
213
214 static int db_tdb_wipe(struct db_context *db)
215 {
216         struct db_tdb_ctx *ctx = talloc_get_type_abort(
217                 db->private_data, struct db_tdb_ctx);
218         return tdb_wipe_all(ctx->wtdb->tdb);
219 }
220
221 struct db_tdb_parse_state {
222         void (*parser)(TDB_DATA key, TDB_DATA data,
223                        void *private_data);
224         void *private_data;
225 };
226
227 /*
228  * tdb_parse_record expects a parser returning int, mixing up tdb and
229  * parser errors. Wrap around that by always returning 0 and have
230  * dbwrap_parse_record expect a parser returning void.
231  */
232
233 static int db_tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
234 {
235         struct db_tdb_parse_state *state =
236                 (struct db_tdb_parse_state *)private_data;
237         state->parser(key, data, state->private_data);
238         return 0;
239 }
240
241 static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
242                              void (*parser)(TDB_DATA key, TDB_DATA data,
243                                            void *private_data),
244                              void *private_data)
245 {
246         struct db_tdb_ctx *ctx = talloc_get_type_abort(
247                 db->private_data, struct db_tdb_ctx);
248         struct db_tdb_parse_state state;
249         int ret;
250
251         state.parser = parser;
252         state.private_data = private_data;
253
254         ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_parser, &state);
255         return map_nt_error_from_tdb(ret);
256 }
257
258 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
259 {
260         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
261                                                        struct db_tdb_ctx);
262
263         /*
264          * This has a bug: We need to replace rec->value for correct
265          * operation, but right now brlock and locking don't use the value
266          * anymore after it was stored.
267          */
268
269         return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
270                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
271 }
272
273 static NTSTATUS db_tdb_delete(struct db_record *rec)
274 {
275         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
276                                                        struct db_tdb_ctx);
277
278         if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
279                 return NT_STATUS_OK;
280         }
281
282         if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
283                 return NT_STATUS_NOT_FOUND;
284         }
285
286         return NT_STATUS_UNSUCCESSFUL;
287 }
288
289 struct db_tdb_traverse_ctx {
290         struct db_context *db;
291         int (*f)(struct db_record *rec, void *private_data);
292         void *private_data;
293 };
294
295 static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
296                                 void *private_data)
297 {
298         struct db_tdb_traverse_ctx *ctx =
299                 (struct db_tdb_traverse_ctx *)private_data;
300         struct db_record rec;
301
302         rec.key = kbuf;
303         rec.value = dbuf;
304         rec.store = db_tdb_store;
305         rec.delete_rec = db_tdb_delete;
306         rec.private_data = ctx->db->private_data;
307
308         return ctx->f(&rec, ctx->private_data);
309 }
310
311 static int db_tdb_traverse(struct db_context *db,
312                            int (*f)(struct db_record *rec, void *private_data),
313                            void *private_data)
314 {
315         struct db_tdb_ctx *db_ctx =
316                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
317         struct db_tdb_traverse_ctx ctx;
318
319         ctx.db = db;
320         ctx.f = f;
321         ctx.private_data = private_data;
322         return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
323 }
324
325 static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
326 {
327         return NT_STATUS_MEDIA_WRITE_PROTECTED;
328 }
329
330 static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
331 {
332         return NT_STATUS_MEDIA_WRITE_PROTECTED;
333 }
334
335 static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
336                                 void *private_data)
337 {
338         struct db_tdb_traverse_ctx *ctx =
339                 (struct db_tdb_traverse_ctx *)private_data;
340         struct db_record rec;
341
342         rec.key = kbuf;
343         rec.value = dbuf;
344         rec.store = db_tdb_store_deny;
345         rec.delete_rec = db_tdb_delete_deny;
346         rec.private_data = ctx->db->private_data;
347
348         return ctx->f(&rec, ctx->private_data);
349 }
350
351 static int db_tdb_traverse_read(struct db_context *db,
352                            int (*f)(struct db_record *rec, void *private_data),
353                            void *private_data)
354 {
355         struct db_tdb_ctx *db_ctx =
356                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
357         struct db_tdb_traverse_ctx ctx;
358
359         ctx.db = db;
360         ctx.f = f;
361         ctx.private_data = private_data;
362         return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
363 }
364
365 static int db_tdb_get_seqnum(struct db_context *db)
366
367 {
368         struct db_tdb_ctx *db_ctx =
369                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
370         return tdb_get_seqnum(db_ctx->wtdb->tdb);
371 }
372
373 static int db_tdb_get_flags(struct db_context *db)
374
375 {
376         struct db_tdb_ctx *db_ctx =
377                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
378         return tdb_get_flags(db_ctx->wtdb->tdb);
379 }
380
381 static int db_tdb_transaction_start(struct db_context *db)
382 {
383         struct db_tdb_ctx *db_ctx =
384                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
385         return tdb_transaction_start(db_ctx->wtdb->tdb) ? -1 : 0;
386 }
387
388 static int db_tdb_transaction_commit(struct db_context *db)
389 {
390         struct db_tdb_ctx *db_ctx =
391                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
392         return tdb_transaction_commit(db_ctx->wtdb->tdb) ? -1 : 0;
393 }
394
395 static int db_tdb_transaction_cancel(struct db_context *db)
396 {
397         struct db_tdb_ctx *db_ctx =
398                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
399         tdb_transaction_cancel(db_ctx->wtdb->tdb);
400         return 0;
401 }
402
403 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
404                                const char *name,
405                                int hash_size, int tdb_flags,
406                                int open_flags, mode_t mode)
407 {
408         struct db_context *result = NULL;
409         struct db_tdb_ctx *db_tdb;
410         struct loadparm_context *lp_ctx;
411
412         result = talloc_zero(mem_ctx, struct db_context);
413         if (result == NULL) {
414                 DEBUG(0, ("talloc failed\n"));
415                 goto fail;
416         }
417         lp_ctx = loadparm_init_s3(result, loadparm_s3_context());
418
419         result->private_data = db_tdb = talloc(result, struct db_tdb_ctx);
420         if (db_tdb == NULL) {
421                 DEBUG(0, ("talloc failed\n"));
422                 goto fail;
423         }
424
425         db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
426                                      open_flags, mode, lp_ctx);
427         talloc_unlink(result, lp_ctx);
428         if (db_tdb->wtdb == NULL) {
429                 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
430                 goto fail;
431         }
432
433         result->fetch_locked = db_tdb_fetch_locked;
434         result->fetch = db_tdb_fetch;
435         result->traverse = db_tdb_traverse;
436         result->traverse_read = db_tdb_traverse_read;
437         result->parse_record = db_tdb_parse;
438         result->get_seqnum = db_tdb_get_seqnum;
439         result->get_flags = db_tdb_get_flags;
440         result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
441         result->transaction_start = db_tdb_transaction_start;
442         result->transaction_commit = db_tdb_transaction_commit;
443         result->transaction_cancel = db_tdb_transaction_cancel;
444         result->exists = db_tdb_exists;
445         result->wipe = db_tdb_wipe;
446         return result;
447
448  fail:
449         if (result != NULL) {
450                 TALLOC_FREE(result);
451         }
452         return NULL;
453 }