r13622: Allow to rename machine accounts in a Samba Domain. This still uses the
[jra/samba/.git] / source / lib / util_str.c
index 394c8e27cff2a31696df30abacf08b90b545d3ac..e799556cd1ebb6ad87208561b429f38979331b7b 100644 (file)
@@ -183,7 +183,7 @@ char **toktocliplist(int *ctok, const char *sep)
 int StrCaseCmp(const char *s, const char *t)
 {
 
-       const char * ps, * pt;
+       const char *ps, *pt;
        size_t size;
        smb_ucs2_t *buffer_s, *buffer_t;
        int ret;
@@ -201,8 +201,8 @@ int StrCaseCmp(const char *s, const char *t)
                        /* not ascii anymore, do it the hard way from here on in */
                        break;
 
-               us = toupper(*ps);
-               ut = toupper(*pt);
+               us = toupper_ascii(*ps);
+               ut = toupper_ascii(*pt);
                if (us == ut)
                        continue;
                else if (us < ut)
@@ -211,17 +211,17 @@ int StrCaseCmp(const char *s, const char *t)
                        return +1;
        }
 
-       size = push_ucs2_allocate(&buffer_s, s);
+       size = push_ucs2_allocate(&buffer_s, ps);
        if (size == (size_t)-1) {
-               return strcmp(s, t); 
+               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 */
        }
        
-       size = push_ucs2_allocate(&buffer_t, t);
+       size = push_ucs2_allocate(&buffer_t, pt);
        if (size == (size_t)-1) {
                SAFE_FREE(buffer_s);
-               return strcmp(s, t); 
+               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 */
        }
@@ -266,12 +266,12 @@ BOOL strequal(const char *s1, const char *s2)
  **/
 BOOL strnequal(const char *s1,const char *s2,size_t n)
 {
-  if (s1 == s2)
-         return(True);
-  if (!s1 || !s2 || !n)
-         return(False);
+       if (s1 == s2)
+               return(True);
+       if (!s1 || !s2 || !n)
+               return(False);
   
-  return(StrnCaseCmp(s1,s2,n)==0);
+       return(StrnCaseCmp(s1,s2,n)==0);
 }
 
 /**
@@ -280,12 +280,12 @@ BOOL strnequal(const char *s1,const char *s2,size_t n)
 
 BOOL strcsequal(const char *s1,const char *s2)
 {
-  if (s1 == s2)
-         return(True);
-  if (!s1 || !s2)
-         return(False);
+       if (s1 == s2)
+               return(True);
+       if (!s1 || !s2)
+               return(False);
   
-  return(strcmp(s1,s2)==0);
+       return(strcmp(s1,s2)==0);
 }
 
 /**
@@ -309,7 +309,7 @@ int strwicmp(const char *psz1, const char *psz2)
                        psz1++;
                while (isspace((int)*psz2))
                        psz2++;
-               if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0'
+               if (toupper_ascii(*psz1) != toupper_ascii(*psz2) || *psz1 == '\0'
                    || *psz2 == '\0')
                        break;
                psz1++;
@@ -363,16 +363,16 @@ BOOL strisnormal(const char *s, int case_default)
  NOTE: oldc and newc must be 7 bit characters
 **/
 
