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