/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 | } |