Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/dbwrap/dbwrap_util.c
Line
Count
Source
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
0
{
37
0
  struct dbwrap_fetch_int32_state *state =
38
0
    (struct dbwrap_fetch_int32_state *)private_data;
39
40
0
  if (data.dsize != sizeof(state->result)) {
41
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
42
0
    return;
43
0
  }
44
0
  state->result = IVAL(data.dptr, 0);
45
0
  state->status = NT_STATUS_OK;
46
0
}
47
48
NTSTATUS dbwrap_fetch_int32(struct db_context *db, TDB_DATA key,
49
          int32_t *result)
50
0
{
51
0
  struct dbwrap_fetch_int32_state state;
52
0
  NTSTATUS status;
53
54
0
  if (result == NULL) {
55
0
    return NT_STATUS_INVALID_PARAMETER;
56
0
  }
57
58
0
  state.status = NT_STATUS_INTERNAL_ERROR;
59
60
0
  status = dbwrap_parse_record(db, key, dbwrap_fetch_int32_parser, &state);
61
0
  if (!NT_STATUS_IS_OK(status)) {
62
0
    return status;
63
0
  }
64
65
0
  if (NT_STATUS_IS_OK(state.status)) {
66
0
    *result = state.result;
67
0
  }
68
0
  return state.status;
69
0
}
70
71
NTSTATUS dbwrap_fetch_int32_bystring(struct db_context *db, const char *keystr,
72
             int32_t *result)
73
0
{
74
0
  return dbwrap_fetch_int32(db, string_term_tdb_data(keystr), result);
75
0
}
76
77
NTSTATUS dbwrap_store_int32_bystring(struct db_context *db, const char *keystr,
78
             int32_t v)
79
0
{
80
0
  uint8_t v_store[sizeof(int32_t)];
81
0
  TDB_DATA data = { .dptr = v_store, .dsize = sizeof(v_store) };
82
0
  NTSTATUS status;
83
84
0
  SIVAL(v_store, 0, v);
85
86
0
  status = dbwrap_store(db, string_term_tdb_data(keystr), data,
87
0
            TDB_REPLACE);
88
0
  return status;
89
0
}
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
0
{
99
0
  struct dbwrap_fetch_uint32_state *state =
100
0
    (struct dbwrap_fetch_uint32_state *)private_data;
101
102
0
  if (data.dsize != sizeof(state->result)) {
103
0
    state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
104
0
    return;
105
0
  }
106
0
  state->result = IVAL(data.dptr, 0);
107
0
  state->status = NT_STATUS_OK;
108
0
}
109
110
NTSTATUS dbwrap_fetch_uint32_bystring(struct db_context *db,
111
              const char *keystr, uint32_t *val)
112
0
{
113
0
  struct dbwrap_fetch_uint32_state state;
114
0
  NTSTATUS status;
115
116
0
  if (val == NULL) {
117
0
    return NT_STATUS_INVALID_PARAMETER;
118
0
  }
119
120
0
  state.status = NT_STATUS_INTERNAL_ERROR;
121
122
0
  status = dbwrap_parse_record(db, string_term_tdb_data(keystr),
123
0
             dbwrap_fetch_uint32_parser, &state);
124
0
  if (!NT_STATUS_IS_OK(status)) {
125
0
    return status;
126
0
  }
127
0
  if (NT_STATUS_IS_OK(state.status)) {
128
0
    *val = state.result;
129
0
  }
130
0
  return state.status;
131
0
}
132
133
NTSTATUS dbwrap_store_uint32_bystring(struct db_context *db,
134
              const char *keystr, uint32_t v)
