s4/selftest: Enable samba.tests.samba_tool.join for py3
[samba.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         uint8_t v_store[sizeof(int32_t)];
81         TDB_DATA data = { .dptr = v_store, .dsize = sizeof(v_store) };
82         NTSTATUS status;
83
84         SIVAL(v_store, 0, v);
85
86         status = dbwrap_store(db, string_term_tdb_data(keystr), data,
87                               TDB_REPLACE);
88         return status;
89 }
90
91 struct dbwrap_fetch_uint32_state {
92         NTSTATUS status;
93         uint32_t result;
94 };
95
96 static void dbwrap_fetch_uint32_parser(TDB_DATA key, TDB_DATA data,
97                                        void *private_data)
98 {
99         struct dbwrap_fetch_uint32_state *state =
100                 (struct dbwrap_fetch_uint32_state *)private_data;
101
102         if (data.dsize != sizeof(state->result)) {
103                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
104                 return;
105         }
106         state->result = IVAL(data.dptr, 0);
107         state->status = NT_STATUS_OK;
108 }
109
110 NTSTATUS dbwrap_fetch_uint32_bystring(struct db_context *db,
111                                       const char *keystr, uint32_t *val)
112 {
113         struct dbwrap_fetch_uint32_state state;
114         NTSTATUS status;
115
116         if (val == NULL) {
117                 return NT_STATUS_INVALID_PARAMETER;
118         }
119
120         state.status = NT_STATUS_INTERNAL_ERROR;
121
122         status = dbwrap_parse_record(db, string_term_tdb_data(keystr),
123                                      dbwrap_fetch_uint32_parser, &state);
124         if (!NT_STATUS_IS_OK(status)) {
125                 return status;
126         }
127         if (NT_STATUS_IS_OK(state.status)) {
128                 *val = state.result;
129         }
130         return state.status;
131 }
132
133 NTSTATUS dbwrap_store_uint32_bystring(struct db_context *db,
134                                       const char *keystr, uint32_t v)
135 {
136         uint8_t v_store[sizeof(uint32_t)];
137         TDB_DATA data = { .dptr = v_store, .dsize = sizeof(v_store) };
138         NTSTATUS status;
139
140         SIVAL(v_store, 0, v);
141
142         status = dbwrap_store(db, string_term_tdb_data(keystr), data,
143                               TDB_REPLACE);
144         return status;
145 }
146
147 /**
148  * Atomic unsigned integer change (addition):
149  *
150  * if value does not exist yet in the db, use *oldval as initial old value.
151  * return old value in *oldval.
152  * store *oldval + change_val to db.
153  */
154
155 struct dbwrap_change_uint32_atomic_context {
156         const char *keystr;
157         uint32_t *oldval;
158         uint32_t change_val;
159 };
160
161 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
162                                                    void *private_data)
163 {
164         struct db_record *rec;
165         uint32_t val = (uint32_t)-1;
166         uint32_t v_store;
167         NTSTATUS ret;
168         struct dbwrap_change_uint32_atomic_context *state;
169         TDB_DATA value;
170
171         state = (struct dbwrap_change_uint32_atomic_context *)private_data;
172
173         rec = dbwrap_fetch_locked(db, talloc_tos(),
174                                   string_term_tdb_data(state->keystr));
175         if (!rec) {
176                 return NT_STATUS_UNSUCCESSFUL;
177         }
178
179         value = dbwrap_record_get_value(rec);
180
181         if (value.dptr == NULL) {
182                 val = *(state->oldval);
183         } else if (value.dsize == sizeof(val)) {
184                 val = IVAL(value.dptr, 0);
185                 *(state->oldval) = val;
186         } else {
187                 ret = NT_STATUS_UNSUCCESSFUL;
188                 goto done;
189         }
190
191         val += state->change_val;
192
193         SIVAL(&v_store, 0, val);
194
195         ret = dbwrap_record_store(rec,
196                                   make_tdb_data((const uint8_t *)&v_store,
197                                                 sizeof(v_store)),
198                                   TDB_REPLACE);
199
200 done:
201         TALLOC_FREE(rec);
202         return ret;
203 }
204
205 NTSTATUS dbwrap_change_uint32_atomic_bystring(struct db_context *db,
206                                               const char *keystr,
207                                               uint32_t *oldval,
208                                               uint32_t change_val)
209 {
210         NTSTATUS ret;
211         struct dbwrap_change_uint32_atomic_context state;
212
213         state.keystr = keystr;
214         state.oldval = oldval;
215         state.change_val = change_val;
216
217         ret = dbwrap_change_uint32_atomic_action(db, &state);
218
219         return ret;
220 }
221
222 NTSTATUS dbwrap_trans_change_uint32_atomic_bystring(struct db_context *db,
223                                                     const char *keystr,
224                                                     uint32_t *oldval,
225                                                     uint32_t change_val)
226 {
227         NTSTATUS ret;
228         struct dbwrap_change_uint32_atomic_context state;
229
230         state.keystr = keystr;
231         state.oldval = oldval;
232         state.change_val = change_val;
233
234         ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
235
236         return ret;
237 }
238
239 /**
240  * Atomic integer change (addition):
241  *
242  * if value does not exist yet in the db, use *oldval as initial old value.
243  * return old value in *oldval.
244  * store *oldval + change_val to db.
245  */
246
247 struct dbwrap_change_int32_atomic_context {
248         TDB_DATA key;
249         int32_t *oldval;
250         int32_t change_val;
251 };
252
253 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
254                                                   void *private_data)
255 {
256         struct db_record *rec;
257         int32_t val = -1;
258         int32_t v_store;
259         NTSTATUS ret;
260         struct dbwrap_change_int32_atomic_context *state;
261         TDB_DATA value;
262
263         state = (struct dbwrap_change_int32_atomic_context *)private_data;
264
265         rec = dbwrap_fetch_locked(db, talloc_tos(), state->key);
266         if (!rec) {
267                 return NT_STATUS_UNSUCCESSFUL;
268         }
269
270         value = dbwrap_record_get_value(rec);
271
272         if (value.dptr == NULL) {
273                 val = *(state->oldval);
274         } else if (value.dsize == sizeof(val)) {
275                 val = IVAL(value.dptr, 0);
276                 *(state->oldval) = val;
277         } else {
278                 ret = NT_STATUS_UNSUCCESSFUL;
279                 goto done;
280         }
281
282         val += state->change_val;
283
284         SIVAL(&v_store, 0, val);
285
286         ret = dbwrap_record_store(rec,
287                                   make_tdb_data((const uint8_t *)&v_store,
288                                                 sizeof(v_store)),
289                                   TDB_REPLACE);
290
291 done:
292         TALLOC_FREE(rec);
293         return ret;
294 }
295
296 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db,
297                                     TDB_DATA key,
298                                     int32_t *oldval,
299                                     int32_t change_val)
300 {
301         NTSTATUS ret;
302         struct dbwrap_change_int32_atomic_context state;
303
304         state.key = key;
305         state.oldval = oldval;
306         state.change_val = change_val;
307
308         ret = dbwrap_change_int32_atomic_action(db, &state);
309
310         return ret;
311 }
312
313 NTSTATUS dbwrap_change_int32_atomic_bystring(struct db_context *db,
314                                              const char *keystr,
315                                              int32_t *oldval,
316                                              int32_t change_val)
317 {
318         return dbwrap_change_int32_atomic(db, string_term_tdb_data(keystr),
319                                           oldval, change_val);
320 }
321
322 NTSTATUS dbwrap_trans_change_int32_atomic_bystring(struct db_context *db,
323                                                    const char *keystr,
324                                                    int32_t *oldval,
325                                                    int32_t change_val)
326 {
327         NTSTATUS ret;
328         struct dbwrap_change_int32_atomic_context state;
329
330         state.key = string_term_tdb_data(keystr);
331         state.oldval = oldval;
332         state.change_val = change_val;
333
334         ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
335
336         return ret;
337 }
338
339 struct dbwrap_store_context {
340         TDB_DATA *key;
341         TDB_DATA *dbuf;
342         int flag;
343 };
344
345 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
346 {
347         NTSTATUS status;
348         struct dbwrap_store_context *store_ctx;
349
350         store_ctx = (struct dbwrap_store_context *)private_data;
351
352         status = dbwrap_store(db, *(store_ctx->key), *(store_ctx->dbuf),
353                               store_ctx->flag);
354         if (!NT_STATUS_IS_OK(status)) {
355                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
356         }
357
358         return status;
359 }
360
361 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
362                             int flag)
363 {
364         NTSTATUS status;
365         struct dbwrap_store_context store_ctx;
366
367         store_ctx.key = &key;
368         store_ctx.dbuf = &dbuf;
369         store_ctx.flag = flag;
370
371         status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
372
373         return status;
374 }
375
376 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
377 {
378         NTSTATUS status;
379         TDB_DATA *key = (TDB_DATA *)private_data;
380
381         status = dbwrap_delete(db, *key);
382         if (!NT_STATUS_IS_OK(status)) {
383                 DBG_INFO("dbwrap_record_delete returned %s\n",
384                          nt_errstr(status));
385         }
386         return  status;
387 }
388
389 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
390 {
391         NTSTATUS status;
392
393         status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
394
395         return status;
396 }
397
398 NTSTATUS dbwrap_trans_store_int32_bystring(struct db_context *db,
399                                            const char *keystr,
400                                            int32_t v)
401 {
402         int32_t v_store;
403
404         SIVAL(&v_store, 0, v);
405
406         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
407                                   make_tdb_data((const uint8_t *)&v_store,
408                                                 sizeof(v_store)),
409                                   TDB_REPLACE);
410 }
411
412 NTSTATUS dbwrap_trans_store_uint32_bystring(struct db_context *db,
413                                             const char *keystr,
414                                             uint32_t v)
415 {
416         uint32_t v_store;
417
418         SIVAL(&v_store, 0, v);
419
420         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
421                                   make_tdb_data((const uint8_t *)&v_store,
422                                                 sizeof(v_store)),
423                                   TDB_REPLACE);
424 }
425
426 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
427                                      TDB_DATA data, int flags)
428 {
429         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
430 }
431
432 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
433 {
434         return dbwrap_trans_delete(db, string_term_tdb_data(key));
435 }
436
437 /**
438  * Wrap db action(s) into a transaction.
439  */
440 NTSTATUS dbwrap_trans_do(struct db_context *db,
441                          NTSTATUS (*action)(struct db_context *, void *),
442                          void *private_data)
443 {
444         int res;
445         NTSTATUS status;
446
447         res = dbwrap_transaction_start(db);
448         if (res != 0) {
449                 DEBUG(5, ("transaction_start failed\n"));
450                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
451         }
452
453         status = action(db, private_data);
454         if (!NT_STATUS_IS_OK(status)) {
455                 if (dbwrap_transaction_cancel(db) != 0) {
456                         smb_panic("Cancelling transaction failed");
457                 }
458                 return status;
459         }
460
461         res = dbwrap_transaction_commit(db);
462         if (res == 0) {
463                 return NT_STATUS_OK;
464         }
465
466         DEBUG(2, ("transaction_commit failed\n"));
467         return NT_STATUS_INTERNAL_DB_CORRUPTION;
468 }
469
470 struct dbwrap_trans_traverse_action_ctx {
471         int (*f)(struct db_record* rec, void* private_data);
472         void* private_data;
473 };
474
475
476 static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
477 {
478         struct dbwrap_trans_traverse_action_ctx* ctx =
479                 (struct dbwrap_trans_traverse_action_ctx*)private_data;
480
481         NTSTATUS status = dbwrap_traverse(db, ctx->f, ctx->private_data, NULL);
482
483         return status;
484 }
485
486 NTSTATUS dbwrap_trans_traverse(struct db_context *db,
487                                int (*f)(struct db_record*, void*),
488                                void *private_data)
489 {
490         struct dbwrap_trans_traverse_action_ctx ctx = {
491                 .f = f,
492                 .private_data = private_data,
493         };
494         return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
495 }
496
497 NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key)
498 {
499         NTSTATUS status;
500
501         status = dbwrap_delete(db, key);
502         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
503                 status = NT_STATUS_OK;
504         }
505
506         return status;
507 }
508
509 NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key)
510 {
511         return dbwrap_purge(db, string_term_tdb_data(key));
512 }
513
514 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
515 {
516         return dbwrap_delete(db, string_term_tdb_data(key));
517 }
518
519 NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
520                                TDB_DATA data, int flags)
521 {
522         return dbwrap_store(db, string_term_tdb_data(key), data, flags);
523 }
524
525 NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
526                                const char *key, TDB_DATA *value)
527 {
528         return dbwrap_fetch(db, mem_ctx, string_term_tdb_data(key), value);
529 }
530
531
532
533 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
534 {
535         char *key_upper;
536         NTSTATUS status;
537
538         key_upper = talloc_strdup_upper(talloc_tos(), key);
539         if (key_upper == NULL) {
540                 return NT_STATUS_NO_MEMORY;
541         }
542
543         status = dbwrap_delete_bystring(db, key_upper);
544
545         talloc_free(key_upper);
546         return status;
547 }
548
549 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
550                                      TDB_DATA data, int flags)
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_store_bystring(db, key_upper, data, flags);
561
562         talloc_free(key_upper);
563         return status;
564 }
565
566 NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
567                                      const char *key, TDB_DATA *value)
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_fetch_bystring(db, mem_ctx, key_upper, value);
578
579         talloc_free(key_upper);
580         return status;
581 }
582
583 struct dbwrap_marshall_state {
584         uint8_t *buf;
585         size_t bufsize;
586         size_t dbsize;
587 };
588
589 static int dbwrap_marshall_fn(struct db_record *rec, void *private_data)
590 {
591         struct dbwrap_marshall_state *state = private_data;
592         TDB_DATA key, value;
593         size_t new_dbsize;
594
595         key = dbwrap_record_get_key(rec);
596         value = dbwrap_record_get_value(rec);
597
598         new_dbsize = state->dbsize;
599         new_dbsize += 8 + key.dsize;
600         new_dbsize += 8 + value.dsize;
601
602         if (new_dbsize <= state->bufsize) {
603                 uint8_t *p = state->buf + state->dbsize;
604
605                 SBVAL(p, 0, key.dsize);
606                 p += 8;
607                 memcpy(p, key.dptr, key.dsize);
608                 p += key.dsize;
609
610                 SBVAL(p, 0, value.dsize);
611                 p += 8;
612                 memcpy(p, value.dptr, value.dsize);
613         }
614         state->dbsize = new_dbsize;
615         return 0;
616 }
617
618 size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize)
619 {
620         struct dbwrap_marshall_state state;
621
622         state.bufsize = bufsize;
623         state.buf = buf;
624         state.dbsize = 0;
625
626         dbwrap_traverse_read(db, dbwrap_marshall_fn, &state, NULL);
627
628         return state.dbsize;
629 }
630
631 static ssize_t dbwrap_unmarshall_get_data(const uint8_t *buf, size_t buflen,
632                                           size_t ofs, TDB_DATA *pdata)
633 {
634         uint64_t space, len;
635         const uint8_t *p;
636
637         if (ofs == buflen) {
638                 return 0;
639         }
640         if (ofs > buflen) {
641                 return -1;
642         }
643
644         space = buflen - ofs;
645         if (space < 8) {
646                 return -1;
647         }
648
649         p = buf + ofs;
650         len = BVAL(p, 0);
651
652         p += 8;
653         space -= 8;
654
655         if (len > space) {
656                 return -1;
657         }
658
659         *pdata = (TDB_DATA) { .dptr = discard_const_p(uint8_t, p),
660                               .dsize = len };
661         return len + 8;
662 }
663
664 NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
665                                    bool (*fn)(TDB_DATA key, TDB_DATA value,
666                                               void *private_data),
667                                    void *private_data)
668 {
669         size_t ofs = 0;
670
671         while (true) {
672                 ssize_t len;
673                 TDB_DATA key, value;
674                 bool ok;
675
676                 len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &key);
677                 if (len == 0) {
678                         break;
679                 }
680                 if (len == -1) {
681                         return NT_STATUS_INVALID_PARAMETER;
682                 }
683                 ofs += len;
684
685                 len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &value);
686                 if (len == 0) {
687                         break;
688                 }
689                 if (len == -1) {
690                         return NT_STATUS_INVALID_PARAMETER;
691                 }
692                 ofs += len;
693
694                 ok = fn(key, value, private_data);
695                 if (!ok) {
696                         break;
697                 }
698         }
699
700         return NT_STATUS_OK;
701 }
702
703 struct dbwrap_unmarshall_state {
704         struct db_context *db;
705         NTSTATUS ret;
706 };
707
708 static bool dbwrap_unmarshall_fn(TDB_DATA key, TDB_DATA value,
709                                  void *private_data)
710 {
711         struct dbwrap_unmarshall_state *state = private_data;
712         NTSTATUS status;
713
714         status = dbwrap_store(state->db, key, value, 0);
715         if (!NT_STATUS_IS_OK(status)) {
716                 DBG_DEBUG("dbwrap_record_store failed: %s\n",
717                           nt_errstr(status));
718                 state->ret = status;
719                 return false;
720         }
721
722         return true;
723 }
724
725 NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
726                            size_t buflen)
727 {
728         struct dbwrap_unmarshall_state state = { .db = db };
729         NTSTATUS status;
730
731         status = dbwrap_parse_marshall_buf(buf, buflen,
732                                            dbwrap_unmarshall_fn, &state);
733         if (!NT_STATUS_IS_OK(status)) {
734                 return status;
735         }
736         return state.ret;
737 }