e57eccfe59812967da055d931bc5e7fa1bed852e
[abartlet/samba.git/.git] / source3 / tdb / tdbutil.c
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
28 static SIG_ATOMIC_T gotalarm;
29
30 /***************************************************************
31  Signal function to tell us we timed out.
32 ****************************************************************/
33
34 static 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
43 static 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
55 static 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
93 int 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
102 int 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
113 void 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
124 int 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
135 void 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
148 int32 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
170 int32 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
180 int 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
198 int 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
208 BOOL 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
229 BOOL 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
239 BOOL 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
261 BOOL 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
270 int 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
282 TDB_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
293 int 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
304 int32 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
345 BOOL 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
388 size_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
482 int 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 *)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  **/
595 size_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  **/
626 size_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  **/
656 size_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  **/
687 size_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
713 static 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
734 TDB_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
755 int 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  **/
772 TDB_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*) 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 = (TDB_LIST_NODE*) malloc(sizeof(*rec));
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  **/
819 void 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 }