From: Daniel Stenberg Date: Wed, 14 Dec 2022 13:49:59 +0000 (+0100) Subject: idn: rename the files to idn.[ch] and hold all IDN functions X-Git-Tag: curl-7_87_0~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cc0aaf6e824e9da70740c6f769a8f6d188fe11ce;p=thirdparty%2Fcurl.git idn: rename the files to idn.[ch] and hold all IDN functions Closes #10094 --- diff --git a/lib/Makefile.inc b/lib/Makefile.inc index f50e941e86..9eafa93b9a 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -162,7 +162,7 @@ LIB_CFILES = \ http_ntlm.c \ http_proxy.c \ http_aws_sigv4.c \ - idn_win32.c \ + idn.c \ if2ip.c \ imap.c \ inet_ntop.c \ @@ -293,6 +293,7 @@ LIB_HFILES = \ http_ntlm.h \ http_proxy.h \ http_aws_sigv4.h \ + idn.h \ if2ip.h \ imap.h \ inet_ntop.h \ diff --git a/lib/idn.c b/lib/idn.c new file mode 100644 index 0000000000..6255221ae1 --- /dev/null +++ b/lib/idn.c @@ -0,0 +1,193 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + + /* + * IDN conversions + */ + +#include "curl_setup.h" +#include "urldata.h" +#include "idn.h" +#include "sendf.h" +#include "curl_multibyte.h" +#include "warnless.h" + +#ifdef USE_LIBIDN2 +#include + +#if defined(WIN32) && defined(UNICODE) +#define IDN2_LOOKUP(name, host, flags) \ + idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags) +#else +#define IDN2_LOOKUP(name, host, flags) \ + idn2_lookup_ul((const char *)name, (char **)host, flags) +#endif +#endif /* USE_LIBIDN2 */ + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +#ifdef USE_WIN32_IDN +/* using Windows kernel32 and normaliz libraries. */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600 +WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags, + const WCHAR *lpUnicodeCharStr, + int cchUnicodeChar, + WCHAR *lpASCIICharStr, + int cchASCIIChar); +WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, + const WCHAR *lpASCIICharStr, + int cchASCIIChar, + WCHAR *lpUnicodeCharStr, + int cchUnicodeChar); +#endif + +#define IDN_MAX_LENGTH 255 + +bool Curl_win32_idn_to_ascii(const char *in, char **out) +{ + bool success = FALSE; + + wchar_t *in_w = curlx_convert_UTF8_to_wchar(in); + if(in_w) { + wchar_t punycode[IDN_MAX_LENGTH]; + int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH); + curlx_unicodefree(in_w); + if(chars) { + char *mstr = curlx_convert_wchar_to_UTF8(punycode); + if(mstr) { + *out = strdup(mstr); + curlx_unicodefree(mstr); + if(*out) + success = TRUE; + } + } + } + + return success; +} + +#endif /* USE_WIN32_IDN */ + +/* + * Helpers for IDNA conversions. + */ +bool Curl_is_ASCII_name(const char *hostname) +{ + /* get an UNSIGNED local version of the pointer */ + const unsigned char *ch = (const unsigned char *)hostname; + + if(!hostname) /* bad input, consider it ASCII! */ + return TRUE; + + while(*ch) { + if(*ch++ & 0x80) + return FALSE; + } + return TRUE; +} + +#ifdef USE_IDN +/* + * Curl_idn_decode() returns an allocated IDN decoded string if it was + * possible. NULL on error. + */ +static char *Curl_idn_decode(const char *input) +{ + char *decoded = NULL; +#ifdef USE_LIBIDN2 + if(idn2_check_version(IDN2_VERSION)) { + int flags = IDN2_NFC_INPUT +#if IDN2_VERSION_NUMBER >= 0x00140000 + /* IDN2_NFC_INPUT: Normalize input string using normalization form C. + IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional + processing. */ + | IDN2_NONTRANSITIONAL +#endif + ; + int rc = IDN2_LOOKUP(input, &decoded, flags); + if(rc != IDN2_OK) + /* fallback to TR46 Transitional mode for better IDNA2003 + compatibility */ + rc = IDN2_LOOKUP(input, &decoded, IDN2_TRANSITIONAL); + if(rc != IDN2_OK) + decoded = NULL; + } +#elif defined(USE_WIN32_IDN) + if(!Curl_win32_idn_to_ascii(input, &decoded)) + decoded = NULL; +#endif + return decoded; +} + +/* + * Frees data allocated by idnconvert_hostname() + */ +void Curl_free_idnconverted_hostname(struct hostname *host) +{ +#if defined(USE_LIBIDN2) + if(host->encalloc) { + idn2_free(host->encalloc); /* must be freed with idn2_free() since this was + allocated by libidn */ + host->encalloc = NULL; + } +#elif defined(USE_WIN32_IDN) + free(host->encalloc); /* must be freed with free() since this was + allocated by Curl_win32_idn_to_ascii */ + host->encalloc = NULL; +#else + (void)host; +#endif +} + +#endif /* USE_IDN */ + +/* + * Perform any necessary IDN conversion of hostname + */ +CURLcode Curl_idnconvert_hostname(struct hostname *host) +{ + /* set the name we use to display the host name */ + host->dispname = host->name; + +#ifdef USE_IDN + /* Check name for non-ASCII and convert hostname if we can */ + if(!Curl_is_ASCII_name(host->name)) { + char *decoded = Curl_idn_decode(host->name); + if(decoded) { + /* successful */ + host->encalloc = decoded; + /* change the name pointer to point to the encoded hostname */ + host->name = host->encalloc; + } + else + return CURLE_URL_MALFORMAT; + } +#endif + return CURLE_OK; +} + diff --git a/lib/idn_win32.h b/lib/idn.h similarity index 75% rename from lib/idn_win32.h rename to lib/idn.h index 8a76403368..2d04efcdff 100644 --- a/lib/idn_win32.h +++ b/lib/idn.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_IDN_WIN32_H -#define HEADER_CURL_IDN_WIN32_H +#ifndef HEADER_CURL_IDN_H +#define HEADER_CURL_IDN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -25,8 +25,14 @@ ***************************************************************************/ #ifdef USE_WIN32_IDN - bool Curl_win32_idn_to_ascii(const char *in, char **out); - #endif /* USE_WIN32_IDN */ -#endif /* HEADER_CURL_IDN_WIN32_H */ +bool Curl_is_ASCII_name(const char *hostname); +CURLcode Curl_idnconvert_hostname(struct hostname *host); +#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) +#define USE_IDN +void Curl_free_idnconverted_hostname(struct hostname *host); +#else +#define Curl_free_idnconverted_hostname(x) +#endif +#endif /* HEADER_CURL_IDN_H */ diff --git a/lib/idn_win32.c b/lib/idn_win32.c deleted file mode 100644 index b3088be6a0..0000000000 --- a/lib/idn_win32.c +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - - /* - * IDN conversions using Windows kernel32 and normaliz libraries. - */ - -#include "curl_setup.h" - -#ifdef USE_WIN32_IDN -#include "idn_win32.h" -#include "curl_multibyte.h" -#include "curl_memory.h" -#include "warnless.h" - - /* The last #include file should be: */ -#include "memdebug.h" - -#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600 -WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags, - const WCHAR *lpUnicodeCharStr, - int cchUnicodeChar, - WCHAR *lpASCIICharStr, - int cchASCIIChar); -WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, - const WCHAR *lpASCIICharStr, - int cchASCIIChar, - WCHAR *lpUnicodeCharStr, - int cchUnicodeChar); -#endif - -#define IDN_MAX_LENGTH 255 - -bool Curl_win32_idn_to_ascii(const char *in, char **out) -{ - bool success = FALSE; - - wchar_t *in_w = curlx_convert_UTF8_to_wchar(in); - if(in_w) { - wchar_t punycode[IDN_MAX_LENGTH]; - int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH); - curlx_unicodefree(in_w); - if(chars) { - char *mstr = curlx_convert_wchar_to_UTF8(punycode); - if(mstr) { - *out = strdup(mstr); - curlx_unicodefree(mstr); - if(*out) - success = TRUE; - } - } - } - - return success; -} - -#endif /* USE_WIN32_IDN */ diff --git a/lib/smtp.c b/lib/smtp.c index cb066d70ec..6d0783f458 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -83,6 +83,7 @@ #include "bufref.h" #include "curl_sasl.h" #include "warnless.h" +#include "idn.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -105,7 +106,7 @@ static CURLcode smtp_setup_connection(struct Curl_easy *data, static CURLcode smtp_parse_url_options(struct connectdata *conn); static CURLcode smtp_parse_url_path(struct Curl_easy *data); static CURLcode smtp_parse_custom_request(struct Curl_easy *data); -static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma, +static CURLcode smtp_parse_address(const char *fqma, char **address, struct hostname *host); static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech, const struct bufref *initresp); @@ -541,7 +542,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data) /* Parse the mailbox to verify into the local address and host name parts, converting the host name to an IDN A-label if necessary */ - result = smtp_parse_address(data, smtp->rcpt->data, + result = smtp_parse_address(smtp->rcpt->data, &address, &host); if(result) return result; @@ -615,7 +616,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data) /* Parse the FROM mailbox into the local address and host name parts, converting the host name to an IDN A-label if necessary */ - result = smtp_parse_address(data, data->set.str[STRING_MAIL_FROM], + result = smtp_parse_address(data->set.str[STRING_MAIL_FROM], &address, &host); if(result) return result; @@ -653,7 +654,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data) /* Parse the AUTH mailbox into the local address and host name parts, converting the host name to an IDN A-label if necessary */ - result = smtp_parse_address(data, data->set.str[STRING_MAIL_AUTH], + result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH], &address, &host); if(result) { free(from); @@ -790,7 +791,7 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data) /* Parse the recipient mailbox into the local address and host name parts, converting the host name to an IDN A-label if necessary */ - result = smtp_parse_address(data, smtp->rcpt->data, + result = smtp_parse_address(smtp->rcpt->data, &address, &host); if(result) return result; @@ -1782,8 +1783,8 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data) * calling function deems it to be) then the input will simply be returned in * the address part with the host name being NULL. */ -static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma, - char **address, struct hostname *host) +static CURLcode smtp_parse_address(const char *fqma, char **address, + struct hostname *host) { CURLcode result = CURLE_OK; size_t length; @@ -1807,7 +1808,7 @@ static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma, host->name = host->name + 1; /* Attempt to convert the host name to IDN ACE */ - (void) Curl_idnconvert_hostname(data, host); + (void) Curl_idnconvert_hostname(host); /* If Curl_idnconvert_hostname() fails then we shall attempt to continue and send the host name using UTF-8 rather than as 7-bit ACE (which is diff --git a/lib/url.c b/lib/url.c index 4f88fa9846..3ab63a068f 100644 --- a/lib/url.c +++ b/lib/url.c @@ -61,24 +61,9 @@ #include -#ifdef USE_LIBIDN2 -#include - -#if defined(WIN32) && defined(UNICODE) -#define IDN2_LOOKUP(name, host, flags) \ - idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags) -#else -#define IDN2_LOOKUP(name, host, flags) \ - idn2_lookup_ul((const char *)name, (char **)host, flags) -#endif -#elif defined(USE_WIN32_IDN) -#include "idn.h" -#endif /* USE_LIBIDN2 */ - #include "doh.h" #include "urldata.h" #include "netrc.h" - #include "formdata.h" #include "mime.h" #include "vtls/vtls.h" @@ -106,6 +91,7 @@ #include "hsts.h" #include "noproxy.h" #include "cfilters.h" +#include "idn.h" /* And now for the protocols */ #include "ftp.h" @@ -1548,111 +1534,6 @@ void Curl_verboseconnect(struct Curl_easy *data, } #endif -/* - * Helpers for IDNA conversions. - */ -bool Curl_is_ASCII_name(const char *hostname) -{ - /* get an UNSIGNED local version of the pointer */ - const unsigned char *ch = (const unsigned char *)hostname; - - if(!hostname) /* bad input, consider it ASCII! */ - return TRUE; - - while(*ch) { - if(*ch++ & 0x80) - return FALSE; - } - return TRUE; -} - -/* - * Perform any necessary IDN conversion of hostname - */ -CURLcode Curl_idnconvert_hostname(struct Curl_easy *data, - struct hostname *host) -{ -#ifndef USE_LIBIDN2 - (void)data; - (void)data; -#elif defined(CURL_DISABLE_VERBOSE_STRINGS) - (void)data; -#endif - - /* set the name we use to display the host name */ - host->dispname = host->name; - - /* Check name for non-ASCII and convert hostname to ACE form if we can */ - if(!Curl_is_ASCII_name(host->name)) { -#ifdef USE_LIBIDN2 - if(idn2_check_version(IDN2_VERSION)) { - char *ace_hostname = NULL; -#if IDN2_VERSION_NUMBER >= 0x00140000 - /* IDN2_NFC_INPUT: Normalize input string using normalization form C. - IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional - processing. */ - int flags = IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL; -#else - int flags = IDN2_NFC_INPUT; -#endif - int rc = IDN2_LOOKUP(host->name, &ace_hostname, flags); - if(rc != IDN2_OK) - /* fallback to TR46 Transitional mode for better IDNA2003 - compatibility */ - rc = IDN2_LOOKUP(host->name, &ace_hostname, - IDN2_TRANSITIONAL); - if(rc == IDN2_OK) { - host->encalloc = (char *)ace_hostname; - /* change the name pointer to point to the encoded hostname */ - host->name = host->encalloc; - } - else { - failf(data, "Failed to convert %s to ACE; %s", host->name, - idn2_strerror(rc)); - return CURLE_URL_MALFORMAT; - } - } -#elif defined(USE_WIN32_IDN) - char *ace_hostname = NULL; - - if(Curl_win32_idn_to_ascii(host->name, &ace_hostname)) { - host->encalloc = ace_hostname; - /* change the name pointer to point to the encoded hostname */ - host->name = host->encalloc; - } - else { - char buffer[STRERROR_LEN]; - failf(data, "Failed to convert %s to ACE; %s", host->name, - Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer))); - return CURLE_URL_MALFORMAT; - } -#else - infof(data, "IDN support not present, can't parse Unicode domains"); -#endif - } - return CURLE_OK; -} - -/* - * Frees data allocated by idnconvert_hostname() - */ -void Curl_free_idnconverted_hostname(struct hostname *host) -{ -#if defined(USE_LIBIDN2) - if(host->encalloc) { - idn2_free(host->encalloc); /* must be freed with idn2_free() since this was - allocated by libidn */ - host->encalloc = NULL; - } -#elif defined(USE_WIN32_IDN) - free(host->encalloc); /* must be freed with free() since this was - allocated by Curl_win32_idn_to_ascii */ - host->encalloc = NULL; -#else - (void)host; -#endif -} - /* * Allocate and initialize a new connectdata object. */ @@ -1992,11 +1873,11 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, /************************************************************* * IDN-convert the hostnames *************************************************************/ - result = Curl_idnconvert_hostname(data, &conn->host); + result = Curl_idnconvert_hostname(&conn->host); if(result) return result; if(conn->bits.conn_to_host) { - result = Curl_idnconvert_hostname(data, &conn->conn_to_host); + result = Curl_idnconvert_hostname(&conn->conn_to_host); if(result) return result; } @@ -3664,12 +3545,12 @@ static CURLcode create_conn(struct Curl_easy *data, *************************************************************/ #ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy) { - result = Curl_idnconvert_hostname(data, &conn->http_proxy.host); + result = Curl_idnconvert_hostname(&conn->http_proxy.host); if(result) return result; } if(conn->bits.socksproxy) { - result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host); + result = Curl_idnconvert_hostname(&conn->socks_proxy.host); if(result) return result; } diff --git a/lib/url.h b/lib/url.h index 26c11ee735..1a03c564c6 100644 --- a/lib/url.h +++ b/lib/url.h @@ -49,11 +49,6 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len, const struct Curl_handler *Curl_builtin_scheme(const char *scheme, size_t schemelen); -bool Curl_is_ASCII_name(const char *hostname); -CURLcode Curl_idnconvert_hostname(struct Curl_easy *data, - struct hostname *host); -void Curl_free_idnconverted_hostname(struct hostname *host); - #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ #define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless specified */