135
0
{
136
0
  uint8_t v_store[sizeof(uint32_t)];
137
0
  TDB_DATA data = { .dptr = v_store, .dsize = sizeof(v_store) };
138
0
  NTSTATUS status;
139
140
0
  SIVAL(v_store, 0, v);
141
142
0
  status = dbwrap_store(db, string_term_tdb_data(keystr), data,
143
0
            TDB_REPLACE);
144
0
  return status;
145
0
}
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
0
{
166
0
  struct dbwrap_change_uint32_atomic_context *state = private_data;
167
0
  uint8_t v_store[4];
168
0
  TDB_DATA data = {
169
0
    .dptr = v_store,
170
0
    .dsize = sizeof(v_store),
171
0
  };
172
0
  uint32_t val = UINT32_MAX;
173
174
0
  if (value.dptr == NULL) {
175
0
    val = *(state->oldval);
176
0
  } else if (value.dsize == sizeof(val)) {
177
0
    val = PULL_LE_U32(value.dptr, 0);
178
0
    *(state->oldval) = val;
179
0
  } else {
180
0
    state->status = NT_STATUS_UNSUCCESSFUL;
181
0
    return;
182
0
  }
183
184
0
  val += state->change_val;
185
0
  PUSH_LE_U32(v_store, 0, val);
186
187
0
  state->status = dbwrap_record_store(rec, data, TDB_REPLACE);
188
0
}
189
190
static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
191
               void *private_data)
192
0
{
193
0
  struct dbwrap_change_uint32_atomic_context *state = private_data;
194
0
  NTSTATUS status;
195
196
0
  status = dbwrap_do_locked(db,
197
0
          string_term_tdb_data(state->keystr),
198
0
          dbwrap_change_uint32_atomic_action_fn,
199
0
          state);
200
0
  if (!NT_STATUS_IS_OK(status)) {
201
0
    DBG_DEBUG("dbwrap_do_locked() failed: %s\n",
202
0
        nt_errstr(status));
203
0
    return status;
204
0
  }
205
0
  if (!NT_STATUS_IS_OK(state->status)) {
206
0
    DBG_DEBUG("dbwrap_change_uint32_atomic_action_fn() "
207
0
        "failed: %s\n",
208
0
        nt_errstr(status));
209
0
    return status;
210
0
  }
211
0
  return NT_STATUS_OK;
212
0
}
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
0
{
219
0
  NTSTATUS ret;
220
0
  struct dbwrap_change_uint32_atomic_context state;
221
222
0
  state.keystr = keystr;
223
0
  state.oldval = oldval;
224
0
  state.change_val = change_val;
225
226
0
  ret = dbwrap_change_uint32_atomic_action(db, &state);
227
228
0
  return ret;
229
0
}
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
0
{
236
0
  NTSTATUS ret;
237
0
  struct dbwrap_change_uint32_atomic_context state;
238
239
0
  state.keystr = keystr;
240
0
  state.oldval = oldval;
241
0
  state.change_val = change_val;
242
243
0
  ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
244
245
0
  return ret;
246
0
}
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
0
{
267
0
  struct dbwrap_change_int32_atomic_context *state = private_data;
268
0
  uint8_t v_store[4];
269
0
  TDB_DATA data = {
270
0
    .dptr = v_store,
271
0
    .dsize = sizeof(v_store),
272
0
  };
273
0
  int32_t val = -1;
274
275
0
  if (value.dptr == NULL) {
276
0
    val = *(state->oldval);
277
0
  } else if (value.dsize == sizeof(val)) {
278
0
    val = PULL_LE_U32(value.dptr, 0);
279
0
    *(state->oldval) = val;
280
0
  } else {
281
0
    state->status = NT_STATUS_UNSUCCESSFUL;
282
0
    return;
283
0
  }
284
285
0
  val += state->change_val;
286
0
  PUSH_LE_U32(v_store, 0, val);
287
288
0
  state->status = dbwrap_record_store(rec, data, TDB_REPLACE);
289
0
}
290
291
static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
292
              void *private_data)
