]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Don't set locale globally, just use it when needed
authorOndřej Surý <ondrej@sury.org>
Tue, 22 Jun 2021 11:05:15 +0000 (13:05 +0200)
committerOndřej Surý <ondrej@sury.org>
Wed, 23 Jun 2021 09:12:00 +0000 (11:12 +0200)
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
bin/dig/host.c
bin/named/main.c
configure.ac

index da87423d6fa0cb192ff69c2c89d113ccf8789b80..fd4c7389ffa5a8e160dd0dfe1c02b903fd379b12 100644 (file)
 #include <errno.h>
 #include <inttypes.h>
 #include <limits.h>
+#include <locale.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif /* ifdef HAVE_LOCALE_H */
-
 #ifdef HAVE_LIBIDN2
 #include <idn2.h>
 #endif /* HAVE_LIBIDN2 */
@@ -91,6 +88,9 @@
 #include <pk11/result.h>
 #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 */
 
index ba0bbe63d0bec74487ab28d74e937ed5ea522edc..602d7a61c204780e4b2955e3e57b72af27a05af2 100644 (file)
 
 #include <inttypes.h>
 #include <limits.h>
+#include <locale.h>
 #include <stdbool.h>
 #include <stdlib.h>
 
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif /* ifdef HAVE_LOCALE_H */
-
 #include <isc/app.h>
 #include <isc/attributes.h>
 #include <isc/commandline.h>
index 46f4b57a9c2e1009bbdd1163ceaa5480ac838be2..a513fc61ae20bc066060194d1aed35ce950b30b0 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <ctype.h>
 #include <inttypes.h>
+#include <locale.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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:"
index 4f059667537f506d9df30b3cb836ba30bff044a5..f1b3ac0b2cc1fec6d07c8830e847b93a6e93df55 100644 (file)
@@ -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?
 #