2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Rafal Szczesniak 2002
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.
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.
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.
25 /* these are little tdb utility functions that are meant to make
26 dealing with a tdb database a little less cumbersome in Samba */
28 static SIG_ATOMIC_T gotalarm
;
30 /***************************************************************
31 Signal function to tell us we timed out.
32 ****************************************************************/
34 static void gotalarm_sig(void)
39 /***************************************************************
40 Make a TDB_DATA and keep the const warning in one place
41 ****************************************************************/
43 TDB_DATA
make_tdb_data(const char *dptr
, size_t dsize
)
46 ret
.dptr
= CONST_DISCARD(char *, dptr
);
51 TDB_DATA
string_tdb_data(const char *string
)
53 return make_tdb_data(string
, strlen(string
));
56 /****************************************************************************
57 Lock a chain with timeout (in seconds).
58 ****************************************************************************/
60 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT
*tdb
, TDB_DATA key
, unsigned int timeout
, int rw_type
)
62 /* Allow tdb_chainlock to be interrupted by an alarm. */
65 tdb_set_lock_alarm(CONST_DISCARD(sig_atomic_t *, &gotalarm
));
68 CatchSignal(SIGALRM
, SIGNAL_CAST gotalarm_sig
);
72 if (rw_type
== F_RDLCK
)
73 ret
= tdb_chainlock_read(tdb
, key
);
75 ret
= tdb_chainlock(tdb
, key
);
79 CatchSignal(SIGALRM
, SIGNAL_CAST SIG_IGN
);
81 DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
82 timeout
, key
.dptr
, tdb
->name
));
83 /* TODO: If we time out waiting for a lock, it might
84 * be nice to use F_GETLK to get the pid of the
85 * process currently holding the lock and print that
86 * as part of the debugging message. -- mbp */
94 /****************************************************************************
95 Write lock a chain. Return -1 if timeout or lock failed.
96 ****************************************************************************/
98 int tdb_chainlock_with_timeout( TDB_CONTEXT
*tdb
, TDB_DATA key
, unsigned int timeout
)
100 return tdb_chainlock_with_timeout_internal(tdb
, key
, timeout
, F_WRLCK
);
103 /****************************************************************************
104 Lock a chain by string. Return -1 if timeout or lock failed.
105 ****************************************************************************/
107 int tdb_lock_bystring(TDB_CONTEXT
*tdb
, const char *keyval
, unsigned int timeout
)
109 TDB_DATA key
= make_tdb_data(keyval
, strlen(keyval
)+1);
111 return tdb_chainlock_with_timeout_internal(tdb
, key
, timeout
, F_WRLCK
);
114 /****************************************************************************
115 Unlock a chain by string.
116 ****************************************************************************/
118 void tdb_unlock_bystring(TDB_CONTEXT
*tdb
, const char *keyval
)
120 TDB_DATA key
= make_tdb_data(keyval
, strlen(keyval
)+1);
122 tdb_chainunlock(tdb
, key
);
125 /****************************************************************************
126 Read lock a chain by string. Return -1 if timeout or lock failed.
127 ****************************************************************************/
129 int tdb_read_lock_bystring(TDB_CONTEXT
*tdb
, const char *keyval
, unsigned int timeout
)
131 TDB_DATA key
= make_tdb_data(keyval
, strlen(keyval
)+1);
133 return tdb_chainlock_with_timeout_internal(tdb
, key
, timeout
, F_RDLCK
);
136 /****************************************************************************
137 Read unlock a chain by string.
138 ****************************************************************************/
140 void tdb_read_unlock_bystring(TDB_CONTEXT
*tdb
, const char *keyval
)
142 TDB_DATA key
= make_tdb_data(keyval
, strlen(keyval
)+1);
144 tdb_chainunlock_read(tdb
, key
);
148 /****************************************************************************
149 Fetch a int32 value by a arbitrary blob key, return -1 if not found.
150 Output is int32 in native byte order.
151 ****************************************************************************/
153 int32
tdb_fetch_int32_byblob(TDB_CONTEXT
*tdb
, const char *keyval
, size_t len
)
155 TDB_DATA key
= make_tdb_data(keyval
, len
);
159 data
= tdb_fetch(tdb
, key
);
160 if (!data
.dptr
|| data
.dsize
!= sizeof(int32
)) {
161 SAFE_FREE(data
.dptr
);
165 ret
= IVAL(data
.dptr
,0);
166 SAFE_FREE(data
.dptr
);
170 /****************************************************************************
171 Fetch a int32 value by string key, return -1 if not found.
172 Output is int32 in native byte order.
173 ****************************************************************************/
175 int32
tdb_fetch_int32(TDB_CONTEXT
*tdb
, const char *keystr
)
177 return tdb_fetch_int32_byblob(tdb
, keystr
, strlen(keystr
) + 1);
180 /****************************************************************************
181 Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
182 Input is int32 in native byte order. Output in tdb is in little-endian.
183 ****************************************************************************/
185 int tdb_store_int32_byblob(TDB_CONTEXT
*tdb
, const char *keystr
, size_t len
, int32 v
)
187 TDB_DATA key
= make_tdb_data(keystr
, len
);
192 data
.dptr
= (void *)&v_store
;
193 data
.dsize
= sizeof(int32
);
195 return tdb_store(tdb
, key
, data
, TDB_REPLACE
);
198 /****************************************************************************
199 Store a int32 value by string key, return 0 on success, -1 on failure.
200 Input is int32 in native byte order. Output in tdb is in little-endian.
201 ****************************************************************************/
203 int tdb_store_int32(TDB_CONTEXT
*tdb
, const char *keystr
, int32 v
)
205 return tdb_store_int32_byblob(tdb
, keystr
, strlen(keystr
) + 1, v
);
208 /****************************************************************************
209 Fetch a uint32 value by a arbitrary blob key, return -1 if not found.
210 Output is uint32 in native byte order.
211 ****************************************************************************/
213 BOOL
tdb_fetch_uint32_byblob(TDB_CONTEXT
*tdb
, const char *keyval
, size_t len
, uint32
*value
)
215 TDB_DATA key
= make_tdb_data(keyval
, len
);
218 data
= tdb_fetch(tdb
, key
);
219 if (!data
.dptr
|| data
.dsize
!= sizeof(uint32
)) {
220 SAFE_FREE(data
.dptr
);
224 *value
= IVAL(data
.dptr
,0);
225 SAFE_FREE(data
.dptr
);
229 /****************************************************************************
230 Fetch a uint32 value by string key, return -1 if not found.
231 Output is uint32 in native byte order.
232 ****************************************************************************/
234 BOOL
tdb_fetch_uint32(TDB_CONTEXT
*tdb
, const char *keystr
, uint32
*value
)
236 return tdb_fetch_uint32_byblob(tdb
, keystr
, strlen(keystr
) + 1, value
);
239 /****************************************************************************
240 Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure.
241 Input is uint32 in native byte order. Output in tdb is in little-endian.
242 ****************************************************************************/
244 BOOL
tdb_store_uint32_byblob(TDB_CONTEXT
*tdb
, const char *keystr
, size_t len
, uint32 value
)
246 TDB_DATA key
= make_tdb_data(keystr
, len
);
251 SIVAL(&v_store
, 0, value
);
252 data
.dptr
= (void *)&v_store
;
253 data
.dsize
= sizeof(uint32
);
255 if (tdb_store(tdb
, key
, data
, TDB_REPLACE
) == -1)
261 /****************************************************************************
262 Store a uint32 value by string key, return 0 on success, -1 on failure.
263 Input is uint32 in native byte order. Output in tdb is in little-endian.
264 ****************************************************************************/
266 BOOL
tdb_store_uint32(TDB_CONTEXT
*tdb
, const char *keystr
, uint32 value
)
268 return tdb_store_uint32_byblob(tdb
, keystr
, strlen(keystr
) + 1, value
);
270 /****************************************************************************
271 Store a buffer by a null terminated string key. Return 0 on success, -1
273 ****************************************************************************/
275 int tdb_store_bystring(TDB_CONTEXT
*tdb
, const char *keystr
, TDB_DATA data
, int flags
)
277 TDB_DATA key
= make_tdb_data(keystr
, strlen(keystr
)+1);
279 return tdb_store(tdb
, key
, data
, flags
);
282 /****************************************************************************
283 Fetch a buffer using a null terminated string key. Don't forget to call
284 free() on the result dptr.
285 ****************************************************************************/
287 TDB_DATA
tdb_fetch_bystring(TDB_CONTEXT
*tdb
, const char *keystr
)
289 TDB_DATA key
= make_tdb_data(keystr
, strlen(keystr
)+1);
291 return tdb_fetch(tdb
, key
);
294 /****************************************************************************
295 Delete an entry using a null terminated string key.
296 ****************************************************************************/
298 int tdb_delete_bystring(TDB_CONTEXT
*tdb
, const char *keystr
)
300 TDB_DATA key
= make_tdb_data(keystr
, strlen(keystr
)+1);
302 return tdb_delete(tdb
, key
);
305 /****************************************************************************
306 Atomic integer change. Returns old value. To create, set initial value in *oldval.
307 ****************************************************************************/
309 int32
tdb_change_int32_atomic(TDB_CONTEXT
*tdb
, const char *keystr
, int32
*oldval
, int32 change_val
)
314 if (tdb_lock_bystring(tdb
, keystr
,0) == -1)
317 if ((val
= tdb_fetch_int32(tdb
, keystr
)) == -1) {
318 /* The lookup failed */
319 if (tdb_error(tdb
) != TDB_ERR_NOEXIST
) {
320 /* but not because it didn't exist */
324 /* Start with 'old' value */
328 /* It worked, set return value (oldval) to tdb data */
332 /* Increment value for storage and return next time */
335 if (tdb_store_int32(tdb
, keystr
, val
) == -1)
342 tdb_unlock_bystring(tdb
, keystr
);
346 /****************************************************************************
347 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
348 ****************************************************************************/
350 BOOL
tdb_change_uint32_atomic(TDB_CONTEXT
*tdb
, const char *keystr
, uint32
*oldval
, uint32 change_val
)
355 if (tdb_lock_bystring(tdb
, keystr
,0) == -1)
358 if (!tdb_fetch_uint32(tdb
, keystr
, &val
)) {
360 if (tdb_error(tdb
) != TDB_ERR_NOEXIST
) {
361 /* and not because it didn't exist */
365 /* Start with 'old' value */
369 /* it worked, set return value (oldval) to tdb data */
374 /* get a new value to store */
377 if (!tdb_store_uint32(tdb
, keystr
, val
))
384 tdb_unlock_bystring(tdb
, keystr
);
388 /****************************************************************************
389 Useful pair of routines for packing/unpacking data consisting of
390 integers and strings.
391 ****************************************************************************/
393 size_t tdb_pack_va(char *buf
, int bufsize
, const char *fmt
, va_list ap
)
404 const char *fmt0
= fmt
;
405 int bufsize0
= bufsize
;
408 switch ((c
= *fmt
++)) {
409 case 'b': /* unsigned 8-bit integer */
411 bt
= (uint8
)va_arg(ap
, int);
412 if (bufsize
&& bufsize
>= len
)
415 case 'w': /* unsigned 16-bit integer */
417 w
= (uint16
)va_arg(ap
, int);
418 if (bufsize
&& bufsize
>= len
)
421 case 'd': /* signed 32-bit integer (standard int in most systems) */
423 d
= va_arg(ap
, uint32
);
424 if (bufsize
&& bufsize
>= len
)
427 case 'p': /* pointer */
429 p
= va_arg(ap
, void *);
431 if (bufsize
&& bufsize
>= len
)
434 case 'P': /* null-terminated string */
435 s
= va_arg(ap
,char *);
438 if (bufsize
&& bufsize
>= len
)
441 case 'f': /* null-terminated string */
442 s
= va_arg(ap
,char *);
445 if (bufsize
&& bufsize
>= len
)
448 case 'B': /* fixed-length string */
450 s
= va_arg(ap
, char *);
452 if (bufsize
&& bufsize
>= len
) {
458 DEBUG(0,("Unknown tdb_pack format %c in %s\n",
471 DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n",
472 fmt0
, bufsize0
, (int)PTR_DIFF(buf
, buf0
)));
474 return PTR_DIFF(buf
, buf0
);
477 size_t tdb_pack(char *buf
, int bufsize
, const char *fmt
, ...)
483 result
= tdb_pack_va(buf
, bufsize
, fmt
, ap
);
488 BOOL
tdb_pack_append(TALLOC_CTX
*mem_ctx
, uint8
**buf
, size_t *len
,
489 const char *fmt
, ...)
495 len1
= tdb_pack_va(NULL
, 0, fmt
, ap
);
499 *buf
= TALLOC_REALLOC_ARRAY(mem_ctx
, *buf
, uint8
,
502 *buf
= SMB_REALLOC_ARRAY(*buf
, uint8
, (*len
) + len1
);
508 len2
= tdb_pack_va((char *)(*buf
)+(*len
), len1
, fmt
, ap
);
519 /****************************************************************************
520 Useful pair of routines for packing/unpacking data consisting of
521 integers and strings.
522 ****************************************************************************/
524 int tdb_unpack(char *buf
, int bufsize
, const char *fmt
, ...)
536 const char *fmt0
= fmt
;
537 int bufsize0
= bufsize
;
542 switch ((c
=*fmt
++)) {
545 bt
= va_arg(ap
, uint8
*);
552 w
= va_arg(ap
, uint16
*);
559 d
= va_arg(ap
, uint32
*);
566 p
= va_arg(ap
, void **);
570 * This isn't a real pointer - only a token (1 or 0)
571 * to mark the fact a pointer is present.
574 *p
= (void *)(IVAL(buf
, 0) ? (void *)1 : NULL
);
577 s
= va_arg(ap
,char *);
578 len
= strlen(buf
) + 1;
579 if (bufsize
< len
|| len
> sizeof(pstring
))
584 s
= va_arg(ap
,char *);
585 len
= strlen(buf
) + 1;
586 if (bufsize
< len
|| len
> sizeof(fstring
))
591 i
= va_arg(ap
, int *);
592 b
= va_arg(ap
, char **);
604 *b
= (char *)SMB_MALLOC(*i
);
607 memcpy(*b
, buf
+4, *i
);
610 DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
623 DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
624 fmt0
, bufsize0
, (int)PTR_DIFF(buf
, buf0
)));
626 return PTR_DIFF(buf
, buf0
);
634 * Pack SID passed by pointer
636 * @param pack_buf pointer to buffer which is to be filled with packed data
637 * @param bufsize size of packing buffer
638 * @param sid pointer to sid to be packed
640 * @return length of the packed representation of the whole structure
642 size_t tdb_sid_pack(char* pack_buf
, int bufsize
, DOM_SID
* sid
)
647 if (!sid
|| !pack_buf
) return -1;
649 len
+= tdb_pack(pack_buf
+ len
, bufsize
- len
, "bb", sid
->sid_rev_num
,
652 for (idx
= 0; idx
< 6; idx
++) {
653 len
+= tdb_pack(pack_buf
+ len
, bufsize
- len
, "b", sid
->id_auth
[idx
]);
656 for (idx
= 0; idx
< MAXSUBAUTHS
; idx
++) {
657 len
+= tdb_pack(pack_buf
+ len
, bufsize
- len
, "d", sid
->sub_auths
[idx
]);
665 * Unpack SID into a pointer
667 * @param pack_buf pointer to buffer with packed representation
668 * @param bufsize size of the buffer
669 * @param sid pointer to sid structure to be filled with unpacked data
671 * @return size of structure unpacked from buffer
673 size_t tdb_sid_unpack(char* pack_buf
, int bufsize
, DOM_SID
* sid
)
677 if (!sid
|| !pack_buf
) return -1;
679 len
+= tdb_unpack(pack_buf
+ len
, bufsize
- len
, "bb",
680 &sid
->sid_rev_num
, &sid
->num_auths
);
682 for (idx
= 0; idx
< 6; idx
++) {
683 len
+= tdb_unpack(pack_buf
+ len
, bufsize
- len
, "b", &sid
->id_auth
[idx
]);
686 for (idx
= 0; idx
< MAXSUBAUTHS
; idx
++) {
687 len
+= tdb_unpack(pack_buf
+ len
, bufsize
- len
, "d", &sid
->sub_auths
[idx
]);
695 * Pack TRUSTED_DOM_PASS passed by pointer
697 * @param pack_buf pointer to buffer which is to be filled with packed data
698 * @param bufsize size of the buffer
699 * @param pass pointer to trusted domain password to be packed
701 * @return length of the packed representation of the whole structure
703 size_t tdb_trusted_dom_pass_pack(char* pack_buf
, int bufsize
, TRUSTED_DOM_PASS
* pass
)
707 if (!pack_buf
|| !pass
) return -1;
709 /* packing unicode domain name and password */
710 len
+= tdb_pack(pack_buf
+ len
, bufsize
- len
, "d", pass
->uni_name_len
);
712 for (idx
= 0; idx
< 32; idx
++)
713 len
+= tdb_pack(pack_buf
+ len
, bufsize
- len
, "w", pass
->uni_name
[idx
]);
715 len
+= tdb_pack(pack_buf
+ len
, bufsize
- len
, "dPd", pass
->pass_len
,
716 pass
->pass
, pass
->mod_time
);
718 /* packing SID structure */
719 len
+= tdb_sid_pack(pack_buf
+ len
, bufsize
- len
, &pass
->domain_sid
);
726 * Unpack TRUSTED_DOM_PASS passed by pointer
728 * @param pack_buf pointer to buffer with packed representation
729 * @param bufsize size of the buffer
730 * @param pass pointer to trusted domain password to be filled with unpacked data
732 * @return size of structure unpacked from buffer
734 size_t tdb_trusted_dom_pass_unpack(char* pack_buf
, int bufsize
, TRUSTED_DOM_PASS
* pass
)
738 if (!pack_buf
|| !pass
) return -1;
740 /* unpack unicode domain name and plaintext password */
741 len
+= tdb_unpack(pack_buf
, bufsize
- len
, "d", &pass
->uni_name_len
);
743 for (idx
= 0; idx
< 32; idx
++)
744 len
+= tdb_unpack(pack_buf
+ len
, bufsize
- len
, "w", &pass
->uni_name
[idx
]);
746 len
+= tdb_unpack(pack_buf
+ len
, bufsize
- len
, "dPd", &pass
->pass_len
, &pass
->pass
,
749 /* unpack domain sid */
750 len
+= tdb_sid_unpack(pack_buf
+ len
, bufsize
- len
, &pass
->domain_sid
);
756 /****************************************************************************
757 Log tdb messages via DEBUG().
758 ****************************************************************************/
760 static void tdb_log(TDB_CONTEXT
*tdb
, int level
, const char *format
, ...)
765 va_start(ap
, format
);
766 vasprintf(&ptr
, format
, ap
);
772 DEBUG(level
, ("tdb(%s): %s", tdb
->name
? tdb
->name
: "unnamed", ptr
));
776 /****************************************************************************
777 Like tdb_open() but also setup a logging function that redirects to
778 the samba DEBUG() system.
779 ****************************************************************************/
781 TDB_CONTEXT
*tdb_open_log(const char *name
, int hash_size
, int tdb_flags
,
782 int open_flags
, mode_t mode
)
787 tdb_flags
|= TDB_NOMMAP
;
789 tdb
= tdb_open_ex(name
, hash_size
, tdb_flags
,
790 open_flags
, mode
, tdb_log
, NULL
);
798 /****************************************************************************
799 Allow tdb_delete to be used as a tdb_traversal_fn.
800 ****************************************************************************/
802 int tdb_traverse_delete_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA key
, TDB_DATA dbuf
,
805 return tdb_delete(the_tdb
, key
);
811 * Search across the whole tdb for keys that match the given pattern
812 * return the result as a list of keys
814 * @param tdb pointer to opened tdb file context
815 * @param pattern searching pattern used by fnmatch(3) functions
817 * @return list of keys found by looking up with given pattern
819 TDB_LIST_NODE
*tdb_search_keys(TDB_CONTEXT
*tdb
, const char* pattern
)
822 TDB_LIST_NODE
*list
= NULL
;
823 TDB_LIST_NODE
*rec
= NULL
;
824 TDB_LIST_NODE
*tmp
= NULL
;
826 for (key
= tdb_firstkey(tdb
); key
.dptr
; key
= next
) {
827 /* duplicate key string to ensure null-termination */
828 char *key_str
= (char*) SMB_STRNDUP(key
.dptr
, key
.dsize
);
830 DEBUG(0, ("tdb_search_keys: strndup() failed!\n"));
831 smb_panic("strndup failed!\n");
834 DEBUG(18, ("checking %s for match to pattern %s\n", key_str
, pattern
));
836 next
= tdb_nextkey(tdb
, key
);
838 /* do the pattern checking */
839 if (fnmatch(pattern
, key_str
, 0) == 0) {
840 rec
= SMB_MALLOC_P(TDB_LIST_NODE
);
845 DLIST_ADD_END(list
, rec
, tmp
);
847 DEBUG(18, ("checking %s matched pattern %s\n", key_str
, pattern
));
852 /* free duplicated key string */
862 * Free the list returned by tdb_search_keys
864 * @param node list of results found by tdb_search_keys
866 void tdb_search_list_free(TDB_LIST_NODE
* node
)
868 TDB_LIST_NODE
*next_node
;
871 next_node
= node
->next
;
872 SAFE_FREE(node
->node_key
.dptr
);