293
0
{
294
0
  struct dbwrap_change_int32_atomic_context *state = private_data;
295
0
  NTSTATUS status;
296
297
0
  status = dbwrap_do_locked(db,
298
0
          state->key,
299
0
          dbwrap_change_int32_atomic_action_fn,
300
0
          state);
301
0
  if (!NT_STATUS_IS_OK(status)) {
302
0
    DBG_DEBUG("dbwrap_do_locked() failed: %s\n",
303
0
        nt_errstr(status));
304
0
    return status;
305
0
  }
306
0
  if (!NT_STATUS_IS_OK(state->status)) {
307
0
    DBG_DEBUG("dbwrap_change_int32_atomic_action_fn() "
308
0
        "failed: %s\n",
309
0
        nt_errstr(status));
310
0
    return status;
311
0
  }
312
0
  return NT_STATUS_OK;
313
0
}
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
0
{
320
0
  NTSTATUS ret;
321
0
  struct dbwrap_change_int32_atomic_context state;
322
323
0
  state.key = key;
324
0
  state.oldval = oldval;
325
0
  state.change_val = change_val;
326
327
0
  ret = dbwrap_change_int32_atomic_action(db, &state);
328
329
0
  return ret;
330
0
}
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
0
{
337
0
  return dbwrap_change_int32_atomic(db, string_term_tdb_data(keystr),
338
0
            oldval, change_val);
339
0
}
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
0
{
346
0
  NTSTATUS ret;
347
0
  struct dbwrap_change_int32_atomic_context state;
348
349
0
  state.key = string_term_tdb_data(keystr);
350
0
  state.oldval = oldval;
351
0
  state.change_val = change_val;
352
353
0
  ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
354
355
0
  return ret;
356
0
}
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
0
{
366
0
  NTSTATUS status;
367
0
  struct dbwrap_store_context *store_ctx;
368
369
0
  store_ctx = (struct dbwrap_store_context *)private_data;
370
371
0
  status = dbwrap_store(db, *(store_ctx->key), *(store_ctx->dbuf),
372
0
            store_ctx->flag);
373
0
  if (!NT_STATUS_IS_OK(status)) {
374
0
    DEBUG(5, ("store returned %s\n", nt_errstr(status)));
375
0
  }
376
377
0
  return status;
378
0
}
379
380
NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
381
          int flag)
382
0
{
383
0
  NTSTATUS status;
384
0
  struct dbwrap_store_context store_ctx;
385
386
0
  store_ctx.key = &key;
387
0
  store_ctx.dbuf = &dbuf;
388
0
  store_ctx.flag = flag;
389
390
0
  status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
391
392
0
  return status;
393
0
}
394
395
static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
396
0
{
397
0
  NTSTATUS status;
398
0
  TDB_DATA *key = (TDB_DATA *)private_data;
399
400
0
  status = dbwrap_delete(db, *key);
401
0
  if (!NT_STATUS_IS_OK(status)) {
402
0
    DBG_INFO("dbwrap_record_delete returned %s\n",
403
0
       nt_errstr(status));
404
0
  }
405
0
  return  status;
406
0
}
407
408
NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
409
0
{
410
0
  NTSTATUS status;
411
412
0
  status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
413
414
0
  return status;
415
0
}
416
417
NTSTATUS dbwrap_trans_store_int32_bystring(struct db_context *db,
418
             const char *keystr,
419
             int32_t v)
420
0
{
421
0
  int32_t v_store;
422
423
0
  SIVAL(&v_store, 0, v);
424
425
0
  return dbwrap_trans_store(db, string_term_tdb_data(keystr),
426
0
          make_tdb_data((const uint8_t *)&v_store,
427
0
            sizeof(v_store)),
428
0
          TDB_REPLACE);
429
0
}
430
431
NTSTATUS dbwrap_trans_store_uint32_bystring(struct db_context *db,
432
              const char *keystr,
433
              uint32_t v)
434
0
{
435
0
  uint32_t v_store;
436
437
0
  SIVAL(&v_store, 0, v);
438
439
0
  return dbwrap_trans_store(db, string_term_tdb_data(keystr),
440
0
          make_tdb_data((const uint8_t *)&v_store,
441
0
            sizeof(v_store)),
442
0
          TDB_REPLACE);
443
0
}
444
445
NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
446
             TDB_DATA data, int flags)
