summaryrefslogtreecommitdiff
path: root/lib/util
diff options
context:
space:
mode:
authorbubulle <bubulle@alioth.debian.org>2010-04-04 16:44:16 +0000
committerbubulle <bubulle@alioth.debian.org>2010-04-04 16:44:16 +0000
commit9e2f5a6ab663f7a111832217c527508c75ddae8a (patch)
tree2e74616febbb3fb658ce2dcc5f9cff00ad4fdb4a /lib/util
parentb5556af8f75a4f74db404dd43ee7abafa2be6ca4 (diff)
downloadsamba-9e2f5a6ab663f7a111832217c527508c75ddae8a.tar.gz
Merge 3.5.1 from experimental
git-svn-id: svn://svn.debian.org/svn/pkg-samba/trunk/samba@3414 fc4039ab-9d04-0410-8cac-899223bdd6b0
Diffstat (limited to 'lib/util')
-rw-r--r--lib/util/asn1.c94
-rw-r--r--lib/util/asn1.h8
-rw-r--r--lib/util/blocking.c62
-rw-r--r--lib/util/charset/charcnv.c4
-rw-r--r--lib/util/charset/charset.h3
-rw-r--r--lib/util/charset/iconv.c54
-rw-r--r--lib/util/charset/tests/iconv.c6
-rw-r--r--lib/util/charset/util_unistr.c15
-rw-r--r--lib/util/config.mk24
-rw-r--r--lib/util/data_blob.c5
-rw-r--r--lib/util/debug.c14
-rw-r--r--lib/util/debug.h13
-rw-r--r--lib/util/dlinklist.h6
-rw-r--r--lib/util/dprintf.c3
-rw-r--r--lib/util/fault.m43
-rw-r--r--lib/util/genrand.c53
-rw-r--r--lib/util/idtree.c8
-rw-r--r--lib/util/parmlist.c106
-rw-r--r--lib/util/parmlist.h56
-rw-r--r--lib/util/rfc1738.c225
-rw-r--r--lib/util/smb_threads.c202
-rw-r--r--lib/util/smb_threads.h134
-rw-r--r--lib/util/smb_threads_internal.h74
-rw-r--r--lib/util/talloc_stack.c101
-rw-r--r--lib/util/talloc_stack.h2
-rw-r--r--lib/util/tests/genrand.c2
-rw-r--r--lib/util/tests/parmlist.c106
-rw-r--r--lib/util/tests/strlist.c425
-rw-r--r--lib/util/tests/time.c25
-rw-r--r--lib/util/tevent_ntstatus.c10
-rw-r--r--lib/util/tevent_ntstatus.h1
-rw-r--r--lib/util/tevent_unix.c20
-rw-r--r--lib/util/tevent_unix.h20
-rw-r--r--lib/util/time.m42
-rw-r--r--lib/util/util.c79
-rw-r--r--lib/util/util.h103
-rw-r--r--lib/util/util_file.c1
-rw-r--r--lib/util/util_id.c88
-rw-r--r--lib/util/util_ldb.c96
-rw-r--r--lib/util/util_ldb.h8
-rw-r--r--lib/util/util_net.c118
-rw-r--r--lib/util/util_net.h46
-rw-r--r--lib/util/util_strlist.c191
-rw-r--r--lib/util/util_tdb.c2
44 files changed, 2418 insertions, 200 deletions
diff --git a/lib/util/asn1.c b/lib/util/asn1.c
index a2665ed539..70c2c57450 100644
--- a/lib/util/asn1.c
+++ b/lib/util/asn1.c
@@ -205,6 +205,15 @@ bool asn1_write_Integer(struct asn1_data *data, int i)
return asn1_pop_tag(data);
}
+/* write a BIT STRING */
+bool asn1_write_BitString(struct asn1_data *data, const void *p, size_t length, uint8_t padding)
+{
+ if (!asn1_push_tag(data, ASN1_BIT_STRING)) return false;
+ if (!asn1_write_uint8(data, padding)) return false;
+ if (!asn1_write(data, p, length)) return false;
+ return asn1_pop_tag(data);
+}
+
bool ber_write_OID_String(DATA_BLOB *blob, const char *OID)
{
uint_t v, v2;
@@ -262,6 +271,7 @@ bool asn1_write_OID(struct asn1_data *data, const char *OID)
}
if (!asn1_write(data, blob.data, blob.length)) {
+ data_blob_free(&blob);
data->has_error = true;
return false;
}
@@ -332,6 +342,29 @@ bool asn1_read_BOOLEAN(struct asn1_data *data, bool *v)
return !data->has_error;
}
+/* write a BOOLEAN in a simple context */
+bool asn1_write_BOOLEAN_context(struct asn1_data *data, bool v, int context)
+{
+ asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(context));
+ asn1_write_uint8(data, v ? 0xFF : 0);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+bool asn1_read_BOOLEAN_context(struct asn1_data *data, bool *v, int context)
+{
+ uint8_t tmp = 0;
+ asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(context));
+ asn1_read_uint8(data, &tmp);
+ if (tmp == 0xFF) {
+ *v = true;
+ } else {
+ *v = false;
+ }
+ asn1_end_tag(data);
+ return !data->has_error;
+}
+
/* check a BOOLEAN */
bool asn1_check_BOOLEAN(struct asn1_data *data, bool v)
{
@@ -653,7 +686,7 @@ bool asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLO
if (data->has_error) {
data_blob_free(blob);
- *blob = data_blob(NULL, 0);
+ *blob = data_blob_null;
return false;
}
return true;
@@ -703,6 +736,39 @@ bool asn1_read_Integer(struct asn1_data *data, int *i)
return asn1_end_tag(data);
}
+/* read a BIT STRING */
+bool asn1_read_BitString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, uint8_t *padding)
+{
+ int len;
+ ZERO_STRUCTP(blob);
+ if (!asn1_start_tag(data, ASN1_BIT_STRING)) return false;
+ len = asn1_tag_remaining(data);
+ if (len < 0) {
+ data->has_error = true;
+ return false;
+ }
+ if (!asn1_read_uint8(data, padding)) return false;
+
+ *blob = data_blob_talloc(mem_ctx, NULL, len);
+ if (!blob->data) {
+ data->has_error = true;
+ return false;
+ }
+ if (asn1_read(data, blob->data, len - 1)) {
+ blob->length--;
+ blob->data[len] = 0;
+ asn1_end_tag(data);
+ }
+
+ if (data->has_error) {
+ data_blob_free(blob);
+ *blob = data_blob_null;
+ *padding = 0;
+ return false;
+ }
+ return true;
+}
+
/* read an integer */
bool asn1_read_enumerated(struct asn1_data *data, int *v)
{
@@ -741,6 +807,32 @@ bool asn1_write_enumerated(struct asn1_data *data, uint8_t v)
}
/*
+ Get us the data just written without copying
+*/
+bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob)
+{
+ if (asn1->has_error) {
+ return false;
+ }
+ if (asn1->nesting != NULL) {
+ return false;
+ }
+ blob->data = asn1->data;
+ blob->length = asn1->length;
+ return true;
+}
+
+/*
+ Fill in an asn1 struct without making a copy
+*/
+void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len)
+{
+ ZERO_STRUCTP(data);
+ data->data = buf;
+ data->length = len;
+}
+
+/*
check if a ASN.1 blob is a full tag
*/
NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
diff --git a/lib/util/asn1.h b/lib/util/asn1.h
index 8ecb85cb81..9abae50d64 100644
--- a/lib/util/asn1.h
+++ b/lib/util/asn1.h
@@ -46,7 +46,7 @@ typedef struct asn1_data ASN1_DATA;
#define ASN1_OID 0x6
#define ASN1_BOOLEAN 0x1
#define ASN1_INTEGER 0x2
-#define ASN1_BITFIELD 0x3
+#define ASN1_BIT_STRING 0x3
#define ASN1_ENUMERATED 0xa
#define ASN1_SET 0x31
@@ -60,6 +60,7 @@ bool asn1_push_tag(struct asn1_data *data, uint8_t tag);
bool asn1_pop_tag(struct asn1_data *data);
bool asn1_write_implicit_Integer(struct asn1_data *data, int i);
bool asn1_write_Integer(struct asn1_data *data, int i);
+bool asn1_write_BitString(struct asn1_data *data, const void *p, size_t length, uint8_t padding);
bool ber_write_OID_String(DATA_BLOB *blob, const char *OID);
bool asn1_write_OID(struct asn1_data *data, const char *OID);
bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length);
@@ -70,6 +71,8 @@ bool asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *bl
bool asn1_write_BOOLEAN(struct asn1_data *data, bool v);
bool asn1_read_BOOLEAN(struct asn1_data *data, bool *v);
bool asn1_check_BOOLEAN(struct asn1_data *data, bool v);
+bool asn1_write_BOOLEAN_context(struct asn1_data *data, bool v, int context);
+bool asn1_read_BOOLEAN_context(struct asn1_data *data, bool *v, int context);
bool asn1_load(struct asn1_data *data, DATA_BLOB blob);
bool asn1_peek(struct asn1_data *data, void *p, int len);
bool asn1_read(struct asn1_data *data, void *p, int len);
@@ -88,9 +91,12 @@ bool asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLO
bool asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob);
bool asn1_read_implicit_Integer(struct asn1_data *data, int *i);
bool asn1_read_Integer(struct asn1_data *data, int *i);
+bool asn1_read_BitString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, uint8_t *padding);
bool asn1_read_enumerated(struct asn1_data *data, int *v);
bool asn1_check_enumerated(struct asn1_data *data, int v);
bool asn1_write_enumerated(struct asn1_data *data, uint8_t v);
+bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob);
+void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len);
NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
#endif /* _ASN_1_H */
diff --git a/lib/util/blocking.c b/lib/util/blocking.c
new file mode 100644
index 0000000000..f5933cc92b
--- /dev/null
+++ b/lib/util/blocking.c
@@ -0,0 +1,62 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
+ Copyright (C) James J Myers 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#undef malloc
+#undef strcasecmp
+#undef strncasecmp
+#undef strdup
+#undef realloc
+
+/**
+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
+ else
+ if SYSV use O_NDELAY
+ if BSD use FNDELAY
+**/
+
+_PUBLIC_ int set_blocking(int fd, bool set)
+{
+ int val;
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+
+ if((val = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+ if(set) /* Turn blocking on - ie. clear nonblock flag */
+ val &= ~FLAG_TO_SET;
+ else
+ val |= FLAG_TO_SET;
+ return fcntl( fd, F_SETFL, val);
+#undef FLAG_TO_SET
+}
diff --git a/lib/util/charset/charcnv.c b/lib/util/charset/charcnv.c
index 94d47a9f7f..a479f44426 100644
--- a/lib/util/charset/charcnv.c
+++ b/lib/util/charset/charcnv.c
@@ -430,7 +430,7 @@ _PUBLIC_ codepoint_t next_codepoint_convenience(struct smb_iconv_convenience *ic
return the number of bytes occupied by the CH_UNIX character, or
-1 on failure
*/
-_PUBLIC_ ssize_t push_codepoint(struct smb_iconv_convenience *ic,
+_PUBLIC_ ssize_t push_codepoint_convenience(struct smb_iconv_convenience *ic,
char *str, codepoint_t c)
{
smb_iconv_t descriptor;
@@ -478,3 +478,5 @@ _PUBLIC_ ssize_t push_codepoint(struct smb_iconv_convenience *ic,
}
return 5 - olen;
}
+
+
diff --git a/lib/util/charset/charset.h b/lib/util/charset/charset.h
index 37c5acafaf..2c8aa41ad5 100644
--- a/lib/util/charset/charset.h
+++ b/lib/util/charset/charset.h
@@ -151,11 +151,12 @@ ssize_t iconv_talloc(TALLOC_CTX *mem_ctx,
extern struct smb_iconv_convenience *global_iconv_convenience;
codepoint_t next_codepoint(const char *str, size_t *size);
+ssize_t push_codepoint(char *str, codepoint_t c);
/* codepoints */
codepoint_t next_codepoint_convenience(struct smb_iconv_convenience *ic,
const char *str, size_t *size);
-ssize_t push_codepoint(struct smb_iconv_convenience *ic,
+ssize_t push_codepoint_convenience(struct smb_iconv_convenience *ic,
char *str, codepoint_t c);
codepoint_t toupper_m(codepoint_t val);
codepoint_t tolower_m(codepoint_t val);
diff --git a/lib/util/charset/iconv.c b/lib/util/charset/iconv.c
index 9825e4be01..8256dc665c 100644
--- a/lib/util/charset/iconv.c
+++ b/lib/util/charset/iconv.c
@@ -22,7 +22,6 @@
#include "../lib/util/dlinklist.h"
#include "system/iconv.h"
#include "system/filesys.h"
-#undef strcasecmp
/**
@@ -50,7 +49,6 @@
static size_t ascii_pull (void *,const char **, size_t *, char **, size_t *);
static size_t ascii_push (void *,const char **, size_t *, char **, size_t *);
-static size_t latin1_push (void *,const char **, size_t *, char **, size_t *);
static size_t utf8_pull (void *,const char **, size_t *, char **, size_t *);
static size_t utf8_push (void *,const char **, size_t *, char **, size_t *);
static size_t utf16_munged_pull(void *,const char **, size_t *, char **, size_t *);
@@ -74,8 +72,6 @@ static const struct charset_functions builtin_functions[] = {
{"UTF16_MUNGED", utf16_munged_pull, iconv_copy},
{"ASCII", ascii_pull, ascii_push},
- {"646", ascii_pull, ascii_push},
- {"ISO-8859-1", ascii_pull, latin1_push},
{"UCS2-HEX", ucs2hex_pull, ucs2hex_push}
};
@@ -162,7 +158,19 @@ static bool is_utf16(const char *name)
strcasecmp(name, "UTF-16LE") == 0;
}
+int smb_iconv_t_destructor(smb_iconv_t hwd)
+{
+#ifdef HAVE_NATIVE_ICONV
+ if (hwd->cd_pull != NULL && hwd->cd_pull != (iconv_t)-1)
+ iconv_close(hwd->cd_pull);
+ if (hwd->cd_push != NULL && hwd->cd_push != (iconv_t)-1)
+ iconv_close(hwd->cd_push);
+ if (hwd->cd_direct != NULL && hwd->cd_direct != (iconv_t)-1)
+ iconv_close(hwd->cd_direct);
+#endif
+ return 0;
+}
_PUBLIC_ smb_iconv_t smb_iconv_open_ex(TALLOC_CTX *mem_ctx, const char *tocode,
const char *fromcode, bool native_iconv)
@@ -179,6 +187,7 @@ _PUBLIC_ smb_iconv_t smb_iconv_open_ex(TALLOC_CTX *mem_ctx, const char *tocode,
return (smb_iconv_t)-1;
}
memset(ret, 0, sizeof(*ret));
+ talloc_set_destructor(ret, smb_iconv_t_destructor);
/* check for the simplest null conversion */
if (strcmp(fromcode, tocode) == 0) {
@@ -251,6 +260,9 @@ _PUBLIC_ smb_iconv_t smb_iconv_open_ex(TALLOC_CTX *mem_ctx, const char *tocode,
}
if (is_utf16(tocode)) {
ret->direct = sys_iconv;
+ /* could be set just above - so we need to close iconv */
+ if (ret->cd_direct != NULL && ret->cd_direct != (iconv_t)-1)
+ iconv_close(ret->cd_direct);
ret->cd_direct = ret->cd_pull;
ret->cd_pull = NULL;
return ret;
@@ -273,7 +285,7 @@ failed:
*/
_PUBLIC_ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
{
- return smb_iconv_open_ex(NULL, tocode, fromcode, true);
+ return smb_iconv_open_ex(talloc_autofree_context(), tocode, fromcode, true);
}
/*
@@ -281,12 +293,6 @@ _PUBLIC_ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
*/
_PUBLIC_ int smb_iconv_close(smb_iconv_t cd)
{
-#ifdef HAVE_NATIVE_ICONV
- if (cd->cd_direct) iconv_close((iconv_t)cd->cd_direct);
- if (cd->cd_pull) iconv_close((iconv_t)cd->cd_pull);
- if (cd->cd_push) iconv_close((iconv_t)cd->cd_push);
-#endif
-
talloc_free(cd);
return 0;
}
@@ -344,32 +350,6 @@ static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
return ir_count;
}
-static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
- char **outbuf, size_t *outbytesleft)
-{
- int ir_count=0;
-
- while (*inbytesleft >= 2 && *outbytesleft >= 1) {
- (*outbuf)[0] = (*inbuf)[0];
- if ((*inbuf)[1]) ir_count++;
- (*inbytesleft) -= 2;
- (*outbytesleft) -= 1;
- (*inbuf) += 2;
- (*outbuf) += 1;
- }
-
- if (*inbytesleft == 1) {
- errno = EINVAL;
- return -1;
- }
-
- if (*inbytesleft > 1) {
- errno = E2BIG;
- return -1;
- }
-
- return ir_count;
-}
static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
diff --git a/lib/util/charset/tests/iconv.c b/lib/util/charset/tests/iconv.c
index 091876f63b..3e2546dc01 100644
--- a/lib/util/charset/tests/iconv.c
+++ b/lib/util/charset/tests/iconv.c
@@ -27,6 +27,7 @@
#include "libcli/raw/libcliraw.h"
#include "param/param.h"
#include "torture/util.h"
+#include "talloc.h"
#if HAVE_NATIVE_ICONV
@@ -288,7 +289,7 @@ static bool test_codepoint(struct torture_context *tctx, unsigned int codepoint)
size_t size, size2;
codepoint_t c;
- size = push_codepoint(lp_iconv_convenience(tctx->lp_ctx), (char *)buf, codepoint);
+ size = push_codepoint_convenience(lp_iconv_convenience(tctx->lp_ctx), (char *)buf, codepoint);
torture_assert(tctx, size != -1 || (codepoint >= 0xd800 && codepoint <= 0x10000),
"Invalid Codepoint range");
@@ -440,7 +441,8 @@ static bool test_string2key(struct torture_context *tctx)
torture_fail(tctx, "Failed to convert fixed buffer to UTF8\n");
}
- torture_assert(tctx, strcmp(correct, out1) == 0, "conversion gave incorrect result\n");
+ torture_assert(tctx, strcmp(correct, (const char *) out1) == 0,
+ "conversion gave incorrect result\n");
talloc_free(mem_ctx);
diff --git a/lib/util/charset/util_unistr.c b/lib/util/charset/util_unistr.c
index ea2bfeab9f..045aa4a3e3 100644
--- a/lib/util/charset/util_unistr.c
+++ b/lib/util/charset/util_unistr.c
@@ -444,7 +444,7 @@ _PUBLIC_ char *strlower_talloc(TALLOC_CTX *ctx, const char *src)
c = tolower_m(c);
- c_size = push_codepoint(iconv_convenience, dest+size, c);
+ c_size = push_codepoint_convenience(iconv_convenience, dest+size, c);
if (c_size == -1) {
talloc_free(dest);
return NULL;
@@ -483,14 +483,14 @@ _PUBLIC_ char *strupper_talloc_n(TALLOC_CTX *ctx, const char *src, size_t n)
return NULL;
}
- while (*src && n--) {
+ while (n-- && *src) {
size_t c_size;
codepoint_t c = next_codepoint_convenience(iconv_convenience, src, &c_size);
src += c_size;
c = toupper_m(c);
- c_size = push_codepoint(iconv_convenience, dest+size, c);
+ c_size = push_codepoint_convenience(iconv_convenience, dest+size, c);
if (c_size == -1) {
talloc_free(dest);
return NULL;
@@ -551,7 +551,7 @@ _PUBLIC_ void strlower_m(char *s)
while (*s) {
size_t c_size, c_size2;
codepoint_t c = next_codepoint_convenience(iconv_convenience, s, &c_size);
- c_size2 = push_codepoint(iconv_convenience, d, tolower_m(c));
+ c_size2 = push_codepoint_convenience(iconv_convenience, d, tolower_m(c));
if (c_size2 > c_size) {
DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strlower_m\n",
c, tolower_m(c), (int)c_size, (int)c_size2));
@@ -590,7 +590,7 @@ _PUBLIC_ void strupper_m(char *s)
while (*s) {
size_t c_size, c_size2;
codepoint_t c = next_codepoint_convenience(iconv_convenience, s, &c_size);
- c_size2 = push_codepoint(iconv_convenience, d, toupper_m(c));
+ c_size2 = push_codepoint_convenience(iconv_convenience, d, toupper_m(c));
if (c_size2 > c_size) {
DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strupper_m\n",
c, toupper_m(c), (int)c_size, (int)c_size2));
@@ -992,3 +992,8 @@ _PUBLIC_ codepoint_t next_codepoint(const char *str, size_t *size)
{
return next_codepoint_convenience(get_iconv_convenience(), str, size);
}
+
+_PUBLIC_ ssize_t push_codepoint(char *str, codepoint_t c)
+{
+ return push_codepoint_convenience(get_iconv_convenience(), str, c);
+}
diff --git a/lib/util/config.mk b/lib/util/config.mk
index 14bdb2a277..b6125563fb 100644
--- a/lib/util/config.mk
+++ b/lib/util/config.mk
@@ -1,11 +1,14 @@
-[SUBSYSTEM::LIBSAMBA-UTIL]
+[LIBRARY::LIBSAMBA-UTIL]
PUBLIC_DEPENDENCIES = \
LIBTALLOC LIBCRYPTO \
SOCKET_WRAPPER LIBREPLACE_NETWORK \
- CHARSET EXECINFO
+ CHARSET EXECINFO UID_WRAPPER
+
+LIBSAMBA-UTIL_VERSION = 0.0.1
+LIBSAMBA-UTIL_SOVERSION = 0
LIBSAMBA-UTIL_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
- xfile.o \
+ xfile.o \
debug.o \
fault.o \
signal.o \
@@ -14,11 +17,13 @@ LIBSAMBA-UTIL_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
genrand.o \
dprintf.o \
util_str.o \
+ rfc1738.o \
substitute.o \
util_strlist.o \
util_file.o \
data_blob.o \
util.o \
+ blocking.o \
util_net.o \
fsusage.o \
ms_fnmatch.o \
@@ -27,7 +32,10 @@ LIBSAMBA-UTIL_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
become_daemon.o \
rbtree.o \
talloc_stack.o \
- params.o)
+ smb_threads.o \
+ params.o \
+ parmlist.o \
+ util_id.o)
PUBLIC_HEADERS += $(addprefix $(libutilsrcdir)/, util.h \
dlinklist.h \
@@ -48,6 +56,7 @@ PUBLIC_HEADERS += $(addprefix $(libutilsrcdir)/, util.h \
ASN1_UTIL_OBJ_FILES = $(libutilsrcdir)/asn1.o
[SUBSYSTEM::UNIX_PRIVS]
+PRIVATE_DEPENDENCIES = UID_WRAPPER
UNIX_PRIVS_OBJ_FILES = $(libutilsrcdir)/unix_privs.o
@@ -68,6 +77,13 @@ PUBLIC_DEPENDENCIES = LIBTDB
UTIL_TDB_OBJ_FILES = $(libutilsrcdir)/util_tdb.o
+[SUBSYSTEM::UTIL_TEVENT]
+PUBLIC_DEPENDENCIES = LIBTEVENT
+
+UTIL_TEVENT_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
+ tevent_unix.o \
+ tevent_ntstatus.o)
+
[SUBSYSTEM::UTIL_LDB]
PUBLIC_DEPENDENCIES = LIBLDB
diff --git a/lib/util/data_blob.c b/lib/util/data_blob.c
index c7d01bacc7..825d8cf88c 100644
--- a/lib/util/data_blob.c
+++ b/lib/util/data_blob.c
@@ -163,8 +163,11 @@ _PUBLIC_ char *data_blob_hex_string(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
return NULL;
}
+ /* this must be lowercase or w2k8 cannot join a samba domain,
+ as this routine is used to encode extended DNs and windows
+ only accepts lowercase hexadecimal numbers */
for (i = 0; i < blob->length; i++)
- slprintf(&hex_string[i*2], 3, "%02X", blob->data[i]);
+ slprintf(&hex_string[i*2], 3, "%02x", blob->data[i]);
hex_string[(blob->length*2)] = '\0';
return hex_string;
diff --git a/lib/util/debug.c b/lib/util/debug.c
index 578822088f..996efdff7e 100644
--- a/lib/util/debug.c
+++ b/lib/util/debug.c
@@ -50,6 +50,7 @@ static struct {
int fd;
enum debug_logtype logtype;
const char *prog_name;
+ bool reopening_logs;
} state;
static bool reopen_logs_scheduled;
@@ -139,6 +140,9 @@ _PUBLIC_ void reopen_logs(void)
{
char *fname = NULL;
int old_fd = state.fd;
+ if (state.reopening_logs) {
+ return;
+ }
switch (state.logtype) {
case DEBUG_STDOUT:
@@ -150,6 +154,7 @@ _PUBLIC_ void reopen_logs(void)
break;
case DEBUG_FILE:
+ state.reopening_logs = true;
if (logfile && (*logfile) == '/') {
fname = strdup(logfile);
} else {
@@ -167,6 +172,7 @@ _PUBLIC_ void reopen_logs(void)
} else {
DEBUG(1, ("Failed to find name for file-based logfile!\n"));
}
+ state.reopening_logs = false;
break;
}
@@ -192,6 +198,14 @@ _PUBLIC_ void setup_logging(const char *prog_name, enum debug_logtype new_logtyp
}
/**
+ Just run logging to stdout for this program
+*/
+_PUBLIC_ void setup_logging_stdout(void)
+{
+ setup_logging(NULL, DEBUG_STDOUT);
+}
+
+/**
return a string constant containing n tabs
no more than 10 tabs are returned
*/
diff --git a/lib/util/debug.h b/lib/util/debug.h
index 85e64fb861..f0d16952a9 100644
--- a/lib/util/debug.h
+++ b/lib/util/debug.h
@@ -74,8 +74,12 @@ extern int DEBUGLEVEL;
*/
#define DEBUGTAB(n) do_debug_tab(n)
-/** Possible destinations for the debug log */
-enum debug_logtype {DEBUG_FILE = 0, DEBUG_STDOUT = 1, DEBUG_STDERR = 2};
+/** Possible destinations for the debug log (in order of precedence -
+ * once set to DEBUG_FILE, it is not possible to reset to DEBUG_STDOUT
+ * for example. This makes it easy to override for debug to stderr on
+ * the command line, as the smb.conf cannot reset it back to
+ * file-based logging */
+enum debug_logtype {DEBUG_STDOUT = 0, DEBUG_FILE = 1, DEBUG_STDERR = 2};
/**
the backend for debug messages. Note that the DEBUG() macro has already
@@ -102,6 +106,11 @@ _PUBLIC_ void debug_schedule_reopen_logs(void);
_PUBLIC_ void setup_logging(const char *prog_name, enum debug_logtype new_logtype);
/**
+ Just run logging to stdout for this program
+*/
+_PUBLIC_ void setup_logging_stdout(void);
+
+/**
return a string constant containing n tabs
no more than 10 tabs are returned
*/
diff --git a/lib/util/dlinklist.h b/lib/util/dlinklist.h
index 1a4ebb6fa0..693b43dd27 100644
--- a/lib/util/dlinklist.h
+++ b/lib/util/dlinklist.h
@@ -87,11 +87,11 @@ do { \
}\
} while (0)
-/* demote an element to the end of the list, needs a tmp pointer */
-#define DLIST_DEMOTE(list, p, tmp) \
+/* demote an element to the end of the list, needs the entry type */
+#define DLIST_DEMOTE(list, p, type) \
do { \
DLIST_REMOVE(list, p); \
- DLIST_ADD_END(list, p, tmp); \
+ DLIST_ADD_END(list, p, type); \
} while (0)
/* concatenate two lists - putting all elements of the 2nd list at the
diff --git a/lib/util/dprintf.c b/lib/util/dprintf.c
index 3e6d0e8bca..e9a15dcbe6 100644
--- a/lib/util/dprintf.c
+++ b/lib/util/dprintf.c
@@ -39,6 +39,9 @@ static smb_iconv_t display_cd = (smb_iconv_t)-1;
void d_set_iconv(smb_iconv_t cd)
{
+ if (display_cd != (smb_iconv_t)-1)
+ talloc_free(display_cd);
+
display_cd = cd;
}
diff --git a/lib/util/fault.m4 b/lib/util/fault.m4
index da077af31d..c22976998e 100644
--- a/lib/util/fault.m4
+++ b/lib/util/fault.m4
@@ -8,6 +8,9 @@ if test x"$ac_cv_header_execinfo_h" = x"yes" -a x"$ac_cv_func_ext_backtrace" = x
EXECINFO_CFLAGS="$CFLAGS"
EXECINFO_CPPFLAGS="$CPPFLAGS"
EXECINFO_LDFLAGS="$LDFLAGS"
+ LIB_REMOVE_USR_LIB(EXECINFO_LDFLAGS)
+ CFLAGS_REMOVE_USR_INCLUDE(EXECINFO_CFLAGS)
+ CFLAGS_REMOVE_USR_INCLUDE(EXECINFO_CPPFLAGS)
else
SMB_ENABLE(EXECINFO,NO)
fi
diff --git a/lib/util/genrand.c b/lib/util/genrand.c
index cd1823a9a0..f0544023f1 100644
--- a/lib/util/genrand.c
+++ b/lib/util/genrand.c
@@ -294,6 +294,7 @@ _PUBLIC_ uint32_t generate_random(void)
_PUBLIC_ bool check_password_quality(const char *s)
{
int has_digit=0, has_capital=0, has_lower=0, has_special=0, has_high=0;
+ const char* reals = s;
while (*s) {
if (isdigit((unsigned char)*s)) {
has_digit |= 1;
@@ -310,7 +311,7 @@ _PUBLIC_ bool check_password_quality(const char *s)
}
return ((has_digit + has_lower + has_capital + has_special) >= 3
- || (has_high > strlen(s)/2));
+ || (has_high > strlen(reals)/2));
}
/**
@@ -359,3 +360,53 @@ again:
return retstr;
}
+
+/**
+ * Generate an array of unique text strings all of the same length.
+ * The returned string will be allocated.
+ * Returns NULL if the number of unique combinations cannot be created.
+ *
+ * Characters used are: abcdefghijklmnopqrstuvwxyz0123456789+_-#.,
+ */
+_PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
+ uint32_t num)
+{
+ const char *c_list = "abcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
+ const unsigned c_size = 42;
+ int i, j;
+ unsigned rem;
+ char ** strs = NULL;
+
+ if (num == 0 || len == 0)
+ return NULL;
+
+ strs = talloc_array(mem_ctx, char *, num);
+ if (strs == NULL) return NULL;
+
+ for (i = 0; i < num; i++) {
+ char *retstr = (char *)talloc_size(strs, len + 1);
+ if (retstr == NULL) {
+ talloc_free(strs);
+ return NULL;
+ }
+ rem = i;
+ for (j = 0; j < len; j++) {
+ retstr[j] = c_list[rem % c_size];
+ rem = rem / c_size;
+ }
+ retstr[j] = 0;
+ strs[i] = retstr;
+ if (rem != 0) {
+ /* we were not able to fit the number of
+ * combinations asked for in the length
+ * specified */
+ DEBUG(0,(__location__ ": Too many combinations %u for length %u\n",
+ num, (unsigned)len));
+
+ talloc_free(strs);
+ return NULL;
+ }
+ }
+
+ return strs;
+}
diff --git a/lib/util/idtree.c b/lib/util/idtree.c
index c8a8b6346a..0af93a229d 100644
--- a/lib/util/idtree.c
+++ b/lib/util/idtree.c
@@ -372,12 +372,16 @@ _PUBLIC_ int idr_get_new_random(struct idr_context *idp, void *ptr, int limit)
/* first try a random starting point in the whole range, and if that fails,
then start randomly in the bottom half of the range. This can only
- fail if the range is over half full */
+ fail if the range is over half full, and finally fallback to any
+ free id */
id = idr_get_new_above(idp, ptr, 1+(generate_random() % limit), limit);
if (id == -1) {
id = idr_get_new_above(idp, ptr, 1+(generate_random()%(limit/2)), limit);
}
-
+ if (id == -1) {
+ id = idr_get_new_above(idp, ptr, 1, limit);
+ }
+
return id;
}
diff --git a/lib/util/parmlist.c b/lib/util/parmlist.c
new file mode 100644
index 0000000000..6658fa7e33
--- /dev/null
+++ b/lib/util/parmlist.c
@@ -0,0 +1,106 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Jelmer Vernooij 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "../lib/util/dlinklist.h"
+#include "../lib/util/parmlist.h"
+
+struct parmlist_entry *parmlist_get(struct parmlist *ctx, const char *name)
+{
+ struct parmlist_entry *e;
+ for (e = ctx->entries; e; e = e->next) {
+ if (strcasecmp(e->key, name) == 0)
+ return e;
+ }
+
+ return NULL;
+}
+
+int parmlist_get_int(struct parmlist *ctx, const char *name, int default_v)
+{
+ struct parmlist_entry *p = parmlist_get(ctx, name);
+
+ if (p != NULL)
+ return strtol(p->value, NULL, 0);
+
+ return default_v;
+}
+
+bool parmlist_get_bool(struct parmlist *ctx, const char *name, bool default_v)
+{
+ struct parmlist_entry *p = parmlist_get(ctx, name);
+ bool ret;
+
+ if (p == NULL)
+ return default_v;
+
+ if (!set_boolean(p->value, &ret)) {
+ DEBUG(0,("lp_bool(%s): value is not boolean!\n", p->value));
+ return default_v;
+ }
+
+ return ret;
+}
+
+const char *parmlist_get_string(struct parmlist *ctx, const char *name,
+ const char *default_v)
+{
+ struct parmlist_entry *p = parmlist_get(ctx, name);
+
+ if (p == NULL)
+ return default_v;
+
+ return p->value;
+}
+
+const char **parmlist_get_string_list(struct parmlist *ctx, const char *name,
+ const char *separator)
+{
+ struct parmlist_entry *p = parmlist_get(ctx, name);
+
+ if (p == NULL)
+ return NULL;
+
+ return (const char **)str_list_make(ctx, p->value, separator);
+}
+
+static struct parmlist_entry *parmlist_get_add(struct parmlist *ctx, const char *name)
+{
+ struct parmlist_entry *e = parmlist_get(ctx, name);
+
+ if (e != NULL)
+ return e;
+
+ e = talloc(ctx, struct parmlist_entry);
+ if (e == NULL)
+ return NULL;
+ e->key = talloc_strdup(e, name);
+ DLIST_ADD(ctx->entries, e);
+ return e;
+}
+
+int parmlist_set_string(struct parmlist *ctx, const char *name,
+ const char *value)
+{
+ struct parmlist_entry *e = parmlist_get_add(ctx, name);
+ if (e == NULL)
+ return -1;
+
+ e->value = talloc_strdup(e, value);
+ return 0;
+}
diff --git a/lib/util/parmlist.h b/lib/util/parmlist.h
new file mode 100644
index 0000000000..b320afee47
--- /dev/null
+++ b/lib/util/parmlist.h
@@ -0,0 +1,56 @@
+/*
+ Unix SMB/CIFS implementation.
+ Generic parameter parsing interface
+ Copyright (C) Jelmer Vernooij 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _PARMLIST_H /* _PARMLIST_H */
+#define _PARMLIST_H
+
+struct parmlist_entry {
+ struct parmlist_entry *prev, *next;
+ char *key;
+ char *value;
+ int priority;
+};
+
+struct parmlist {
+ struct parmlist_entry *entries;
+};
+
+/** Retrieve an integer from a parameter list. If not found, return default_v. */
+int parmlist_get_int(struct parmlist *ctx, const char *name, int default_v);
+
+/** Retrieve a string from a parameter list. If not found, return default_v. */
+const char *parmlist_get_string(struct parmlist *ctx, const char *name,
+ const char *default_v);
+
+/** Retrieve the struct for an entry in a parmlist. */
+struct parmlist_entry *parmlist_get(struct parmlist *ctx, const char *name);
+
+/** Retrieve a string list from a parameter list.
+ * separator can contain characters to consider separators or can be
+ * NULL for the default set. */
+const char **parmlist_get_string_list(struct parmlist *ctx, const char *name,
+ const char *separator);
+
+/** Retrieve boolean from a parameter list. If not set, return default_v. */
+bool parmlist_get_bool(struct parmlist *ctx, const char *name, bool default_v);
+
+/** Set a parameter. */
+int parmlist_set_string(struct parmlist *ctx, const char *name, const char *value);
+
+#endif /* _PARMLIST_H */
diff --git a/lib/util/rfc1738.c b/lib/util/rfc1738.c
new file mode 100644
index 0000000000..b45310a34b
--- /dev/null
+++ b/lib/util/rfc1738.c
@@ -0,0 +1,225 @@
+/*
+ * NOTE:
+ *
+ * This file imported from the Squid project. The licence below is
+ * reproduced intact, but refers to files in Squid's repository, not
+ * in Samba. See COPYING for the GPLv3 notice (being the later
+ * version mentioned below).
+ *
+ * This file has also been modified, in particular to use talloc to
+ * allocate in rfc1738_escape()
+ *
+ * - Andrew Bartlett Oct-2009
+ *
+ */
+
+
+/*
+ * $Id$
+ *
+ * DEBUG:
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "includes.h"
+
+#include "util.h"
+
+/*
+ * RFC 1738 defines that these characters should be escaped, as well
+ * any non-US-ASCII character or anything between 0x00 - 0x1F.
+ */
+static char rfc1738_unsafe_chars[] = {
+ (char) 0x3C, /* < */
+ (char) 0x3E, /* > */
+ (char) 0x22, /* " */
+ (char) 0x23, /* # */
+#if 0 /* done in code */
+ (char) 0x25, /* % */
+#endif
+ (char) 0x7B, /* { */
+ (char) 0x7D, /* } */
+ (char) 0x7C, /* | */
+ (char) 0x5C, /* \ */
+ (char) 0x5E, /* ^ */
+ (char) 0x7E, /* ~ */
+ (char) 0x5B, /* [ */
+ (char) 0x5D, /* ] */
+ (char) 0x60, /* ` */
+ (char) 0x27, /* ' */
+ (char) 0x20 /* space */
+};
+
+static char rfc1738_reserved_chars[] = {
+ (char) 0x3b, /* ; */
+ (char) 0x2f, /* / */
+ (char) 0x3f, /* ? */
+ (char) 0x3a, /* : */
+ (char) 0x40, /* @ */
+ (char) 0x3d, /* = */
+ (char) 0x26 /* & */
+};
+
+/*
+ * rfc1738_escape - Returns a static buffer contains the RFC 1738
+ * compliant, escaped version of the given url.
+ *
+ */
+static char *
+rfc1738_do_escape(TALLOC_CTX *mem_ctx, const char *url, int encode_reserved)
+{
+ size_t bufsize = 0;
+ const char *p;
+ char *buf;
+ char *q;
+ unsigned int i, do_escape;
+
+ bufsize = strlen(url) * 3 + 1;
+ buf = talloc_array(mem_ctx, char, bufsize);
+ if (!buf) {
+ return NULL;
+ }
+
+ talloc_set_name_const(buf, buf);
+ buf[0] = '\0';
+
+ for (p = url, q = buf; *p != '\0' && q < (buf + bufsize - 1); p++, q++) {
+ do_escape = 0;
+
+ /* RFC 1738 defines these chars as unsafe */
+ for (i = 0; i < sizeof(rfc1738_unsafe_chars); i++) {
+ if (*p == rfc1738_unsafe_chars[i]) {
+ do_escape = 1;
+ break;
+ }
+ }
+ /* Handle % separately */
+ if (encode_reserved >= 0 && *p == '%')
+ do_escape = 1;
+ /* RFC 1738 defines these chars as reserved */
+ for (i = 0; i < sizeof(rfc1738_reserved_chars) && encode_reserved > 0; i++) {
+ if (*p == rfc1738_reserved_chars[i]) {
+ do_escape = 1;
+ break;
+ }
+ }
+ /* RFC 1738 says any control chars (0x00-0x1F) are encoded */
+ if ((unsigned char) *p <= (unsigned char) 0x1F) {
+ do_escape = 1;
+ }
+ /* RFC 1738 says 0x7f is encoded */
+ if (*p == (char) 0x7F) {
+ do_escape = 1;
+ }
+ /* RFC 1738 says any non-US-ASCII are encoded */
+ if (((unsigned char) *p >= (unsigned char) 0x80)) {
+ do_escape = 1;
+ }
+ /* Do the triplet encoding, or just copy the char */
+ /* note: while we do not need snprintf here as q is appropriately
+ * allocated, Samba does to avoid our macro banning it -- abartlet */
+
+ if (do_escape == 1) {
+ (void) snprintf(q, 4, "%%%02X", (unsigned char) *p);
+ q += sizeof(char) * 2;
+ } else {
+ *q = *p;
+ }
+ }
+ *q = '\0';
+ return (buf);
+}
+
+/*
+ * rfc1738_escape - Returns a buffer that contains the RFC
+ * 1738 compliant, escaped version of the given url. (escapes unsafe and % characters)
+ */
+char *
+rfc1738_escape(TALLOC_CTX *mem_ctx, const char *url)
+{
+ return rfc1738_do_escape(mem_ctx, url, 0);
+}
+
+/*
+ * rfc1738_escape_unescaped - Returns a buffer that contains
+ * the RFC 1738 compliant, escaped version of the given url (escapes unsafe chars only)
+ */
+char *
+rfc1738_escape_unescaped(TALLOC_CTX *mem_ctx, const char *url)
+{
+ return rfc1738_do_escape(mem_ctx, url, -1);
+}
+
+/*
+ * rfc1738_escape_part - Returns a buffer that contains the RFC
+ * 1738 compliant, escaped version of the given url segment. (escapes
+ * unsafe, reserved and % chars) It would mangle the :// in http://,
+ * and mangle paths (because of /).
+ */
+char *
+rfc1738_escape_part(TALLOC_CTX *mem_ctx, const char *url)
+{
+ return rfc1738_do_escape(mem_ctx, url, 1);
+}
+
+/*
+ * rfc1738_unescape() - Converts escaped characters (%xy numbers) in
+ * given the string. %% is a %. %ab is the 8-bit hexadecimal number "ab"
+ */
+_PUBLIC_ void
+rfc1738_unescape(char *s)
+{
+ char hexnum[3];
+ int i, j; /* i is write, j is read */
+ unsigned int x;
+ for (i = j = 0; s[j]; i++, j++) {
+ s[i] = s[j];
+ if (s[i] != '%')
+ continue;
+ if (s[j + 1] == '%') { /* %% case */
+ j++;
+ continue;
+ }
+ if (s[j + 1] && s[j + 2]) {
+ if (s[j + 1] == '0' && s[j + 2] == '0') { /* %00 case */
+ j += 2;
+ continue;
+ }
+ hexnum[0] = s[j + 1];
+ hexnum[1] = s[j + 2];
+ hexnum[2] = '\0';
+ if (1 == sscanf(hexnum, "%x", &x)) {
+ s[i] = (char) (0x0ff & x);
+ j += 2;
+ }
+ }
+ }
+ s[i] = '\0';
+}
diff --git a/lib/util/smb_threads.c b/lib/util/smb_threads.c
new file mode 100644
index 0000000000..58ea2daa67
--- /dev/null
+++ b/lib/util/smb_threads.c
@@ -0,0 +1,202 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client library implementation (thread interface functions).
+ Copyright (C) Jeremy Allison, 2009.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * This code is based in the ideas in openssl
+ * but somewhat simpler and expended to include
+ * thread local storage.
+ */
+
+#include "includes.h"
+#include "smb_threads.h"
+
+/*********************************************************
+ Functions to vector the locking primitives used internally
+ by libsmbclient.
+*********************************************************/
+
+const struct smb_thread_functions *global_tfp;
+
+/*********************************************************
+ Dynamic lock array.
+*********************************************************/
+
+void **global_lock_array;
+
+/*********************************************************
+ Mutex used for our internal "once" function
+*********************************************************/
+
+static void *once_mutex = NULL;
+
+
+/*********************************************************
+ Function to set the locking primitives used by libsmbclient.
+*********************************************************/
+
+int smb_thread_set_functions(const struct smb_thread_functions *tf)
+{
+ int i;
+
+ global_tfp = tf;
+
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef malloc
+#undef malloc
+#endif
+#endif
+
+ /* Here we initialize any static locks we're using. */
+ global_lock_array = (void **)malloc(sizeof(void *) *NUM_GLOBAL_LOCKS);
+
+#if defined(PARANOID_MALLOC_CHECKER)
+#define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+#endif
+
+ if (global_lock_array == NULL) {
+ return ENOMEM;
+ }
+
+ for (i = 0; i < NUM_GLOBAL_LOCKS; i++) {
+ char *name = NULL;
+ if (asprintf(&name, "global_lock_%d", i) == -1) {
+ SAFE_FREE(global_lock_array);
+ return ENOMEM;
+ }
+ if (global_tfp->create_mutex(name,
+ &global_lock_array[i],
+ __location__)) {
+ smb_panic("smb_thread_set_functions: create mutexes failed");
+ }
+ SAFE_FREE(name);
+ }
+
+ /* Create the mutex we'll use for our "once" function */
+ if (SMB_THREAD_CREATE_MUTEX("smb_once", once_mutex) != 0) {
+ smb_panic("smb_thread_set_functions: failed to create 'once' mutex");
+ }
+
+ return 0;
+}
+
+/*******************************************************************
+ Call a function only once. We implement this ourselves
+ using our own mutex rather than using the thread implementation's
+ *_once() function because each implementation has its own
+ type for the variable which keeps track of whether the function
+ has been called, and there's no easy way to allocate the correct
+ size variable in code internal to Samba without knowing the
+ implementation's "once" type.
+********************************************************************/
+
+int smb_thread_once(smb_thread_once_t *ponce,
+ void (*init_fn)(void *pdata),
+ void *pdata)
+{
+ int ret;
+
+ /* Lock our "once" mutex in order to test and initialize ponce */
+ if (SMB_THREAD_LOCK(once_mutex) != 0) {
+ smb_panic("error locking 'once'");
+ }
+
+ /* Keep track of whether we ran their init function */
+ ret = ! *ponce;
+
+ /*
+ * See if another thread got here after we tested it initially but
+ * before we got our lock.
+ */
+ if (! *ponce) {
+ /* Nope, we need to run the initialization function */
+ (*init_fn)(pdata);
+
+ /* Now we can indicate that the function has been run */
+ *ponce = true;
+ }
+
+ /* Unlock the mutex */
+ if (SMB_THREAD_UNLOCK(once_mutex) != 0) {
+ smb_panic("error unlocking 'once'");
+ }
+
+ /*
+ * Tell 'em whether we ran their init function. If they passed a data
+ * pointer to the init function and the init function could change
+ * something in the pointed-to data, this will tell them whether that
+ * data is valid or not.
+ */
+ return ret;
+}
+
+
+#if 0
+/* Test. - pthread implementations. */
+#include <pthread.h>
+
+#ifdef malloc
+#undef malloc
+#endif
+
+SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION(tf);
+
+static smb_thread_once_t ot = SMB_THREAD_ONCE_INIT;
+void *pkey = NULL;
+
+static void init_fn(void)
+{
+ int ret;
+
+ if (!global_tfp) {
+ /* Non-thread safe init case. */
+ if (ot) {
+ return;
+ }
+ ot = true;
+ }
+
+ if ((ret = SMB_THREAD_CREATE_TLS("test_tls", pkey)) != 0) {
+ printf("Create tls once error: %d\n", ret);
+ }
+}
+
+/* Test function. */
+int test_threads(void)
+{
+ int ret;
+ void *plock = NULL;
+ smb_thread_set_functions(&tf);
+
+ SMB_THREAD_ONCE(&ot, init_fn);
+
+ if ((ret = SMB_THREAD_CREATE_MUTEX("test", plock)) != 0) {
+ printf("Create lock error: %d\n", ret);
+ }
+ if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_LOCK)) != 0) {
+ printf("lock error: %d\n", ret);
+ }
+ if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_UNLOCK)) != 0) {
+ printf("unlock error: %d\n", ret);
+ }
+ SMB_THREAD_DESTROY_MUTEX(plock);
+ SMB_THREAD_DESTROY_TLS(pkey);
+
+ return 0;
+}
+#endif
diff --git a/lib/util/smb_threads.h b/lib/util/smb_threads.h
new file mode 100644
index 0000000000..9a09616774
--- /dev/null
+++ b/lib/util/smb_threads.h
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB thread interface functions.
+ Copyright (C) Jeremy Allison, 2009.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _smb_threads_h_
+#define _smb_threads_h_
+
+typedef bool smb_thread_once_t;
+#define SMB_THREAD_ONCE_INIT false
+
+enum smb_thread_lock_type {
+ SMB_THREAD_LOCK = 1,
+ SMB_THREAD_UNLOCK
+};
+
+struct smb_thread_functions {
+ /* Mutex and tls functions. */
+ int (*create_mutex)(const char *lockname,
+ void **pplock,
+ const char *location);
+ void (*destroy_mutex)(void *plock,
+ const char *location);
+ int (*lock_mutex)(void *plock,
+ int lock_type,
+ const char *location);
+
+ /* Thread local storage. */
+ int (*create_tls)(const char *keyname,
+ void **ppkey,
+ const char *location);
+ void (*destroy_tls)(void **pkey,
+ const char *location);
+ int (*set_tls)(void *pkey, const void *pval, const char *location);
+ void *(*get_tls)(void *pkey, const char *location);
+};
+
+int smb_thread_set_functions(const struct smb_thread_functions *tf);
+int smb_thread_once(smb_thread_once_t *ponce,
+ void (*init_fn)(void *pdata),
+ void *pdata);
+
+extern const struct smb_thread_functions *global_tfp;
+
+/* Define the pthread version of the functions. */
+
+#define SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION(tf) \
+ \
+static int smb_create_mutex_pthread(const char *lockname, void **pplock, const char *location) \
+{ \
+ pthread_mutex_t *pmut = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); \
+ if (!pmut) { \
+ return ENOMEM; \
+ } \
+ pthread_mutex_init(pmut, NULL); \
+ *pplock = (void *)pmut; \
+ return 0; \
+} \
+ \
+static void smb_destroy_mutex_pthread(void *plock, const char *location) \
+{ \
+ pthread_mutex_destroy((pthread_mutex_t *)plock); \
+ free(plock); \
+} \
+ \
+static int smb_lock_pthread(void *plock, int lock_type, const char *location) \
+{ \
+ if (lock_type == SMB_THREAD_UNLOCK) { \
+ return pthread_mutex_unlock((pthread_mutex_t *)plock); \
+ } else { \
+ return pthread_mutex_lock((pthread_mutex_t *)plock); \
+ } \
+} \
+ \
+static int smb_create_tls_pthread(const char *keyname, void **ppkey, const char *location) \
+{ \
+ int ret; \
+ pthread_key_t *pkey; \
+ pkey = (pthread_key_t *)malloc(sizeof(pthread_key_t)); \
+ if (!pkey) { \
+ return ENOMEM; \
+ } \
+ ret = pthread_key_create(pkey, NULL); \
+ if (ret) { \
+ free(pkey); \
+ return ret; \
+ } \
+ *ppkey = (void *)pkey; \
+ return 0; \
+} \
+ \
+static void smb_destroy_tls_pthread(void **ppkey, const char *location) \
+{ \
+ if (*ppkey) { \
+ pthread_key_delete(*(pthread_key_t *)ppkey); \
+ free(*ppkey); \
+ *ppkey = NULL; \
+ } \
+} \
+ \
+static int smb_set_tls_pthread(void *pkey, const void *pval, const char *location) \
+{ \
+ return pthread_setspecific(*(pthread_key_t *)pkey, pval); \
+} \
+ \
+static void *smb_get_tls_pthread(void *pkey, const char *location) \
+{ \
+ return pthread_getspecific(*(pthread_key_t *)pkey); \
+} \
+ \
+static const struct smb_thread_functions (tf) = { \
+ smb_create_mutex_pthread, \
+ smb_destroy_mutex_pthread, \
+ smb_lock_pthread, \
+ smb_create_tls_pthread, \
+ smb_destroy_tls_pthread, \
+ smb_set_tls_pthread, \
+ smb_get_tls_pthread }
+
+#endif
diff --git a/lib/util/smb_threads_internal.h b/lib/util/smb_threads_internal.h
new file mode 100644
index 0000000000..afd7559f3b
--- /dev/null
+++ b/lib/util/smb_threads_internal.h
@@ -0,0 +1,74 @@
+/*
+ SMB/CIFS implementation.
+ SMB thread interface internal macros.
+ Copyright (C) Jeremy Allison, 2009.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _smb_threads_internal_h_
+#define _smb_threads_internal_h_
+
+#define SMB_THREAD_CREATE_MUTEX(name, lockvar) \
+ (global_tfp ? global_tfp->create_mutex((name), &(lockvar), __location__) : 0)
+
+#define SMB_THREAD_DESTROY_MUTEX(plock) \
+ do { \
+ if (global_tfp) { \
+ global_tfp->destroy_mutex(plock, __location__); \
+ }; \
+ } while (0)
+
+#define SMB_THREAD_LOCK_INTERNAL(plock, type, location) \
+ (global_tfp ? global_tfp->lock_mutex((plock), (type), location) : 0)
+
+#define SMB_THREAD_LOCK(plock) \
+ SMB_THREAD_LOCK_INTERNAL(plock, SMB_THREAD_LOCK, __location__)
+
+#define SMB_THREAD_UNLOCK(plock) \
+ SMB_THREAD_LOCK_INTERNAL(plock, SMB_THREAD_UNLOCK, __location__)
+
+#define SMB_THREAD_ONCE(ponce, init_fn, pdata) \
+ (global_tfp \
+ ? (! *(ponce) \
+ ? smb_thread_once((ponce), (init_fn), (pdata)) \
+ : 0) \
+ : ((init_fn(pdata)), *(ponce) = true, 1))
+
+#define SMB_THREAD_CREATE_TLS(keyname, key) \
+ (global_tfp ? global_tfp->create_tls((keyname), &(key), __location__) : 0)
+
+#define SMB_THREAD_DESTROY_TLS(key) \
+ do { \
+ if (global_tfp) { \
+ global_tfp->destroy_tls(&(key), __location__); \
+ }; \
+ } while (0)
+
+#define SMB_THREAD_SET_TLS(key, val) \
+ (global_tfp ? global_tfp->set_tls((key),(val),__location__) : \
+ ((key) = (val), 0))
+
+#define SMB_THREAD_GET_TLS(key) \
+ (global_tfp ? global_tfp->get_tls((key), __location__) : (key))
+
+/*
+ * Global thread lock list.
+ */
+
+#define NUM_GLOBAL_LOCKS 1
+
+#define GLOBAL_LOCK(locknum) (global_lock_array ? global_lock_array[(locknum)] : NULL)
+
+#endif
diff --git a/lib/util/talloc_stack.c b/lib/util/talloc_stack.c
index 2f3ea11377..596efbf6cd 100644
--- a/lib/util/talloc_stack.c
+++ b/lib/util/talloc_stack.c
@@ -2,6 +2,7 @@
Unix SMB/CIFS implementation.
Implement a stack of talloc contexts
Copyright (C) Volker Lendecke 2007
+ Copyright (C) Jeremy Allison 2009 - made thread safe.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,22 +39,73 @@
#include "includes.h"
-static int talloc_stacksize;
-static int talloc_stack_arraysize;
-static TALLOC_CTX **talloc_stack;
+struct talloc_stackframe {
+ int talloc_stacksize;
+ int talloc_stack_arraysize;
+ TALLOC_CTX **talloc_stack;
+};
+
+/*
+ * In the single threaded case this is a pointer
+ * to the global talloc_stackframe. In the MT-case
+ * this is the pointer to the thread-specific key
+ * used to look up the per-thread talloc_stackframe
+ * pointer.
+ */
+
+static void *global_ts;
+
+/* Variable to ensure TLS value is only initialized once. */
+static smb_thread_once_t ts_initialized = SMB_THREAD_ONCE_INIT;
+
+static void talloc_stackframe_init(void * unused)
+{
+ if (SMB_THREAD_CREATE_TLS("talloc_stackframe", global_ts)) {
+ smb_panic("talloc_stackframe_init create_tls failed");
+ }
+}
+
+static struct talloc_stackframe *talloc_stackframe_create(void)
+{
+#if defined(PARANOID_MALLOC_CHECKER)
+#ifdef malloc
+#undef malloc
+#endif
+#endif
+ struct talloc_stackframe *ts =
+ (struct talloc_stackframe *)malloc(sizeof(struct talloc_stackframe));
+#if defined(PARANOID_MALLOC_CHECKER)
+#define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
+#endif
+
+ if (!ts) {
+ smb_panic("talloc_stackframe_init malloc failed");
+ }
+
+ ZERO_STRUCTP(ts);
+
+ SMB_THREAD_ONCE(&ts_initialized, talloc_stackframe_init, NULL);
+
+ if (SMB_THREAD_SET_TLS(global_ts, ts)) {
+ smb_panic("talloc_stackframe_init set_tls failed");
+ }
+ return ts;
+}
static int talloc_pop(TALLOC_CTX *frame)
{
+ struct talloc_stackframe *ts =
+ (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
int i;
- for (i=talloc_stacksize-1; i>0; i--) {
- if (frame == talloc_stack[i]) {
+ for (i=ts->talloc_stacksize-1; i>0; i--) {
+ if (frame == ts->talloc_stack[i]) {
break;
}
- talloc_free(talloc_stack[i]);
+ talloc_free(ts->talloc_stack[i]);
}
- talloc_stacksize = i;
+ ts->talloc_stacksize = i;
return 0;
}
@@ -67,22 +119,27 @@ static int talloc_pop(TALLOC_CTX *frame)
static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
{
TALLOC_CTX **tmp, *top, *parent;
+ struct talloc_stackframe *ts =
+ (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
- if (talloc_stack_arraysize < talloc_stacksize + 1) {
- tmp = talloc_realloc(NULL, talloc_stack, TALLOC_CTX *,
- talloc_stacksize + 1);
+ if (ts == NULL) {
+ ts = talloc_stackframe_create();
+ }
+
+ if (ts->talloc_stack_arraysize < ts->talloc_stacksize + 1) {
+ tmp = talloc_realloc(NULL, ts->talloc_stack, TALLOC_CTX *,
+ ts->talloc_stacksize + 1);
if (tmp == NULL) {
goto fail;
}
- talloc_stack = tmp;
- talloc_stack_arraysize = talloc_stacksize + 1;
+ ts->talloc_stack = tmp;
+ ts->talloc_stack_arraysize = ts->talloc_stacksize + 1;
}
- if (talloc_stacksize == 0) {
- parent = talloc_stack;
- }
- else {
- parent = talloc_stack[talloc_stacksize-1];
+ if (ts->talloc_stacksize == 0) {
+ parent = ts->talloc_stack;
+ } else {
+ parent = ts->talloc_stack[ts->talloc_stacksize-1];
}
if (poolsize) {
@@ -97,7 +154,7 @@ static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
talloc_set_destructor(top, talloc_pop);
- talloc_stack[talloc_stacksize++] = top;
+ ts->talloc_stack[ts->talloc_stacksize++] = top;
return top;
fail:
@@ -121,10 +178,14 @@ TALLOC_CTX *talloc_stackframe_pool(size_t poolsize)
TALLOC_CTX *talloc_tos(void)
{
- if (talloc_stacksize == 0) {
+ struct talloc_stackframe *ts =
+ (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
+
+ if (ts == NULL) {
talloc_stackframe();
+ ts = (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
DEBUG(0, ("no talloc stackframe around, leaking memory\n"));
}
- return talloc_stack[talloc_stacksize-1];
+ return ts->talloc_stack[ts->talloc_stacksize-1];
}
diff --git a/lib/util/talloc_stack.h b/lib/util/talloc_stack.h
index bb22b8a029..777671164d 100644
--- a/lib/util/talloc_stack.h
+++ b/lib/util/talloc_stack.h
@@ -35,7 +35,7 @@
#ifndef _TALLOC_STACK_H
#define _TALLOC_STACK_H
-#include "../talloc/talloc.h"
+#include "talloc.h"
/*
* Create a new talloc stack frame.
diff --git a/lib/util/tests/genrand.c b/lib/util/tests/genrand.c
index 5fe229c089..20a20ac7fa 100644
--- a/lib/util/tests/genrand.c
+++ b/lib/util/tests/genrand.c
@@ -40,6 +40,8 @@ static bool test_check_password_quality(struct torture_context *tctx)
torture_assert(tctx, !check_password_quality("aaaaaaaaaaaa"), "same char password");
torture_assert(tctx, !check_password_quality("BLA"), "multiple upcases password");
torture_assert(tctx, !check_password_quality("123"), "digits only");
+ torture_assert(tctx, !check_password_quality("matthiéu"), "not enough high symbols");
+ torture_assert(tctx, check_password_quality("abcdééàçè"), "valid");
torture_assert(tctx, check_password_quality("A2e"), "valid");
torture_assert(tctx, check_password_quality("BA2eLi443"), "valid");
return true;
diff --git a/lib/util/tests/parmlist.c b/lib/util/tests/parmlist.c
new file mode 100644
index 0000000000..4b1d875715
--- /dev/null
+++ b/lib/util/tests/parmlist.c
@@ -0,0 +1,106 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ parmlist testing
+
+ Copyright (C) Jelmer Vernooij 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "../lib/util/parmlist.h"
+
+static bool test_get_int(struct torture_context *tctx)
+{
+ struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
+ parmlist_set_string(pctx, "bar", "3");
+ parmlist_set_string(pctx, "notint", "bla");
+ torture_assert_int_equal(tctx, 3, parmlist_get_int(pctx, "bar", 42),
+ "existing");
+ torture_assert_int_equal(tctx, 42, parmlist_get_int(pctx, "foo", 42),
+ "default");
+ torture_assert_int_equal(tctx, 0, parmlist_get_int(pctx, "notint", 42),
+ "Not an integer");
+ return true;
+}
+
+static bool test_get_string(struct torture_context *tctx)
+{
+ struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
+ parmlist_set_string(pctx, "bar", "mystring");
+ torture_assert_str_equal(tctx, "mystring",
+ parmlist_get_string(pctx, "bar", "bla"), "existing");
+ torture_assert_str_equal(tctx, "bla",
+ parmlist_get_string(pctx, "foo", "bla"), "default");
+ return true;
+}
+
+static bool test_get(struct torture_context *tctx)
+{
+ struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
+ struct parmlist_entry *e;
+ parmlist_set_string(pctx, "bar", "mystring");
+
+ e = parmlist_get(pctx, "bar");
+ torture_assert(tctx, e != NULL, "entry");
+ torture_assert_str_equal(tctx, e->key, "bar", "key");
+ torture_assert_str_equal(tctx, e->value, "mystring", "value");
+
+ e = parmlist_get(pctx, "nonexistant");
+ torture_assert(tctx, e == NULL, "nonexistant");
+ return true;
+}
+
+static bool test_get_bool(struct torture_context *tctx)
+{
+ struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
+ parmlist_set_string(pctx, "bar", "true");
+ parmlist_set_string(pctx, "gasoline", "invalid");
+
+ torture_assert(tctx, parmlist_get_bool(pctx, "bar", false), "set");
+ torture_assert(tctx, !parmlist_get_bool(pctx, "foo", false), "default");
+ torture_assert(tctx, !parmlist_get_bool(pctx, "gasoline", false),
+ "invalid");
+ return true;
+}
+
+static bool test_get_string_list(struct torture_context *tctx)
+{
+ struct parmlist *pctx = talloc_zero(tctx, struct parmlist);
+ const char **ret;
+ parmlist_set_string(pctx, "bar", "true, false");
+
+ ret = parmlist_get_string_list(pctx, "bar", NULL);
+ torture_assert_int_equal(tctx, str_list_length(ret), 2, "length");
+ torture_assert_str_equal(tctx, "true", ret[0], "ret[0]");
+ torture_assert_str_equal(tctx, "false", ret[1], "ret[1]");
+ torture_assert(tctx, NULL == parmlist_get_string_list(pctx, "nonexistant", NULL), "nonexistant");
+
+ return true;
+}
+
+struct torture_suite *torture_local_util_parmlist(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "PARMLIST");
+
+ torture_suite_add_simple_test(suite, "get_int", test_get_int);
+ torture_suite_add_simple_test(suite, "get_string", test_get_string);
+ torture_suite_add_simple_test(suite, "get", test_get);
+ torture_suite_add_simple_test(suite, "get_bool", test_get_bool);
+ torture_suite_add_simple_test(suite, "get_string_list", test_get_string_list);
+
+ return suite;
+}
diff --git a/lib/util/tests/strlist.c b/lib/util/tests/strlist.c
index 8605102954..a974f58184 100644
--- a/lib/util/tests/strlist.c
+++ b/lib/util/tests/strlist.c
@@ -4,6 +4,7 @@
util_strlist testing
Copyright (C) Jelmer Vernooij 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,28 +22,96 @@
#include "includes.h"
#include "torture/torture.h"
+#include "param/param.h"
-static const char *test_lists_shell_strings[] = {
- "",
- "foo",
- "foo bar",
- "foo bar \"bla \"",
- "foo \"\" bla",
- "bla \"\"\"\" blie",
- NULL
+struct test_list_element {
+ const char *list_as_string;
+ const char *seperators;
+ const char *list[5];
+};
+
+struct test_list_element test_lists_strings[] = {
+ {
+ .list_as_string = "",
+ .list = { NULL }
+ },
+ {
+ .list_as_string = "foo",
+ .list = { "foo", NULL }
+ },
+ {
+ .list_as_string = "foo bar",
+ .list = { "foo", "bar", NULL }
+ },
+ {
+ .list_as_string = "foo bar",
+ .list = { "foo bar", NULL },
+ .seperators = ";"
+ },
+ {
+ .list_as_string = "\"foo bar\"",
+ .list = { "\"foo", "bar\"", NULL }
+ },
+ {
+ .list_as_string = "\"foo bar\",comma\ttab",
+ .list = { "\"foo", "bar\"", "comma", "tab", NULL }
+ },
+ {
+ .list_as_string = "\"foo bar\",comma;semicolon",
+ .list = { "\"foo bar\",comma", "semicolon", NULL },
+ .seperators = ";"
+ }
+};
+
+struct test_list_element test_lists_shell_strings[] = {
+ {
+ .list_as_string = "",
+ .list = { NULL }
+ },
+ {
+ .list_as_string = "foo",
+ .list = { "foo", NULL }
+ },
+ {
+ .list_as_string = "foo bar",
+ .list = { "foo", "bar", NULL }
+ },
+ {
+ .list_as_string = "foo bar",
+ .list = { "foo bar", NULL },
+ .seperators = ";"
+ },
+ {
+ .list_as_string = "\"foo bar\"",
+ .list = { "foo bar", NULL }
+ },
+ {
+ .list_as_string = "foo bar \"bla \"",
+ .list = { "foo", "bar", "bla ", NULL }
+ },
+ {
+ .list_as_string = "foo \"\" bla",
+ .list = { "foo", "", "bla", NULL },
+ },
+ {
+ .list_as_string = "bla \"\"\"\" blie",
+ .list = { "bla", "", "", "blie", NULL },
+ }
};
static bool test_lists_shell(struct torture_context *tctx,
- const void *test_data)
+ const void *data)
{
- const char *data = (const char *)test_data;
+ const struct test_list_element *element = data;
const char **ret1, **ret2, *tmp;
bool match = true;
TALLOC_CTX *mem_ctx = tctx;
- ret1 = str_list_make_shell(mem_ctx, data, " ");
- tmp = str_list_join_shell(mem_ctx, ret1, ' ');
- ret2 = str_list_make_shell(mem_ctx, tmp, " ");
+ ret1 = str_list_make_shell(mem_ctx, element->list_as_string, element->seperators);
+
+ torture_assert(tctx, ret1, "str_list_make_shell() must not return NULL");
+ tmp = str_list_join_shell(mem_ctx, ret1, element->seperators ? *element->seperators : ' ');
+ ret2 = str_list_make_shell(mem_ctx, tmp, element->seperators);
if ((ret1 == NULL || ret2 == NULL) && ret2 != ret1) {
match = false;
@@ -60,7 +129,25 @@ static bool test_lists_shell(struct torture_context *tctx,
}
torture_assert(tctx, match, talloc_asprintf(tctx,
- "str_list_{make,join}_shell: Error double parsing, first run:\n%s\nSecond run: \n%s", data, tmp));
+ "str_list_{make,join}_shell: Error double parsing, first run:\n%s\nSecond run: \n%s", element->list_as_string, tmp));
+ torture_assert(tctx, str_list_equal(ret1, element->list),
+ talloc_asprintf(tctx,
+ "str_list_make_shell(%s) failed to create correct list",
+ element->list_as_string));
+
+ return true;
+}
+
+static bool test_list_make(struct torture_context *tctx, const void *data)
+{
+ const struct test_list_element *element = data;
+ char **result;
+ result = str_list_make(tctx, element->list_as_string, element->seperators);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ torture_assert(tctx, str_list_equal((const char **)result, element->list),
+ talloc_asprintf(tctx,
+ "str_list_make(%s) failed to create correct list",
+ element->list_as_string));
return true;
}
@@ -87,17 +174,325 @@ static bool test_list_copy(struct torture_context *tctx)
return true;
}
+static bool test_list_make_empty(struct torture_context *tctx)
+{
+ char **result;
+
+ result = str_list_make_empty(tctx);
+ torture_assert(tctx, result, "str_list_make_empty() must not return NULL");
+ torture_assert(tctx, result[0] == NULL, "first element in str_list_make_empty() result must be NULL");
+
+ result = str_list_make(tctx, NULL, NULL);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ torture_assert(tctx, result[0] == NULL, "first element in str_list_make(ctx, NULL, NULL) result must be NULL");
+
+ result = str_list_make(tctx, "", NULL);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ torture_assert(tctx, result[0] == NULL, "first element in str_list_make(ctx, "", NULL) result must be NULL");
+
+ return true;
+}
+
+static bool test_list_make_single(struct torture_context *tctx)
+{
+ char **result;
+
+ result = str_list_make_single(tctx, "foo");
+
+ torture_assert(tctx, result, "str_list_make_single() must not return NULL");
+ torture_assert_str_equal(tctx, result[0], "foo", "element 0");
+ torture_assert(tctx, result[1] == NULL, "second element in result must be NULL");
+
+ return true;
+}
+
+static bool test_list_copy_const(struct torture_context *tctx)
+{
+ const char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ NULL
+ };
+ result = str_list_copy_const(tctx, list);
+ torture_assert(tctx, result, "str_list_copy() must not return NULL");
+ torture_assert(tctx, str_list_equal(result, list),
+ "str_list_copy() failed");
+
+ return true;
+}
+
+static bool test_list_length(struct torture_context *tctx)
+{
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ NULL
+ };
+ const char *list2[] = {
+ NULL
+ };
+ torture_assert_int_equal(tctx, str_list_length(list), 4,
+ "str_list_length() failed");
+
+ torture_assert_int_equal(tctx, str_list_length(list2), 0,
+ "str_list_length() failed");
+
+ torture_assert_int_equal(tctx, str_list_length(NULL), 0,
+ "str_list_length() failed");
+
+ return true;
+}
+
+static bool test_list_add(struct torture_context *tctx)
+{
+ char **result, **result2;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ NULL
+ };
+ result = str_list_make(tctx, "element_0, element_1, element_2", NULL);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ result2 = str_list_add(result, "element_3");
+ torture_assert(tctx, result2, "str_list_add() must not return NULL");
+ torture_assert(tctx, str_list_equal(result2, list),
+ "str_list_add() failed");
+
+ return true;
+}
+
+static bool test_list_add_const(struct torture_context *tctx)
+{
+ char **result, **result2;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ NULL
+ };
+ result = str_list_make(tctx, "element_0, element_1, element_2", NULL);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ result2 = str_list_add_const(result, "element_3");
+ torture_assert(tctx, result2, "str_list_add_const() must not return NULL");
+ torture_assert(tctx, str_list_equal(result2, list),
+ "str_list_add() failed");
+
+ return true;
+}
+
+static bool test_list_remove(struct torture_context *tctx)
+{
+ char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_3",
+ NULL
+ };
+ result = str_list_make(tctx, "element_0, element_1, element_2, element_3", NULL);
+ torture_assert(tctx, result, "str_list_make() must not return NULL");
+ str_list_remove(result, "element_2");
+ torture_assert(tctx, str_list_equal(result, list),
+ "str_list_remove() failed");
+
+ return true;
+}
+
+static bool test_list_check(struct torture_context *tctx)
+{
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ torture_assert(tctx, str_list_check(list, "element_1"),
+ "str_list_check() failed");
+
+ return true;
+}
+
+static bool test_list_check_ci(struct torture_context *tctx)
+{
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ torture_assert(tctx, str_list_check_ci(list, "ELEMENT_1"),
+ "str_list_check_ci() failed");
+
+ return true;
+}
+
+static bool test_list_unique(struct torture_context *tctx)
+{
+ char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ const char *list_dup[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_0",
+ "element_2",
+ "element_1",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ result = str_list_copy(tctx, list_dup);
+ /* We must copy the list, as str_list_unique does a talloc_realloc() on it's parameter */
+ result = str_list_unique(result);
+ torture_assert(tctx, result, "str_list_unique() must not return NULL");
+
+ torture_assert(tctx, str_list_equal(list, result),
+ "str_list_unique() failed");
+
+ return true;
+}
+
+static bool test_list_unique_2(struct torture_context *tctx)
+{
+ int i;
+ int count, num_dups;
+ const char **result;
+ const char **list = (const char **)str_list_make_empty(tctx);
+ const char **list_dup = (const char **)str_list_make_empty(tctx);
+
+ count = lp_parm_int(tctx->lp_ctx, NULL, "list_unique", "count", 9);
+ num_dups = lp_parm_int(tctx->lp_ctx, NULL, "list_unique", "dups", 7);
+ torture_comment(tctx, "test_list_unique_2() with %d elements and %d dups\n", count, num_dups);
+
+ for (i = 0; i < count; i++) {
+ list = str_list_add_const(list, (const char *)talloc_asprintf(tctx, "element_%03d", i));
+ }
+
+ for (i = 0; i < num_dups; i++) {
+ list_dup = str_list_append(list_dup, list);
+ }
+
+ result = (const char **)str_list_copy(tctx, list_dup);
+ /* We must copy the list, as str_list_unique does a talloc_realloc() on it's parameter */
+ result = str_list_unique(result);
+ torture_assert(tctx, result, "str_list_unique() must not return NULL");
+
+ torture_assert(tctx, str_list_equal(list, result),
+ "str_list_unique() failed");
+
+ return true;
+}
+
+static bool test_list_append(struct torture_context *tctx)
+{
+ char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ const char *list2[] = {
+ "element_3",
+ "element_4",
+ "element_5",
+ NULL
+ };
+ const char *list_combined[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ "element_4",
+ "element_5",
+ NULL
+ };
+ result = str_list_copy(tctx, list);
+ torture_assert(tctx, result, "str_list_copy() must not return NULL");
+ result = str_list_append(result, list2);
+ torture_assert(tctx, result, "str_list_append() must not return NULL");
+ torture_assert(tctx, str_list_equal(list_combined, result),
+ "str_list_unique() failed");
+
+ return true;
+}
+
+static bool test_list_append_const(struct torture_context *tctx)
+{
+ char **result;
+ const char *list[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ NULL
+ };
+ const char *list2[] = {
+ "element_3",
+ "element_4",
+ "element_5",
+ NULL
+ };
+ const char *list_combined[] = {
+ "element_0",
+ "element_1",
+ "element_2",
+ "element_3",
+ "element_4",
+ "element_5",
+ NULL
+ };
+ result = str_list_copy(tctx, list);
+ torture_assert(tctx, result, "str_list_copy() must not return NULL");
+ result = str_list_append_const(result, list2);
+ torture_assert(tctx, result, "str_list_append_const() must not return NULL");
+ torture_assert(tctx, str_list_equal(list_combined, result),
+ "str_list_unique() failed");
+
+ return true;
+}
+
struct torture_suite *torture_local_util_strlist(TALLOC_CTX *mem_ctx)
{
struct torture_suite *suite = torture_suite_create(mem_ctx, "STRLIST");
int i;
- for (i = 0; test_lists_shell_strings[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(test_lists_shell_strings); i++) {
torture_suite_add_simple_tcase_const(suite, "lists_shell",
test_lists_shell, &test_lists_shell_strings[i]);
}
+ for (i = 0; i < ARRAY_SIZE(test_lists_strings); i++) {
+ torture_suite_add_simple_tcase_const(suite, "lists",
+ test_list_make, &test_lists_strings[i]);
+ }
+
torture_suite_add_simple_test(suite, "list_copy", test_list_copy);
+ torture_suite_add_simple_test(suite, "make_empty", test_list_make_empty);
+ torture_suite_add_simple_test(suite, "make_single", test_list_make_single);
+ torture_suite_add_simple_test(suite, "list_copy_const", test_list_copy_const);
+ torture_suite_add_simple_test(suite, "list_length", test_list_length);
+ torture_suite_add_simple_test(suite, "list_add", test_list_add);
+ torture_suite_add_simple_test(suite, "list_add_const", test_list_add_const);
+ torture_suite_add_simple_test(suite, "list_remove", test_list_remove);
+ torture_suite_add_simple_test(suite, "list_check", test_list_check);
+ torture_suite_add_simple_test(suite, "list_check_ci", test_list_check_ci);
+ torture_suite_add_simple_test(suite, "list_unique", test_list_unique);
+ torture_suite_add_simple_test(suite, "list_unique_2", test_list_unique_2);
+ torture_suite_add_simple_test(suite, "list_append", test_list_append);
+ torture_suite_add_simple_test(suite, "list_append_const", test_list_append_const);
return suite;
}
diff --git a/lib/util/tests/time.c b/lib/util/tests/time.c
index b7cb608611..d08a4e79d1 100644
--- a/lib/util/tests/time.c
+++ b/lib/util/tests/time.c
@@ -44,7 +44,17 @@ static bool test_http_timestring(struct torture_context *tctx)
{
const char *start = "Thu, 01 Jan 1970";
char *result;
- result = http_timestring(tctx, 42);
+ /*
+ * Correct test for negative UTC offset. Without the correction, the
+ * test fails when run on hosts with negative UTC offsets, as the date
+ * returned is back in 1969 (pre-epoch).
+ */
+ time_t now = time(NULL);
+ struct tm local = *localtime(&now);
+ struct tm gmt = *gmtime(&now);
+ time_t utc_offset = mktime(&local) - mktime(&gmt);
+
+ result = http_timestring(tctx, 42 - (utc_offset < 0 ? utc_offset : 0));
torture_assert(tctx, !strncmp(start, result,
strlen(start)), result);
torture_assert_str_equal(tctx, "never",
@@ -55,7 +65,18 @@ static bool test_http_timestring(struct torture_context *tctx)
static bool test_timestring(struct torture_context *tctx)
{
const char *start = "Thu Jan 1";
- char *result = timestring(tctx, 42);
+ char *result;
+ /*
+ * Correct test for negative UTC offset. Without the correction, the
+ * test fails when run on hosts with negative UTC offsets, as the date
+ * returned is back in 1969 (pre-epoch).
+ */
+ time_t now = time(NULL);
+ struct tm local = *localtime(&now);
+ struct tm gmt = *gmtime(&now);
+ time_t utc_offset = mktime(&local) - mktime(&gmt);
+
+ result = timestring(tctx, 42 - (utc_offset < 0 ? utc_offset : 0));
torture_assert(tctx, !strncmp(start, result, strlen(start)),
result);
return true;
diff --git a/lib/util/tevent_ntstatus.c b/lib/util/tevent_ntstatus.c
index 6aa576da66..d6cb0affd9 100644
--- a/lib/util/tevent_ntstatus.c
+++ b/lib/util/tevent_ntstatus.c
@@ -49,3 +49,13 @@ bool tevent_req_is_nterror(struct tevent_req *req, NTSTATUS *status)
}
return true;
}
+
+NTSTATUS tevent_req_simple_recv_ntstatus(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
diff --git a/lib/util/tevent_ntstatus.h b/lib/util/tevent_ntstatus.h
index acfb903961..22fe9188d0 100644
--- a/lib/util/tevent_ntstatus.h
+++ b/lib/util/tevent_ntstatus.h
@@ -27,5 +27,6 @@
bool tevent_req_nterror(struct tevent_req *req, NTSTATUS status);
bool tevent_req_is_nterror(struct tevent_req *req, NTSTATUS *pstatus);
+NTSTATUS tevent_req_simple_recv_ntstatus(struct tevent_req *req);
#endif
diff --git a/lib/util/tevent_unix.c b/lib/util/tevent_unix.c
index b89d5cd4d4..0a8c4c6b30 100644
--- a/lib/util/tevent_unix.c
+++ b/lib/util/tevent_unix.c
@@ -3,17 +3,21 @@
Wrap unix errno around tevent_req
Copyright (C) Volker Lendecke 2009
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
+ ** NOTE! The following LGPL license applies to the tevent_unix
+ ** helper library. This does NOT imply that all of Samba is released
+ ** under the LGPL
- This program is distributed in the hope that it will be useful,
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/lib/util/tevent_unix.h b/lib/util/tevent_unix.h
index dc3ffaef33..bc2cea9199 100644
--- a/lib/util/tevent_unix.h
+++ b/lib/util/tevent_unix.h
@@ -3,17 +3,21 @@
Wrap unix errno around tevent_req
Copyright (C) Volker Lendecke 2009
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
+ ** NOTE! The following LGPL license applies to the tevent_unix
+ ** helper library. This does NOT imply that all of Samba is released
+ ** under the LGPL
- This program is distributed in the hope that it will be useful,
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/lib/util/time.m4 b/lib/util/time.m4
index f61ae4cd25..675e20129f 100644
--- a/lib/util/time.m4
+++ b/lib/util/time.m4
@@ -3,7 +3,7 @@ AC_TRY_RUN([
#include <sys/time.h>
#include <unistd.h>
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
- samba_cv_HAVE_GETTIMEOFDAY_TZ=yes,samba_cv_HAVE_GETTIMEOFDAY_TZ=no,samba_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
+ samba_cv_HAVE_GETTIMEOFDAY_TZ=yes,samba_cv_HAVE_GETTIMEOFDAY_TZ=no,samba_cv_HAVE_GETTIMEOFDAY_TZ=yes)])
if test x"$samba_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ,1,[Whether gettimeofday() is available])
fi
diff --git a/lib/util/util.c b/lib/util/util.c
index af682ac15f..d1297a09dd 100644
--- a/lib/util/util.c
+++ b/lib/util/util.c
@@ -133,8 +133,13 @@ _PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid,
umask(old_umask);
return false;
}
- if ((st.st_uid != uid) ||
- ((st.st_mode & 0777) != dir_perms)) {
+ if (st.st_uid != uid && !uwrap_enabled()) {
+ DEBUG(0, ("invalid ownership on directory "
+ "%s\n", dname));
+ umask(old_umask);
+ return false;
+ }
+ if ((st.st_mode & 0777) != dir_perms) {
DEBUG(0, ("invalid permissions on directory "
"%s\n", dname));
umask(old_umask);
@@ -146,37 +151,6 @@ _PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid,
/**
- Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
- else
- if SYSV use O_NDELAY
- if BSD use FNDELAY
-**/
-
-_PUBLIC_ int set_blocking(int fd, bool set)
-{
- int val;
-#ifdef O_NONBLOCK
-#define FLAG_TO_SET O_NONBLOCK
-#else
-#ifdef SYSV
-#define FLAG_TO_SET O_NDELAY
-#else /* BSD */
-#define FLAG_TO_SET FNDELAY
-#endif
-#endif
-
- if((val = fcntl(fd, F_GETFL, 0)) == -1)
- return -1;
- if(set) /* Turn blocking on - ie. clear nonblock flag */
- val &= ~FLAG_TO_SET;
- else
- val |= FLAG_TO_SET;
- return fcntl( fd, F_SETFL, val);
-#undef FLAG_TO_SET
-}
-
-
-/**
Sleep for a specified number of milliseconds.
**/
@@ -296,15 +270,13 @@ static void _dump_data(int level, const uint8_t *buf, int len,
bool omit_zero_bytes)
{
int i=0;
- const uint8_t empty[16];
+ static const uint8_t empty[16] = { 0, };
bool skipped = false;
if (len<=0) return;
if (!DEBUGLVL(level)) return;
- memset(&empty, '\0', 16);
-
for (i=0;i<len;) {
if (i%16 == 0) {
@@ -695,41 +667,6 @@ _PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_
}
/**
- Unescape a URL encoded string, in place.
-**/
-
-_PUBLIC_ void rfc1738_unescape(char *buf)
-{
- char *p=buf;
-
- while (p && *p && (p=strchr(p,'%'))) {
- int c1 = p[1];
- int c2 = p[2];
-
- if (c1 >= '0' && c1 <= '9')
- c1 = c1 - '0';
- else if (c1 >= 'A' && c1 <= 'F')
- c1 = 10 + c1 - 'A';
- else if (c1 >= 'a' && c1 <= 'f')
- c1 = 10 + c1 - 'a';
- else {p++; continue;}
-
- if (c2 >= '0' && c2 <= '9')
- c2 = c2 - '0';
- else if (c2 >= 'A' && c2 <= 'F')
- c2 = 10 + c2 - 'A';
- else if (c2 >= 'a' && c2 <= 'f')
- c2 = 10 + c2 - 'a';
- else {p++; continue;}
-
- *p = (c1<<4) | c2;
-
- memmove(p+1, p+3, strlen(p+3)+1);
- p++;
- }
-}
-
-/**
varient of strcmp() that handles NULL ptrs
**/
_PUBLIC_ int strcmp_safe(const char *s1, const char *s2)
diff --git a/lib/util/util.h b/lib/util/util.h
index defef127d9..159f812d98 100644
--- a/lib/util/util.h
+++ b/lib/util/util.h
@@ -21,8 +21,6 @@
#ifndef _SAMBA_UTIL_H_
#define _SAMBA_UTIL_H_
-#include <netinet/in.h>
-
#if _SAMBA_BUILD_ == 4
#include "../lib/util/charset/charset.h"
#endif
@@ -192,6 +190,16 @@ _PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const c
*/
_PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len);
+/**
+ * Generate an array of unique text strings all of the same length.
+ * The returned strings will be allocated.
+ * Returns NULL if the number of unique combinations cannot be created.
+ *
+ * Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
+ */
+_PUBLIC_ char** generate_unique_strs(TALLOC_CTX *mem_ctx, size_t len,
+ uint32_t num);
+
/* The following definitions come from lib/util/dprintf.c */
#if _SAMBA_BUILD_ == 4
@@ -299,6 +307,31 @@ _PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, siz
**/
_PUBLIC_ void rfc1738_unescape(char *buf);
+
+/**
+ * rfc1738_escape
+ * Returns a static buffer that contains the RFC
+ * 1738 compliant, escaped version of the given url. (escapes unsafe and % characters)
+ **/
+_PUBLIC_ char *rfc1738_escape(TALLOC_CTX *mem_ctx, const char *url);
+
+/**
+ * rfc1738_escape_unescaped
+ *
+ * Returns a static buffer that contains
+ * the RFC 1738 compliant, escaped version of the given url (escapes unsafe chars only)
+ **/
+_PUBLIC_ char *rfc1738_escape_unescaped(TALLOC_CTX *mem_ctx, const char *url);
+
+/**
+ * rfc1738_escape_part
+ * Returns a static buffer that contains the RFC
+ * 1738 compliant, escaped version of the given url segment. (escapes
+ * unsafe, reserved and % chars) It would mangle the :// in http://,
+ * and mangle paths (because of /).
+ **/
+_PUBLIC_ char *rfc1738_escape_part(TALLOC_CTX *mem_ctx, const char *url);
+
/**
format a string into length-prefixed dotted domain format, as used in NBT
and in some ADS structures
@@ -397,18 +430,30 @@ _PUBLIC_ bool strequal(const char *s1, const char *s2);
#endif
/**
+ build an empty (only NULL terminated) list of strings (for expansion with str_list_add() etc)
+*/
+_PUBLIC_ char **str_list_make_empty(TALLOC_CTX *mem_ctx);
+
+/**
+ place the only element 'entry' into a new, NULL terminated string list
+*/
+_PUBLIC_ char **str_list_make_single(TALLOC_CTX *mem_ctx,
+ const char *entry);
+
+/**
build a null terminated list of strings from a input string and a
separator list. The separator list must contain characters less than
or equal to 0x2f for this to work correctly on multi-byte strings
*/
-_PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
+_PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string,
+ const char *sep);
/**
* build a null terminated list of strings from an argv-like input string
* Entries are seperated by spaces and can be enclosed by quotes.
* Does NOT support escaping
*/
-_PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
+_PUBLIC_ char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
/**
* join a list back to one string
@@ -453,6 +498,43 @@ _PUBLIC_ bool str_list_check(const char **list, const char *s);
return true if a string is in a list, case insensitively
*/
_PUBLIC_ bool str_list_check_ci(const char **list, const char *s);
+/**
+ append one list to another - expanding list1
+*/
+_PUBLIC_ const char **str_list_append(const char **list1,
+ const char * const *list2);
+
+/**
+ remove duplicate elements from a list
+*/
+_PUBLIC_ const char **str_list_unique(const char **list);
+
+/*
+ very useful when debugging complex list related code
+ */
+_PUBLIC_ void str_list_show(const char **list);
+
+
+/**
+ append one list to another - expanding list1
+ this assumes the elements of list2 are const pointers, so we can re-use them
+*/
+_PUBLIC_ const char **str_list_append_const(const char **list1,
+ const char **list2);
+
+/**
+ add an entry to a string list
+ this assumes s will not change
+*/
+_PUBLIC_ const char **str_list_add_const(const char **list, const char *s);
+
+/**
+ copy a string list
+ this assumes list will not change
+*/
+_PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
+ const char **list);
+
/* The following definitions come from lib/util/util_file.c */
@@ -771,4 +853,17 @@ bool unmap_file(void *start, size_t size);
void print_asc(int level, const uint8_t *buf,int len);
+/**
+ * Add an id to an array of ids.
+ *
+ * num should be a pointer to an integer that holds the current
+ * number of elements in ids. It will be updated by this function.
+ */
+
+bool add_uid_to_array_unique(TALLOC_CTX *mem_ctx, uid_t uid,
+ uid_t **uids, size_t *num_uids);
+bool add_gid_to_array_unique(TALLOC_CTX *mem_ctx, gid_t gid,
+ gid_t **gids, size_t *num_gids);
+
+
#endif /* _SAMBA_UTIL_H_ */
diff --git a/lib/util/util_file.c b/lib/util/util_file.c
index 0275e78c54..7466004e5c 100644
--- a/lib/util/util_file.c
+++ b/lib/util/util_file.c
@@ -380,6 +380,7 @@ _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length)
return false;
}
if (write(fd, packet, length) != (size_t)length) {
+ close(fd);
return false;
}
close(fd);
diff --git a/lib/util/util_id.c b/lib/util/util_id.c
new file mode 100644
index 0000000000..8744ce4e4e
--- /dev/null
+++ b/lib/util/util_id.c
@@ -0,0 +1,88 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Helper routines for uid and gid arrays
+
+ Copyright (C) Guenther Deschner 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Add a gid to an array of gids if it's not already there.
+****************************************************************************/
+
+bool add_gid_to_array_unique(TALLOC_CTX *mem_ctx, gid_t gid,
+ gid_t **gids, size_t *num_gids)
+{
+ int i;
+
+ if ((*num_gids != 0) && (*gids == NULL)) {
+ /*
+ * A former call to this routine has failed to allocate memory
+ */
+ return false;
+ }
+
+ for (i=0; i<*num_gids; i++) {
+ if ((*gids)[i] == gid) {
+ return true;
+ }
+ }
+
+ *gids = talloc_realloc(mem_ctx, *gids, gid_t, *num_gids+1);
+ if (*gids == NULL) {
+ *num_gids = 0;
+ return false;
+ }
+
+ (*gids)[*num_gids] = gid;
+ *num_gids += 1;
+ return true;
+}
+
+/****************************************************************************
+ Add a uid to an array of uids if it's not already there.
+****************************************************************************/
+
+bool add_uid_to_array_unique(TALLOC_CTX *mem_ctx, uid_t uid,
+ uid_t **uids, size_t *num_uids)
+{
+ int i;
+
+ if ((*num_uids != 0) && (*uids == NULL)) {
+ /*
+ * A former call to this routine has failed to allocate memory
+ */
+ return false;
+ }
+
+ for (i=0; i<*num_uids; i++) {
+ if ((*uids)[i] == uid) {
+ return true;
+ }
+ }
+
+ *uids = talloc_realloc(mem_ctx, *uids, uid_t, *num_uids+1);
+ if (*uids == NULL) {
+ *num_uids = 0;
+ return false;
+ }
+
+ (*uids)[*num_uids] = uid;
+ *num_uids += 1;
+ return true;
+}
diff --git a/lib/util/util_ldb.c b/lib/util/util_ldb.c
index c11b6879d2..ac1e11566e 100644
--- a/lib/util/util_ldb.c
+++ b/lib/util/util_ldb.c
@@ -130,3 +130,99 @@ char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n)
}
+
+/*
+ search the LDB for a single record, with the extended_dn control
+ return LDB_SUCCESS on success, or an ldb error code on error
+
+ if the search returns 0 entries, return LDB_ERR_NO_SUCH_OBJECT
+ if the search returns more than 1 entry, return LDB_ERR_CONSTRAINT_VIOLATION
+*/
+int gendb_search_single_extended_dn(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *basedn,
+ enum ldb_scope scope,
+ struct ldb_message **msg,
+ const char * const *attrs,
+ const char *format, ...)
+{
+ va_list ap;
+ int ret;
+ struct ldb_request *req;
+ char *filter;
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_result *res;
+ struct ldb_extended_dn_control *ctrl;
+
+ tmp_ctx = talloc_new(mem_ctx);
+
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ if (!res) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ va_start(ap, format);
+ filter = talloc_vasprintf(tmp_ctx, format, ap);
+ va_end(ap);
+
+ if (filter == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_search_req(&req, ldb, tmp_ctx,
+ basedn,
+ scope,
+ filter,
+ attrs,
+ NULL,
+ res,
+ ldb_search_default_callback,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ ctrl = talloc(tmp_ctx, struct ldb_extended_dn_control);
+ if (ctrl == NULL) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ctrl->type = 1;
+
+ ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, ctrl);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_request(ldb, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ if (res->count == 0) {
+ talloc_free(tmp_ctx);
+ return LDB_ERR_NO_SUCH_OBJECT;
+ }
+
+ if (res->count > 1) {
+ /* the function is only supposed to return a single entry */
+ DEBUG(0,(__location__ ": More than one return for baseDN %s filter %s\n",
+ ldb_dn_get_linearized(basedn), filter));
+ talloc_free(tmp_ctx);
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ *msg = talloc_steal(mem_ctx, res->msgs[0]);
+
+ talloc_free(tmp_ctx);
+
+ return LDB_SUCCESS;
+}
diff --git a/lib/util/util_ldb.h b/lib/util/util_ldb.h
index f9eb028916..4575c6565a 100644
--- a/lib/util/util_ldb.h
+++ b/lib/util/util_ldb.h
@@ -26,4 +26,12 @@ int gendb_search_dn(struct ldb_context *ldb,
int gendb_add_ldif(struct ldb_context *ldb, const char *ldif_string);
char *wrap_casefold(void *context, void *mem_ctx, const char *s, size_t n);
+int gendb_search_single_extended_dn(struct ldb_context *ldb,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *basedn,
+ enum ldb_scope scope,
+ struct ldb_message **msg,
+ const char * const *attrs,
+ const char *format, ...) PRINTF_ATTRIBUTE(7,8);
+
#endif /* __LIB_UTIL_UTIL_LDB_H__ */
diff --git a/lib/util/util_net.c b/lib/util/util_net.c
index d1dadc2494..0ce495e57c 100644
--- a/lib/util/util_net.c
+++ b/lib/util/util_net.c
@@ -3,10 +3,11 @@
Samba utility functions
Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
Copyright (C) Andrew Tridgell 1992-1998
- Copyright (C) Jeremy Allison 2001-2007
+ Copyright (C) Jeremy Allison 1992-2007
Copyright (C) Simo Sorce 2001
Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
Copyright (C) James J Myers 2003
+ Copyright (C) Tim Potter 2000-2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,6 +29,17 @@
#include "system/filesys.h"
#undef strcasecmp
+/*******************************************************************
+ Set an address to INADDR_ANY.
+******************************************************************/
+
+void zero_sockaddr(struct sockaddr_storage *pss)
+{
+ memset(pss, '\0', sizeof(*pss));
+ /* Ensure we're at least a valid sockaddr-storage. */
+ pss->ss_family = AF_INET;
+}
+
/**
* Wrap getaddrinfo...
*/
@@ -59,6 +71,110 @@ bool interpret_string_addr_internal(struct addrinfo **ppres,
return true;
}
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Takes a flag which allows it to
+ prefer an IPv4 address (needed for DC's).
+******************************************************************/
+
+static bool interpret_string_addr_pref(struct sockaddr_storage *pss,
+ const char *str,
+ int flags,
+ bool prefer_ipv4)
+{
+ struct addrinfo *res = NULL;
+#if defined(HAVE_IPV6)
+ char addr[INET6_ADDRSTRLEN];
+ unsigned int scope_id = 0;
+
+ if (strchr_m(str, ':')) {
+ char *p = strchr_m(str, '%');
+
+ /*
+ * Cope with link-local.
+ * This is IP:v6:addr%ifname.
+ */
+
+ if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) {
+ strlcpy(addr, str,
+ MIN(PTR_DIFF(p,str)+1,
+ sizeof(addr)));
+ str = addr;
+ }
+ }
+#endif
+
+ zero_sockaddr(pss);
+
+ if (!interpret_string_addr_internal(&res, str, flags|AI_ADDRCONFIG)) {
+ return false;
+ }
+ if (!res) {
+ return false;
+ }
+
+ if (prefer_ipv4) {
+ struct addrinfo *p;
+
+ for (p = res; p; p = p->ai_next) {
+ if (p->ai_family == AF_INET) {
+ memcpy(pss, p->ai_addr, p->ai_addrlen);
+ break;
+ }
+ }
+ if (p == NULL) {
+ /* Copy the first sockaddr. */
+ memcpy(pss, res->ai_addr, res->ai_addrlen);
+ }
+ } else {
+ /* Copy the first sockaddr. */
+ memcpy(pss, res->ai_addr, res->ai_addrlen);
+ }
+
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6 && scope_id) {
+ struct sockaddr_in6 *ps6 = (struct sockaddr_in6 *)pss;
+ if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) &&
+ ps6->sin6_scope_id == 0) {
+ ps6->sin6_scope_id = scope_id;
+ }
+ }
+#endif
+
+ freeaddrinfo(res);
+ return true;
+}
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Address agnostic version.
+******************************************************************/
+
+bool interpret_string_addr(struct sockaddr_storage *pss,
+ const char *str,
+ int flags)
+{
+ return interpret_string_addr_pref(pss,
+ str,
+ flags,
+ false);
+}
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Version that prefers IPv4.
+******************************************************************/
+
+bool interpret_string_addr_prefer_ipv4(struct sockaddr_storage *pss,
+ const char *str,
+ int flags)
+{
+ return interpret_string_addr_pref(pss,
+ str,
+ flags,
+ true);
+}
+
/**
* Interpret an internet address or name into an IP address in 4 byte form.
* RETURNS IN NETWORK BYTE ORDER (big endian).
diff --git a/lib/util/util_net.h b/lib/util/util_net.h
new file mode 100644
index 0000000000..6eacfc395f
--- /dev/null
+++ b/lib/util/util_net.h
@@ -0,0 +1,46 @@
+/*
+ Unix SMB/CIFS implementation.
+ Utility functions for Samba
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SAMBA_UTIL_NET_H_
+#define _SAMBA_UTIL_NET_H_
+
+#include "system/network.h"
+
+/* The following definitions come from lib/util/util_net.c */
+
+void zero_sockaddr(struct sockaddr_storage *pss);
+
+bool interpret_string_addr_internal(struct addrinfo **ppres,
+ const char *str, int flags);
+
+bool interpret_string_addr(struct sockaddr_storage *pss,
+ const char *str,
+ int flags);
+
+/*******************************************************************
+ Map a text hostname or IP address (IPv4 or IPv6) into a
+ struct sockaddr_storage. Version that prefers IPv4.
+******************************************************************/
+
+bool interpret_string_addr_prefer_ipv4(struct sockaddr_storage *pss,
+ const char *str,
+ int flags);
+
+#endif /* _SAMBA_UTIL_NET_H_ */
diff --git a/lib/util/util_strlist.c b/lib/util/util_strlist.c
index b069a11e38..8d69eef233 100644
--- a/lib/util/util_strlist.c
+++ b/lib/util/util_strlist.c
@@ -29,6 +29,45 @@
*/
/**
+ build an empty (only NULL terminated) list of strings (for expansion with str_list_add() etc)
+*/
+_PUBLIC_ char **str_list_make_empty(TALLOC_CTX *mem_ctx)
+{
+ char **ret = NULL;
+
+ ret = talloc_array(mem_ctx, char *, 1);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ ret[0] = NULL;
+
+ return ret;
+}
+
+/**
+ place the only element 'entry' into a new, NULL terminated string list
+*/
+_PUBLIC_ char **str_list_make_single(TALLOC_CTX *mem_ctx, const char *entry)
+{
+ char **ret = NULL;
+
+ ret = talloc_array(mem_ctx, char *, 2);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ ret[0] = talloc_strdup(ret, entry);
+ if (!ret[0]) {
+ talloc_free(ret);
+ return NULL;
+ }
+ ret[1] = NULL;
+
+ return ret;
+}
+
+/**
build a null terminated list of strings from a input string and a
separator list. The separator list must contain characters less than
or equal to 0x2f for this to work correctly on multi-byte strings
@@ -56,7 +95,8 @@ _PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const cha
continue;
}
- ret2 = talloc_realloc(mem_ctx, ret, char *, num_elements+2);
+ ret2 = talloc_realloc(mem_ctx, ret, char *,
+ num_elements+2);
if (ret2 == NULL) {
talloc_free(ret);
return NULL;
@@ -83,12 +123,12 @@ _PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const cha
* Entries are seperated by spaces and can be enclosed by quotes.
* Does NOT support escaping
*/
-_PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
+_PUBLIC_ char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
{
int num_elements = 0;
- const char **ret = NULL;
+ char **ret = NULL;
- ret = talloc_array(mem_ctx, const char *, 1);
+ ret = talloc_array(mem_ctx, char *, 1);
if (ret == NULL) {
return NULL;
}
@@ -99,7 +139,7 @@ _PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *strin
while (string && *string) {
size_t len = strcspn(string, sep);
char *element;
- const char **ret2;
+ char **ret2;
if (len == 0) {
string += strspn(string, sep);
@@ -121,7 +161,7 @@ _PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *strin
return NULL;
}
- ret2 = talloc_realloc(mem_ctx, ret, const char *, num_elements+2);
+ ret2 = talloc_realloc(mem_ctx, ret, char *, num_elements+2);
if (ret2 == NULL) {
talloc_free(ret);
return NULL;
@@ -187,7 +227,7 @@ _PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char
/**
return the number of elements in a string list
*/
-_PUBLIC_ size_t str_list_length(const char * const*list)
+_PUBLIC_ size_t str_list_length(const char * const *list)
{
size_t ret;
for (ret=0;list && list[ret];ret++) /* noop */ ;
@@ -308,3 +348,140 @@ _PUBLIC_ bool str_list_check_ci(const char **list, const char *s)
}
+/**
+ append one list to another - expanding list1
+*/
+_PUBLIC_ const char **str_list_append(const char **list1,
+ const char * const *list2)
+{
+ size_t len1 = str_list_length(list1);
+ size_t len2 = str_list_length(list2);
+ const char **ret;
+ int i;
+
+ ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
+ if (ret == NULL) return NULL;
+
+ for (i=len1;i<len1+len2;i++) {
+ ret[i] = talloc_strdup(ret, list2[i-len1]);
+ if (ret[i] == NULL) {
+ return NULL;
+ }
+ }
+ ret[i] = NULL;
+
+ return ret;
+}
+
+static int list_cmp(const char **el1, const char **el2)
+{
+ return strcmp(*el1, *el2);
+}
+
+/*
+ return a list that only contains the unique elements of a list,
+ removing any duplicates
+ */
+_PUBLIC_ const char **str_list_unique(const char **list)
+{
+ size_t len = str_list_length(list);
+ const char **list2;
+ int i, j;
+ if (len < 2) {
+ return list;
+ }
+ list2 = (const char **)talloc_memdup(list, list,
+ sizeof(list[0])*(len+1));
+ qsort(list2, len, sizeof(list2[0]), QSORT_CAST list_cmp);
+ list[0] = list2[0];
+ for (i=j=1;i<len;i++) {
+ if (strcmp(list2[i], list[j-1]) != 0) {
+ list[j] = list2[i];
+ j++;
+ }
+ }
+ list[j] = NULL;
+ list = talloc_realloc(NULL, list, const char *, j + 1);
+ talloc_free(list2);
+ return list;
+}
+
+/*
+ very useful when debugging complex list related code
+ */
+_PUBLIC_ void str_list_show(const char **list)
+{
+ int i;
+ DEBUG(0,("{ "));
+ for (i=0;list && list[i];i++) {
+ DEBUG(0,("\"%s\", ", list[i]));
+ }
+ DEBUG(0,("}\n"));
+}
+
+
+
+/**
+ append one list to another - expanding list1
+ this assumes the elements of list2 are const pointers, so we can re-use them
+*/
+_PUBLIC_ const char **str_list_append_const(const char **list1,
+ const char **list2)
+{
+ size_t len1 = str_list_length(list1);
+ size_t len2 = str_list_length(list2);
+ const char **ret;
+ int i;
+
+ ret = talloc_realloc(NULL, list1, const char *, len1+len2+1);
+ if (ret == NULL) return NULL;
+
+ for (i=len1;i<len1+len2;i++) {
+ ret[i] = list2[i-len1];
+ }
+ ret[i] = NULL;
+
+ return ret;
+}
+
+/**
+ add an entry to a string list
+ this assumes s will not change
+*/
+_PUBLIC_ const char **str_list_add_const(const char **list, const char *s)
+{
+ size_t len = str_list_length(list);
+ const char **ret;
+
+ ret = talloc_realloc(NULL, list, const char *, len+2);
+ if (ret == NULL) return NULL;
+
+ ret[len] = s;
+ ret[len+1] = NULL;
+
+ return ret;
+}
+
+/**
+ copy a string list
+ this assumes list will not change
+*/
+_PUBLIC_ const char **str_list_copy_const(TALLOC_CTX *mem_ctx,
+ const char **list)
+{
+ int i;
+ const char **ret;
+
+ if (list == NULL)
+ return NULL;
+
+ ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
+ if (ret == NULL)
+ return NULL;
+
+ for (i=0;list && list[i];i++) {
+ ret[i] = list[i];
+ }
+ ret[i] = NULL;
+ return ret;
+}
diff --git a/lib/util/util_tdb.c b/lib/util/util_tdb.c
index e107cbdc4a..cda8dc75b2 100644
--- a/lib/util/util_tdb.c
+++ b/lib/util/util_tdb.c
@@ -20,7 +20,7 @@
*/
#include "includes.h"
-#include "../tdb/include/tdb.h"
+#include "tdb.h"
#include "../lib/util/util_tdb.h"
/* these are little tdb utility functions that are meant to make