From e3f5b542707e2328030b9d5eff0836a904eccde5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 11 Mar 2004 22:48:24 +0000 Subject: Restore the contract on all convert_stringXX() interfaces. Add a "allow_bad_conv" boolean parameter that allows broken iconv conversions to work. Gets rid of the nasty errno checks in mangle_hash2 and check_path_syntax and allows correct return code checking. Jeremy. (This used to be commit 7b96765c23637613f079d37566d95d5edd511f05) --- source3/lib/charcnv.c | 102 +++++++++++++++++++++++++++----------------- source3/lib/dprintf.c | 2 +- source3/lib/smbldap.c | 2 +- source3/lib/util_unistr.c | 4 +- source3/libsmb/climessage.c | 2 +- source3/smbd/mangle_hash2.c | 6 +-- source3/smbd/message.c | 2 +- source3/smbd/reply.c | 28 +++--------- source3/utils/ntlm_auth.c | 2 +- source3/web/cgi.c | 8 ++-- 10 files changed, 81 insertions(+), 77 deletions(-) diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c index 9db05d8e16..cab81fccc5 100644 --- a/source3/lib/charcnv.c +++ b/source3/lib/charcnv.c @@ -156,6 +156,7 @@ void init_iconv(void) * @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 + * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors) * @returns the number of bytes occupied in the destination * * Ensure the srclen contains the terminating zero. @@ -164,7 +165,7 @@ void init_iconv(void) static size_t convert_string_internal(charset_t from, charset_t to, void const *src, size_t srclen, - void *dest, size_t destlen) + void *dest, size_t destlen, BOOL allow_bad_conv) { size_t i_len, o_len; size_t retval; @@ -188,7 +189,7 @@ static size_t convert_string_internal(charset_t from, charset_t to, if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) { if (!conv_silent) DEBUG(0,("convert_string_internal: Conversion not supported.\n")); - return 0; + return (size_t)-1; } i_len=srclen; @@ -204,7 +205,9 @@ static size_t convert_string_internal(charset_t from, charset_t to, reason="Incomplete multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); - goto use_as_is; + if (allow_bad_conv) + goto use_as_is; + break; case E2BIG: reason="No more room"; if (!conv_silent) @@ -219,7 +222,9 @@ static size_t convert_string_internal(charset_t from, charset_t to, reason="Illegal multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); - goto use_as_is; + 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)); @@ -313,6 +318,7 @@ static size_t convert_string_internal(charset_t from, charset_t to, * @param srclen length of the source string in bytes, or -1 for nul terminated. * @param dest pointer to destination string (multibyte or singlebyte) * @param destlen maximal length allowed for string - *NEVER* -1. + * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors) * @returns the number of bytes occupied in the destination * * Ensure the srclen contains the terminating zero. @@ -323,7 +329,7 @@ static size_t convert_string_internal(charset_t from, charset_t to, size_t convert_string(charset_t from, charset_t to, void const *src, size_t srclen, - void *dest, size_t destlen) + void *dest, size_t destlen, BOOL allow_bad_conv) { /* * NB. We deliberately don't do a strlen here if srclen == -1. @@ -361,7 +367,7 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - return retval + convert_string_internal(from, to, p, slen, q, dlen); + return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); #endif } } @@ -390,7 +396,7 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - return retval + convert_string_internal(from, to, p, slen, q, dlen); + return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); #endif } } @@ -419,7 +425,7 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS goto general_case; #else - return retval + convert_string_internal(from, to, p, slen, q, dlen); + return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv); #endif } } @@ -429,7 +435,7 @@ size_t convert_string(charset_t from, charset_t to, #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS general_case: #endif - return convert_string_internal(from, to, src, srclen, dest, destlen); + return convert_string_internal(from, to, src, srclen, dest, destlen, allow_bad_conv); } /** @@ -449,7 +455,7 @@ size_t convert_string(charset_t from, charset_t to, **/ size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to, - void const *src, size_t srclen, void **dest) + void const *src, size_t srclen, void **dest, BOOL allow_bad_conv) { size_t i_len, o_len, destlen = MAX(srclen, 512); size_t retval; @@ -471,7 +477,9 @@ size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to, if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) { if (!conv_silent) DEBUG(0,("convert_string_allocate: Conversion not supported.\n")); - goto use_as_is; + if (allow_bad_conv) + goto use_as_is; + return (size_t)-1; } convert: @@ -515,14 +523,18 @@ size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to, reason="Incomplete multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf)); - goto use_as_is; + 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)); - goto use_as_is; + if (allow_bad_conv) + goto use_as_is; + break; } if (!conv_silent) DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf)); @@ -633,12 +645,12 @@ size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to, * @returns Size in bytes of the converted string; or -1 in case of error. **/ static size_t convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to, - void const *src, size_t srclen, void **dest) + void const *src, size_t srclen, void **dest, BOOL allow_bad_conv) { size_t dest_len; *dest = NULL; - dest_len=convert_string_allocate(ctx, from, to, src, srclen, dest); + dest_len=convert_string_allocate(ctx, from, to, src, srclen, dest, allow_bad_conv); if (dest_len == (size_t)-1) return (size_t)-1; if (*dest == NULL) @@ -652,7 +664,7 @@ size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen) smb_ucs2_t *buffer; size = push_ucs2_allocate(&buffer, src); - if (size == -1) { + if (size == (size_t)-1) { smb_panic("failed to create UCS2 buffer"); } if (!strupper_w(buffer) && (dest == src)) { @@ -660,7 +672,7 @@ size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen) return srclen; } - size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen); + size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen, True); free(buffer); return size; } @@ -696,15 +708,15 @@ char *strdup_upper(const char *s) /* MB case. */ size_t size; wpstring buffer; - size = convert_string(CH_UNIX, CH_UCS2, s, -1, buffer, sizeof(buffer)); - if (size == -1) { + size = convert_string(CH_UNIX, CH_UCS2, s, -1, buffer, sizeof(buffer), True); + if (size == (size_t)-1) { return NULL; } strupper_w(buffer); - size = convert_string(CH_UCS2, CH_UNIX, buffer, -1, out_buffer, sizeof(out_buffer)); - if (size == -1) { + size = convert_string(CH_UCS2, CH_UNIX, buffer, -1, out_buffer, sizeof(out_buffer), True); + if (size == (size_t)-1) { return NULL; } } @@ -718,15 +730,15 @@ size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen) smb_ucs2_t *buffer = NULL; size = convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, srclen, - (void **) &buffer); - if (size == -1 || !buffer) { + (void **) &buffer, True); + if (size == (size_t)-1 || !buffer) { smb_panic("failed to create UCS2 buffer"); } if (!strlower_w(buffer) && (dest == src)) { SAFE_FREE(buffer); return srclen; } - size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen); + size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen, True); SAFE_FREE(buffer); return size; } @@ -751,7 +763,7 @@ char *strdup_lower(const char *s) size = pull_ucs2_allocate(&out_buffer, buffer); SAFE_FREE(buffer); - if (size == -1) { + if (size == (size_t)-1) { return NULL; } @@ -798,7 +810,7 @@ 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); + return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, True); } size_t push_ascii_fstring(void *dest, const char *src) @@ -849,7 +861,10 @@ 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); + ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, True); + if (ret == (size_t)-1) { + dest_len = 0; + } if (dest_len) dest[MIN(ret, dest_len-1)] = 0; @@ -895,6 +910,7 @@ size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_ { size_t len=0; size_t src_len; + size_t ret; /* treat a pstring as "unlimited" length */ if (dest_len == (size_t)-1) @@ -916,7 +932,12 @@ size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_ /* ucs2 is always a multiple of 2 bytes */ dest_len &= ~1; - len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len); + ret = convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len, True); + if (ret == (size_t)-1) { + return 0; + } + + len += ret; if (flags & STR_UPPER) { smb_ucs2_t *dest_ucs2 = dest; @@ -947,7 +968,7 @@ size_t push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src) size_t src_len = strlen(src)+1; *dest = NULL; - return convert_string_talloc(ctx, CH_UNIX, CH_UCS2, src, src_len, (void **)dest); + return convert_string_talloc(ctx, CH_UNIX, CH_UCS2, src, src_len, (void **)dest, True); } @@ -965,7 +986,7 @@ size_t push_ucs2_allocate(smb_ucs2_t **dest, const char *src) size_t src_len = strlen(src)+1; *dest = NULL; - return convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, src_len, (void **)dest); + return convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, src_len, (void **)dest, True); } /** @@ -996,7 +1017,7 @@ static size_t push_utf8(void *dest, const char *src, size_t dest_len, int flags) if (flags & STR_TERMINATE) src_len++; - return convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len); + return convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len, True); } size_t push_utf8_fstring(void *dest, const char *src) @@ -1017,7 +1038,7 @@ size_t push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src) size_t src_len = strlen(src)+1; *dest = NULL; - return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, (void**)dest); + return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, (void**)dest, True); } /** @@ -1033,7 +1054,7 @@ size_t push_utf8_allocate(char **dest, const char *src) size_t src_len = strlen(src)+1; *dest = NULL; - return convert_string_allocate(NULL, CH_UNIX, CH_UTF8, src, src_len, (void **)dest); + return convert_string_allocate(NULL, CH_UNIX, CH_UTF8, src, src_len, (void **)dest, True); } /** @@ -1074,8 +1095,11 @@ size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_ if (src_len != (size_t)-1) src_len &= ~1; - ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len); - + ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len, True); + if (ret == (size_t)-1) { + return 0; + } + if (src_len == (size_t)-1) src_len = ret*2; @@ -1109,7 +1133,7 @@ size_t pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src) { size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t); *dest = NULL; - return convert_string_talloc(ctx, CH_UCS2, CH_UNIX, src, src_len, (void **)dest); + return convert_string_talloc(ctx, CH_UCS2, CH_UNIX, src, src_len, (void **)dest, True); } /** @@ -1124,7 +1148,7 @@ size_t pull_ucs2_allocate(char **dest, const smb_ucs2_t *src) { size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t); *dest = NULL; - return convert_string_allocate(NULL, CH_UCS2, CH_UNIX, src, src_len, (void **)dest); + return convert_string_allocate(NULL, CH_UCS2, CH_UNIX, src, src_len, (void **)dest, True); } /** @@ -1139,7 +1163,7 @@ size_t pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src) { size_t src_len = strlen(src)+1; *dest = NULL; - return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, (void **)dest); + return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, (void **)dest, True); } /** @@ -1154,7 +1178,7 @@ size_t pull_utf8_allocate(char **dest, const char *src) { size_t src_len = strlen(src)+1; *dest = NULL; - return convert_string_allocate(NULL, CH_UTF8, CH_UNIX, src, src_len, (void **)dest); + return convert_string_allocate(NULL, CH_UTF8, CH_UNIX, src, src_len, (void **)dest, True); } /** diff --git a/source3/lib/dprintf.c b/source3/lib/dprintf.c index 70387bbd61..c62a1f41d1 100644 --- a/source3/lib/dprintf.c +++ b/source3/lib/dprintf.c @@ -59,7 +59,7 @@ again: SAFE_FREE(p); return -1; } - clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen); + clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen, True); if (clen >= maxlen) { /* it didn't fit - try a larger buffer */ diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index 2ade9d5197..2c76e84254 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -306,7 +306,7 @@ static BOOL fetch_ldap_pw(char **dn, char** pw) return False; } - if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len) == (size_t)-1) { + if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, max_len, False) == (size_t)-1) { DEBUG(1, ("smbldap_get_single_attribute: string conversion of [%s] = [%s] failed!\n", attribute, values[0])); ldap_value_free(values); diff --git a/source3/lib/util_unistr.c b/source3/lib/util_unistr.c index e90a824395..005f10a4c0 100644 --- a/source3/lib/util_unistr.c +++ b/source3/lib/util_unistr.c @@ -109,9 +109,9 @@ static int check_dos_char_slowly(smb_ucs2_t c) char buf[10]; smb_ucs2_t c2 = 0; int len1, len2; - len1 = convert_string(CH_UCS2, CH_DOS, &c, 2, buf, sizeof(buf)); + len1 = convert_string(CH_UCS2, CH_DOS, &c, 2, buf, sizeof(buf),False); if (len1 == 0) return 0; - len2 = convert_string(CH_DOS, CH_UCS2, buf, len1, &c2, 2); + len2 = convert_string(CH_DOS, CH_UCS2, buf, len1, &c2, 2,False); if (len2 != 2) return 0; return (c == c2); } diff --git a/source3/libsmb/climessage.c b/source3/libsmb/climessage.c index 035088212c..8429ca4f41 100644 --- a/source3/libsmb/climessage.c +++ b/source3/libsmb/climessage.c @@ -87,7 +87,7 @@ int cli_message_text_build(struct cli_state *cli, char *msg, int len, int grp) p = smb_buf(cli->outbuf); *p++ = 1; - if ((lendos = convert_string_allocate(NULL,CH_UNIX, CH_DOS, msg,len, (void **) &msgdos)) < 0 || !msgdos) { + if ((lendos = (int)convert_string_allocate(NULL,CH_UNIX, CH_DOS, msg,len, (void **) &msgdos, True)) < 0 || !msgdos) { DEBUG(3,("Conversion failed, sending message in UNIX charset\n")); SSVAL(p, 0, len); p += 2; memcpy(p, msg, len); diff --git a/source3/smbd/mangle_hash2.c b/source3/smbd/mangle_hash2.c index 8dfa84d054..62087e7e59 100644 --- a/source3/smbd/mangle_hash2.c +++ b/source3/smbd/mangle_hash2.c @@ -453,17 +453,13 @@ static BOOL is_legal_name(const char *name) /* Possible start of mb character. */ char mbc[2]; /* - * We know the following will return 2 bytes. What - * we need to know was if errno was set. * Note that if CH_UNIX is utf8 a string may be 3 * bytes, but this is ok as mb utf8 characters don't * contain embedded ascii bytes. We are really checking * for mb UNIX asian characters like Japanese (SJIS) here. * JRA. */ - errno = 0; - convert_string(CH_UNIX, CH_UCS2, name, 2, mbc, 2); - if (!errno) { + if (convert_string(CH_UNIX, CH_UCS2, name, 2, mbc, 2, False) == 2) { /* Was a good mb string. */ name += 2; continue; diff --git a/source3/smbd/message.c b/source3/smbd/message.c index 88f833e468..f853a91475 100644 --- a/source3/smbd/message.c +++ b/source3/smbd/message.c @@ -64,7 +64,7 @@ static void msg_deliver(void) * Incoming message is in DOS codepage format. Convert to UNIX. */ - if ((len = convert_string_allocate(NULL,CH_DOS, CH_UNIX, msgbuf, msgpos, (void **) &msg)) < 0 || !msg) { + if ((len = (int)convert_string_allocate(NULL,CH_DOS, CH_UNIX, msgbuf, msgpos, (void **) &msg, True)) < 0 || !msg) { DEBUG(3,("Conversion failed, delivering message in DOS codepage format\n")); for (i = 0; i < msgpos;) { if (msgbuf[i] == '\r' && i < (msgpos-1) && msgbuf[i+1] == '\n') { diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index dc9f0be401..4a0c06f442 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -117,35 +117,19 @@ NTSTATUS check_path_syntax(pstring destname, const pstring srcname) * conversion to unicode. If the one byte char converts then * it really is a directory separator following. Otherwise if * the two byte character converts (and it should or our assumption - * about character sets is broken and we panic) then copy both + * about character sets is broken and we return an error) then copy both * bytes as it's a MB character, not a directory separator. */ uint16 ucs2_val; - /* - * We know the following will return 2 bytes. What - * we need to know was if errno was set. - * Note that if CH_UNIX is utf8 a string may be 3 - * bytes, but this is ok as mb utf8 characters don't - * contain embedded directory separators. We are really checking - * for mb UNIX asian characters like Japanese (SJIS) here. - * JRA. - */ - - errno = 0; - convert_string(CH_UNIX, CH_UCS2, s, 1, &ucs2_val, 2); - if (errno == 0) { + if (convert_string(CH_UNIX, CH_UCS2, s, 1, &ucs2_val, 2, False) == 2) { ; + } else if (convert_string(CH_UNIX, CH_UCS2, s, 2, &ucs2_val, 2, False) == 2) { + *d++ = *s++; } else { - errno = 0; - convert_string(CH_UNIX, CH_UCS2, s, 2, &ucs2_val, 2); - if (errno == 0) { - *d++ = *s++; - } else { - DEBUG(0,("check_path_syntax: directory separator assumptions invalid !\n")); - return NT_STATUS_INVALID_PARAMETER; - } + DEBUG(0,("check_path_syntax: directory separator assumptions invalid !\n")); + return NT_STATUS_INVALID_PARAMETER; } } /* Just copy the char (or the second byte of the mb char). */ diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index d2a1547f77..ec0f404176 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1864,7 +1864,7 @@ static BOOL test_plaintext(enum ntlm_break break_which) if ((convert_string_allocate(NULL, CH_UNIX, CH_DOS, password, strlen(password)+1, - (void**)&lm_response.data)) == -1) { + (void**)&lm_response.data,True)) == -1) { DEBUG(0, ("push_ascii_allocate failed!\n")); exit(1); } diff --git a/source3/web/cgi.c b/source3/web/cgi.c index aac009893c..07b9f52ff7 100644 --- a/source3/web/cgi.c +++ b/source3/web/cgi.c @@ -203,13 +203,13 @@ void cgi_load_variables(void) convert_string(CH_DISPLAY, CH_UNIX, variables[i].name, -1, - dest, sizeof(dest)); + dest, sizeof(dest), True); free(variables[i].name); variables[i].name = strdup(dest); convert_string(CH_DISPLAY, CH_UNIX, variables[i].value, -1, - dest, sizeof(dest)); + dest, sizeof(dest), True); free(variables[i].value); variables[i].value = strdup(dest); } @@ -336,11 +336,11 @@ static BOOL cgi_handle_authorization(char *line) convert_string(CH_DISPLAY, CH_UNIX, line, -1, - user, sizeof(user)); + user, sizeof(user), True); convert_string(CH_DISPLAY, CH_UNIX, p+1, -1, - user_pass, sizeof(user_pass)); + user_pass, sizeof(user_pass), True); /* * Try and get the user from the UNIX password file. -- cgit