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