447
0
{
448
0
  return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
449
0
}
450
451
NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
452
0
{
453
0
  return dbwrap_trans_delete(db, string_term_tdb_data(key));
454
0
}
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
0
{
463
0
  int res;
464
0
  NTSTATUS status;
465
466
0
  res = dbwrap_transaction_start(db);
467
0
  if (res != 0) {
468
0
    DEBUG(5, ("transaction_start failed\n"));
469
0
    return NT_STATUS_INTERNAL_DB_CORRUPTION;
470
0
  }
471
472
0
  status = action(db, private_data);
473
0
  if (!NT_STATUS_IS_OK(status)) {
474
0
    if (dbwrap_transaction_cancel(db) != 0) {
475
0
      smb_panic("Cancelling transaction failed");
476
0
    }
477
0
    return status;
478
0
  }
479
480
0
  res = dbwrap_transaction_commit(db);
481
0
  if (res == 0) {
482
0
    return NT_STATUS_OK;
483
0
  }
484
485
0
  DEBUG(2, ("transaction_commit failed\n"));
486
0
  return NT_STATUS_INTERNAL_DB_CORRUPTION;
487
0
}
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
0
{
497
0
  struct dbwrap_trans_traverse_action_ctx* ctx =
498
0
    (struct dbwrap_trans_traverse_action_ctx*)private_data;
499
500
0
  NTSTATUS status = dbwrap_traverse(db, ctx->f, ctx->private_data, NULL);
501
502
0
  return status;
503
0
}
504
505
NTSTATUS dbwrap_trans_traverse(struct db_context *db,
506
             int (*f)(struct db_record*, void*),
507
             void *private_data)
508
0
{
509
0
  struct dbwrap_trans_traverse_action_ctx ctx = {
510
0
    .f = f,
511
0
    .private_data = private_data,
512
0
  };
513
0
  return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
514
0
}
515
516
NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key)
517
0
{
518
0
  NTSTATUS status;
519
520
0
  status = dbwrap_delete(db, key);
521
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
522
0
    status = NT_STATUS_OK;
523
0
  }
524
525
0
  return status;
526
0
}
527
528
NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key)
529
0
{
530
0
  return dbwrap_purge(db, string_term_tdb_data(key));
531
0
}
532
533
NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
534
0
{
535
0
  return dbwrap_delete(db, string_term_tdb_data(key));
536
0
}
537
538
NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
539
             TDB_DATA data, int flags)
540
0
{
541
0
  return dbwrap_store(db, string_term_tdb_data(key), data, flags);
542
0
}
543
544
NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
545
             const char *key, TDB_DATA *value)
546
0
{
547
0
  return dbwrap_fetch(db, mem_ctx, string_term_tdb_data(key), value);
548
0
}
549
550
551
552
NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
553
0
{
554
0
  char *key_upper;
555
0
  NTSTATUS status;
556
557
0
  key_upper = talloc_strdup_upper(talloc_tos(), key);
558
0
  if (key_upper == NULL) {
559
0
    return NT_STATUS_NO_MEMORY;
560
0
  }
561
562
0
  status = dbwrap_delete_bystring(db, key_upper);
563
564
0
  talloc_free(key_upper);
565
0
  return status;
566
0
}
567
568
NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
569
             TDB_DATA data, int flags)
570
0
{
571
0
  char *key_upper;
572
0
  NTSTATUS status;
573
574
0
  key_upper = talloc_strdup_upper(talloc_tos(), key);
575
0
  if (key_upper == NULL) {
576
0
    return NT_STATUS_NO_MEMORY;
577
0
  }
578
579
0
  status = dbwrap_store_bystring(db, key_upper, data, flags);
580
581
0
  talloc_free(key_upper);
582
0
  return status;
583
0
}
584
585
NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
586
             const char *key, TDB_DATA *value)
