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