Copyright (C) Andrew Tridgell 1992-2001
Copyright (C) Simo Sorce 2001-2002
Copyright (C) Martin Pool 2003
+ Copyright (C) James Peach 2006
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
+ 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,
**/
/**
- * Get the next token from a string, return False if none found.
- * Handles double-quotes.
- *
+ * Internal function to get the next token from a string, return False if none
+ * found. Handles double-quotes. This is the work horse function called by
+ * next_token() and next_token_no_ltrim().
+ *
* Based on a routine by GJC@VILLAGE.COM.
* Extensively modified by Andrew.Tridgell@anu.edu.au
- **/
-BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
+ */
+static BOOL next_token_internal(const char **ptr,
+ char *buff,
+ const char *sep,
+ size_t bufsize,
+ BOOL ltrim)
{
char *s;
char *pbuf;
if (!sep)
sep = " \t\n\r";
- /* find the first non sep char */
- while (*s && strchr_m(sep,*s))
- s++;
+ /* find the first non sep char, if left-trimming is requested */
+ if (ltrim) {
+ while (*s && strchr_m(sep,*s))
+ s++;
+ }
/* nothing left? */
if (! *s)
return(True);
}
+/*
+ * Get the next token from a string, return False if none found. Handles
+ * double-quotes. This version trims leading separator characters before
+ * looking for a token.
+ */
+BOOL next_token(const char **ptr, char *buff, const char *sep, size_t bufsize)
+{
+ return next_token_internal(ptr, buff, sep, bufsize, True);
+}
+
+/*
+ * Get the next token from a string, return False if none found. Handles
+ * double-quotes. This version does not trim leading separator characters
+ * before looking for a token.
+ */
+BOOL next_token_no_ltrim(const char **ptr,
+ char *buff,
+ const char *sep,
+ size_t bufsize)
+{
+ return next_token_internal(ptr, buff, sep, bufsize, False);
+}
+
/**
This is like next_token but is not re-entrant and "remembers" the first
parameter so you can pass NULL. This is useful for user interface code
return ret;
}
-static uint16 tmpbuf[sizeof(pstring)];
-
void set_first_token(char *ptr)
{
last_ptr = ptr;
NOTE: oldc and newc must be 7 bit characters
**/
-void string_replace( pstring s, char oldc, char newc )
+void string_replace( char *s, char oldc, char newc )
{
char *p;
+ smb_ucs2_t *tmp;
+ size_t src_len, len;
/* this is quite a common operation, so we want it to be
fast. We optimise for the ascii case, knowing that all our
/* With compose characters we must restart from the beginning. JRA. */
p = s;
#endif
- push_ucs2(NULL, tmpbuf, p, sizeof(tmpbuf), STR_TERMINATE);
- string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc));
- pull_ucs2(NULL, p, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);
+ src_len = strlen(p);
+ len = push_ucs2_allocate(&tmp, p);
+ if (len == -1) {
+ return;
+ }
+ string_replace_w(tmp, UCS2_CHAR(oldc), UCS2_CHAR(newc));
+ pull_ucs2(NULL, p, tmp, src_len+1, -1, STR_TERMINATE);
+ SAFE_FREE(tmp);
}
/**
- Skip past some strings in a buffer.
-**/
+ * Skip past some strings in a buffer - old version - no checks.
+ * **/
-char *skip_string(char *buf,size_t n)
+char *push_skip_string(char *buf)
{
- while (n--)
- buf += strlen(buf) + 1;
+ buf += strlen(buf) + 1;
return(buf);
}
+/**
+ Skip past a string in a buffer. Buffer may not be
+ null terminated. end_ptr points to the first byte after
+ then end of the buffer.
+**/
+
+char *skip_string(const char *base, size_t len, char *buf)
+{
+ const char *end_ptr = base + len;
+
+ if (end_ptr < base || !base || !buf || buf >= end_ptr) {
+ return NULL;
+ }
+
+ /* Skip the string */
+ while (*buf) {
+ buf++;
+ if (buf >= end_ptr) {
+ return NULL;
+ }
+ }
+ /* Skip the '\0' */
+ buf++;
+ return buf;
+}
+
/**
Count the number of characters in a string. Normally this will
be the same as the number of bytes in a string for single byte strings,
BOOL strhasupper(const char *s)
{
- smb_ucs2_t *ptr;
- push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
- for(ptr=tmpbuf;*ptr;ptr++)
- if(isupper_w(*ptr))
- return True;
- return(False);
+ smb_ucs2_t *tmp, *p;
+ BOOL ret;
+
+ if (push_ucs2_allocate(&tmp, s) == -1) {
+ return False;
+ }
+
+ for(p = tmp; *p != 0; p++) {
+ if(isupper_w(*p)) {
+ break;
+ }
+ }
+
+ ret = (*p != 0);
+ SAFE_FREE(tmp);
+ return ret;
}
/**
BOOL strhaslower(const char *s)
{
- smb_ucs2_t *ptr;
- push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE);
- for(ptr=tmpbuf;*ptr;ptr++)
- if(islower_w(*ptr))
- return True;
- return(False);
+ smb_ucs2_t *tmp, *p;
+ BOOL ret;
+
+ if (push_ucs2_allocate(&tmp, s) == -1) {
+ return False;
+ }
+
+ for(p = tmp; *p != 0; p++) {
+ if(islower_w(*p)) {
+ break;
+ }
+ }
+
+ ret = (*p != 0);
+ SAFE_FREE(tmp);
+ return ret;
}
/**
}
/* this is used to prevent lots of mallocs of size 1 */
-static char *null_string = NULL;
+static const char *null_string = "";
/**
Set a string value, allocing the space for the string
static BOOL string_init(char **dest,const char *src)
{
size_t l;
+
if (!src)
src = "";
l = strlen(src);
if (l == 0) {
- if (!null_string) {
- if((null_string = (char *)SMB_MALLOC(1)) == NULL) {
- DEBUG(0,("string_init: malloc fail for null_string.\n"));
- return False;
- }
- *null_string = 0;
- }
- *dest = null_string;
+ *dest = CONST_DISCARD(char*, null_string);
} else {
(*dest) = SMB_STRDUP(src);
if ((*dest) == NULL) {
**/
void string_sub2(char *s,const char *pattern, const char *insert, size_t len,
- BOOL remove_unsafe_characters, BOOL replace_once)
+ BOOL remove_unsafe_characters, BOOL replace_once, BOOL allow_trailing_dollar)
{
char *p;
ssize_t ls,lp,li, i;
case '\'':
case ';':
case '$':
+ /* allow a trailing $ (as in machine accounts) */
+ if (allow_trailing_dollar && (i == li - 1 )) {
+ p[i] = insert[i];
+ break;
+ }
case '%':
case '\r':
case '\n':
void string_sub_once(char *s, const char *pattern, const char *insert, size_t len)
{
- string_sub2( s, pattern, insert, len, True, True );
+ string_sub2( s, pattern, insert, len, True, True, False );
}
void string_sub(char *s,const char *pattern, const char *insert, size_t len)
{
- string_sub2( s, pattern, insert, len, True, False );
+ string_sub2( s, pattern, insert, len, True, False, False );
}
void fstring_sub(char *s,const char *pattern,const char *insert)
while ((p = strstr_m(s,pattern))) {
if (ld > 0) {
int offset = PTR_DIFF(s,string);
- char *t = SMB_REALLOC(string, ls + ld + 1);
- if (!t) {
+ string = (char *)SMB_REALLOC(string, ls + ld + 1);
+ if (!string) {
DEBUG(0, ("realloc_string_sub: out of memory!\n"));
SAFE_FREE(in);
return NULL;
}
- string = t;
- p = t + offset + (p - s);
+ p = string + offset + (p - s);
}
if (li != lp) {
memmove(p+li,p+lp,strlen(p+lp)+1);
while ((p = strstr_m(s,pattern))) {
if (ld > 0) {
int offset = PTR_DIFF(s,string);
- char *t = TALLOC_REALLOC(mem_ctx, string, ls + ld + 1);
- if (!t) {
+ string = (char *)TALLOC_REALLOC(mem_ctx, string,
+ ls + ld + 1);
+ if (!string) {
DEBUG(0, ("talloc_string_sub: out of "
"memory!\n"));
SAFE_FREE(in);
return NULL;
}
- string = t;
- p = t + offset + (p - s);
+ p = string + offset + (p - s);
}
if (li != lp) {
memmove(p+li,p+lp,strlen(p+lp)+1);
errno = errno_save;
}
+/**
+ Count the number of UCS2 characters in a string. Normally this will
+ be the same as the number of bytes in a string for single byte strings,
+ but will be different for multibyte.
+**/
+
+size_t strlen_m(const char *s)
+{
+ size_t count = 0;
+
+ if (!s) {
+ return 0;
+ }
+
+ while (*s && !(((uint8_t)*s) & 0x80)) {
+ s++;
+ count++;
+ }
+
+ if (!*s) {
+ return count;
+ }
+
+ while (*s) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(s, &c_size);
+ if (c < 0x10000) {
+ /* Unicode char fits into 16 bits. */
+ count += 1;
+ } else {
+ /* Double-width unicode char - 32 bits. */
+ count += 2;
+ }
+ s += c_size;
+ }
+
+ return count;
+}
+
+/**
+ Count the number of UCS2 characters in a string including the null
+ terminator.
+**/
+
+size_t strlen_m_term(const char *s)
+{
+ if (!s) {
+ return 0;
+ }
+ return strlen_m(s) + 1;
+}
+
+/*
+ * Weird helper routine for the winreg pipe: If nothing is around, return 0,
+ * if a string is there, include the terminator.
+ */
+
+size_t strlen_m_term_null(const char *s)
+{
+ size_t len;
+ if (!s) {
+ return 0;
+ }
+ len = strlen_m(s);
+ if (len == 0) {
+ return 0;
+ }
+
+ return len+1;
+}
/**
Return a RFC2254 binary string representation of a buffer.
Used in LDAP filters.
Caller must free.
**/
-char *binary_string(char *buf, int len)
+char *binary_string_rfc2254(char *buf, int len)
{
char *s;
int i, j;
const char *hex = "0123456789ABCDEF";
- s = SMB_MALLOC(len * 3 + 1);
+ s = (char *)SMB_MALLOC(len * 3 + 1);
if (!s)
return NULL;
for (j=i=0;i<len;i++) {
return s;
}
+char *binary_string(char *buf, int len)
+{
+ char *s;
+ int i, j;
+ const char *hex = "0123456789ABCDEF";
+ s = (char *)SMB_MALLOC(len * 2 + 1);
+ if (!s)
+ return NULL;
+ for (j=i=0;i<len;i++) {
+ s[j] = hex[((unsigned char)buf[i]) >> 4];
+ s[j+1] = hex[((unsigned char)buf[i]) & 0xF];
+ j += 2;
+ }
+ s[j] = 0;
+ return s;
+}
/**
Just a typesafety wrapper for snprintf into a pstring.
**/
return ret;
}
-
-#if !defined(HAVE_STRNDUP) || defined(BROKEN_STRNDUP)
-/**
- Some platforms don't have strndup.
-**/
-#if defined(PARANOID_MALLOC_CHECKER)
-#undef strndup
-#endif
-
- char *strndup(const char *s, size_t n)
-{
- char *ret;
-
- n = strnlen(s, n);
- ret = SMB_MALLOC(n+1);
- if (!ret)
- return NULL;
- memcpy(ret, s, n);
- ret[n] = 0;
-
- return ret;
-}
-
-#if defined(PARANOID_MALLOC_CHECKER)
-#define strndup(s,n) __ERROR_DONT_USE_STRNDUP_DIRECTLY
-#endif
-
-#endif
-
-#if !defined(HAVE_STRNLEN) || defined(BROKEN_STRNLEN)
-/**
- Some platforms don't have strnlen
-**/
-
- size_t strnlen(const char *s, size_t n)
-{
- size_t i;
- for (i=0; i<n && s[i] != '\0'; i++)
- /* noop */ ;
- return i;
-}
-#endif
-
/**
List of Strings manipulation functions
**/
if (mem_ctx) {
rlist = TALLOC_REALLOC_ARRAY(mem_ctx, list, char *, lsize +1);
} else {
- rlist = SMB_REALLOC_ARRAY(list, char *, lsize +1);
+ /* We need to keep the old list on error so we can free the elements
+ if the realloc fails. */
+ rlist = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR(list, char *, lsize +1);
}
if (!rlist) {
DEBUG(0,("str_list_make: Unable to allocate memory"));
SAFE_FREE(s);
}
return NULL;
- } else
+ } else {
list = rlist;
+ }
memset (&list[num], 0, ((sizeof(char**)) * (S_LIST_ABS +1)));
}
while (src[num]) {
if (num == lsize) {
lsize += S_LIST_ABS;
- rlist = SMB_REALLOC_ARRAY(list, char *, lsize +1);
+ rlist = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR(list, char *, lsize +1);
if (!rlist) {
DEBUG(0,("str_list_copy: Unable to re-allocate memory"));
str_list_free(&list);
return False;
- } else
+ } else {
list = rlist;
+ }
memset (&list[num], 0, ((sizeof(char **)) * (S_LIST_ABS +1)));
}
for the work
*****************************************************************************/
-BOOL str_list_sub_basic( char **list, const char *smb_name )
+BOOL str_list_sub_basic( char **list, const char *smb_name,
+ const char *domain_name )
{
char *s, *tmpstr;
while ( *list ) {
s = *list;
- tmpstr = alloc_sub_basic(smb_name, s);
+ tmpstr = alloc_sub_basic(smb_name, domain_name, s);
if ( !tmpstr ) {
DEBUG(0,("str_list_sub_basic: alloc_sub_basic() return NULL!\n"));
return False;
int i;
/* arguments checking */
- if (!ip_list && !ipstr_list) return 0;
+ if (!ip_list || !ipstr_list) return 0;
*ipstr_list = NULL;
out_cnt = 0;
len = data.length;
output_len = data.length * 2;
- result = SMB_MALLOC(output_len); /* get us plenty of space */
+ result = (char *)SMB_MALLOC(output_len); /* get us plenty of space */
while (len-- && out_cnt < (data.length * 2) - 5) {
int c = (unsigned char) *(data.data++);
SMB_BIG_UINT val = -1;
const char *p = nptr;
- while (p && *p && isspace(*p))
+ if (!p) {
+ if (entptr) {
+ *entptr = p;
+ }
+ return val;
+ }
+
+ while (*p && isspace(*p))
p++;
+
#ifdef LARGE_SMB_OFF_T
sscanf(p,"%llu",&val);
#else /* LARGE_SMB_OFF_T */
sscanf(p,"%lu",&val);
#endif /* LARGE_SMB_OFF_T */
if (entptr) {
- while (p && *p && isdigit(*p))
+ while (*p && isdigit(*p))
p++;
*entptr = p;
}
return val;
}
+/* Convert a size specification to a count of bytes. We accept the following
+ * suffixes:
+ * bytes if there is no suffix
+ * kK kibibytes
+ * mM mebibytes
+ * gG gibibytes
+ * tT tibibytes
+ * pP whatever the ISO name for petabytes is
+ *
+ * Returns 0 if the string can't be converted.
+ */
+SMB_OFF_T conv_str_size(const char * str)
+{
+ SMB_OFF_T lval;
+ char * end;
+
+ if (str == NULL || *str == '\0') {
+ return 0;
+ }
+
+#ifdef HAVE_STRTOULL
+ if (sizeof(SMB_OFF_T) == 8) {
+ lval = strtoull(str, &end, 10 /* base */);
+ } else {
+ lval = strtoul(str, &end, 10 /* base */);
+ }
+#else
+ lval = strtoul(str, &end, 10 /* base */);
+#endif
+
+ if (end == NULL || end == str) {
+ return 0;
+ }
+
+ if (*end) {
+ SMB_OFF_T lval_orig = lval;
+
+ if (strwicmp(end, "K") == 0) {
+ lval *= (SMB_OFF_T)1024;
+ } else if (strwicmp(end, "M") == 0) {
+ lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024);
+ } else if (strwicmp(end, "G") == 0) {
+ lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024 *
+ (SMB_OFF_T)1024);
+ } else if (strwicmp(end, "T") == 0) {
+ lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024 *
+ (SMB_OFF_T)1024 * (SMB_OFF_T)1024);
+ } else if (strwicmp(end, "P") == 0) {
+ lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024 *
+ (SMB_OFF_T)1024 * (SMB_OFF_T)1024 *
+ (SMB_OFF_T)1024);
+ } else {
+ return 0;
+ }
+
+ /* Primitive attempt to detect wrapping on platforms with
+ * 4-byte SMB_OFF_T. It's better to let the caller handle
+ * a failure than some random number.
+ */
+ if (lval_orig <= lval) {
+ return 0;
+ }
+ }
+
+ return lval;
+}
+
void string_append(char **left, const char *right)
{
int new_len = strlen(right) + 1;
if (*left == NULL) {
- *left = SMB_MALLOC(new_len);
+ *left = (char *)SMB_MALLOC(new_len);
*left[0] = '\0';
} else {
new_len += strlen(*left);
- *left = SMB_REALLOC(*left, new_len);
+ *left = (char *)SMB_REALLOC(*left, new_len);
}
- if (*left == NULL)
+ if (*left == NULL) {
return;
+ }
safe_strcat(*left, right, new_len-1);
}
*strings = TALLOC_REALLOC_ARRAY(mem_ctx, *strings, const char *, (*num)+1);
- if ((*strings == NULL) || (dup_str == NULL))
+ if ((*strings == NULL) || (dup_str == NULL)) {
+ *num = 0;
return False;
+ }
(*strings)[*num] = dup_str;
*num += 1;
if (*bufsize == 0)
*bufsize = 128;
- if (mem_ctx != NULL)
- *string = TALLOC_ARRAY(mem_ctx, char, *bufsize);
- else
- *string = SMB_MALLOC_ARRAY(char, *bufsize);
-
+ *string = TALLOC_ARRAY(mem_ctx, char, *bufsize);
if (*string == NULL)
goto error;
}
}
if (increased) {
- if (mem_ctx != NULL)
- *string = TALLOC_REALLOC_ARRAY(mem_ctx, *string, char,
- *bufsize);
- else
- *string = SMB_REALLOC_ARRAY(*string, char, *bufsize);
-
- if (*string == NULL)
+ *string = TALLOC_REALLOC_ARRAY(mem_ctx, *string, char,
+ *bufsize);
+ if (*string == NULL) {
goto error;
+ }
}
StrnCpy((*string)+(*len), newstr, ret);
return True;
}
+
+/**
+return the number of bytes occupied by a buffer in ASCII format
+the result includes the null termination
+limited by 'n' bytes
+**/
+size_t ascii_len_n(const char *src, size_t n)
+{
+ size_t len;
+
+ len = strnlen(src, n);
+ if (len+1 <= n) {
+ len += 1;
+ }
+
+ return len;
+}
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+**/
+size_t utf16_len(const void *buf)
+{
+ size_t len;
+
+ for (len = 0; SVAL(buf,len); len += 2) ;
+
+ return len + 2;
+}
+
+/**
+return the number of bytes occupied by a buffer in CH_UTF16 format
+the result includes the null termination
+limited by 'n' bytes
+**/
+size_t utf16_len_n(const void *src, size_t n)
+{
+ size_t len;
+
+ for (len = 0; (len+2 < n) && SVAL(src, len); len += 2) ;
+
+ if (len+2 <= n) {
+ len += 2;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ Add a shell escape character '\' to any character not in a known list
+ of characters. UNIX charset format.
+*******************************************************************/
+
+#define INCLUDE_LIST "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_/ \t.,"
+#define INSIDE_DQUOTE_LIST "$`\n\"\\"
+
+char *escape_shell_string(const char *src)
+{
+ size_t srclen = strlen(src);
+ char *ret = SMB_MALLOC_ARRAY(char, (srclen * 2) + 1);
+ char *dest = ret;
+ BOOL in_s_quote = False;
+ BOOL in_d_quote = False;
+ BOOL next_escaped = False;
+
+ if (!ret) {
+ return NULL;
+ }
+
+ while (*src) {
+ size_t c_size;
+ codepoint_t c = next_codepoint(src, &c_size);
+
+ if (c == INVALID_CODEPOINT) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+
+ if (c_size > 1) {
+ memcpy(dest, src, c_size);
+ src += c_size;
+ dest += c_size;
+ next_escaped = False;
+ continue;
+ }
+
+ /*
+ * Deal with backslash escaped state.
+ * This only lasts for one character.
+ */
+
+ if (next_escaped) {
+ *dest++ = *src++;
+ next_escaped = False;
+ continue;
+ }
+
+ /*
+ * Deal with single quote state. The
+ * only thing we care about is exiting
+ * this state.
+ */
+
+ if (in_s_quote) {
+ if (*src == '\'') {
+ in_s_quote = False;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * Deal with double quote state. The most
+ * complex state. We must cope with \, meaning
+ * possibly escape next char (depending what it
+ * is), ", meaning exit this state, and possibly
+ * add an \ escape to any unprotected character
+ * (listed in INSIDE_DQUOTE_LIST).
+ */
+
+ if (in_d_quote) {
+ if (*src == '\\') {
+ /*
+ * Next character might be escaped.
+ * We have to peek. Inside double
+ * quotes only INSIDE_DQUOTE_LIST
+ * characters are escaped by a \.
+ */
+
+ char nextchar;
+
+ c = next_codepoint(&src[1], &c_size);
+ if (c == INVALID_CODEPOINT) {
+ SAFE_FREE(ret);
+ return NULL;
+ }
+ if (c_size > 1) {
+ /*
+ * Don't escape the next char.
+ * Just copy the \.
+ */
+ *dest++ = *src++;
+ continue;
+ }
+
+ nextchar = src[1];
+
+ if (nextchar && strchr(INSIDE_DQUOTE_LIST, (int)nextchar)) {
+ next_escaped = True;
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\"') {
+ /* Exit double quote state. */
+ in_d_quote = False;
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * We know the character isn't \ or ",
+ * so escape it if it's any of the other
+ * possible unprotected characters.
+ */
+
+ if (strchr(INSIDE_DQUOTE_LIST, (int)*src)) {
+ *dest++ = '\\';
+ }
+ *dest++ = *src++;
+ continue;
+ }
+
+ /*
+ * From here to the end of the loop we're
+ * not in the single or double quote state.
+ */
+
+ if (*src == '\\') {
+ /* Next character must be escaped. */
+ next_escaped = True;
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\'') {
+ /* Go into single quote state. */
+ in_s_quote = True;
+ *dest++ = *src++;
+ continue;
+ }
+
+ if (*src == '\"') {
+ /* Go into double quote state. */
+ in_d_quote = True;
+ *dest++ = *src++;
+ continue;
+ }
+
+ /* Check if we need to escape the character. */
+
+ if (!strchr(INCLUDE_LIST, (int)*src)) {
+ *dest++ = '\\';
+ }
+ *dest++ = *src++;
+ }
+ *dest++ = '\0';
+ return ret;
+}