587
0
{
588
0
  char *key_upper;
589
0
  NTSTATUS status;
590
591
0
  key_upper = talloc_strdup_upper(talloc_tos(), key);
592
0
  if (key_upper == NULL) {
593
0
    return NT_STATUS_NO_MEMORY;
594
0
  }
595
596
0
  status = dbwrap_fetch_bystring(db, mem_ctx, key_upper, value);
597
598
0
  talloc_free(key_upper);
599
0
  return status;
600
0
}
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
0
{
610
0
  struct dbwrap_marshall_state *state = private_data;
611
0
  TDB_DATA key, value;
612
0
  size_t new_dbsize;
613
614
0
  key = dbwrap_record_get_key(rec);
615
0
  value = dbwrap_record_get_value(rec);
616
617
0
  new_dbsize = state->dbsize;
618
0
  new_dbsize += 8 + key.dsize;
619
0
  new_dbsize += 8 + value.dsize;
620
621
0
  if (new_dbsize <= state->bufsize) {
622
0
    uint8_t *p = state->buf + state->dbsize;
623
624
0
    SBVAL(p, 0, key.dsize);
625
0
    p += 8;
626
0
    memcpy(p, key.dptr, key.dsize);
627
0
    p += key.dsize;
628
629
0
    SBVAL(p, 0, value.dsize);
630
0
    p += 8;
631
0
    memcpy(p, value.dptr, value.dsize);
632
0
  }
633
0
  state->dbsize = new_dbsize;
634
0
  return 0;
635
0
}
636
637
size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize)
638
0
{
639
0
  struct dbwrap_marshall_state state;
640
641
0
  state.bufsize = bufsize;
642
0
  state.buf = buf;
643
0
  state.dbsize = 0;
644
645
0
  dbwrap_traverse_read(db, dbwrap_marshall_fn, &state, NULL);
646
647
0
  return state.dbsize;
648
0
}
649
650
static ssize_t dbwrap_unmarshall_get_data(const uint8_t *buf, size_t buflen,
651
            size_t ofs, TDB_DATA *pdata)
652
0
{
653
0
  uint64_t space, len;
654
0
  const uint8_t *p;
655
656
0
  if (ofs == buflen) {
657
0
    return 0;
658
0
  }
659
0
  if (ofs > buflen) {
660
0
    return -1;
661
0
  }
662
663
0
  space = buflen - ofs;
664
0
  if (space < 8) {
665
0
    return -1;
666
0
  }
667
668
0
  p = buf + ofs;
669
0
  len = BVAL(p, 0);
670
671
0
  p += 8;
672
0
  space -= 8;
673
674
0
  if (len > space) {
675
0
    return -1;
676
0
  }
677
678
0
  *pdata = (TDB_DATA) { .dptr = discard_const_p(uint8_t, p),
679
0
            .dsize = len };
680
0
  return len + 8;
681
0
}
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
0
{
688
0
  size_t ofs = 0;
689
690
0
  while (true) {
691
0
    ssize_t len;
692
0
    TDB_DATA key, value;
693
0
    bool ok;
694
695
0
    len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &key);
696
0
    if (len == 0) {
697
0
      break;
698
0
    }
699
0
    if (len == -1) {
700
0
      return NT_STATUS_INVALID_PARAMETER;
701
0
    }
702
0
    ofs += len;
703
704
0
    len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &value);
705
0
    if (len == 0) {
706
0
      break;
707
0
    }
708
0
    if (len == -1) {
709
0
      return NT_STATUS_INVALID_PARAMETER;
710
0
    }
711
0
    ofs += len;
712
713
0
    ok = fn(key, value, private_data);
714
0
    if (!ok) {
715
0
      break;
716
0
    }
717
0
  }
718
719
0
  return NT_STATUS_OK;
720
0
}
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
0
{
730
0
  struct dbwrap_unmarshall_state *state = private_data;
731
0
  NTSTATUS status;
732
733
0
  status = dbwrap_store(state->db, key, value, 0);
734
0
  if (!NT_STATUS_IS_OK(status)) {
735
0
    DBG_DEBUG("dbwrap_record_store failed: %s\n",
736
0
        nt_errstr(status));
737
0
    state->ret = status;
738
0
    return false;
739
0
  }
740
741
0
  return true;
742
0
}
743
744
NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
745
         size_t buflen)
746
0
{
747
0
  struct dbwrap_unmarshall_state state = { .db = db };
748
0
  NTSTATUS status;
749
750
0
  status = dbwrap_parse_marshall_buf(buf, buflen,
751
0
             dbwrap_unmarshall_fn, &state);
752
0
  if (!NT_STATUS_IS_OK(status)) {
753
0
    return status;
754
0
  }
755
0
  return state.ret;
756
0
}