5118fb788f391b18dc892023cff39ee865f3527c
[kai/samba-autobuild/.git] / lib / dbwrap / dbwrap_util.c
1 /*
2    Unix SMB/CIFS implementation.
3    Utility functions for the dbwrap API
4    Copyright (C) Volker Lendecke 2007
5    Copyright (C) Michael Adam 2009
6    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
7
8    Major code contributions from Aleksey Fedoseev (fedoseev@ru.ibm.com)
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "dbwrap.h"
27 #include "lib/util/util_tdb.h"
28
29 struct dbwrap_fetch_int32_state {
30         NTSTATUS status;
31         int32_t result;
32 };
33
34 static void dbwrap_fetch_int32_parser(TDB_DATA key, TDB_DATA data,
35                                       void *private_data)
36 {
37         struct dbwrap_fetch_int32_state *state =
38                 (struct dbwrap_fetch_int32_state *)private_data;
39
40         if (data.dsize != sizeof(state->result)) {
41                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
42                 return;
43         }
44         state->result = IVAL(data.dptr, 0);
45         state->status = NT_STATUS_OK;
46 }
47
48 NTSTATUS dbwrap_fetch_int32(struct db_context *db, TDB_DATA key,
49                             int32_t *result)
50 {
51         struct dbwrap_fetch_int32_state state;
52         NTSTATUS status;
53
54         if (result == NULL) {
55                 return NT_STATUS_INVALID_PARAMETER;
56         }
57
58         state.status = NT_STATUS_INTERNAL_ERROR;
59
60         status = dbwrap_parse_record(db, key, dbwrap_fetch_int32_parser, &state);
61         if (!NT_STATUS_IS_OK(status)) {
62                 return status;
63         }
64
65         if (NT_STATUS_IS_OK(state.status)) {
66                 *result = state.result;
67         }
68         return state.status;
69 }
70
71 NTSTATUS dbwrap_fetch_int32_bystring(struct db_context *db, const char *keystr,
72                                      int32_t *result)
73 {
74         return dbwrap_fetch_int32(db, string_term_tdb_data(keystr), result);
75 }
76
77 NTSTATUS dbwrap_store_int32_bystring(struct db_context *db, const char *keystr,
78                                      int32_t v)
79 {
80         struct db_record *rec;
81         int32_t v_store;
82         NTSTATUS status;
83
84         rec = dbwrap_fetch_locked(db, talloc_tos(),
85                                   string_term_tdb_data(keystr));
86         if (rec == NULL) {
87                 return NT_STATUS_UNSUCCESSFUL;
88         }
89
90         SIVAL(&v_store, 0, v);
91
92         status = dbwrap_record_store(rec,
93                                      make_tdb_data((const uint8_t *)&v_store,
94                                                    sizeof(v_store)),
95                                      TDB_REPLACE);
96         TALLOC_FREE(rec);
97         return status;
98 }
99
100 struct dbwrap_fetch_uint32_state {
101         NTSTATUS status;
102         uint32_t result;
103 };
104
105 static void dbwrap_fetch_uint32_parser(TDB_DATA key, TDB_DATA data,
106                                        void *private_data)
107 {
108         struct dbwrap_fetch_uint32_state *state =
109                 (struct dbwrap_fetch_uint32_state *)private_data;
110
111         if (data.dsize != sizeof(state->result)) {
112                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
113                 return;
114         }
115         state->result = IVAL(data.dptr, 0);
116         state->status = NT_STATUS_OK;
117 }
118
119 NTSTATUS dbwrap_fetch_uint32_bystring(struct db_context *db,
120                                       const char *keystr, uint32_t *val)
121 {
122         struct dbwrap_fetch_uint32_state state;
123         NTSTATUS status;
124
125         if (val == NULL) {
126                 return NT_STATUS_INVALID_PARAMETER;
127         }
128
129         state.status = NT_STATUS_INTERNAL_ERROR;
130
131         status = dbwrap_parse_record(db, string_term_tdb_data(keystr),
132                                      dbwrap_fetch_uint32_parser, &state);
133         if (!NT_STATUS_IS_OK(status)) {
134                 return status;
135         }
136         if (NT_STATUS_IS_OK(state.status)) {
137                 *val = state.result;
138         }
139         return state.status;
140 }
141
142 NTSTATUS dbwrap_store_uint32_bystring(struct db_context *db,
143                                       const char *keystr, uint32_t v)
144 {
145         struct db_record *rec;
146         uint32_t v_store;
147         NTSTATUS status;
148
149         rec = dbwrap_fetch_locked(db, talloc_tos(),
150                                   string_term_tdb_data(keystr));
151         if (rec == NULL) {
152                 return NT_STATUS_INVALID_PARAMETER;
153         }
154
155         SIVAL(&v_store, 0, v);
156
157         status = dbwrap_record_store(rec,
158                                      make_tdb_data((const uint8_t *)&v_store,
159                                                    sizeof(v_store)),
160                                      TDB_REPLACE);
161         TALLOC_FREE(rec);
162         return status;
163 }
164
165 /**
166  * Atomic unsigned integer change (addition):
167  *
168  * if value does not exist yet in the db, use *oldval as initial old value.
169  * return old value in *oldval.
170  * store *oldval + change_val to db.
171  */
172
173 struct dbwrap_change_uint32_atomic_context {
174         const char *keystr;
175         uint32_t *oldval;
176         uint32_t change_val;
177 };
178
179 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
180                                                    void *private_data)
181 {
182         struct db_record *rec;
183         uint32_t val = (uint32_t)-1;
184         uint32_t v_store;
185         NTSTATUS ret;
186         struct dbwrap_change_uint32_atomic_context *state;
187         TDB_DATA value;
188
189         state = (struct dbwrap_change_uint32_atomic_context *)private_data;
190
191         rec = dbwrap_fetch_locked(db, talloc_tos(),
192                                   string_term_tdb_data(state->keystr));
193         if (!rec) {
194                 return NT_STATUS_UNSUCCESSFUL;
195         }
196
197         value = dbwrap_record_get_value(rec);
198
199         if (value.dptr == NULL) {
200                 val = *(state->oldval);
201         } else if (value.dsize == sizeof(val)) {
202                 val = IVAL(value.dptr, 0);
203                 *(state->oldval) = val;
204         } else {
205                 ret = NT_STATUS_UNSUCCESSFUL;
206                 goto done;
207         }
208
209         val += state->change_val;
210
211         SIVAL(&v_store, 0, val);
212
213         ret = dbwrap_record_store(rec,
214                                   make_tdb_data((const uint8_t *)&v_store,
215                                                 sizeof(v_store)),
216                                   TDB_REPLACE);
217
218 done:
219         TALLOC_FREE(rec);
220         return ret;
221 }
222
223 NTSTATUS dbwrap_change_uint32_atomic_bystring(struct db_context *db,
224                                               const char *keystr,
225                                               uint32_t *oldval,
226                                               uint32_t change_val)
227 {
228         NTSTATUS ret;
229         struct dbwrap_change_uint32_atomic_context state;
230
231         state.keystr = keystr;
232         state.oldval = oldval;
233         state.change_val = change_val;
234
235         ret = dbwrap_change_uint32_atomic_action(db, &state);
236
237         return ret;
238 }
239
240 NTSTATUS dbwrap_trans_change_uint32_atomic_bystring(struct db_context *db,
241                                                     const char *keystr,
242                                                     uint32_t *oldval,
243                                                     uint32_t change_val)
244 {
245         NTSTATUS ret;
246         struct dbwrap_change_uint32_atomic_context state;
247
248         state.keystr = keystr;
249         state.oldval = oldval;
250         state.change_val = change_val;
251
252         ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
253
254         return ret;
255 }
256
257 /**
258  * Atomic integer change (addition):
259  *
260  * if value does not exist yet in the db, use *oldval as initial old value.
261  * return old value in *oldval.
262  * store *oldval + change_val to db.
263  */
264
265 struct dbwrap_change_int32_atomic_context {
266         TDB_DATA key;
267         int32_t *oldval;
268         int32_t change_val;
269 };
270
271 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
272                                                   void *private_data)
273 {
274         struct db_record *rec;
275         int32_t val = -1;
276         int32_t v_store;
277         NTSTATUS ret;
278         struct dbwrap_change_int32_atomic_context *state;
279         TDB_DATA value;
280
281         state = (struct dbwrap_change_int32_atomic_context *)private_data;
282
283         rec = dbwrap_fetch_locked(db, talloc_tos(), state->key);
284         if (!rec) {
285                 return NT_STATUS_UNSUCCESSFUL;
286         }
287
288         value = dbwrap_record_get_value(rec);
289
290         if (value.dptr == NULL) {
291                 val = *(state->oldval);
292         } else if (value.dsize == sizeof(val)) {
293                 val = IVAL(value.dptr, 0);
294                 *(state->oldval) = val;
295         } else {
296                 ret = NT_STATUS_UNSUCCESSFUL;
297                 goto done;
298         }
299
300         val += state->change_val;
301
302         SIVAL(&v_store, 0, val);
303
304         ret = dbwrap_record_store(rec,
305                                   make_tdb_data((const uint8_t *)&v_store,
306                                                 sizeof(v_store)),
307                                   TDB_REPLACE);
308
309 done:
310         TALLOC_FREE(rec);
311         return ret;
312 }
313
314 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db,
315                                     TDB_DATA key,
316                                     int32_t *oldval,
317                                     int32_t change_val)
318 {
319         NTSTATUS ret;
320         struct dbwrap_change_int32_atomic_context state;
321
322         state.key = key;
323         state.oldval = oldval;
324         state.change_val = change_val;
325
326         ret = dbwrap_change_int32_atomic_action(db, &state);
327
328         return ret;
329 }
330
331 NTSTATUS dbwrap_change_int32_atomic_bystring(struct db_context *db,
332                                              const char *keystr,
333                                              int32_t *oldval,
334                                              int32_t change_val)
335 {
336         return dbwrap_change_int32_atomic(db, string_term_tdb_data(keystr),
337                                           oldval, change_val);
338 }
339
340 NTSTATUS dbwrap_trans_change_int32_atomic_bystring(struct db_context *db,
341                                                    const char *keystr,
342                                                    int32_t *oldval,
343                                                    int32_t change_val)
344 {
345         NTSTATUS ret;
346         struct dbwrap_change_int32_atomic_context state;
347
348         state.key = string_term_tdb_data(keystr);
349         state.oldval = oldval;
350         state.change_val = change_val;
351
352         ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
353
354         return ret;
355 }
356
357 struct dbwrap_store_context {
358         TDB_DATA *key;
359         TDB_DATA *dbuf;
360         int flag;
361 };
362
363 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
364 {
365         struct db_record *rec = NULL;
366         NTSTATUS status;
367         struct dbwrap_store_context *store_ctx;
368
369         store_ctx = (struct dbwrap_store_context *)private_data;
370
371         rec = dbwrap_fetch_locked(db, talloc_tos(), *(store_ctx->key));
372         if (rec == NULL) {
373                 DEBUG(5, ("fetch_locked failed\n"));
374                 return NT_STATUS_NO_MEMORY;
375         }
376
377         status = dbwrap_record_store(rec, *(store_ctx->dbuf), store_ctx->flag);
378         if (!NT_STATUS_IS_OK(status)) {
379                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
380         }
381
382         TALLOC_FREE(rec);
383         return status;
384 }
385
386 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
387                             int flag)
388 {
389         NTSTATUS status;
390         struct dbwrap_store_context store_ctx;
391
392         store_ctx.key = &key;
393         store_ctx.dbuf = &dbuf;
394         store_ctx.flag = flag;
395
396         status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
397
398         return status;
399 }
400
401 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
402 {
403         NTSTATUS status;
404         struct db_record *rec;
405         TDB_DATA *key = (TDB_DATA *)private_data;
406
407         rec = dbwrap_fetch_locked(db, talloc_tos(), *key);
408         if (rec == NULL) {
409                 DEBUG(5, ("fetch_locked failed\n"));
410                 return NT_STATUS_NO_MEMORY;
411         }
412
413         status = dbwrap_record_delete(rec);
414         if (!NT_STATUS_IS_OK(status)) {
415                 DBG_INFO("dbwrap_record_delete returned %s\n",
416                          nt_errstr(status));
417         }
418
419         talloc_free(rec);
420         return  status;
421 }
422
423 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
424 {
425         NTSTATUS status;
426
427         status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
428
429         return status;
430 }
431
432 NTSTATUS dbwrap_trans_store_int32_bystring(struct db_context *db,
433                                            const char *keystr,
434                                            int32_t v)
435 {
436         int32_t v_store;
437
438         SIVAL(&v_store, 0, v);
439
440         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
441                                   make_tdb_data((const uint8_t *)&v_store,
442                                                 sizeof(v_store)),
443                                   TDB_REPLACE);
444 }
445
446 NTSTATUS dbwrap_trans_store_uint32_bystring(struct db_context *db,
447                                             const char *keystr,
448                                             uint32_t v)
449 {
450         uint32_t v_store;
451
452         SIVAL(&v_store, 0, v);
453
454         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
455                                   make_tdb_data((const uint8_t *)&v_store,
456                                                 sizeof(v_store)),
457                                   TDB_REPLACE);
458 }
459
460 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
461                                      TDB_DATA data, int flags)
462 {
463         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
464 }
465
466 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
467 {
468         return dbwrap_trans_delete(db, string_term_tdb_data(key));
469 }
470
471 /**
472  * Wrap db action(s) into a transaction.
473  */
474 NTSTATUS dbwrap_trans_do(struct db_context *db,
475                          NTSTATUS (*action)(struct db_context *, void *),
476                          void *private_data)
477 {
478         int res;
479         NTSTATUS status;
480
481         res = dbwrap_transaction_start(db);
482         if (res != 0) {
483                 DEBUG(5, ("transaction_start failed\n"));
484                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
485         }
486
487         status = action(db, private_data);
488         if (!NT_STATUS_IS_OK(status)) {
489                 if (dbwrap_transaction_cancel(db) != 0) {
490                         smb_panic("Cancelling transaction failed");
491                 }
492                 return status;
493         }
494
495         res = dbwrap_transaction_commit(db);
496         if (res == 0) {
497                 return NT_STATUS_OK;
498         }
499
500         DEBUG(2, ("transaction_commit failed\n"));
501         return NT_STATUS_INTERNAL_DB_CORRUPTION;
502 }
503
504 struct dbwrap_trans_traverse_action_ctx {
505         int (*f)(struct db_record* rec, void* private_data);
506         void* private_data;
507 };
508
509
510 static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
511 {
512         struct dbwrap_trans_traverse_action_ctx* ctx =
513                 (struct dbwrap_trans_traverse_action_ctx*)private_data;
514
515         NTSTATUS status = dbwrap_traverse(db, ctx->f, ctx->private_data, NULL);
516
517         return status;
518 }
519
520 NTSTATUS dbwrap_trans_traverse(struct db_context *db,
521                                int (*f)(struct db_record*, void*),
522                                void *private_data)
523 {
524         struct dbwrap_trans_traverse_action_ctx ctx = {
525                 .f = f,
526                 .private_data = private_data,
527         };
528         return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
529 }
530
531 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
532 {
533         return dbwrap_delete(db, string_term_tdb_data(key));
534 }
535
536 NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
537                                TDB_DATA data, int flags)
538 {
539         return dbwrap_store(db, string_term_tdb_data(key), data, flags);
540 }
541
542 NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
543                                const char *key, TDB_DATA *value)
544 {
545         return dbwrap_fetch(db, mem_ctx, string_term_tdb_data(key), value);
546 }
547
548
549
550 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
551 {
552         char *key_upper;
553         NTSTATUS status;
554
555         key_upper = talloc_strdup_upper(talloc_tos(), key);
556         if (key_upper == NULL) {
557                 return NT_STATUS_NO_MEMORY;
558         }
559
560         status = dbwrap_delete_bystring(db, key_upper);
561
562         talloc_free(key_upper);
563         return status;
564 }
565
566 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
567                                      TDB_DATA data, int flags)
568 {
569         char *key_upper;
570         NTSTATUS status;
571
572         key_upper = talloc_strdup_upper(talloc_tos(), key);
573         if (key_upper == NULL) {
574                 return NT_STATUS_NO_MEMORY;
575         }
576
577         status = dbwrap_store_bystring(db, key_upper, data, flags);
578
579         talloc_free(key_upper);
580         return status;
581 }
582
583 NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
584                                      const char *key, TDB_DATA *value)
585 {
586         char *key_upper;
587         NTSTATUS status;
588
589         key_upper = talloc_strdup_upper(talloc_tos(), key);
590         if (key_upper == NULL) {
591                 return NT_STATUS_NO_MEMORY;
592         }
593
594         status = dbwrap_fetch_bystring(db, mem_ctx, key_upper, value);
595
596         talloc_free(key_upper);
597         return status;
598 }
599
600 struct dbwrap_marshall_state {
601         uint8_t *buf;
602         size_t bufsize;
603         size_t dbsize;
604 };
605
606 static int dbwrap_marshall_fn(struct db_record *rec, void *private_data)
607 {
608         struct dbwrap_marshall_state *state = private_data;
609         TDB_DATA key, value;
610         size_t new_dbsize;
611
612         key = dbwrap_record_get_key(rec);
613         value = dbwrap_record_get_value(rec);
614
615         new_dbsize = state->dbsize;
616         new_dbsize += 8 + key.dsize;
617         new_dbsize += 8 + value.dsize;
618
619         if (new_dbsize <= state->bufsize) {
620                 uint8_t *p = state->buf + state->dbsize;
621
622                 SBVAL(p, 0, key.dsize);
623                 p += 8;
624                 memcpy(p, key.dptr, key.dsize);
625                 p += key.dsize;
626
627                 SBVAL(p, 0, value.dsize);
628                 p += 8;
629                 memcpy(p, value.dptr, value.dsize);
630         }
631         state->dbsize = new_dbsize;
632         return 0;
633 }
634
635 size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize)
636 {
637         struct dbwrap_marshall_state state;
638
639         state.bufsize = bufsize;
640         state.buf = buf;
641         state.dbsize = 0;
642
643         dbwrap_traverse_read(db, dbwrap_marshall_fn, &state, NULL);
644
645         return state.dbsize;
646 }
647
648 static ssize_t dbwrap_unmarshall_get_data(const uint8_t *buf, size_t buflen,
649                                           size_t ofs, TDB_DATA *pdata)
650 {
651         uint64_t space, len;
652         const uint8_t *p;
653
654         if (ofs == buflen) {
655                 return 0;
656         }
657         if (ofs > buflen) {
658                 return -1;
659         }
660
661         space = buflen - ofs;
662         if (space < 8) {
663                 return -1;
664         }
665
666         p = buf + ofs;
667         len = BVAL(p, 0);
668
669         p += 8;
670         space -= 8;
671
672         if (len > space) {
673                 return -1;
674         }
675
676         *pdata = (TDB_DATA) { .dptr = discard_const_p(uint8_t, p),
677                               .dsize = len };
678         return len + 8;
679 }
680
681 NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
682                                    bool (*fn)(TDB_DATA key, TDB_DATA value,
683                                               void *private_data),
684                                    void *private_data)
685 {
686         size_t ofs = 0;
687
688         while (true) {
689                 ssize_t len;
690                 TDB_DATA key, value;
691                 bool ok;
692
693                 len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &key);
694                 if (len == 0) {
695                         break;
696                 }
697                 if (len == -1) {
698                         return NT_STATUS_INVALID_PARAMETER;
699                 }
700                 ofs += len;
701
702                 len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &value);
703                 if (len == 0) {
704                         break;
705                 }
706                 if (len == -1) {
707                         return NT_STATUS_INVALID_PARAMETER;
708                 }
709                 ofs += len;
710
711                 ok = fn(key, value, private_data);
712                 if (!ok) {
713                         break;
714                 }
715         }
716
717         return NT_STATUS_OK;
718 }
719
720 struct dbwrap_unmarshall_state {
721         struct db_context *db;
722         NTSTATUS ret;
723 };
724
725 static bool dbwrap_unmarshall_fn(TDB_DATA key, TDB_DATA value,
726                                  void *private_data)
727 {
728         struct dbwrap_unmarshall_state *state = private_data;
729         struct db_record *rec;
730         NTSTATUS status;
731
732         rec = dbwrap_fetch_locked(state->db, state->db, key);
733         if (rec == NULL) {
734                 DEBUG(10, ("%s: dbwrap_fetch_locked failed\n",
735                            __func__));
736                 state->ret = NT_STATUS_NO_MEMORY;
737                 return false;
738         }
739
740         status = dbwrap_record_store(rec, value, 0);
741         TALLOC_FREE(rec);
742         if (!NT_STATUS_IS_OK(status)) {
743                 DEBUG(10, ("%s: dbwrap_record_store failed: %s\n",
744                            __func__, nt_errstr(status)));
745                 state->ret = status;
746                 return false;
747         }
748
749         return true;
750 }
751
752 NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
753                            size_t buflen)
754 {
755         struct dbwrap_unmarshall_state state = { .db = db };
756         NTSTATUS status;
757
758         status = dbwrap_parse_marshall_buf(buf, buflen,
759                                            dbwrap_unmarshall_fn, &state);
760         if (!NT_STATUS_IS_OK(status)) {
761                 return status;
762         }
763         return state.ret;
764 }