-void string_replace(pstring s,char oldc,char newc)
+void string_replace( pstring s, char oldc, char newc )
 {
-       unsigned char *p;
+       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 = (unsigned char *)s; *p; p++) {
+       for (p = s; *p; p++) {
                if (*p & 0x80) /* mb string - slow path. */
                        break;
                if (*p == oldc)
@@ -680,7 +680,7 @@ char *alpha_strcpy_fn(const char *fn, int line, char *dest, const char *src, con
 
        for(i = 0; i < len; i++) {
                int val = (src[i] & 0xff);
-               if (isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val))
+               if (isupper_ascii(val) || islower_ascii(val) || isdigit(val) || strchr_m(other_safe_chars, val))
                        dest[i] = src[i];
                else
                        dest[i] = '_';
@@ -774,12 +774,12 @@ size_t strhex_to_str(char *p, size_t len, const char *strhex)
                        continue;
                }
 
-               if (!(p1 = strchr_m(hexchars, toupper(strhex[i]))))
+               if (!(p1 = strchr_m(hexchars, toupper_ascii(strhex[i]))))
                        break;
 
                i++; /* next hex digit */
 
-               if (!(p2 = strchr_m(hexchars, toupper(strhex[i]))))
+               if (!(p2 = strchr_m(hexchars, toupper_ascii(strhex[i]))))
                        break;
 
                /* get the two nybbles */
@@ -795,11 +795,16 @@ size_t strhex_to_str(char *p, size_t len, const char *strhex)
        return num_chars;
 }
 
-DATA_BLOB strhex_to_data_blob(const char *strhex) 
+DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) 
 {
-       DATA_BLOB ret_blob = data_blob(NULL, strlen(strhex)/2+1);
+       DATA_BLOB ret_blob;
+
+       if (mem_ctx != NULL)
+               ret_blob = data_blob_talloc(mem_ctx, NULL, strlen(strhex)/2+1);
+       else
+               ret_blob = data_blob(NULL, strlen(strhex)/2+1);
 
-       ret_blob.length = strhex_to_str(ret_blob.data,  
+       ret_blob.length = strhex_to_str((char*)ret_blob.data,   
                                        strlen(strhex), 
                                        strhex);
 
@@ -810,23 +815,24 @@ DATA_BLOB strhex_to_data_blob(const char *strhex)
  * Routine to print a buffer as HEX digits, into an allocated string.
  */
 
-void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
+char *hex_encode(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len)
 {
        int i;
        char *hex_buffer;
 
-       *out_hex_buffer = SMB_XMALLOC_ARRAY(char, (len*2)+1);
-       hex_buffer = *out_hex_buffer;
+       hex_buffer = TALLOC_ARRAY(mem_ctx, char, (len*2)+1);
 
        for (i = 0; i < len; i++)
                slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
+
+       return hex_buffer;
 }
 
 /**
  Check if a string is part of a list.
 **/
 
-BOOL in_list(char *s,char *list,BOOL casesensitive)
+BOOL in_list(const char *s, const char *list, BOOL casesensitive)
 {
        pstring tok;
        const char *p=list;
@@ -909,14 +915,15 @@ BOOL string_set(char **dest,const char *src)
  enough room!
 
  This routine looks for pattern in s and replaces it with 
- insert. It may do multiple replacements.
+ 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_sub(char *s,const char *pattern, const char *insert, size_t len)
+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;
@@ -948,20 +955,42 @@ void string_sub(char *s,const char *pattern, const char *insert, size_t len)
                        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':
-                               p[i] = '_';
-                               break;
+                               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));
@@ -979,7 +1008,8 @@ void pstring_sub(char *s,const char *pattern,const char *insert)
  as string.
 **/
 
-char *realloc_string_sub(char *string, const char *pattern, const char *insert)
+char *realloc_string_sub(char *string, const char *pattern,
+                        const char *insert)
 {
        char *p, *in;
        char *s;
@@ -1039,6 +1069,77 @@ char *realloc_string_sub(char *string, const char *pattern, const char *insert)
        return string;
 }
 
+/* Same as string_sub, but returns a talloc'ed string */
+
+char *talloc_string_sub(TALLOC_CTX *mem_ctx, const char *src,
+                       const char *pattern, const char *insert)
+{
+       char *p, *in;
+       char *s;
+       char *string;
+       ssize_t ls,lp,li,ld, i;
+
+       if (!insert || !pattern || !*pattern || !src || !*src)
+               return NULL;
+
+       string = talloc_strdup(mem_ctx, src);
+       if (string == NULL) {
+               DEBUG(0, ("talloc_strdup failed\n"));
+               return NULL;
+       }
+
+       s = string;
+
+       in = SMB_STRDUP(insert);
+       if (!in) {
+               DEBUG(0, ("talloc_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 '`':
+                       case '"':
+                       case '\'':
+                       case ';':
+                       case '$':
+                       case '%':
+                       case '\r':
+                       case '\n':
+                               in[i] = '_';
+                       default:
+                               /* ok */
+                               break;
+               }
+       }
+       
+       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) {
+                               DEBUG(0, ("talloc_string_sub: out of "
+                                         "memory!\n"));
+                               SAFE_FREE(in);
+                               return NULL;
+                       }
+                       string = t;
+                       p = t + 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;
+}
+
 /**
  Similar to string_sub() but allows for any character to be substituted. 
  Use with caution!
@@ -1334,7 +1435,7 @@ char *strstr_m(const char *src, const char *findstr)
 
        /* for correctness */
        if (!findstr[0]) {
-               return src;
+               return (char*)src;
        }
 
        /* Samba does single character findstr calls a *lot*. */
@@ -1414,7 +1515,7 @@ void strlower_m(char *s)
           (ie. they match for the first 128 chars) */
 
        while (*s && !(((unsigned char)s[0]) & 0x80)) {
-               *s = tolower((unsigned char)*s);
+               *s = tolower_ascii((unsigned char)*s);
                s++;
        }
 
@@ -1448,7 +1549,7 @@ void strupper_m(char *s)
           (ie. they match for the first 128 chars) */
 
        while (*s && !(((unsigned char)s[0]) & 0x80)) {
-               *s = toupper((unsigned char)*s);
+               *s = toupper_ascii((unsigned char)*s);
                s++;
        }
 
@@ -1571,7 +1672,7 @@ int fstr_sprintf(fstring s, const char *fmt, ...)
 
 #define S_LIST_ABS 16 /* List Allocation Block Size */
 
-char **str_list_make(const char *string, const char *sep)
+static char **str_list_make_internal(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
 {
        char **list, **rlist;
        const char *str;
@@ -1581,7 +1682,11 @@ char **str_list_make(const char *string, const char *sep)
        
        if (!string || !*string)
                return NULL;
-       s = SMB_STRDUP(string);
+       if (mem_ctx) {
+               s = talloc_strdup(mem_ctx, string);
+       } else {
+               s = SMB_STRDUP(string);
+       }
        if (!s) {
                DEBUG(0,("str_list_make: Unable to allocate memory"));
                return NULL;
@@ -1595,32 +1700,64 @@ char **str_list_make(const char *string, const char *sep)
        while (next_token(&str, tok, sep, sizeof(tok))) {               
                if (num == lsize) {
                        lsize += S_LIST_ABS;
-                       rlist = SMB_REALLOC_ARRAY(list, char *, lsize +1);
+                       if (mem_ctx) {
+                               rlist = TALLOC_REALLOC_ARRAY(mem_ctx, list, char *, lsize +1);
+                       } else {
+                               rlist = SMB_REALLOC_ARRAY(list, char *, lsize +1);
+                       }
                        if (!rlist) {
                                DEBUG(0,("str_list_make: Unable to allocate memory"));
                                str_list_free(&list);
-                               SAFE_FREE(s);
+                               if (mem_ctx) {
+                                       TALLOC_FREE(s);
+                               } else {
+                                       SAFE_FREE(s);
+                               }
                                return NULL;
                        } else
                                list = rlist;
                        memset (&list[num], 0, ((sizeof(char**)) * (S_LIST_ABS +1)));
                }
+
+               if (mem_ctx) {
+                       list[num] = talloc_strdup(mem_ctx, tok);
+               } else {
+                       list[num] = SMB_STRDUP(tok);
+               }
                
-               list[num] = SMB_STRDUP(tok);
                if (!list[num]) {
                        DEBUG(0,("str_list_make: Unable to allocate memory"));
                        str_list_free(&list);
-                       SAFE_FREE(s);
+                       if (mem_ctx) {
+                               TALLOC_FREE(s);
+                       } else {
+                               SAFE_FREE(s);
+                       }
                        return NULL;
                }
        
                num++;  
        }
-       
-       SAFE_FREE(s);
+
+       if (mem_ctx) {
+               TALLOC_FREE(s);
+       } else {
+               SAFE_FREE(s);
+       }
+
        return list;
 }
 
+char **str_list_make_talloc(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
+{
+       return str_list_make_internal(mem_ctx, string, sep);
+}
+
+char **str_list_make(const char *string, const char *sep)
+{
+       return str_list_make_internal(NULL, string, sep);
+}
+
 BOOL str_list_copy(char ***dest, const char **src)
 {
        char **list, **rlist;
@@ -1682,16 +1819,52 @@ BOOL str_list_compare(char **list1, char **list2)
        return True;
 }
 
-void str_list_free(char ***list)
+static void str_list_free_internal(TALLOC_CTX *mem_ctx, char ***list)
 {
        char **tlist;
        
        if (!list || !*list)
                return;
        tlist = *list;
-       for(; *tlist; tlist++)
-               SAFE_FREE(*tlist);
-       SAFE_FREE(*list);
+       for(; *tlist; tlist++) {
+               if (mem_ctx) {
+                       TALLOC_FREE(*tlist);
+               } else {
+                       SAFE_FREE(*tlist);
+               }
+       }
+       if (mem_ctx) {
+               TALLOC_FREE(*tlist);
+       } else {
+               SAFE_FREE(*list);
+       }
+}
+
+void str_list_free_talloc(TALLOC_CTX *mem_ctx, char ***list)
+{
+       str_list_free_internal(mem_ctx, list);
+}
+
+void str_list_free(char ***list)
+{
+       str_list_free_internal(NULL, list);
+}
+
+/******************************************************************************
+ *****************************************************************************/
+
+int str_list_count( const char **list )
+{
+       int i = 0;
+
+       if ( ! list )
+               return 0;
+
+       /* count the number of list members */
+       
+       for ( i=0; *list; i++, list++ );
+       
+       return i;
 }
 
 /******************************************************************************
@@ -2016,10 +2189,16 @@ char * base64_encode_data_blob(DATA_BLOB data)
 {
        int bits = 0;
        int char_count = 0;
-       size_t out_cnt = 0;
-       size_t len = data.length;
-       size_t output_len = data.length * 2;
-       char *result = SMB_MALLOC(output_len); /* get us plenty of space */
+       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;
+       result = SMB_MALLOC(output_len); /* get us plenty of space */
 
        while (len-- && out_cnt < (data.length * 2) - 5) {
                int c = (unsigned char) *(data.data++);
@@ -2108,3 +2287,116 @@ BOOL add_string_to_array(TALLOC_CTX *mem_ctx,
        *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 */
+
+void sprintf_append(TALLOC_CTX *mem_ctx, char **string, ssize_t *len,
+                   size_t *bufsize, const char *fmt, ...)
+{
+       va_list ap;
+       char *newstr;
+       int ret;
+       BOOL increased;
+
+       /* len<0 is an internal marker that something failed */
+       if (*len < 0)
+               goto error;
+
+       if (*string == NULL) {
+               if (*bufsize == 0)
+                       *bufsize = 128;
+
+               if (mem_ctx != NULL)
+                       *string = TALLOC_ARRAY(mem_ctx, char, *bufsize);
+               else
+                       *string = SMB_MALLOC_ARRAY(char, *bufsize);
+
+               if (*string == NULL)
+                       goto error;
+       }
+
+       va_start(ap, fmt);
+       ret = vasprintf(&newstr, fmt, ap);
+       va_end(ap);
+
+       if (ret < 0)
+               goto error;
+
+       increased = False;
+
+       while ((*len)+ret >= *bufsize) {
+               increased = True;
+               *bufsize *= 2;
+               if (*bufsize >= (1024*1024*256))
+                       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)
+                       goto error;
+       }
+
+       StrnCpy((*string)+(*len), newstr, ret);
+       (*len) += ret;
+       free(newstr);
+       return;
+
+ error:
+       *len = -1;
+       *string = NULL;
+}
+
+/*
+   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"));
+               return NULL;
+       }
+       memcpy(temp3, temp1+1, len-1);
+       temp3[len-1] = '\0';
+       return temp3;
+}
+
+/********************************************************************
+ Check a string for any occurrences of a specified list of invalid
+ characters.
+********************************************************************/
+
+BOOL validate_net_name( const char *name, const char *invalid_chars, int max_len )
+{
+       int i;
+
+       for ( i=0; i<max_len && name[i]; i++ ) {
+               /* fail if strchr_m() finds one of the invalid characters */
+               if ( name[i] && strchr_m( invalid_chars, name[i] ) ) {
+                       return False;
+               }
+       }
+
+       return True;
+}
+