Fix a segv in winbindd caused by trying to free an fstring. Make a copy of the machin...
[tprouty/samba.git] / source / lib / charcnv.c
index ebc97033acd90064c1c510887274e5cf3e81d445..7b52830cde1658109be41b55b8b9dfb1724f3873 100644 (file)
@@ -871,10 +871,11 @@ size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
 {
        size_t src_len = strlen(src);
        pstring tmpbuf;
+       size_t ret;
 
-       /* treat a pstring as "unlimited" length */
+       /* No longer allow a length of -1 */
        if (dest_len == (size_t)-1)
-               dest_len = sizeof(pstring);
+               smb_panic("push_ascii - dest_len == -1");
 
        if (flags & STR_UPPER) {
                pstrcpy(tmpbuf, src);
@@ -885,7 +886,13 @@ size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
        if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
                src_len++;
 
-       return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, True);
+       ret =convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, True);
+       if (ret == (size_t)-1 &&
+                       (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
+                       && dest_len > 0) {
+               ((char *)dest)[0] = '\0';
+       }
+       return ret;
 }
 
 size_t push_ascii_fstring(void *dest, const char *src)
@@ -972,13 +979,18 @@ size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len,
 
        ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, True);
        if (ret == (size_t)-1) {
+               ret = 0;
                dest_len = 0;
        }
 
-       if (dest_len)
-               dest[MIN(ret, dest_len-1)] = 0;
-       else 
+       if (dest_len && ret) {
+               /* Did we already process the terminating zero ? */
+               if (dest[MIN(ret-1, dest_len-1)] != 0) {
+                       dest[MIN(ret, dest_len-1)] = 0;
+               }
+       } else  {
                dest[0] = 0;
+       }
 
        return src_len;
 }
@@ -1053,7 +1065,11 @@ size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_
        if (flags & STR_UPPER) {
                smb_ucs2_t *dest_ucs2 = (smb_ucs2_t *)dest;
                size_t i;
-               for (i = 0; i < (dest_len / 2) && dest_ucs2[i]; i++) {
+
+               /* We check for i < (ret / 2) below as the dest string isn't null
+                  terminated if STR_TERMINATE isn't set. */
+
+               for (i = 0; i < (ret / 2) && i < (dest_len / 2) && dest_ucs2[i]; i++) {
                        smb_ucs2_t v = toupper_w(dest_ucs2[i]);
                        if (v != dest_ucs2[i]) {
                                dest_ucs2[i] = v;
@@ -1215,10 +1231,14 @@ size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_
        if (src_len == (size_t)-1)
                src_len = ret*2;
                
-       if (dest_len)
-               dest[MIN(ret, dest_len-1)] = 0;
-       else 
+       if (dest_len && ret) {
+               /* Did we already process the terminating zero ? */
+               if (dest[MIN(ret-1, dest_len-1)] != 0) {
+                       dest[MIN(ret, dest_len-1)] = 0;
+               }
+       } else {
                dest[0] = 0;
+       }
 
        return src_len;
 }