1/* 2 Unix SMB/CIFS implementation. 3 tdb utility functions 4 Copyright (C) Andrew Tridgell 1992-1998 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22#include <fnmatch.h> 23 24/* these are little tdb utility functions that are meant to make 25 dealing with a tdb database a little less cumbersome in Samba */ 26 27static SIG_ATOMIC_T gotalarm; 28 29/*************************************************************** 30 Signal function to tell us we timed out. 31****************************************************************/ 32 33static void gotalarm_sig(void) 34{ 35 gotalarm = 1; 36} 37 38/*************************************************************** 39 Make a TDB_DATA and keep the const warning in one place 40****************************************************************/ 41 42static TDB_DATA make_tdb_data(const char *dptr, size_t dsize) 43{ 44 TDB_DATA ret; 45 ret.dptr = dptr; 46 ret.dsize = dsize; 47 return ret; 48} 49 50/**************************************************************************** 51 Lock a chain with timeout (in seconds). 52****************************************************************************/ 53 54static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type) 55{ 56 /* Allow tdb_chainlock to be interrupted by an alarm. */ 57 int ret; 58 gotalarm = 0; 59 tdb_set_lock_alarm(&gotalarm); 60 61 if (timeout) { 62 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); 63 alarm(timeout); 64 } 65 66 if (rw_type == F_RDLCK) 67 ret = tdb_chainlock_read(tdb, key); 68 else 69 ret = tdb_chainlock(tdb, key); 70 71 if (timeout) { 72 alarm(0); 73 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN); 74 if (gotalarm) { 75 DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n", 76 timeout, key.dptr, tdb->name )); 77 /* TODO: If we time out waiting for a lock, it might 78 * be nice to use F_GETLK to get the pid of the 79 * process currently holding the lock and print that 80 * as part of the debugging message. -- mbp */ 81 return -1; 82 } 83 } 84 85 return ret; 86} 87 88/**************************************************************************** 89 Write lock a chain. Return -1 if timeout or lock failed. 90****************************************************************************/ 91 92int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout) 93{ 94 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK); 95} 96 97/**************************************************************************** 98 Lock a chain by string. Return -1 if timeout or lock failed. 99****************************************************************************/ 100 101int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout) 102{ 103 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1); 104 105 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK); 106} 107 108/**************************************************************************** 109 Unlock a chain by string. 110****************************************************************************/ 111 112void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval) 113{ 114 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1); 115 116 tdb_chainunlock(tdb, key); 117} 118 119/**************************************************************************** 120 Read lock a chain by string. Return -1 if timeout or lock failed. 121****************************************************************************/ 122 123int tdb_read_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout) 124{ 125 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1); 126 127 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK); 128} 129 130/**************************************************************************** 131 Read unlock a chain by string. 132****************************************************************************/ 133 134void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval) 135{ 136 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1); 137 138 tdb_chainunlock_read(tdb, key); 139} 140 141 142/**************************************************************************** 143 Fetch a int32 value by a arbitrary blob key, return -1 if not found. 144 Output is int32 in native byte order. 145****************************************************************************/ 146 147int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len) 148{ 149 TDB_DATA key = make_tdb_data(keyval, len); 150 TDB_DATA data; 151 int32 ret; 152 153 data = tdb_fetch(tdb, key); 154 if (!data.dptr || data.dsize != sizeof(int32)) { 155 SAFE_FREE(data.dptr); 156 return -1; 157 } 158 159 ret = IVAL(data.dptr,0); 160 SAFE_FREE(data.dptr); 161 return ret; 162} 163 164/**************************************************************************** 165 Fetch a int32 value by string key, return -1 if not found. 166 Output is int32 in native byte order. 167****************************************************************************/ 168 169int32 tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr) 170{ 171 return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1); 172} 173 174/**************************************************************************** 175 Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure. 176 Input is int32 in native byte order. Output in tdb is in little-endian. 177****************************************************************************/ 178 179int tdb_store_int32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, int32 v) 180{ 181 TDB_DATA key = make_tdb_data(keystr, len); 182 TDB_DATA data; 183 int32 v_store; 184 185 SIVAL(&v_store,0,v); 186 data.dptr = (void *)&v_store; 187 data.dsize = sizeof(int32); 188 189 return tdb_store(tdb, key, data, TDB_REPLACE); 190} 191 192/**************************************************************************** 193 Store a int32 value by string key, return 0 on success, -1 on failure. 194 Input is int32 in native byte order. Output in tdb is in little-endian. 195****************************************************************************/ 196 197int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32 v) 198{ 199 return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v); 200} 201 202/**************************************************************************** 203 Fetch a uint32 value by a arbitrary blob key, return -1 if not found. 204 Output is uint32 in native byte order. 205****************************************************************************/ 206 207BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len, uint32 *value) 208{ 209 TDB_DATA key = make_tdb_data(keyval, len); 210 TDB_DATA data; 211 212 data = tdb_fetch(tdb, key); 213 if (!data.dptr || data.dsize != sizeof(uint32)) { 214 SAFE_FREE(data.dptr); 215 return False; 216 } 217 218 *value = IVAL(data.dptr,0); 219 SAFE_FREE(data.dptr); 220 return True; 221} 222 223/**************************************************************************** 224 Fetch a uint32 value by string key, return -1 if not found. 225 Output is uint32 in native byte order. 226****************************************************************************/ 227 228BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 *value) 229{ 230 return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value); 231} 232 233/**************************************************************************** 234 Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure. 235 Input is uint32 in native byte order. Output in tdb is in little-endian. 236****************************************************************************/ 237 238BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, uint32 value) 239{ 240 TDB_DATA key = make_tdb_data(keystr, len); 241 TDB_DATA data; 242 uint32 v_store; 243 BOOL ret = True; 244 245 SIVAL(&v_store, 0, value); 246 data.dptr = (void *)&v_store; 247 data.dsize = sizeof(uint32); 248 249 if (tdb_store(tdb, key, data, TDB_REPLACE) == -1) 250 ret = False; 251 252 return ret; 253} 254 255/**************************************************************************** 256 Store a uint32 value by string key, return 0 on success, -1 on failure. 257 Input is uint32 in native byte order. Output in tdb is in little-endian. 258****************************************************************************/ 259 260BOOL tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 value) 261{ 262 return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value); 263} 264/**************************************************************************** 265 Store a buffer by a null terminated string key. Return 0 on success, -1 266 on failure. 267****************************************************************************/ 268 269int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags) 270{ 271 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1); 272 273 return tdb_store(tdb, key, data, flags); 274} 275 276/**************************************************************************** 277 Fetch a buffer using a null terminated string key. Don't forget to call 278 free() on the result dptr. 279****************************************************************************/ 280 281TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr) 282{ 283 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1); 284 285 return tdb_fetch(tdb, key); 286} 287 288/**************************************************************************** 289 Delete an entry using a null terminated string key. 290****************************************************************************/ 291 292int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr) 293{ 294 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1); 295 296 return tdb_delete(tdb, key); 297} 298 299/**************************************************************************** 300 Atomic integer change. Returns old value. To create, set initial value in *oldval. 301****************************************************************************/ 302 303int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32 *oldval, int32 change_val) 304{ 305 int32 val; 306 int32 ret = -1; 307 308 if (tdb_lock_bystring(tdb, keystr,0) == -1) 309 return -1; 310 311 if ((val = tdb_fetch_int32(tdb, keystr)) == -1) { 312 /* The lookup failed */ 313 if (tdb_error(tdb) != TDB_ERR_NOEXIST) { 314 /* but not because it didn't exist */ 315 goto err_out; 316 } 317 318 /* Start with 'old' value */ 319 val = *oldval; 320 321 } else { 322 /* It worked, set return value (oldval) to tdb data */ 323 *oldval = val; 324 } 325 326 /* Increment value for storage and return next time */ 327 val += change_val; 328 329 if (tdb_store_int32(tdb, keystr, val) == -1) 330 goto err_out; 331 332 ret = 0; 333 334 err_out: 335 336 tdb_unlock_bystring(tdb, keystr); 337 return ret; 338} 339 340/**************************************************************************** 341 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval. 342****************************************************************************/ 343 344BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32 *oldval, uint32 change_val) 345{ 346 uint32 val; 347 BOOL ret = False; 348 349 if (tdb_lock_bystring(tdb, keystr,0) == -1) 350 return False; 351 352 if (!tdb_fetch_uint32(tdb, keystr, &val)) { 353 /* It failed */ 354 if (tdb_error(tdb) != TDB_ERR_NOEXIST) { 355 /* and not because it didn't exist */ 356 goto err_out; 357 } 358 359 /* Start with 'old' value */ 360 val = *oldval; 361 362 } else { 363 /* it worked, set return value (oldval) to tdb data */ 364 *oldval = val; 365 366 } 367 368 /* get a new value to store */ 369 val += change_val; 370 371 if (!tdb_store_uint32(tdb, keystr, val)) 372 goto err_out; 373 374 ret = True; 375 376 err_out: 377 378 tdb_unlock_bystring(tdb, keystr); 379 return ret; 380} 381 382/**************************************************************************** 383 Useful pair of routines for packing/unpacking data consisting of 384 integers and strings. 385****************************************************************************/ 386 387size_t tdb_pack(char *buf, int bufsize, const char *fmt, ...) 388{ 389 va_list ap; 390 uint8 bt; 391 uint16 w; 392 uint32 d; 393 int i; 394 void *p; 395 int len; 396 char *s; 397 char c; 398 char *buf0 = buf; 399 const char *fmt0 = fmt; 400 int bufsize0 = bufsize; 401 402 va_start(ap, fmt); 403 404 while (*fmt) { 405 switch ((c = *fmt++)) { 406 case 'b': /* unsigned 8-bit integer */ 407 len = 1; 408 bt = (uint8)va_arg(ap, int); 409 if (bufsize && bufsize >= len) 410 SSVAL(buf, 0, bt); 411 break; 412 case 'w': /* unsigned 16-bit integer */ 413 len = 2; 414 w = (uint16)va_arg(ap, int); 415 if (bufsize && bufsize >= len) 416 SSVAL(buf, 0, w); 417 break; 418 case 'd': /* signed 32-bit integer (standard int in most systems) */ 419 len = 4; 420 d = va_arg(ap, uint32); 421 if (bufsize && bufsize >= len) 422 SIVAL(buf, 0, d); 423 break; 424 case 'p': /* pointer */ 425 len = 4; 426 p = va_arg(ap, void *); 427 d = p?1:0; 428 if (bufsize && bufsize >= len) 429 SIVAL(buf, 0, d); 430 break; 431 case 'P': /* null-terminated string */ 432 s = va_arg(ap,char *); 433 w = strlen(s); 434 len = w + 1; 435 if (bufsize && bufsize >= len) 436 memcpy(buf, s, len); 437 break; 438 case 'f': /* null-terminated string */ 439 s = va_arg(ap,char *); 440 w = strlen(s); 441 len = w + 1; 442 if (bufsize && bufsize >= len) 443 memcpy(buf, s, len); 444 break; 445 case 'B': /* fixed-length string */ 446 i = va_arg(ap, int); 447 s = va_arg(ap, char *); 448 len = 4+i; 449 if (bufsize && bufsize >= len) { 450 SIVAL(buf, 0, i); 451 memcpy(buf+4, s, i); 452 } 453 break; 454 default: 455 DEBUG(0,("Unknown tdb_pack format %c in %s\n", 456 c, fmt)); 457 len = 0; 458 break; 459 } 460 461 buf += len; 462 if (bufsize) 463 bufsize -= len; 464 if (bufsize < 0) 465 bufsize = 0; 466 } 467 468 va_end(ap); 469 470 DEBUG(18,("tdb_pack(%s, %d) -> %d\n", 471 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0))); 472 473 return PTR_DIFF(buf, buf0); 474} 475 476/**************************************************************************** 477 Useful pair of routines for packing/unpacking data consisting of 478 integers and strings. 479****************************************************************************/ 480 481int tdb_unpack(char *buf, int bufsize, const char *fmt, ...) 482{ 483 va_list ap; 484 uint8 *bt; 485 uint16 *w; 486 uint32 *d; 487 int len; 488 int *i; 489 void **p; 490 char *s, **b; 491 char c; 492 char *buf0 = buf; 493 const char *fmt0 = fmt; 494 int bufsize0 = bufsize; 495 496 va_start(ap, fmt); 497 498 while (*fmt) { 499 switch ((c=*fmt++)) { 500 case 'b': 501 len = 1; 502 bt = va_arg(ap, uint8 *); 503 if (bufsize < len) 504 goto no_space; 505 *bt = SVAL(buf, 0); 506 break; 507 case 'w': 508 len = 2; 509 w = va_arg(ap, uint16 *); 510 if (bufsize < len) 511 goto no_space; 512 *w = SVAL(buf, 0); 513 break; 514 case 'd': 515 len = 4; 516 d = va_arg(ap, uint32 *); 517 if (bufsize < len) 518 goto no_space; 519 *d = IVAL(buf, 0); 520 break; 521 case 'p': 522 len = 4; 523 p = va_arg(ap, void **); 524 if (bufsize < len) 525 goto no_space; 526 *p = (void *)IVAL(buf, 0); 527 break; 528 case 'P': 529 s = va_arg(ap,char *); 530 len = strlen(buf) + 1; 531 if (bufsize < len || len > sizeof(pstring)) 532 goto no_space; 533 memcpy(s, buf, len); 534 break; 535 case 'f': 536 s = va_arg(ap,char *); 537 len = strlen(buf) + 1; 538 if (bufsize < len || len > sizeof(fstring)) 539 goto no_space; 540 memcpy(s, buf, len); 541 break; 542 case 'B': 543 i = va_arg(ap, int *); 544 b = va_arg(ap, char **); 545 len = 4; 546 if (bufsize < len) 547 goto no_space; 548 *i = IVAL(buf, 0); 549 if (! *i) { 550 *b = NULL; 551 break; 552 } 553 len += *i; 554 if (bufsize < len) 555 goto no_space; 556 *b = (char *)malloc(*i); 557 if (! *b) 558 goto no_space; 559 memcpy(*b, buf+4, *i); 560 break; 561 default: 562 DEBUG(0,("Unknown tdb_unpack format %c in %s\n", 563 c, fmt)); 564 565 len = 0; 566 break; 567 } 568 569 buf += len; 570 bufsize -= len; 571 } 572 573 va_end(ap); 574 575 DEBUG(18,("tdb_unpack(%s, %d) -> %d\n", 576 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0))); 577 578 return PTR_DIFF(buf, buf0); 579 580 no_space: 581 return -1; 582} 583 584 585/** 586 * Pack SID passed by pointer 587 * 588 * @param pack_buf pointer to buffer which is to be filled with packed data 589 * @param bufsize size of packing buffer 590 * @param sid pointer to sid to be packed 591 * 592 * @return length of the packed representation of the whole structure 593 **/ 594size_t tdb_sid_pack(char* pack_buf, int bufsize, DOM_SID* sid) 595{ 596 int idx; 597 size_t len = 0; 598 599 if (!sid || !pack_buf) return -1; 600 601 len += tdb_pack(pack_buf + len, bufsize - len, "bb", sid->sid_rev_num, 602 sid->num_auths); 603 604 for (idx = 0; idx < 6; idx++) { 605 len += tdb_pack(pack_buf + len, bufsize - len, "b", sid->id_auth[idx]); 606 } 607 608 for (idx = 0; idx < MAXSUBAUTHS; idx++) { 609 len += tdb_pack(pack_buf + len, bufsize - len, "d", sid->sub_auths[idx]); 610 } 611 612 return len; 613} 614 615 616/** 617 * Unpack SID into a pointer 618 * 619 * @param pack_buf pointer to buffer with packed representation 620 * @param bufsize size of the buffer 621 * @param sid pointer to sid structure to be filled with unpacked data 622 * 623 * @return size of structure unpacked from buffer 624 **/ 625size_t tdb_sid_unpack(char* pack_buf, int bufsize, DOM_SID* sid) 626{ 627 int idx, len = 0; 628 629 if (!sid || !pack_buf) return -1; 630 631 len += tdb_unpack(pack_buf + len, bufsize - len, "bb", 632 &sid->sid_rev_num, &sid->num_auths); 633 634 for (idx = 0; idx < 6; idx++) { 635 len += tdb_unpack(pack_buf + len, bufsize - len, "b", &sid->id_auth[idx]); 636 } 637 638 for (idx = 0; idx < MAXSUBAUTHS; idx++) { 639 len += tdb_unpack(pack_buf + len, bufsize - len, "d", &sid->sub_auths[idx]); 640 } 641 642 return len; 643} 644 645 646/** 647 * Pack TRUSTED_DOM_PASS passed by pointer 648 * 649 * @param pack_buf pointer to buffer which is to be filled with packed data 650 * @param bufsize size of the buffer 651 * @param pass pointer to trusted domain password to be packed 652 * 653 * @return length of the packed representation of the whole structure 654 **/ 655size_t tdb_trusted_dom_pass_pack(char* pack_buf, int bufsize, TRUSTED_DOM_PASS* pass) 656{ 657 int idx, len = 0; 658 659 if (!pack_buf || !pass) return -1; 660 661 /* packing unicode domain name and password */ 662 len += tdb_pack(pack_buf + len, bufsize - len, "d", pass->uni_name_len); 663 664 for (idx = 0; idx < 32; idx++) 665 len += tdb_pack(pack_buf + len, bufsize - len, "w", pass->uni_name[idx]); 666 667 len += tdb_pack(pack_buf + len, bufsize - len, "dPd", pass->pass_len, 668 pass->pass, pass->mod_time); 669 670 /* packing SID structure */ 671 len += tdb_sid_pack(pack_buf + len, bufsize - len, &pass->domain_sid); 672 673 return len; 674} 675 676 677/** 678 * Unpack TRUSTED_DOM_PASS passed by pointer 679 * 680 * @param pack_buf pointer to buffer with packed representation 681 * @param bufsize size of the buffer 682 * @param pass pointer to trusted domain password to be filled with unpacked data 683 * 684 * @return size of structure unpacked from buffer 685 **/ 686size_t tdb_trusted_dom_pass_unpack(char* pack_buf, int bufsize, TRUSTED_DOM_PASS* pass) 687{ 688 int idx, len = 0; 689 690 if (!pack_buf || !pass) return -1; 691 692 /* unpack unicode domain name and plaintext password */ 693 len += tdb_unpack(pack_buf, bufsize - len, "d", &pass->uni_name_len); 694 695 for (idx = 0; idx < 32; idx++) 696 len += tdb_unpack(pack_buf + len, bufsize - len, "w", &pass->uni_name[idx]); 697 698 len += tdb_unpack(pack_buf + len, bufsize - len, "dPd", &pass->pass_len, &pass->pass, 699 &pass->mod_time); 700 701 /* unpack domain sid */ 702 len += tdb_sid_unpack(pack_buf + len, bufsize - len, &pass->domain_sid); 703 704 return len; 705} 706 707 708/**************************************************************************** 709 Log tdb messages via DEBUG(). 710****************************************************************************/ 711 712static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...) 713{ 714 va_list ap; 715 char *ptr = NULL; 716 717 va_start(ap, format); 718 vasprintf(&ptr, format, ap); 719 va_end(ap); 720 721 if (!ptr || !*ptr) 722 return; 723 724 DEBUG(level, ("tdb(%s): %s", tdb->name ? tdb->name : "unnamed", ptr)); 725 SAFE_FREE(ptr); 726} 727 728/**************************************************************************** 729 Like tdb_open() but also setup a logging function that redirects to 730 the samba DEBUG() system. 731****************************************************************************/ 732 733TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags, 734 int open_flags, mode_t mode) 735{ 736 TDB_CONTEXT *tdb; 737 738 if (!lp_use_mmap()) 739 tdb_flags |= TDB_NOMMAP; 740 741 tdb = tdb_open_ex(name, hash_size, tdb_flags, 742 open_flags, mode, tdb_log); 743 if (!tdb) 744 return NULL; 745 746 return tdb; 747} 748 749 750/**************************************************************************** 751 Allow tdb_delete to be used as a tdb_traversal_fn. 752****************************************************************************/ 753 754int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, 755 void *state) 756{ 757 return tdb_delete(the_tdb, key); 758} 759 760 761 762/** 763 * Search across the whole tdb for keys that match the given pattern 764 * return the result as a list of keys 765 * 766 * @param tdb pointer to opened tdb file context 767 * @param pattern searching pattern used by fnmatch(3) functions 768 * 769 * @return list of keys found by looking up with given pattern 770 **/ 771TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern) 772{ 773 TDB_DATA key, next; 774 TDB_LIST_NODE *list = NULL; 775 TDB_LIST_NODE *rec = NULL; 776 TDB_LIST_NODE *tmp = NULL; 777 778 for (key = tdb_firstkey(tdb); key.dptr; key = next) { 779 /* duplicate key string to ensure null-termination */ 780 char *key_str = (char*) strndup(key.dptr, key.dsize); 781 if (!key_str) { 782 DEBUG(0, ("tdb_search_keys: strndup() failed!\n")); 783 smb_panic("strndup failed!\n"); 784 } 785 786 DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern)); 787 788 next = tdb_nextkey(tdb, key); 789 790 /* do the pattern checking */ 791 if (fnmatch(pattern, key_str, 0) == 0) { 792 rec = (TDB_LIST_NODE*) malloc(sizeof(*rec)); 793 ZERO_STRUCTP(rec); 794 795 rec->node_key = key; 796 797 DLIST_ADD_END(list, rec, tmp); 798 799 DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern)); 800 } else { 801 free(key.dptr); 802 } 803 804 /* free duplicated key string */ 805 free(key_str); 806 } 807 808 return list; 809 810} 811 812 813/** 814 * Free the list returned by tdb_search_keys 815 * 816 * @param node list of results found by tdb_search_keys 817 **/ 818void tdb_search_list_free(TDB_LIST_NODE* node) 819{ 820 TDB_LIST_NODE *next_node; 821 822 while (node) { 823 next_node = node->next; 824 SAFE_FREE(node->node_key.dptr); 825 SAFE_FREE(node); 826 node = next_node; 827 }; 828} 829 830 831