diff options
Diffstat (limited to 'source3/lib/util_str.c')
-rw-r--r-- | source3/lib/util_str.c | 1524 |
1 files changed, 146 insertions, 1378 deletions
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c index 470152814e..aa77d75ad3 100644 --- a/source3/lib/util_str.c +++ b/source3/lib/util_str.c @@ -23,6 +23,7 @@ */ #include "includes.h" +#include "lib/param/loadparm.h" const char toupper_ascii_fast_table[128] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, @@ -36,164 +37,6 @@ const char toupper_ascii_fast_table[128] = { }; /** - * Case insensitive string compararison. - * - * iconv does not directly give us a way to compare strings in - * arbitrary unix character sets -- all we can is convert and then - * compare. This is expensive. - * - * As an optimization, we do a first pass that considers only the - * prefix of the strings that is entirely 7-bit. Within this, we - * check whether they have the same value. - * - * Hopefully this will often give the answer without needing to copy. - * In particular it should speed comparisons to literal ascii strings - * or comparisons of strings that are "obviously" different. - * - * If we find a non-ascii character we fall back to converting via - * iconv. - * - * This should never be slower than convering the whole thing, and - * often faster. - * - * A different optimization would be to compare for bitwise equality - * in the binary encoding. (It would be possible thought hairy to do - * both simultaneously.) But in that case if they turn out to be - * different, we'd need to restart the whole thing. - * - * Even better is to implement strcasecmp for each encoding and use a - * function pointer. - **/ -int StrCaseCmp(const char *s, const char *t) -{ - - const char *ps, *pt; - size_t size; - smb_ucs2_t *buffer_s, *buffer_t; - int ret; - - for (ps = s, pt = t; ; ps++, pt++) { - char us, ut; - - if (!*ps && !*pt) - return 0; /* both ended */ - else if (!*ps) - return -1; /* s is a prefix */ - else if (!*pt) - return +1; /* t is a prefix */ - else if ((*ps & 0x80) || (*pt & 0x80)) - /* not ascii anymore, do it the hard way - * from here on in */ - break; - - us = toupper_ascii_fast(*ps); - ut = toupper_ascii_fast(*pt); - if (us == ut) - continue; - else if (us < ut) - return -1; - else if (us > ut) - return +1; - } - - if (!push_ucs2_talloc(talloc_tos(), &buffer_s, ps, &size)) { - return strcmp(ps, pt); - /* Not quite the right answer, but finding the right one - under this failure case is expensive, and it's pretty - close */ - } - - if (!push_ucs2_talloc(talloc_tos(), &buffer_t, pt, &size)) { - TALLOC_FREE(buffer_s); - return strcmp(ps, pt); - /* Not quite the right answer, but finding the right one - under this failure case is expensive, and it's pretty - close */ - } - - ret = strcasecmp_w(buffer_s, buffer_t); - TALLOC_FREE(buffer_s); - TALLOC_FREE(buffer_t); - return ret; -} - - -/** - Case insensitive string compararison, length limited. -**/ -int StrnCaseCmp(const char *s, const char *t, size_t len) -{ - size_t n = 0; - const char *ps, *pt; - size_t size; - smb_ucs2_t *buffer_s, *buffer_t; - int ret; - - for (ps = s, pt = t; n < len ; ps++, pt++, n++) { - char us, ut; - - if (!*ps && !*pt) - return 0; /* both ended */ - else if (!*ps) - return -1; /* s is a prefix */ - else if (!*pt) - return +1; /* t is a prefix */ - else if ((*ps & 0x80) || (*pt & 0x80)) - /* not ascii anymore, do it the - * hard way from here on in */ - break; - - us = toupper_ascii_fast(*ps); - ut = toupper_ascii_fast(*pt); - if (us == ut) - continue; - else if (us < ut) - return -1; - else if (us > ut) - return +1; - } - - if (n == len) { - return 0; - } - - if (!push_ucs2_talloc(talloc_tos(), &buffer_s, ps, &size)) { - return strncmp(ps, pt, len-n); - /* Not quite the right answer, but finding the right one - under this failure case is expensive, - and it's pretty close */ - } - - if (!push_ucs2_talloc(talloc_tos(), &buffer_t, pt, &size)) { - TALLOC_FREE(buffer_s); - return strncmp(ps, pt, len-n); - /* Not quite the right answer, but finding the right one - under this failure case is expensive, - and it's pretty close */ - } - - ret = strncasecmp_w(buffer_s, buffer_t, len-n); - TALLOC_FREE(buffer_s); - TALLOC_FREE(buffer_t); - return ret; -} - -/** - * Compare 2 strings. - * - * @note The comparison is case-insensitive. - **/ -bool strequal(const char *s1, const char *s2) -{ - if (s1 == s2) - return(true); - if (!s1 || !s2) - return(false); - - return(StrCaseCmp(s1,s2)==0); -} - -/** * Compare 2 strings up to and including the nth char. * * @note The comparison is case-insensitive. @@ -205,119 +48,19 @@ bool strnequal(const char *s1,const char *s2,size_t n) if (!s1 || !s2 || !n) return(false); - return(StrnCaseCmp(s1,s2,n)==0); -} - -/** - Compare 2 strings (case sensitive). -**/ - -bool strcsequal(const char *s1,const char *s2) -{ - if (s1 == s2) - return(true); - if (!s1 || !s2) - return(false); - - return(strcmp(s1,s2)==0); -} - -/** -Do a case-insensitive, whitespace-ignoring string compare. -**/ - -int strwicmp(const char *psz1, const char *psz2) -{ - /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */ - /* appropriate value. */ - if (psz1 == psz2) - return (0); - else if (psz1 == NULL) - return (-1); - else if (psz2 == NULL) - return (1); - - /* sync the strings on first non-whitespace */ - while (1) { - while (isspace((int)*psz1)) - psz1++; - while (isspace((int)*psz2)) - psz2++; - if (toupper_m(*psz1) != toupper_m(*psz2) || - *psz1 == '\0' || *psz2 == '\0') - break; - psz1++; - psz2++; - } - return (*psz1 - *psz2); + return(strncasecmp_m(s1,s2,n)==0); } /** Convert a string to "normal" form. **/ -void strnorm(char *s, int case_default) +bool strnorm(char *s, int case_default) { if (case_default == CASE_UPPER) - strupper_m(s); + return strupper_m(s); else - strlower_m(s); -} - -/** - Check if a string is in "normal" case. -**/ - -bool strisnormal(const char *s, int case_default) -{ - if (case_default == CASE_UPPER) - return(!strhaslower(s)); - - return(!strhasupper(s)); -} - - -/** - String replace. - NOTE: oldc and newc must be 7 bit characters -**/ -void string_replace( char *s, char oldc, char newc ) -{ - char *p; - - /* this is quite a common operation, so we want it to be - fast. We optimise for the ascii case, knowing that all our - supported multi-byte character sets are ascii-compatible - (ie. they match for the first 128 chars) */ - - for (p = s; *p; p++) { - if (*p & 0x80) /* mb string - slow path. */ - break; - if (*p == oldc) { - *p = newc; - } - } - - if (!*p) - return; - - /* Slow (mb) path. */ -#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS - /* With compose characters we must restart from the beginning. JRA. */ - p = s; -#endif - - while (*p) { - size_t c_size; - next_codepoint(p, &c_size); - - if (c_size == 1) { - if (*p == oldc) { - *p = newc; - } - } - p += c_size; - } + return strlower_m(s); } /** @@ -374,24 +117,6 @@ size_t str_charnum(const char *s) return ret; } -/** - 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, - but will be different for multibyte. -**/ - -size_t str_ascii_charnum(const char *s) -{ - size_t ret, converted_size; - char *tmpbuf2 = NULL; - if (!push_ascii_talloc(talloc_tos(), &tmpbuf2, s, &converted_size)) { - return 0; - } - ret = strlen(tmpbuf2); - TALLOC_FREE(tmpbuf2); - return ret; -} - bool trim_char(char *s,char cfront,char cback) { bool ret = false; @@ -446,216 +171,15 @@ bool trim_char(char *s,char cfront,char cback) } /** - Does a string have any uppercase chars in it? -**/ - -bool strhasupper(const char *s) -{ - smb_ucs2_t *tmp, *p; - bool ret; - size_t converted_size; - - if (!push_ucs2_talloc(talloc_tos(), &tmp, s, &converted_size)) { - return false; - } - - for(p = tmp; *p != 0; p++) { - if(isupper_w(*p)) { - break; - } - } - - ret = (*p != 0); - TALLOC_FREE(tmp); - return ret; -} - -/** - Does a string have any lowercase chars in it? -**/ - -bool strhaslower(const char *s) -{ - smb_ucs2_t *tmp, *p; - bool ret; - size_t converted_size; - - if (!push_ucs2_talloc(talloc_tos(), &tmp, s, &converted_size)) { - return false; - } - - for(p = tmp; *p != 0; p++) { - if(islower_w(*p)) { - break; - } - } - - ret = (*p != 0); - TALLOC_FREE(tmp); - return ret; -} - -/** - Safe string copy into a known length string. maxlength does not - include the terminating zero. -**/ - -char *safe_strcpy_fn(const char *fn, - int line, - char *dest, - const char *src, - size_t maxlength) -{ - size_t len; - - if (!dest) { - DEBUG(0,("ERROR: NULL dest in safe_strcpy, " - "called from [%s][%d]\n", fn, line)); - return NULL; - } - -#ifdef DEVELOPER - clobber_region(fn,line,dest, maxlength+1); -#endif - - if (!src) { - *dest = 0; - return dest; - } - - len = strnlen(src, maxlength+1); - - if (len > maxlength) { - DEBUG(0,("ERROR: string overflow by " - "%lu (%lu - %lu) in safe_strcpy [%.50s]\n", - (unsigned long)(len-maxlength), (unsigned long)len, - (unsigned long)maxlength, src)); - len = maxlength; - } - - memmove(dest, src, len); - dest[len] = 0; - return dest; -} - -/** - Safe string cat into a string. maxlength does not - include the terminating zero. -**/ -char *safe_strcat_fn(const char *fn, - int line, - char *dest, - const char *src, - size_t maxlength) -{ - size_t src_len, dest_len; - - if (!dest) { - DEBUG(0,("ERROR: NULL dest in safe_strcat, " - "called from [%s][%d]\n", fn, line)); - return NULL; - } - - if (!src) - return dest; - - src_len = strnlen(src, maxlength + 1); - dest_len = strnlen(dest, maxlength + 1); - -#ifdef DEVELOPER - clobber_region(fn, line, dest + dest_len, maxlength + 1 - dest_len); -#endif - - if (src_len + dest_len > maxlength) { - DEBUG(0,("ERROR: string overflow by %d " - "in safe_strcat [%.50s]\n", - (int)(src_len + dest_len - maxlength), src)); - if (maxlength > dest_len) { - memcpy(&dest[dest_len], src, maxlength - dest_len); - } - dest[maxlength] = 0; - return NULL; - } - - memcpy(&dest[dest_len], src, src_len); - dest[dest_len + src_len] = 0; - return dest; -} - -/** - Paranoid strcpy into a buffer of given length (includes terminating - zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars - and replaces with '_'. Deliberately does *NOT* check for multibyte - characters. Treats src as an array of bytes, not as a multibyte - string. Any byte >0x7f is automatically converted to '_'. - other_safe_chars must also contain an ascii string (bytes<0x7f). -**/ - -char *alpha_strcpy_fn(const char *fn, - int line, - char *dest, - const char *src, - const char *other_safe_chars, - size_t maxlength) -{ - size_t len, i; - -#ifdef DEVELOPER - clobber_region(fn, line, dest, maxlength); -#endif - - if (!dest) { - DEBUG(0,("ERROR: NULL dest in alpha_strcpy, " - "called from [%s][%d]\n", fn, line)); - return NULL; - } - - if (!src) { - *dest = 0; - return dest; - } - - len = strlen(src); - if (len >= maxlength) - len = maxlength - 1; - - if (!other_safe_chars) - other_safe_chars = ""; - - for(i = 0; i < len; i++) { - int val = (src[i] & 0xff); - if (val > 0x7f) { - dest[i] = '_'; - continue; - } - if (isupper(val) || islower(val) || - isdigit(val) || strchr(other_safe_chars, val)) - dest[i] = src[i]; - else - dest[i] = '_'; - } - - dest[i] = '\0'; - - return dest; -} - -/** Like strncpy but always null terminates. Make sure there is room! The variable n should always be one less than the available size. **/ -char *StrnCpy_fn(const char *fn, int line,char *dest,const char *src,size_t n) +char *StrnCpy(char *dest,const char *src,size_t n) { char *d = dest; -#ifdef DEVELOPER - clobber_region(fn, line, dest, n+1); -#endif - if (!dest) { - DEBUG(0,("ERROR: NULL dest in StrnCpy, " - "called from [%s][%d]\n", fn, line)); - return(NULL); + smb_panic("ERROR: NULL dest in StrnCpy"); } if (!src) { @@ -672,34 +196,6 @@ char *StrnCpy_fn(const char *fn, int line,char *dest,const char *src,size_t n) return(dest); } -#if 0 -/** - Like strncpy but copies up to the character marker. always null terminates. - returns a pointer to the character marker in the source string (src). -**/ - -static char *strncpyn(char *dest, const char *src, size_t n, char c) -{ - char *p; - size_t str_len; - -#ifdef DEVELOPER - clobber_region(dest, n+1); -#endif - p = strchr_m(src, c); - if (p == NULL) { - DEBUG(5, ("strncpyn: separator character (%c) not found\n", c)); - return NULL; - } - - str_len = PTR_DIFF(p, src); - strncpy(dest, src, MIN(n, str_len)); - dest[str_len] = '\0'; - - return p; -} -#endif - /** Check if a string is part of a list. **/ @@ -722,7 +218,7 @@ bool in_list(const char *s, const char *list, bool casesensitive) break; } } else { - if (StrCaseCmp(tok,s) == 0) { + if (strcasecmp_m(tok,s) == 0) { ret = true; break; } @@ -732,235 +228,6 @@ bool in_list(const char *s, const char *list, bool casesensitive) return ret; } -/* this is used to prevent lots of mallocs of size 1 */ -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) { - *dest = CONST_DISCARD(char*, null_string); - } else { - (*dest) = SMB_STRDUP(src); - if ((*dest) == NULL) { - DEBUG(0,("Out of memory in string_init\n")); - return false; - } - } - return(true); -} - -/** - Free a string value. -**/ - -void string_free(char **s) -{ - if (!s || !(*s)) - return; - if (*s == null_string) - *s = NULL; - SAFE_FREE(*s); -} - -/** - Set a string value, deallocating any existing space, and allocing the space - for the string -**/ - -bool string_set(char **dest,const char *src) -{ - string_free(dest); - return(string_init(dest,src)); -} - -/** - Substitute a string for a pattern in another string. Make sure there is - enough room! - - This routine looks for pattern in s and replaces it with - insert. It may do multiple replacements or just one. - - Any of " ; ' $ or ` in the insert string are replaced with _ - if len==0 then the string cannot be extended. This is different from the old - use of len==0 which was for no length checks to be done. -**/ - -void string_sub2(char *s,const char *pattern, const char *insert, size_t len, - bool remove_unsafe_characters, bool replace_once, - bool allow_trailing_dollar) -{ - char *p; - ssize_t ls,lp,li, i; - - if (!insert || !pattern || !*pattern || !s) - return; - - ls = (ssize_t)strlen(s); - lp = (ssize_t)strlen(pattern); - li = (ssize_t)strlen(insert); - - if (len == 0) - len = ls + 1; /* len is number of *bytes* */ - - while (lp <= ls && (p = strstr_m(s,pattern))) { - if (ls + (li-lp) >= len) { - DEBUG(0,("ERROR: string overflow by " - "%d in string_sub(%.50s, %d)\n", - (int)(ls + (li-lp) - len), - pattern, (int)len)); - break; - } - if (li != lp) { - memmove(p+li,p+lp,strlen(p+lp)+1); - } - for (i=0;i<li;i++) { - switch (insert[i]) { - case '$': - /* allow a trailing $ - * (as in machine accounts) */ - if (allow_trailing_dollar && (i == li - 1 )) { - p[i] = insert[i]; - break; - } - case '`': - case '"': - case '\'': - case ';': - case '%': - case '\r': - case '\n': - if ( remove_unsafe_characters ) { - p[i] = '_'; - /* yes this break should be here - * since we want to fall throw if - * not replacing unsafe chars */ - break; - } - default: - p[i] = insert[i]; - } - } - s = p + li; - ls += (li-lp); - - if (replace_once) - break; - } -} - -void string_sub_once(char *s, const char *pattern, - const char *insert, size_t len) -{ - 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, false ); -} - -void fstring_sub(char *s,const char *pattern,const char *insert) -{ - string_sub(s, pattern, insert, sizeof(fstring)); -} - -/** - Similar to string_sub2, but it will accept only allocated strings - and may realloc them so pay attention at what you pass on no - pointers inside strings, no const may be passed - as string. -**/ - -char *realloc_string_sub2(char *string, - const char *pattern, - const char *insert, - bool remove_unsafe_characters, - bool allow_trailing_dollar) -{ - char *p, *in; - char *s; - ssize_t ls,lp,li,ld, i; - - if (!insert || !pattern || !*pattern || !string || !*string) - return NULL; - - s = string; - - in = SMB_STRDUP(insert); - if (!in) { - DEBUG(0, ("realloc_string_sub: out of memory!\n")); - return NULL; - } - ls = (ssize_t)strlen(s); - lp = (ssize_t)strlen(pattern); - li = (ssize_t)strlen(insert); - ld = li - lp; - for (i=0;i<li;i++) { - switch (in[i]) { - case '$': - /* allow a trailing $ - * (as in machine accounts) */ - if (allow_trailing_dollar && (i == li - 1 )) { - break; - } - case '`': - case '"': - case '\'': - case ';': - case '%': - case '\r': - case '\n': - if ( remove_unsafe_characters ) { - in[i] = '_'; - break; - } - default: - /* ok */ - break; - } - } - - while ((p = strstr_m(s,pattern))) { - if (ld > 0) { - int offset = PTR_DIFF(s,string); - string = (char *)SMB_REALLOC(string, ls + ld + 1); - if (!string) { - DEBUG(0, ("realloc_string_sub: " - "out of memory!\n")); - SAFE_FREE(in); - return NULL; - } - p = string + offset + (p - s); - } - if (li != lp) { - memmove(p+li,p+lp,strlen(p+lp)+1); - } - memcpy(p, in, li); - s = p + li; - ls += ld; - } - SAFE_FREE(in); - return string; -} - -char *realloc_string_sub(char *string, - const char *pattern, - const char *insert) -{ - return realloc_string_sub2(string, pattern, insert, true, false); -} - /* * Internal guts of talloc_string_sub and talloc_all_string_sub. * talloc version of string_sub2. @@ -991,7 +258,7 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src, s = string; - in = SMB_STRDUP(insert); + in = talloc_strdup(mem_ctx, insert); if (!in) { DEBUG(0, ("talloc_string_sub2: ENOMEM\n")); return NULL; @@ -1034,7 +301,7 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src, if (!string) { DEBUG(0, ("talloc_string_sub: out of " "memory!\n")); - SAFE_FREE(in); + TALLOC_FREE(in); return NULL; } p = string + offset + (p - s); @@ -1050,7 +317,7 @@ char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src, break; } } - SAFE_FREE(in); + TALLOC_FREE(in); return string; } @@ -1065,48 +332,6 @@ char *talloc_string_sub(TALLOC_CTX *mem_ctx, true, false, false); } -/** - Similar to string_sub() but allows for any character to be substituted. - Use with caution! - if len==0 then the string cannot be extended. This is different from the old - use of len==0 which was for no length checks to be done. -**/ - -void all_string_sub(char *s,const char *pattern,const char *insert, size_t len) -{ - char *p; - ssize_t ls,lp,li; - - if (!insert || !pattern || !s) - return; - - ls = (ssize_t)strlen(s); - lp = (ssize_t)strlen(pattern); - li = (ssize_t)strlen(insert); - - if (!*pattern) - return; - - if (len == 0) - len = ls + 1; /* len is number of *bytes* */ - - while (lp <= ls && (p = strstr_m(s,pattern))) { - if (ls + (li-lp) >= len) { - DEBUG(0,("ERROR: string overflow by " - "%d in all_string_sub(%.50s, %d)\n", - (int)(ls + (li-lp) - len), - pattern, (int)len)); - break; - } - if (li != lp) { - memmove(p+li,p+lp,strlen(p+lp)+1); - } - memcpy(p, insert, li); - s = p + li; - ls += (li-lp); - } -} - char *talloc_all_string_sub(TALLOC_CTX *ctx, const char *src, const char *pattern, @@ -1145,136 +370,6 @@ char *string_truncate(char *s, unsigned int length) return s; } -/** - Strchr and strrchr_m are very hard to do on general multi-byte strings. - We convert via ucs2 for now. -**/ - -char *strchr_m(const char *src, char c) -{ - smb_ucs2_t *ws = NULL; - char *s2 = NULL; - smb_ucs2_t *p; - const char *s; - char *ret; - size_t converted_size; - - /* characters below 0x3F are guaranteed to not appear in - non-initial position in multi-byte charsets */ - if ((c & 0xC0) == 0) { - return strchr(src, c); - } - - /* this is quite a common operation, so we want it to be - fast. We optimise for the ascii case, knowing that all our - supported multi-byte character sets are ascii-compatible - (ie. they match for the first 128 chars) */ - - for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) { - if (*s == c) - return (char *)s; - } - - if (!*s) - return NULL; - -#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS - /* With compose characters we must restart from the beginning. JRA. */ - s = src; -#endif - - if (!push_ucs2_talloc(talloc_tos(), &ws, s, &converted_size)) { - /* Wrong answer, but what can we do... */ - return strchr(src, c); - } - p = strchr_w(ws, UCS2_CHAR(c)); - if (!p) { - TALLOC_FREE(ws); - return NULL; - } - *p = 0; - if (!pull_ucs2_talloc(talloc_tos(), &s2, ws, &converted_size)) { - SAFE_FREE(ws); - /* Wrong answer, but what can we do... */ - return strchr(src, c); - } - ret = (char *)(s+strlen(s2)); - TALLOC_FREE(ws); - TALLOC_FREE(s2); - return ret; -} - -char *strrchr_m(const char *s, char c) -{ - /* characters below 0x3F are guaranteed to not appear in - non-initial position in multi-byte charsets */ - if ((c & 0xC0) == 0) { - return strrchr(s, c); - } - - /* this is quite a common operation, so we want it to be - fast. We optimise for the ascii case, knowing that all our - supported multi-byte character sets are ascii-compatible - (ie. they match for the first 128 chars). Also, in Samba - we only search for ascii characters in 'c' and that - in all mb character sets with a compound character - containing c, if 'c' is not a match at position - p, then p[-1] > 0x7f. JRA. */ - - { - size_t len = strlen(s); - const char *cp = s; - bool got_mb = false; - - if (len == 0) - return NULL; - cp += (len - 1); - do { - if (c == *cp) { - /* Could be a match. Part of a multibyte ? */ - if ((cp > s) && - (((unsigned char)cp[-1]) & 0x80)) { - /* Yep - go slow :-( */ - got_mb = true; - break; - } - /* No - we have a match ! */ - return (char *)cp; - } - } while (cp-- != s); - if (!got_mb) - return NULL; - } - - /* String contained a non-ascii char. Slow path. */ - { - smb_ucs2_t *ws = NULL; - char *s2 = NULL; - smb_ucs2_t *p; - char *ret; - size_t converted_size; - - if (!push_ucs2_talloc(talloc_tos(), &ws, s, &converted_size)) { - /* Wrong answer, but what can we do. */ - return strrchr(s, c); - } - p = strrchr_w(ws, UCS2_CHAR(c)); - if (!p) { - TALLOC_FREE(ws); - return NULL; - } - *p = 0; - if (!pull_ucs2_talloc(talloc_tos(), &s2, ws, &converted_size)) { - TALLOC_FREE(ws); - /* Wrong answer, but what can we do. */ - return strrchr(s, c); - } - ret = (char *)(s+strlen(s2)); - TALLOC_FREE(ws); - TALLOC_FREE(s2); - return ret; - } -} /*********************************************************************** Return the equivalent of doing strrchr 'n' times - always going @@ -1304,101 +399,72 @@ char *strnrchr_m(const char *s, char c, unsigned int n) /* Too hard to try and get right. */ return NULL; } - ret = (char *)(s+strlen(s2)); + ret = discard_const_p(char, (s+strlen(s2))); TALLOC_FREE(ws); TALLOC_FREE(s2); return ret; } -/*********************************************************************** - strstr_m - We convert via ucs2 for now. -***********************************************************************/ - -char *strstr_m(const char *src, const char *findstr) +static bool unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen) { - smb_ucs2_t *p; - smb_ucs2_t *src_w, *find_w; - const char *s; - char *s2; - char *retp; - - size_t converted_size, findstr_len = 0; + size_t size; + smb_ucs2_t *buffer = NULL; + bool ret; - /* for correctness */ - if (!findstr[0]) { - return (char*)src; + if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_UTF16LE, src, srclen, + (void **)(void *)&buffer, &size)) + { + return false; } - - /* Samba does single character findstr calls a *lot*. */ - if (findstr[1] == '\0') - return strchr_m(src, *findstr); - - /* We optimise for the ascii case, knowing that all our - supported multi-byte character sets are ascii-compatible - (ie. they match for the first 128 chars) */ - - for (s = src; *s && !(((unsigned char)s[0]) & 0x80); s++) { - if (*s == *findstr) { - if (!findstr_len) - findstr_len = strlen(findstr); - - if (strncmp(s, findstr, findstr_len) == 0) { - return (char *)s; - } - } + if (!strlower_w(buffer) && (dest == src)) { + TALLOC_FREE(buffer); + return true; } + ret = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, &size); + TALLOC_FREE(buffer); + return ret; +} - if (!*s) - return NULL; - -#if 1 /* def BROKEN_UNICODE_COMPOSE_CHARACTERS */ - /* 'make check' fails unless we do this */ +#if 0 /* Alternate function that avoid talloc calls for ASCII and non ASCII */ - /* With compose characters we must restart from the beginning. JRA. */ - s = src; -#endif - - if (!push_ucs2_talloc(talloc_tos(), &src_w, src, &converted_size)) { - DEBUG(0,("strstr_m: src malloc fail\n")); - return NULL; - } - - if (!push_ucs2_talloc(talloc_tos(), &find_w, findstr, &converted_size)) { - TALLOC_FREE(src_w); - DEBUG(0,("strstr_m: find malloc fail\n")); - return NULL; - } +/** + Convert a string to lower case. +**/ +_PUBLIC_ void strlower_m(char *s) +{ + char *d; + struct smb_iconv_handle *iconv_handle; - p = strstr_w(src_w, find_w); + iconv_handle = get_iconv_handle(); - if (!p) { - TALLOC_FREE(src_w); - TALLOC_FREE(find_w); - return NULL; - } + d = s; - *p = 0; - if (!pull_ucs2_talloc(talloc_tos(), &s2, src_w, &converted_size)) { - TALLOC_FREE(src_w); - TALLOC_FREE(find_w); - DEBUG(0,("strstr_m: dest malloc fail\n")); - return NULL; + while (*s) { + size_t c_size, c_size2; + codepoint_t c = next_codepoint_handle(iconv_handle, s, &c_size); + c_size2 = push_codepoint_handle(iconv_handle, 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)); + smb_panic("codepoint expansion in strlower_m\n"); + } + s += c_size; + d += c_size2; } - retp = (char *)(s+strlen(s2)); - TALLOC_FREE(src_w); - TALLOC_FREE(find_w); - TALLOC_FREE(s2); - return retp; + *d = 0; } +#endif + /** Convert a string to lower case. **/ -void strlower_m(char *s) +bool strlower_m(char *s) { size_t len; int errno_save; + bool ret = false; /* this is quite a common operation, so we want it to be fast. We optimise for the ascii case, knowing that all our @@ -1411,28 +477,82 @@ void strlower_m(char *s) } if (!*s) - return; + return true; /* I assume that lowercased string takes the same number of bytes * as source string even in UTF-8 encoding. (VIV) */ len = strlen(s) + 1; errno_save = errno; errno = 0; - unix_strlower(s,len,s,len); + ret = unix_strlower(s,len,s,len); /* Catch mb conversion errors that may not terminate. */ - if (errno) + if (errno) { s[len-1] = '\0'; + } errno = errno_save; + return ret; +} + +static bool unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen) +{ + size_t size; + smb_ucs2_t *buffer; + bool ret; + + if (!push_ucs2_talloc(talloc_tos(), &buffer, src, &size)) { + return false; + } + + if (!strupper_w(buffer) && (dest == src)) { + TALLOC_FREE(buffer); + return true; + } + + ret = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, &size); + TALLOC_FREE(buffer); + return ret; +} + +#if 0 /* Alternate function that avoid talloc calls for ASCII and non ASCII */ + +/** + Convert a string to UPPER case. +**/ +_PUBLIC_ void strupper_m(char *s) +{ + char *d; + struct smb_iconv_handle *iconv_handle; + + iconv_handle = get_iconv_handle(); + + d = s; + + while (*s) { + size_t c_size, c_size2; + codepoint_t c = next_codepoint_handle(iconv_handle, s, &c_size); + c_size2 = push_codepoint_handle(iconv_handle, 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)); + smb_panic("codepoint expansion in strupper_m\n"); + } + s += c_size; + d += c_size2; + } + *d = 0; } +#endif + /** Convert a string to upper case. **/ -void strupper_m(char *s) +bool strupper_m(char *s) { size_t len; int errno_save; + bool ret = false; /* this is quite a common operation, so we want it to be fast. We optimise for the ascii case, knowing that all our @@ -1445,142 +565,20 @@ void strupper_m(char *s) } if (!*s) - return; + return true; /* I assume that lowercased string takes the same number of bytes * as source string even in multibyte encoding. (VIV) */ len = strlen(s) + 1; errno_save = errno; errno = 0; - unix_strupper(s,len,s,len); + ret = unix_strupper(s,len,s,len); /* Catch mb conversion errors that may not terminate. */ - if (errno) + if (errno) { s[len-1] = '\0'; - errno = errno_save; -} - -/** - * Calculate the number of units (8 or 16-bit, depending on the - * destination charset), that would be needed to convert the input - * string which is expected to be in in src_charset encoding to the - * destination charset (which should be a unicode charset). - */ - -size_t strlen_m_ext(const char *s, const charset_t src_charset, - const charset_t dst_charset) -{ - 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_ext(s, src_charset, &c_size); - s += c_size; - - switch (dst_charset) { - case CH_UTF16LE: - case CH_UTF16BE: - case CH_UTF16MUNGED: - if (c < 0x10000) { - /* Unicode char fits into 16 bits. */ - count += 1; - } else { - /* Double-width unicode char - 32 bits. */ - count += 2; - } - break; - case CH_UTF8: - /* - * this only checks ranges, and does not - * check for invalid codepoints - */ - if (c < 0x80) { - count += 1; - } else if (c < 0x800) { - count += 2; - } else if (c < 0x1000) { - count += 3; - } else { - count += 4; - } - break; - default: - /* - * non-unicode encoding: - * assume that each codepoint fits into - * one unit in the destination encoding. - */ - count += 1; - } - } - - return count; -} - -size_t strlen_m_ext_term(const char *s, const charset_t src_charset, - const charset_t dst_charset) -{ - if (!s) { - return 0; - } - return strlen_m_ext(s, src_charset, dst_charset) + 1; -} - -/** - * Calculate the number of 16-bit units that would bee needed to convert - * the input string which is expected to be in CH_UNIX encoding to UTF16. - * - * 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) -{ - return strlen_m_ext(s, CH_UNIX, CH_UTF16LE); -} - -/** - 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; + errno = errno_save; + return ret; } /** @@ -1605,35 +603,6 @@ int fstr_sprintf(fstring s, const char *fmt, ...) #define S_LIST_ABS 16 /* List Allocation Block Size */ /****************************************************************************** - version of standard_sub_basic() for string lists; uses talloc_sub_basic() - for the work - *****************************************************************************/ - -bool str_list_sub_basic( char **list, const char *smb_name, - const char *domain_name ) -{ - TALLOC_CTX *ctx = list; - char *s, *tmpstr; - - while ( *list ) { - s = *list; - tmpstr = talloc_sub_basic(ctx, smb_name, domain_name, s); - if ( !tmpstr ) { - DEBUG(0,("str_list_sub_basic: " - "alloc_sub_basic() return NULL!\n")); - return false; - } - - TALLOC_FREE(*list); - *list = tmpstr; - - list++; - } - - return true; -} - -/****************************************************************************** substitute a specific pattern in a string list *****************************************************************************/ @@ -1662,7 +631,7 @@ bool str_list_substitute(char **list, const char *pattern, const char *insert) t = *list; d = p -t; if (ld) { - t = TALLOC_ARRAY(ctx, char, ls +ld +1); + t = talloc_array(ctx, char, ls +ld +1); if (!t) { DEBUG(0,("str_list_substitute: " "Unable to allocate memory")); @@ -1866,121 +835,6 @@ void ipstr_list_free(char* ipstr_list) SAFE_FREE(ipstr_list); } -static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/** - * Decode a base64 string into a DATA_BLOB - simple and slow algorithm - **/ -DATA_BLOB base64_decode_data_blob(const char *s) -{ - int bit_offset, byte_offset, idx, i, n; - DATA_BLOB decoded = data_blob(s, strlen(s)+1); - unsigned char *d = decoded.data; - char *p; - - n=i=0; - - while (*s && (p=strchr_m(b64,*s))) { - idx = (int)(p - b64); - byte_offset = (i*6)/8; - bit_offset = (i*6)%8; - d[byte_offset] &= ~((1<<(8-bit_offset))-1); - if (bit_offset < 3) { - d[byte_offset] |= (idx << (2-bit_offset)); - n = byte_offset+1; - } else { - d[byte_offset] |= (idx >> (bit_offset-2)); - d[byte_offset+1] = 0; - d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF; - n = byte_offset+2; - } - s++; i++; - } - - if ((n > 0) && (*s == '=')) { - n -= 1; - } - - /* fix up length */ - decoded.length = n; - return decoded; -} - -/** - * Decode a base64 string in-place - wrapper for the above - **/ -void base64_decode_inplace(char *s) -{ - DATA_BLOB decoded = base64_decode_data_blob(s); - - if ( decoded.length != 0 ) { - memcpy(s, decoded.data, decoded.length); - - /* null terminate */ - s[decoded.length] = '\0'; - } else { - *s = '\0'; - } - - data_blob_free(&decoded); -} - -/** - * Encode a base64 string into a talloc()ed string caller to free. - * - * From SQUID: adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c - * with adjustments - **/ - -char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data) -{ - int bits = 0; - int char_count = 0; - size_t out_cnt, len, output_len; - char *result; - - if (!data.length || !data.data) - return NULL; - - out_cnt = 0; - len = data.length; - output_len = data.length * 2 + 4; /* Account for closing bytes. 4 is - * random but should be enough for - * the = and \0 */ - result = TALLOC_ARRAY(mem_ctx, char, output_len); /* get us plenty of space */ - SMB_ASSERT(result != NULL); - - while (len--) { - int c = (unsigned char) *(data.data++); - bits += c; - char_count++; - if (char_count == 3) { - result[out_cnt++] = b64[bits >> 18]; - result[out_cnt++] = b64[(bits >> 12) & 0x3f]; - result[out_cnt++] = b64[(bits >> 6) & 0x3f]; - result[out_cnt++] = b64[bits & 0x3f]; - bits = 0; - char_count = 0; - } else { - bits <<= 8; - } - } - if (char_count != 0) { - bits <<= 16 - (8 * char_count); - result[out_cnt++] = b64[bits >> 18]; - result[out_cnt++] = b64[(bits >> 12) & 0x3f]; - if (char_count == 1) { - result[out_cnt++] = '='; - result[out_cnt++] = '='; - } else { - result[out_cnt++] = b64[(bits >> 6) & 0x3f]; - result[out_cnt++] = '='; - } - } - result[out_cnt] = '\0'; /* terminate */ - return result; -} - /* read a SMB_BIG_UINT from a string */ uint64_t STR_TO_SMB_BIG_UINT(const char *nptr, const char **entptr) { @@ -2019,25 +873,16 @@ uint64_t STR_TO_SMB_BIG_UINT(const char *nptr, const char **entptr) * * Returns 0 if the string can't be converted. */ -SMB_OFF_T conv_str_size(const char * str) +uint64_t conv_str_size(const char * str) { - SMB_OFF_T lval_orig; - SMB_OFF_T lval; + uint64_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 + lval = strtoull(str, &end, 10 /* base */); if (end == NULL || end == str) { return 0; @@ -2047,79 +892,27 @@ SMB_OFF_T conv_str_size(const char * str) return lval; } - lval_orig = lval; - if (strwicmp(end, "K") == 0) { - lval *= (SMB_OFF_T)1024; + lval *= 1024ULL; } else if (strwicmp(end, "M") == 0) { - lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024); + lval *= (1024ULL * 1024ULL); } else if (strwicmp(end, "G") == 0) { - lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024 * - (SMB_OFF_T)1024); + lval *= (1024ULL * 1024ULL * + 1024ULL); } else if (strwicmp(end, "T") == 0) { - lval *= ((SMB_OFF_T)1024 * (SMB_OFF_T)1024 * - (SMB_OFF_T)1024 * (SMB_OFF_T)1024); + lval *= (1024ULL * 1024ULL * + 1024ULL * 1024ULL); } 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); + lval *= (1024ULL * 1024ULL * + 1024ULL * 1024ULL * + 1024ULL); } 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 = (char *)SMB_MALLOC(new_len); - if (*left == NULL) { - return; - } - *left[0] = '\0'; - } else { - new_len += strlen(*left); - *left = (char *)SMB_REALLOC(*left, new_len); - } - - if (*left == NULL) { - return; - } - - safe_strcat(*left, right, new_len-1); -} - -bool add_string_to_array(TALLOC_CTX *mem_ctx, - const char *str, const char ***strings, - int *num) -{ - char *dup_str = talloc_strdup(mem_ctx, str); - - *strings = TALLOC_REALLOC_ARRAY(mem_ctx, *strings, - const char *, (*num)+1); - - if ((*strings == NULL) || (dup_str == NULL)) { - *num = 0; - return false; - } - - (*strings)[*num] = dup_str; - *num += 1; - return true; -} - /* Append an sprintf'ed string. Double buffer size on demand. Usable without * error checking in between. The indiation that something weird happened is * string==NULL */ @@ -2140,7 +933,7 @@ void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len, if (*bufsize == 0) *bufsize = 128; - *string = TALLOC_ARRAY(mem_ctx, char, *bufsize); + *string = talloc_array(mem_ctx, char, *bufsize); if (*string == NULL) goto error; } @@ -2162,7 +955,7 @@ void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len, } if (increased) { - *string = TALLOC_REALLOC_ARRAY(mem_ctx, *string, char, + *string = talloc_realloc(mem_ctx, *string, char, *bufsize); if (*string == NULL) { goto error; @@ -2196,7 +989,11 @@ int asprintf_strupper_m(char **strp, const char *fmt, ...) if (ret == -1) return -1; - strupper_m(result); + if (!strupper_m(result)) { + SAFE_FREE(result); + return -1; + } + *strp = result; return ret; } @@ -2213,7 +1010,10 @@ char *talloc_asprintf_strupper_m(TALLOC_CTX *t, const char *fmt, ...) if (ret == NULL) { return NULL; } - strupper_m(ret); + if (!strupper_m(ret)) { + TALLOC_FREE(ret); + return NULL; + } return ret; } @@ -2229,38 +1029,14 @@ char *talloc_asprintf_strlower_m(TALLOC_CTX *t, const char *fmt, ...) if (ret == NULL) { return NULL; } - strlower_m(ret); - return ret; -} - - -/* - Returns the substring from src between the first occurrence of - the char "front" and the first occurence of the char "back". - Mallocs the return string which must be freed. Not for use - with wide character strings. -*/ -char *sstring_sub(const char *src, char front, char back) -{ - char *temp1, *temp2, *temp3; - ptrdiff_t len; - - temp1 = strchr(src, front); - if (temp1 == NULL) return NULL; - temp2 = strchr(src, back); - if (temp2 == NULL) return NULL; - len = temp2 - temp1; - if (len <= 0) return NULL; - temp3 = (char*)SMB_MALLOC(len); - if (temp3 == NULL) { - DEBUG(1,("Malloc failure in sstring_sub\n")); + if (!strlower_m(ret)) { + TALLOC_FREE(ret); return NULL; } - memcpy(temp3, temp1+1, len-1); - temp3[len-1] = '\0'; - return temp3; + return ret; } + /******************************************************************** Check a string for any occurrences of a specified list of invalid characters. @@ -2470,7 +1246,7 @@ char **str_list_make_v3(TALLOC_CTX *mem_ctx, const char *string, if (!string || !*string) return NULL; - list = TALLOC_ARRAY(mem_ctx, char *, S_LIST_ABS+1); + list = talloc_array(mem_ctx, char *, S_LIST_ABS+1); if (list == NULL) { return NULL; } @@ -2494,7 +1270,7 @@ char **str_list_make_v3(TALLOC_CTX *mem_ctx, const char *string, lsize += S_LIST_ABS; - tmp = TALLOC_REALLOC_ARRAY(mem_ctx, list, char *, + tmp = talloc_realloc(mem_ctx, list, char *, lsize + 1); if (tmp == NULL) { DEBUG(0,("str_list_make: " @@ -2518,11 +1294,3 @@ char **str_list_make_v3(TALLOC_CTX *mem_ctx, const char *string, TALLOC_FREE(s); return list; } - -char *sanitize_username(TALLOC_CTX *mem_ctx, const char *username) -{ - fstring tmp; - - alpha_strcpy(tmp, username, ". _-$", sizeof(tmp)); - return talloc_strdup(mem_ctx, tmp); -} |