int check_dos_char(smb_ucs2_t c) { lazy_initialize_conv(); /* Find the right byte, and right bit within the byte; return * 1 or 0 */ return (doschar_table[(c & 0xffff) / 8] & (1 << (c & 7))) != 0; }
/* * FIXME the size is a mess we really need a malloc/free logic *`dest size must be dest_len +2 */ size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_charset, const char *src, size_t src_len, char *dest, size_t dest_len, uint16_t *flags) { size_t i_len, o_len; ucs2_t *u; ucs2_t buffer[MAXPATHLEN +2]; ucs2_t buffer2[MAXPATHLEN +2]; lazy_initialize_conv(); /* convert from_set to UCS2 */ if ((size_t)(-1) == ( o_len = pull_charset_flags( from_set, to_set, cap_charset, src, src_len, (char *) buffer, sizeof(buffer) -2, flags)) ) { LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from_set)); return (size_t) -1; } if ( o_len == 0) return o_len; /* Do pre/decomposition */ i_len = sizeof(buffer2) -2; u = buffer2; if (CHECK_FLAGS(flags, CONV_DECOMPOSE) || (charsets[to_set] && (charsets[to_set]->flags & CHARSET_DECOMPOSED)) ) { if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) ) return (size_t)(-1); } else if (CHECK_FLAGS(flags, CONV_PRECOMPOSE) || !charsets[from_set] || (charsets[from_set]->flags & CHARSET_DECOMPOSED)) { if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) ) return (size_t)(-1); } else { u = buffer; i_len = o_len; } /* null terminate */ u[i_len] = 0; u[i_len +1] = 0; /* Do case conversions */ if (CHECK_FLAGS(flags, CONV_TOUPPER)) { strupper_w(u); } else if (CHECK_FLAGS(flags, CONV_TOLOWER)) { strlower_w(u); } /* Convert UCS2 to to_set */ if ((size_t)(-1) == ( o_len = push_charset_flags( to_set, cap_charset, (char *)u, i_len, dest, dest_len, flags )) ) { LOG(log_error, logtype_default, "Conversion failed (CH_UCS2 to %s):%s", charset_name(to_set), strerror(errno)); return (size_t) -1; } /* null terminate */ dest[o_len] = 0; dest[o_len +1] = 0; return o_len; }
/** * Convert string from one encoding to another, making error checking etc * * @param src pointer to source string (multibyte or singlebyte) * @param srclen length of the source string in bytes * @param dest pointer to destination string (multibyte or singlebyte) * @param destlen maximal length allowed for string * @returns the number of bytes occupied in the destination **/ static size_t convert_string_internal(charset_t from, charset_t to, void const *src, size_t srclen, void *dest, size_t destlen) { size_t i_len, o_len; size_t retval; const char* inbuf = (const char*)src; char* outbuf = (char*)dest; char* o_save = outbuf; atalk_iconv_t descriptor; /* Fixed based on Samba 3.0.6 */ if (srclen == (size_t)-1) { if (from == CH_UCS2) { srclen = (strlen_w((const ucs2_t *)src)) * 2; } else { srclen = strlen((const char *)src); } } lazy_initialize_conv(); descriptor = conv_handles[from][to]; if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) { return (size_t) -1; } i_len=srclen; o_len=destlen; retval = atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len); if(retval==(size_t)-1) { const char *reason="unknown error"; switch(errno) { case EINVAL: reason="Incomplete multibyte sequence"; break; case E2BIG: reason="No more room"; break; case EILSEQ: reason="Illegal multibyte sequence"; break; } LOG(log_debug, logtype_default,"Conversion error: %s",reason); return (size_t)-1; } /* Terminate the string */ return add_null( to, o_save, o_len, destlen -o_len); }
charset_t add_charset(const char* name) { static charset_t max_charset_t = NUM_CHARSETS-1; charset_t cur_charset_t = max_charset_t+1; unsigned int c1; lazy_initialize_conv(); for (c1=0; c1<=max_charset_t;c1++) { if ( strcasecmp(name, charset_name(c1)) == 0) return (c1); } if ( cur_charset_t >= MAX_CHARSETS ) { LOG (log_debug, logtype_default, "Adding charset %s failed, too many charsets (max. %u allowed)", name, MAX_CHARSETS); return (charset_t) -1; } /* First try to setup the required conversions */ conv_handles[cur_charset_t][CH_UCS2] = atalk_iconv_open( charset_name(CH_UCS2), name); if (conv_handles[cur_charset_t][CH_UCS2] == (atalk_iconv_t)-1) { LOG(log_error, logtype_default, "Required conversion from %s to %s not supported", name, charset_name(CH_UCS2)); conv_handles[cur_charset_t][CH_UCS2] = NULL; return (charset_t) -1; } conv_handles[CH_UCS2][cur_charset_t] = atalk_iconv_open( name, charset_name(CH_UCS2)); if (conv_handles[CH_UCS2][cur_charset_t] == (atalk_iconv_t)-1) { LOG(log_error, logtype_default, "Required conversion from %s to %s not supported", charset_name(CH_UCS2), name); conv_handles[CH_UCS2][cur_charset_t] = NULL; return (charset_t) -1; } /* register the new charset_t name */ charset_names[cur_charset_t] = strdup(name); charsets[cur_charset_t] = get_charset_functions (cur_charset_t); max_charset_t++; #ifdef DEBUG LOG(log_debug9, logtype_default, "Added charset %s with handle %u", name, cur_charset_t); #endif return (cur_charset_t); }
void init_valid_table(void) { static int mapped_file; int i; const char *allowed = ".!#$%&'()_-@^`~"; uint8 *valid_file; if (mapped_file) { /* Can't unmap files, so stick with what we have */ return; } valid_file = (uint8 *)map_file(data_path("valid.dat"), 0x10000); if (valid_file) { valid_table = valid_file; mapped_file = 1; valid_table_use_unmap = True; return; } /* Otherwise, we're using a dynamically created valid_table. * It might need to be regenerated if the code page changed. * We know that we're not using a mapped file, so we can * free() the old one. */ SAFE_FREE(valid_table); /* use free rather than unmap */ valid_table_use_unmap = False; DEBUG(2,("creating default valid table\n")); valid_table = (uint8 *)SMB_MALLOC(0x10000); SMB_ASSERT(valid_table != NULL); for (i=0;i<128;i++) { valid_table[i] = isalnum(i) || strchr(allowed,i); } lazy_initialize_conv(); for (;i<0x10000;i++) { smb_ucs2_t c; SSVAL(&c, 0, i); valid_table[i] = check_dos_char_slowly(c); } }
size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to, void const *src, size_t srclen, void *dst, BOOL allow_bad_conv) { size_t i_len, o_len, destlen = (srclen * 3) / 2; size_t retval; const char *inbuf = (const char *)src; char *outbuf = NULL, *ob = NULL; smb_iconv_t descriptor; void **dest = (void **)dst; *dest = NULL; if (src == NULL || srclen == (size_t)-1) return (size_t)-1; if (srclen == 0) return 0; lazy_initialize_conv(); descriptor = conv_handles[from][to]; if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) { if (!conv_silent) DEBUG(0,("convert_string_allocate: Conversion not supported.\n")); return (size_t)-1; } convert: /* +2 is for ucs2 null termination. */ if ((destlen*2)+2 < destlen) { /* wrapped ! abort. */ if (!conv_silent) DEBUG(0, ("convert_string_allocate: destlen wrapped !\n")); if (!ctx) SAFE_FREE(outbuf); return (size_t)-1; } else { destlen = destlen * 2; } /* +2 is for ucs2 null termination. */ if (ctx) { ob = (char *)TALLOC_REALLOC(ctx, ob, destlen + 2); } else { ob = (char *)SMB_REALLOC(ob, destlen + 2); } if (!ob) { DEBUG(0, ("convert_string_allocate: realloc failed!\n")); return (size_t)-1; } outbuf = ob; i_len = srclen; o_len = destlen; again: retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len); if(retval == (size_t)-1) { const char *reason="unknown error"; switch(errno) { case EINVAL: reason="Incomplete multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf)); if (allow_bad_conv) goto use_as_is; break; case E2BIG: goto convert; case EILSEQ: reason="Illegal multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf)); if (allow_bad_conv) goto use_as_is; break; } if (!conv_silent) DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf)); /* smb_panic(reason); */ return (size_t)-1; } out: destlen = destlen - o_len; if (ctx) { /* We're shrinking here so we know the +2 is safe from wrap. */ ob = (char *)TALLOC_REALLOC(ctx,ob,destlen + 2); } else { ob = (char *)SMB_REALLOC(ob,destlen + 2); } if (destlen && !ob) { DEBUG(0, ("convert_string_allocate: out of memory!\n")); return (size_t)-1; } *dest = ob; /* Must ucs2 null terminate in the extra space we allocated. */ ob[destlen] = '\0'; ob[destlen+1] = '\0'; return destlen; use_as_is: /* * Conversion not supported. This is actually an error, but there are so * many misconfigured iconv systems and smb.conf's out there we can't just * fail. Do a very bad conversion instead.... JRA. */ { if (o_len == 0 || i_len == 0) goto out; if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) && ((to != CH_UTF16LE)||(to != CH_UTF16BE))) { /* Can't convert from utf16 any endian to multibyte. Replace with the default fail char. */ if (i_len < 2) goto out; if (i_len >= 2) { *outbuf = lp_failed_convert_char(); outbuf++; o_len--; inbuf += 2; i_len -= 2; } if (o_len == 0 || i_len == 0) goto out; /* Keep trying with the next char... */ goto again; } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) { /* Can't convert to UTF16LE - just widen by adding the default fail char then zero. */ if (o_len < 2) goto out; outbuf[0] = lp_failed_convert_char(); outbuf[1] = '\0'; inbuf++; i_len--; outbuf += 2; o_len -= 2; if (o_len == 0 || i_len == 0) goto out; /* Keep trying with the next char... */ goto again; } else if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE && to != CH_UTF16BE) { /* Failed multibyte to multibyte. Just copy the default fail char and try again. */ outbuf[0] = lp_failed_convert_char(); inbuf++; i_len--; outbuf++; o_len--; if (o_len == 0 || i_len == 0) goto out; /* Keep trying with the next char... */ goto again; } else { /* Keep compiler happy.... */ goto out; } } }
static size_t convert_string_internal(charset_t from, charset_t to, void const *src, size_t srclen, void *dest, size_t destlen, BOOL allow_bad_conv) { size_t i_len, o_len; size_t retval; const char* inbuf = (const char*)src; char* outbuf = (char*)dest; smb_iconv_t descriptor; lazy_initialize_conv(); descriptor = conv_handles[from][to]; if (srclen == (size_t)-1) { if (from == CH_UTF16LE || from == CH_UTF16BE) { srclen = (strlen_w((const smb_ucs2_t *)src)+1) * 2; } else { srclen = strlen((const char *)src)+1; } } if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) { if (!conv_silent) DEBUG(0,("convert_string_internal: Conversion not supported.\n")); return (size_t)-1; } i_len=srclen; o_len=destlen; again: retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len); if(retval==(size_t)-1) { const char *reason="unknown error"; switch(errno) { case EINVAL: reason="Incomplete multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); if (allow_bad_conv) goto use_as_is; break; case E2BIG: reason="No more room"; if (!conv_silent) { if (from == CH_UNIX) { DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u - '%s'\n", charset_name(from), charset_name(to), (unsigned int)srclen, (unsigned int)destlen, (const char *)src)); } else { DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u\n", charset_name(from), charset_name(to), (unsigned int)srclen, (unsigned int)destlen)); } } break; case EILSEQ: reason="Illegal multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); if (allow_bad_conv) goto use_as_is; break; default: if (!conv_silent) DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); break; } /* smb_panic(reason); */ } return destlen-o_len; use_as_is: /* * Conversion not supported. This is actually an error, but there are so * many misconfigured iconv systems and smb.conf's out there we can't just * fail. Do a very bad conversion instead.... JRA. */ { if (o_len == 0 || i_len == 0) return destlen - o_len; if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) && ((to != CH_UTF16LE)||(to != CH_UTF16BE))) { /* Can't convert from utf16 any endian to multibyte. Replace with the default fail char. */ if (i_len < 2) return destlen - o_len; if (i_len >= 2) { *outbuf = lp_failed_convert_char(); outbuf++; o_len--; inbuf += 2; i_len -= 2; } if (o_len == 0 || i_len == 0) return destlen - o_len; /* Keep trying with the next char... */ goto again; } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) { /* Can't convert to UTF16LE - just widen by adding the default fail char then zero. */ if (o_len < 2) return destlen - o_len; outbuf[0] = lp_failed_convert_char(); outbuf[1] = '\0'; inbuf++; i_len--; outbuf += 2; o_len -= 2; if (o_len == 0 || i_len == 0) return destlen - o_len; /* Keep trying with the next char... */ goto again; } else if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE && to != CH_UTF16BE) { /* Failed multibyte to multibyte. Just copy the default fail char and try again. */ outbuf[0] = lp_failed_convert_char(); inbuf++; i_len--; outbuf++; o_len--; if (o_len == 0 || i_len == 0) return destlen - o_len; /* Keep trying with the next char... */ goto again; } else { /* Keep compiler happy.... */ return destlen - o_len; } } }
codepoint_t next_codepoint(const char *str, size_t *size) { /* It cannot occupy more than 4 bytes in UTF16 format */ uint8_t buf[4]; smb_iconv_t descriptor; size_t ilen_orig; size_t ilen; size_t olen; char *outbuf; if ((str[0] & 0x80) == 0) { *size = 1; return (codepoint_t)str[0]; } /* We assume that no multi-byte character can take more than 5 bytes. This is OK as we only support codepoints up to 1M */ ilen_orig = strnlen(str, 5); ilen = ilen_orig; lazy_initialize_conv(); descriptor = conv_handles[CH_UNIX][CH_UTF16LE]; if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) { *size = 1; return INVALID_CODEPOINT; } /* This looks a little strange, but it is needed to cope with codepoints above 64k which are encoded as per RFC2781. */ olen = 2; outbuf = (char *)buf; smb_iconv(descriptor, &str, &ilen, &outbuf, &olen); if (olen == 2) { /* We failed to convert to a 2 byte character. See if we can convert to a 4 UTF16-LE byte char encoding. */ olen = 4; outbuf = (char *)buf; smb_iconv(descriptor, &str, &ilen, &outbuf, &olen); if (olen == 4) { /* We didn't convert any bytes */ *size = 1; return INVALID_CODEPOINT; } olen = 4 - olen; } else { olen = 2 - olen; } *size = ilen_orig - ilen; if (olen == 2) { /* 2 byte, UTF16-LE encoded value. */ return (codepoint_t)SVAL(buf, 0); } if (olen == 4) { /* Decode a 4 byte UTF16-LE character manually. See RFC2871 for the encoding machanism. */ codepoint_t w1 = SVAL(buf,0) & ~0xD800; codepoint_t w2 = SVAL(buf,2) & ~0xDC00; return (codepoint_t)0x10000 + (w1 << 10) + w2; } /* no other length is valid */ return INVALID_CODEPOINT; }
static size_t convert_string_allocate_internal(charset_t from, charset_t to, void const *src, size_t srclen, char **dest) { size_t i_len, o_len, destlen; size_t retval; const char *inbuf = (const char *)src; char *outbuf = NULL, *ob = NULL; atalk_iconv_t descriptor; *dest = NULL; if (src == NULL || srclen == (size_t)-1) return (size_t)-1; lazy_initialize_conv(); descriptor = conv_handles[from][to]; if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) { /* conversion not supported, return -1*/ LOG(log_debug, logtype_default, "convert_string_allocate: conversion not supported!"); return -1; } destlen = MAX(srclen, 512); convert: destlen = destlen * 2; outbuf = (char *)realloc(ob, destlen); if (!outbuf) { LOG(log_debug, logtype_default,"convert_string_allocate: realloc failed!"); SAFE_FREE(ob); return (size_t)-1; } else { ob = outbuf; } inbuf = src; /* this restarts the whole conversion if buffer needed to be increased */ i_len = srclen; o_len = destlen; retval = atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len); if(retval == (size_t)-1) { const char *reason="unknown error"; switch(errno) { case EINVAL: reason="Incomplete multibyte sequence"; break; case E2BIG: goto convert; case EILSEQ: reason="Illegal multibyte sequence"; break; } LOG(log_debug, logtype_default,"Conversion error: %s(%s)",reason,inbuf); SAFE_FREE(ob); return (size_t)-1; } destlen = destlen - o_len; /* Terminate the string */ if (to == CH_UCS2 && o_len >= 2) { ob[destlen] = 0; ob[destlen+1] = 0; *dest = (char *)realloc(ob,destlen+2); } else if ( to != CH_UCS2 && o_len > 0 ) { ob[destlen] = 0; *dest = (char *)realloc(ob,destlen+1); } else { goto convert; /* realloc */ } if (destlen && !*dest) { LOG(log_debug, logtype_default, "convert_string_allocate: out of memory!"); SAFE_FREE(ob); return (size_t)-1; } return destlen; }