From 0d35b3f1a95ba0fd90fd93f1e146a4bf4396f794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Tue, 22 Jun 2021 13:05:15 +0200 Subject: [PATCH] Don't set locale globally, just use it when needed Previously, we would set the locale on a global level and that could possibly lead to different behaviour in underlying functions. In this commit, we change to code to use the system locale only when calling the libidn2 functions and reset the locale back to "POSIX" when exiting the libidn2 code. --- bin/dig/dighost.c | 41 ++++++++++++++++++++++++++--------------- bin/dig/host.c | 5 +---- bin/named/main.c | 13 +++++++++++++ configure.ac | 6 ------ 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index da87423d6f..fd4c7389ff 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -22,15 +22,12 @@ #include #include #include +#include #include #include #include #include -#ifdef HAVE_LOCALE_H -#include -#endif /* ifdef HAVE_LOCALE_H */ - #ifdef HAVE_LIBIDN2 #include #endif /* HAVE_LIBIDN2 */ @@ -91,6 +88,9 @@ #include #endif /* if USE_PKCS11 */ +#define systemlocale(l) (void)setlocale(l, "") +#define resetlocale(l) (void)setlocale(l, "C") + dig_lookuplist_t lookup_list; dig_serverlist_t server_list; dig_searchlistlist_t search_list; @@ -1295,11 +1295,6 @@ setup_system(bool ipv4only, bool ipv6only) { irs_resconf_destroy(&resconf); -#ifdef HAVE_SETLOCALE - /* Set locale */ - (void)setlocale(LC_ALL, ""); -#endif /* ifdef HAVE_SETLOCALE */ - if (keyfile[0] != 0) { setup_file_key(); } else if (keysecret[0] != 0) { @@ -4288,8 +4283,9 @@ destroy_libs(void) { #ifdef HAVE_LIBIDN2 static isc_result_t idn_output_filter(isc_buffer_t *buffer, unsigned int used_org) { - char src[MXNAME], *dst; + char src[MXNAME], *dst = NULL; size_t srclen, dstlen; + isc_result_t result = ISC_R_SUCCESS; /* * Copy name from 'buffer' to 'src' and terminate it with NULL. @@ -4297,23 +4293,27 @@ idn_output_filter(isc_buffer_t *buffer, unsigned int used_org) { srclen = isc_buffer_usedlength(buffer) - used_org; if (srclen >= sizeof(src)) { warn("Input name too long to perform IDN conversion"); - return (ISC_R_SUCCESS); + goto cleanup; } memmove(src, (char *)isc_buffer_base(buffer) + used_org, srclen); src[srclen] = '\0'; + systemlocale(LC_ALL); + /* * Convert 'src' to the current locale's character encoding. */ idn_ace_to_locale(src, &dst); + resetlocale(LC_ALL); + /* * Check whether the converted name will fit back into 'buffer'. */ dstlen = strlen(dst); if (isc_buffer_length(buffer) < used_org + dstlen) { - idn2_free(dst); - return (ISC_R_NOSPACE); + result = ISC_R_NOSPACE; + goto cleanup; } /* @@ -4326,9 +4326,12 @@ idn_output_filter(isc_buffer_t *buffer, unsigned int used_org) { /* * Clean up. */ - idn2_free(dst); +cleanup: + if (dst != NULL) { + idn2_free(dst); + } - return (ISC_R_SUCCESS); + return (result); } /*% @@ -4344,6 +4347,8 @@ idn_locale_to_ace(const char *src, char *dst, size_t dstlen) { char *ascii_src; int res; + systemlocale(LC_ALL); + /* * We trust libidn2 to return an error if 'src' is too large to be a * valid domain name. @@ -4364,6 +4369,8 @@ idn_locale_to_ace(const char *src, char *dst, size_t dstlen) { (void)strlcpy(dst, final_src, dstlen); idn2_free(ascii_src); + + resetlocale(LC_ALL); } /*% @@ -4378,6 +4385,8 @@ idn_ace_to_locale(const char *src, char **dst) { char *local_src, *utf8_src; int res; + systemlocale(LC_ALL); + /* * We need to: * @@ -4443,6 +4452,8 @@ idn_ace_to_locale(const char *src, char **dst) { idn2_free(utf8_src); *dst = local_src; + + resetlocale(LC_ALL); } #endif /* HAVE_LIBIDN2 */ diff --git a/bin/dig/host.c b/bin/dig/host.c index ba0bbe63d0..602d7a61c2 100644 --- a/bin/dig/host.c +++ b/bin/dig/host.c @@ -13,13 +13,10 @@ #include #include +#include #include #include -#ifdef HAVE_LOCALE_H -#include -#endif /* ifdef HAVE_LOCALE_H */ - #include #include #include diff --git a/bin/named/main.c b/bin/named/main.c index 46f4b57a9c..a513fc61ae 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -1423,6 +1424,18 @@ main(int argc, char *argv[]) { xmlInitThreads(); #endif /* HAVE_LIBXML2 */ + /* + * Technically, this call is superfluous because on startup of the main + * program, the portable "C" locale is selected by default. This + * explicit call here is for a reference that the BIND 9 code base is + * not locale aware and the locale MUST be set to "C" (or "POSIX") when + * calling any BIND 9 library code. If you are calling external + * libraries that use locale, such calls must be wrapped into + * setlocale(LC_ALL, ""); before the call and setlocale(LC_ALL, "C"); + * after the call, and no BIND 9 library calls must be made in between. + */ + setlocale(LC_ALL, "C"); + /* * Record version in core image. * strings named.core | grep "named version:" diff --git a/configure.ac b/configure.ac index 4f05966753..f1b3ac0b2c 100644 --- a/configure.ac +++ b/configure.ac @@ -1363,12 +1363,6 @@ AC_SUBST([CMOCKA_LIBS]) AM_CONDITIONAL([HAVE_CMOCKA], [test "$with_cmocka" = "yes"]) -# -# Check for i18n -# -AC_CHECK_HEADERS(locale.h) -AC_CHECK_FUNCS(setlocale) - # # was --with-tuning specified? #