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? # diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 06ac91d793..d8a8fcb8e3 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -13,6 +13,7 @@ /* #define inline */ +#include #include #include #include @@ -9840,11 +9841,9 @@ setownercase(rdatasetheader_t *header, const dns_name_t *name) { memset(header->upper, 0, sizeof(header->upper)); fully_lower = true; for (i = 0; i < name->length; i++) { - if (name->ndata[i] >= 'A' && name->ndata[i] <= 'Z') { - { - header->upper[i / 8] |= 1 << (i % 8); - fully_lower = false; - } + if (isupper(name->ndata[i])) { + header->upper[i / 8] |= 1 << (i % 8); + fully_lower = false; } } RDATASET_ATTR_SET(header, RDATASET_ATTR_CASESET); @@ -9869,24 +9868,6 @@ rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) { isc_rwlocktype_write); } -static const unsigned char maptolower[256] = { - ['A'] = 'a', ['B'] = 'b', ['C'] = 'c', ['D'] = 'd', ['E'] = 'e', - ['F'] = 'f', ['G'] = 'g', ['H'] = 'h', ['I'] = 'i', ['J'] = 'j', - ['K'] = 'k', ['L'] = 'l', ['M'] = 'm', ['N'] = 'n', ['O'] = 'o', - ['P'] = 'p', ['Q'] = 'q', ['R'] = 'r', ['S'] = 's', ['T'] = 't', - ['U'] = 'u', ['V'] = 'v', ['W'] = 'w', ['X'] = 'x', ['Y'] = 'y', - ['Z'] = 'z', -}; - -static const unsigned char maptoupper[256] = { - ['a'] = 'A', ['b'] = 'B', ['c'] = 'C', ['d'] = 'D', ['e'] = 'E', - ['f'] = 'F', ['g'] = 'G', ['h'] = 'H', ['i'] = 'I', ['j'] = 'J', - ['k'] = 'K', ['l'] = 'L', ['m'] = 'M', ['n'] = 'N', ['o'] = 'O', - ['p'] = 'P', ['q'] = 'Q', ['r'] = 'R', ['s'] = 'S', ['t'] = 'T', - ['u'] = 'U', ['v'] = 'V', ['w'] = 'W', ['x'] = 'X', ['y'] = 'Y', - ['z'] = 'Z', -}; - static void rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { dns_rbtdb_t *rbtdb = rdataset->private1; @@ -9907,15 +9888,10 @@ rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { if (ISC_LIKELY(CASEFULLYLOWER(header))) { for (size_t i = 0; i < name->length; i++) { - uint8_t c = name->ndata[i]; - if (c >= 'A' && c <= 'Z') { - name->ndata[i] = maptolower[c]; - } + name->ndata[i] = tolower(name->ndata[i]); } } else { for (size_t i = 0; i < name->length; i++) { - uint8_t c = name->ndata[i]; - if (mask == (1 << 7)) { bits = header->upper[i / 8]; mask = 1; @@ -9923,15 +9899,9 @@ rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { mask <<= 1; } - if (c >= 'a' && c <= 'z') { - if ((bits & mask) != 0) { - name->ndata[i] = maptoupper[c]; - } - } else if (c >= 'A' && c <= 'Z') { - if ((bits & mask) == 0) { - name->ndata[i] = maptolower[c]; - } - } + name->ndata[i] = ((bits & mask) != 0) + ? toupper(name->ndata[i]) + : tolower(name->ndata[i]); } }