Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : tdb utility functions
5 :
6 : Copyright (C) Andrew Tridgell 1992-2006
7 : Copyright (C) Volker Lendecke 2007-2011
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "replace.h"
24 : #include <talloc.h>
25 : #include "libcli/util/ntstatus.h"
26 : #include "lib/util/memory.h"
27 : #include "lib/util/byteorder.h"
28 : #include "system/filesys.h"
29 : #include "../lib/tdb/include/tdb.h"
30 : #include "../lib/util/util_tdb.h"
31 :
32 : /* these are little tdb utility functions that are meant to make
33 : dealing with a tdb database a little less cumbersome in Samba */
34 :
35 : /***************************************************************
36 : Make a TDB_DATA and keep the const warning in one place
37 : ****************************************************************/
38 :
39 95460295 : TDB_DATA make_tdb_data(const uint8_t *dptr, size_t dsize)
40 : {
41 1296939 : TDB_DATA ret;
42 95460295 : ret.dptr = discard_const_p(uint8_t, dptr);
43 95460295 : ret.dsize = dsize;
44 95460295 : return ret;
45 : }
46 :
47 6 : bool tdb_data_equal(TDB_DATA t1, TDB_DATA t2)
48 : {
49 6 : if (t1.dsize != t2.dsize) {
50 2 : return false;
51 : }
52 4 : return (memcmp(t1.dptr, t2.dptr, t1.dsize) == 0);
53 : }
54 :
55 2880 : bool tdb_data_is_empty(TDB_DATA d)
56 : {
57 2880 : return (d.dsize == 0) || (d.dptr == NULL);
58 : }
59 :
60 350960 : TDB_DATA string_tdb_data(const char *string)
61 : {
62 350960 : return make_tdb_data((const uint8_t *)string, string ? strlen(string) : 0 );
63 : }
64 :
65 16794199 : TDB_DATA string_term_tdb_data(const char *string)
66 : {
67 16794199 : return make_tdb_data((const uint8_t *)string, string ? strlen(string) + 1 : 0);
68 : }
69 :
70 4775 : TDB_DATA tdb_data_talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data) {
71 4849 : TDB_DATA ret = {
72 4775 : .dptr = (uint8_t *)talloc_size(mem_ctx, data.dsize+1),
73 4701 : .dsize = data.dsize
74 : };
75 4775 : if (ret.dptr == NULL) {
76 0 : ret.dsize = 0;
77 : } else {
78 4775 : memcpy(ret.dptr, data.dptr, data.dsize);
79 4775 : ret.dptr[ret.dsize] = '\0';
80 : }
81 4775 : return ret;
82 : }
83 :
84 :
85 : /****************************************************************************
86 : Lock a chain by string. Return non-zero if lock failed.
87 : ****************************************************************************/
88 :
89 1476 : int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval)
90 : {
91 1476 : TDB_DATA key = string_term_tdb_data(keyval);
92 :
93 1476 : return tdb_chainlock(tdb, key);
94 : }
95 :
96 : /****************************************************************************
97 : Unlock a chain by string.
98 : ****************************************************************************/
99 :
100 23962 : void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval)
101 : {
102 23962 : TDB_DATA key = string_term_tdb_data(keyval);
103 :
104 23962 : tdb_chainunlock(tdb, key);
105 23962 : }
106 :
107 : /****************************************************************************
108 : Read lock a chain by string. Return non-zero if lock failed.
109 : ****************************************************************************/
110 :
111 0 : int tdb_read_lock_bystring(struct tdb_context *tdb, const char *keyval)
112 : {
113 0 : TDB_DATA key = string_term_tdb_data(keyval);
114 :
115 0 : return tdb_chainlock_read(tdb, key);
116 : }
117 :
118 : /****************************************************************************
119 : Read unlock a chain by string.
120 : ****************************************************************************/
121 :
122 236 : void tdb_read_unlock_bystring(struct tdb_context *tdb, const char *keyval)
123 : {
124 236 : TDB_DATA key = string_term_tdb_data(keyval);
125 :
126 236 : tdb_chainunlock_read(tdb, key);
127 236 : }
128 :
129 :
130 : /****************************************************************************
131 : Fetch a int32_t value by a arbitrary blob key, return -1 if not found.
132 : Output is int32_t in native byte order.
133 : ****************************************************************************/
134 :
135 10765 : static int fetch_int32_parser(TDB_DATA key, TDB_DATA data, void *private_data)
136 : {
137 10765 : if (data.dsize == sizeof(int32_t)) {
138 10765 : *((int32_t *)private_data) = PULL_LE_I32(data.dptr, 0);
139 : }
140 10765 : return 0;
141 : }
142 :
143 11077 : static int32_t tdb_fetch_int32_byblob(struct tdb_context *tdb, TDB_DATA key)
144 : {
145 11077 : int32_t v = -1;
146 11077 : int32_t ret = tdb_parse_record(tdb, key, fetch_int32_parser, &v);
147 11077 : if (ret == -1) {
148 312 : return ret;
149 : }
150 10765 : return v;
151 : }
152 :
153 : /****************************************************************************
154 : Fetch a int32_t value by string key, return -1 if not found.
155 : Output is int32_t in native byte order.
156 : ****************************************************************************/
157 :
158 11077 : int32_t tdb_fetch_int32(struct tdb_context *tdb, const char *keystr)
159 : {
160 11077 : return tdb_fetch_int32_byblob(tdb, string_term_tdb_data(keystr));
161 : }
162 :
163 : /****************************************************************************
164 : Store a int32_t value by an arbitrary blob key, return 0 on success, -ve on failure.
165 : Input is int32_t in native byte order. Output in tdb is in little-endian.
166 : ****************************************************************************/
167 :
168 5327 : static int tdb_store_int32_byblob(struct tdb_context *tdb, TDB_DATA key,
169 : int32_t v)
170 : {
171 0 : TDB_DATA data;
172 0 : int32_t v_store;
173 :
174 5327 : SIVAL(&v_store,0,v);
175 5327 : data.dptr = (unsigned char *)&v_store;
176 5327 : data.dsize = sizeof(int32_t);
177 :
178 5327 : return tdb_store(tdb, key, data, TDB_REPLACE);
179 : }
180 :
181 : /****************************************************************************
182 : Store a int32_t value by string key, return 0 on success, -ve on failure.
183 : Input is int32_t in native byte order. Output in tdb is in little-endian.
184 : ****************************************************************************/
185 :
186 5327 : int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32_t v)
187 : {
188 5327 : return tdb_store_int32_byblob(tdb, string_term_tdb_data(keystr), v);
189 : }
190 :
191 : /****************************************************************************
192 : Fetch a uint32_t value by a arbitrary blob key, return false if not found.
193 : Output is uint32_t in native byte order.
194 : ****************************************************************************/
195 :
196 3762 : static int fetch_uint32_parser(TDB_DATA key, TDB_DATA data, void *private_data)
197 : {
198 3762 : if (data.dsize != sizeof(uint32_t)) {
199 0 : return -1;
200 : }
201 3762 : *((uint32_t *)private_data) = PULL_LE_U32(data.dptr, 0);
202 3762 : return 0;
203 : }
204 :
205 3895 : static bool tdb_fetch_uint32_byblob(struct tdb_context *tdb, TDB_DATA key,
206 : uint32_t *value)
207 : {
208 3897 : int ret = tdb_parse_record(tdb, key, fetch_uint32_parser, value);
209 :
210 3895 : if (ret == -1) {
211 133 : return false;
212 : }
213 :
214 3762 : return true;
215 : }
216 :
217 : /****************************************************************************
218 : Fetch a uint32_t value by string key, return false if not found.
219 : Output is uint32_t in native byte order.
220 : ****************************************************************************/
221 :
222 3895 : bool tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32_t *value)
223 : {
224 3895 : return tdb_fetch_uint32_byblob(tdb, string_term_tdb_data(keystr), value);
225 : }
226 :
227 : /****************************************************************************
228 : Store a uint32_t value by an arbitrary blob key, return true on success, false on failure.
229 : Input is uint32_t in native byte order. Output in tdb is in little-endian.
230 : ****************************************************************************/
231 :
232 2361 : static bool tdb_store_uint32_byblob(struct tdb_context *tdb, TDB_DATA key,
233 : uint32_t value)
234 : {
235 0 : TDB_DATA data;
236 0 : uint32_t v_store;
237 2361 : bool ret = true;
238 :
239 2361 : SIVAL(&v_store, 0, value);
240 2361 : data.dptr = (unsigned char *)&v_store;
241 2361 : data.dsize = sizeof(uint32_t);
242 :
243 2361 : if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
244 0 : ret = false;
245 :
246 2361 : return ret;
247 : }
248 :
249 : /****************************************************************************
250 : Store a uint32_t value by string key, return true on success, false on failure.
251 : Input is uint32_t in native byte order. Output in tdb is in little-endian.
252 : ****************************************************************************/
253 :
254 2361 : bool tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32_t value)
255 : {
256 2361 : return tdb_store_uint32_byblob(tdb, string_term_tdb_data(keystr), value);
257 : }
258 : /****************************************************************************
259 : Store a buffer by a null terminated string key. Return 0 on success, -ve
260 : on failure.
261 : ****************************************************************************/
262 :
263 2608 : int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags)
264 : {
265 2608 : TDB_DATA key = string_term_tdb_data(keystr);
266 :
267 2608 : return tdb_store(tdb, key, data, flags);
268 : }
269 :
270 : /****************************************************************************
271 : Fetch a buffer using a null terminated string key. Don't forget to call
272 : free() on the result dptr.
273 : ****************************************************************************/
274 :
275 224837 : TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr)
276 : {
277 224837 : TDB_DATA key = string_term_tdb_data(keystr);
278 :
279 224837 : return tdb_fetch(tdb, key);
280 : }
281 :
282 : /****************************************************************************
283 : Delete an entry using a null terminated string key.
284 : ****************************************************************************/
285 :
286 4 : int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr)
287 : {
288 4 : TDB_DATA key = string_term_tdb_data(keystr);
289 :
290 4 : return tdb_delete(tdb, key);
291 : }
292 :
293 : /****************************************************************************
294 : Atomic integer change. Returns old value. To create, set initial value in *oldval.
295 : ****************************************************************************/
296 :
297 988 : int32_t tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
298 : {
299 0 : int32_t val;
300 988 : int32_t ret = -1;
301 :
302 988 : if (tdb_lock_bystring(tdb, keystr) != 0)
303 0 : return -1;
304 :
305 988 : if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
306 : /* The lookup failed */
307 6 : if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
308 : /* but not because it didn't exist */
309 0 : goto err_out;
310 : }
311 :
312 : /* Start with 'old' value */
313 6 : val = *oldval;
314 :
315 : } else {
316 : /* It worked, set return value (oldval) to tdb data */
317 982 : *oldval = val;
318 : }
319 :
320 : /* Increment value for storage and return next time */
321 988 : val += change_val;
322 :
323 988 : if (tdb_store_int32(tdb, keystr, val) != 0)
324 0 : goto err_out;
325 :
326 988 : ret = 0;
327 :
328 988 : err_out:
329 :
330 988 : tdb_unlock_bystring(tdb, keystr);
331 988 : return ret;
332 : }
333 :
334 : /****************************************************************************
335 : Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
336 : ****************************************************************************/
337 :
338 0 : bool tdb_change_uint32_atomic(struct tdb_context *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
339 : {
340 0 : uint32_t val;
341 0 : bool ret = false;
342 :
343 0 : if (tdb_lock_bystring(tdb, keystr) != 0)
344 0 : return false;
345 :
346 0 : if (!tdb_fetch_uint32(tdb, keystr, &val)) {
347 : /* It failed */
348 0 : if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
349 : /* and not because it didn't exist */
350 0 : goto err_out;
351 : }
352 :
353 : /* Start with 'old' value */
354 0 : val = *oldval;
355 :
356 : } else {
357 : /* it worked, set return value (oldval) to tdb data */
358 0 : *oldval = val;
359 :
360 : }
361 :
362 : /* get a new value to store */
363 0 : val += change_val;
364 :
365 0 : if (!tdb_store_uint32(tdb, keystr, val))
366 0 : goto err_out;
367 :
368 0 : ret = true;
369 :
370 0 : err_out:
371 :
372 0 : tdb_unlock_bystring(tdb, keystr);
373 0 : return ret;
374 : }
375 :
376 : /****************************************************************************
377 : Return an NTSTATUS from a TDB_ERROR
378 : ****************************************************************************/
379 :
380 9106919 : NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
381 : {
382 32869 : NTSTATUS result;
383 :
384 9106919 : switch (err) {
385 0 : case TDB_SUCCESS:
386 0 : result = NT_STATUS_OK;
387 0 : break;
388 0 : case TDB_ERR_CORRUPT:
389 0 : result = NT_STATUS_INTERNAL_DB_CORRUPTION;
390 0 : break;
391 0 : case TDB_ERR_IO:
392 0 : result = NT_STATUS_UNEXPECTED_IO_ERROR;
393 0 : break;
394 0 : case TDB_ERR_OOM:
395 0 : result = NT_STATUS_NO_MEMORY;
396 0 : break;
397 0 : case TDB_ERR_EXISTS:
398 0 : result = NT_STATUS_OBJECT_NAME_COLLISION;
399 0 : break;
400 :
401 0 : case TDB_ERR_LOCK:
402 : /*
403 : * TDB_ERR_LOCK is very broad, we could for example
404 : * distinguish between fcntl locks and invalid lock
405 : * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
406 : * compromise.
407 : */
408 0 : result = NT_STATUS_FILE_LOCK_CONFLICT;
409 0 : break;
410 :
411 0 : case TDB_ERR_NOLOCK:
412 : case TDB_ERR_LOCK_TIMEOUT:
413 : /*
414 : * These two ones in the enum are not actually used
415 : */
416 0 : result = NT_STATUS_FILE_LOCK_CONFLICT;
417 0 : break;
418 9074050 : case TDB_ERR_NOEXIST:
419 9074050 : result = NT_STATUS_NOT_FOUND;
420 9074050 : break;
421 0 : case TDB_ERR_EINVAL:
422 0 : result = NT_STATUS_INVALID_PARAMETER;
423 0 : break;
424 0 : case TDB_ERR_RDONLY:
425 0 : result = NT_STATUS_ACCESS_DENIED;
426 0 : break;
427 0 : case TDB_ERR_NESTING:
428 0 : result = NT_STATUS_INTERNAL_ERROR;
429 0 : break;
430 0 : default:
431 0 : result = NT_STATUS_INTERNAL_ERROR;
432 0 : break;
433 32869 : };
434 9106919 : return result;
435 : }
436 :
437 1780712 : int map_unix_error_from_tdb(enum TDB_ERROR err)
438 : {
439 1780712 : int result = EINVAL;
440 :
441 1780712 : switch (err) {
442 0 : case TDB_SUCCESS:
443 0 : result = 0;
444 0 : break;
445 0 : case TDB_ERR_CORRUPT:
446 0 : result = EILSEQ;
447 0 : break;
448 0 : case TDB_ERR_IO:
449 0 : result = EIO;
450 0 : break;
451 0 : case TDB_ERR_OOM:
452 0 : result = ENOMEM;
453 0 : break;
454 0 : case TDB_ERR_EXISTS:
455 0 : result = EEXIST;
456 0 : break;
457 :
458 0 : case TDB_ERR_LOCK:
459 : /*
460 : * TDB_ERR_LOCK is very broad, we could for example
461 : * distinguish between fcntl locks and invalid lock
462 : * sequences. EWOULDBLOCK is wrong, but there is no real
463 : * generic lock error code in errno.h
464 : */
465 0 : result = EWOULDBLOCK;
466 0 : break;
467 :
468 0 : case TDB_ERR_NOLOCK:
469 : case TDB_ERR_LOCK_TIMEOUT:
470 : /*
471 : * These two ones in the enum are not actually used
472 : */
473 0 : result = ENOLCK;
474 0 : break;
475 1756296 : case TDB_ERR_NOEXIST:
476 1756296 : result = ENOENT;
477 1756296 : break;
478 0 : case TDB_ERR_EINVAL:
479 0 : result = EINVAL;
480 0 : break;
481 0 : case TDB_ERR_RDONLY:
482 0 : result = EROFS;
483 0 : break;
484 0 : case TDB_ERR_NESTING:
485 : /*
486 : * Well, this db is already busy...
487 : */
488 0 : result = EBUSY;
489 0 : break;
490 24416 : };
491 1780712 : return result;
492 : }
493 :
494 : struct tdb_fetch_talloc_state {
495 : TALLOC_CTX *mem_ctx;
496 : uint8_t *buf;
497 : };
498 :
499 1887891 : static int tdb_fetch_talloc_parser(TDB_DATA key, TDB_DATA data,
500 : void *private_data)
501 : {
502 1887891 : struct tdb_fetch_talloc_state *state = private_data;
503 1887891 : state->buf = talloc_memdup(state->mem_ctx, data.dptr, data.dsize);
504 1887891 : return 0;
505 : }
506 :
507 3668603 : int tdb_fetch_talloc(struct tdb_context *tdb, TDB_DATA key,
508 : TALLOC_CTX *mem_ctx, uint8_t **buf)
509 : {
510 3668603 : struct tdb_fetch_talloc_state state = { .mem_ctx = mem_ctx };
511 31997 : int ret;
512 :
513 3668603 : ret = tdb_parse_record(tdb, key, tdb_fetch_talloc_parser, &state);
514 3668603 : if (ret == -1) {
515 1780712 : enum TDB_ERROR err = tdb_error(tdb);
516 1780712 : return map_unix_error_from_tdb(err);
517 : }
518 :
519 1887891 : if (state.buf == NULL) {
520 0 : return ENOMEM;
521 : }
522 :
523 1887891 : *buf = state.buf;
524 1887891 : return 0;
525 : }
|