diff options
author | bubulle <bubulle@alioth.debian.org> | 2010-04-04 16:44:16 +0000 |
---|---|---|
committer | bubulle <bubulle@alioth.debian.org> | 2010-04-04 16:44:16 +0000 |
commit | 9e2f5a6ab663f7a111832217c527508c75ddae8a (patch) | |
tree | 2e74616febbb3fb658ce2dcc5f9cff00ad4fdb4a /lib/util | |
parent | b5556af8f75a4f74db404dd43ee7abafa2be6ca4 (diff) | |
download | samba-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')
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 |