diff --git a/NEWS b/NEWS index 481f13ba64..36633d36d6 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,10 @@ CHANGES WITH 260 in spe: * Meson options '-Dintegration-tests=' and '-Dcryptolib=' (deprecated in v258) have been removed. + * Support for libidn has been removed. IDN functionality now requires + libidn2. The corresponding meson option '-Dlibidn=' is deprecated + too and will be dropped in a future release. + CHANGES WITH 259: Announcements of Future Feature Removals and Incompatible Changes: diff --git a/README b/README index 2d6d30dc78..766863e4bc 100644 --- a/README +++ b/README @@ -240,7 +240,7 @@ REQUIREMENTS: libqrencode >= 3 (optional) libmicrohttpd >= 0.9.33 (optional) libcurl >= 7.32.0 (optional) - libidn2 or libidn (optional) + libidn2 (optional) gnutls >= 3.1.4 (optional) openssl >= 3.0.0 (optional, required to support DNS-over-TLS) p11-kit >= 0.23.3 (optional) diff --git a/TODO b/TODO index 9590ebb5d0..da8cddce0f 100644 --- a/TODO +++ b/TODO @@ -563,8 +563,6 @@ Features: * port copy.c over to use LabelOps for all labelling. -* get rid of compat with libidn.so.11 (retain only for libidn.so.12) - * get rid of compat with libbpf.so.0 (retainly only for libbpf.so.1) * define a generic "report" varlink interface, which services can implement to diff --git a/meson.build b/meson.build index ff8cb279a8..de685fe9ce 100644 --- a/meson.build +++ b/meson.build @@ -1290,18 +1290,10 @@ libcurl = dependency('libcurl', conf.set10('HAVE_LIBCURL', libcurl.found()) conf.set10('CURL_NO_OLDIES', conf.get('BUILD_MODE_DEVELOPER') == 1) -feature = get_option('libidn2').disable_auto_if(get_option('libidn').enabled()) -libidn = dependency('libidn2', - required : feature) -have = libidn.found() -if not have - # libidn is used for both libidn and libidn2 objects - libidn = dependency('libidn', - required : get_option('libidn')) -endif -libidn_cflags = libidn.partial_dependency(includes: true, compile_args: true) -conf.set10('HAVE_LIBIDN', not have and libidn.found()) -conf.set10('HAVE_LIBIDN2', have) +libidn2 = dependency('libidn2', + required : get_option('libidn2')) +libidn2_cflags = libidn2.partial_dependency(includes: true, compile_args: true) +conf.set10('HAVE_LIBIDN2', libidn2.found()) libqrencode = dependency('libqrencode', version : '>= 3', @@ -3118,7 +3110,6 @@ foreach tuple : [ ['libcurl'], ['libfdisk'], ['libfido2'], - ['libidn'], ['libidn2'], ['microhttpd'], ['openssl'], diff --git a/meson_options.txt b/meson_options.txt index acf1205b36..e43c0a21c4 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -438,7 +438,7 @@ option('idn', type : 'boolean', description : 'use IDN when printing hostnames') option('libidn2', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, description : 'libidn2 support') -option('libidn', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, +option('libidn', type : 'feature', deprecated : true, description : 'libidn support') option('libiptc', type : 'feature', deprecated : true, description : 'libiptc support') diff --git a/src/basic/build.c b/src/basic/build.c index b9341b184d..f5695eeb93 100644 --- a/src/basic/build.c +++ b/src/basic/build.c @@ -120,12 +120,6 @@ const char* const systemd_features = " -IDN2" #endif -#if HAVE_LIBIDN - " +IDN" -#else - " -IDN" -#endif - #if HAVE_KMOD " +KMOD" #else diff --git a/src/resolve/meson.build b/src/resolve/meson.build index 49ac293f51..be2979343f 100644 --- a/src/resolve/meson.build +++ b/src/resolve/meson.build @@ -68,6 +68,7 @@ endif resolve_common_template = { 'dependencies' : [ + libidn2_cflags, libopenssl, libm, threads, @@ -91,9 +92,6 @@ executables += [ 'resolvconf-compat.c', 'resolvectl.c', ), - 'dependencies' : resolve_common_template['dependencies'] + [ - libidn, - ], 'objects' : ['systemd-resolved'], }, resolve_test_template + { diff --git a/src/resolve/resolved-util.c b/src/resolve/resolved-util.c index 8b7f0ed44a..eec2819767 100644 --- a/src/resolve/resolved-util.c +++ b/src/resolve/resolved-util.c @@ -12,11 +12,6 @@ int resolve_system_hostname(char **full_hostname, char **first_label) { _cleanup_free_ char *h = NULL, *n = NULL; -#if HAVE_LIBIDN2 - _cleanup_free_ char *utf8 = NULL; -#elif HAVE_LIBIDN - int k; -#endif char label[DNS_LABEL_MAX+1]; const char *p, *decoded; int r; @@ -38,15 +33,10 @@ int resolve_system_hostname(char **full_hostname, char **first_label) { return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Couldn't find a single label in hostname."); -#if HAVE_LIBIDN || HAVE_LIBIDN2 - r = dlopen_idn(); - if (r < 0) { - log_debug_errno(r, "Failed to initialize IDN support, ignoring: %m"); - decoded = label; /* no decoding */ - } else -#endif - { #if HAVE_LIBIDN2 + _cleanup_free_ char *utf8 = NULL; + + if (dlopen_idn() >= 0) { r = sym_idn2_to_unicode_8z8z(label, &utf8, 0); if (r != IDN2_OK) return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN), @@ -55,21 +45,9 @@ int resolve_system_hostname(char **full_hostname, char **first_label) { r = strlen(utf8); decoded = utf8; -#elif HAVE_LIBIDN - k = dns_label_undo_idna(label, r, label, sizeof label); - if (k < 0) - return log_debug_errno(k, "Failed to undo IDNA: %m"); - if (k > 0) - r = k; - - if (!utf8_is_valid(label)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "System hostname is not UTF-8 clean."); - decoded = label; -#else - decoded = label; /* no decoding */ + } else #endif - } + decoded = label; /* no decoding */ r = dns_label_escape_new(decoded, r, &n); if (r < 0) diff --git a/src/resolve/test-dns-query.c b/src/resolve/test-dns-query.c index de561aa8b7..3fcc93d9e4 100644 --- a/src/resolve/test-dns-query.c +++ b/src/resolve/test-dns-query.c @@ -85,7 +85,7 @@ TEST(dns_query_new_multi_question_different_domain) { ASSERT_NULL(query); } -#if HAVE_LIBIDN || HAVE_LIBIDN2 +#if HAVE_LIBIDN2 TEST(dns_query_new_same_utf8_and_idna) { Manager manager = {}; _cleanup_(dns_question_unrefp) DnsQuestion *q_utf8 = NULL, *q_idna = NULL; @@ -434,7 +434,7 @@ TEST(dns_query_process_cname_one_success_match_dname) { dns_resource_key_unref(key); } -#if HAVE_LIBIDN || HAVE_LIBIDN2 +#if HAVE_LIBIDN2 TEST(dns_query_process_cname_one_success_match_dname_utf8_same) { Manager manager = {}; _cleanup_(dns_question_unrefp) DnsQuestion *q_utf8 = NULL, *q_idna = NULL; diff --git a/src/resolve/test-dns-question.c b/src/resolve/test-dns-question.c index c30739a595..2fb5b8ca4f 100644 --- a/src/resolve/test-dns-question.c +++ b/src/resolve/test-dns-question.c @@ -62,7 +62,7 @@ TEST(dns_question_new_address) { ASSERT_OK_POSITIVE(dns_question_contains_key(question, key6)); } -#if HAVE_LIBIDN || HAVE_LIBIDN2 +#if HAVE_LIBIDN2 TEST(dns_question_new_address_convert_idna) { _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; @@ -162,7 +162,7 @@ TEST(dns_question_new_service) { question = dns_question_unref(question); key = dns_resource_key_unref(key); -#if HAVE_LIBIDN || HAVE_LIBIDN2 +#if HAVE_LIBIDN2 /* convert idna with type */ ASSERT_OK(dns_question_new_service( &question, diff --git a/src/resolve/test-dnssec-complex.c b/src/resolve/test-dnssec-complex.c index 7dab5b8fe0..f486cf09a3 100644 --- a/src/resolve/test-dnssec-complex.c +++ b/src/resolve/test-dnssec-complex.c @@ -195,7 +195,7 @@ int main(int argc, char* argv[]) { test_hostname_lookup(bus, "poettering.de", AF_INET, NULL); test_hostname_lookup(bus, "poettering.de", AF_INET6, NULL); -#if HAVE_LIBIDN2 || HAVE_LIBIDN +#if HAVE_LIBIDN2 /* Unsigned A with IDNA conversion necessary */ test_hostname_lookup(bus, "pöttering.de", AF_UNSPEC, NULL); test_hostname_lookup(bus, "pöttering.de", AF_INET, NULL); diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index c5805a593b..727e1d0625 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -301,111 +301,6 @@ int dns_name_parent(const char **name) { return dns_label_unescape(name, NULL, DNS_LABEL_MAX, 0); } -#if HAVE_LIBIDN -int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) { - _cleanup_free_ uint32_t *input = NULL; - size_t input_size, l; - bool contains_8_bit = false; - char buffer[DNS_LABEL_MAX+1]; - int r; - - assert(encoded); - assert(decoded); - - /* Converts a U-label into an A-label */ - - r = dlopen_idn(); - if (r < 0) - return r; - - if (encoded_size <= 0) - return -EINVAL; - - for (const char *p = encoded; p < encoded + encoded_size; p++) - if ((uint8_t) *p > 127) - contains_8_bit = true; - - if (!contains_8_bit) { - if (encoded_size > DNS_LABEL_MAX) - return -EINVAL; - - return 0; - } - - input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); - if (!input) - return -ENOMEM; - - if (sym_idna_to_ascii_4i(input, input_size, buffer, 0) != 0) - return -EINVAL; - - l = strlen(buffer); - - /* Verify that the result is not longer than one DNS label. */ - if (l <= 0 || l > DNS_LABEL_MAX) - return -EINVAL; - if (l > decoded_max) - return -ENOBUFS; - - memcpy(decoded, buffer, l); - - /* If there's room, append a trailing NUL byte, but only then */ - if (decoded_max > l) - decoded[l] = 0; - - return (int) l; -} - -int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) { - size_t input_size, output_size; - _cleanup_free_ uint32_t *input = NULL; - _cleanup_free_ char *result = NULL; - uint32_t *output = NULL; - size_t w; - int r; - - /* To be invoked after unescaping. Converts an A-label into a U-label. */ - - assert(encoded); - assert(decoded); - - r = dlopen_idn(); - if (r < 0) - return r; - - if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX) - return -EINVAL; - - if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX)) - return 0; - - input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); - if (!input) - return -ENOMEM; - - output_size = input_size; - output = newa(uint32_t, output_size); - - sym_idna_to_unicode_44i(input, input_size, output, &output_size, 0); - - result = sym_stringprep_ucs4_to_utf8(output, output_size, NULL, &w); - if (!result) - return -ENOMEM; - if (w <= 0) - return -EINVAL; - if (w > decoded_max) - return -ENOBUFS; - - memcpy(decoded, result, w); - - /* Append trailing NUL byte if there's space, but only then. */ - if (decoded_max > w) - decoded[w] = 0; - - return w; -} -#endif - int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret) { _cleanup_free_ char *result = NULL; size_t n_result = 0, n_unescaped = 0; @@ -1369,7 +1264,7 @@ int dns_name_apply_idna(const char *name, char **ret) { /* Return negative on error, 0 if not implemented, positive on success. */ -#if HAVE_LIBIDN2 || HAVE_LIBIDN2 +#if HAVE_LIBIDN2 int r; r = dlopen_idn(); @@ -1379,9 +1274,7 @@ int dns_name_apply_idna(const char *name, char **ret) { } if (r < 0) return r; -#endif -#if HAVE_LIBIDN2 _cleanup_free_ char *t = NULL; assert(name); @@ -1429,55 +1322,6 @@ int dns_name_apply_idna(const char *name, char **ret) { return -ENOSPC; return -EINVAL; -#elif HAVE_LIBIDN - _cleanup_free_ char *buf = NULL; - size_t n = 0; - bool first = true; - int r, q; - - assert(name); - assert(ret); - - for (;;) { - char label[DNS_LABEL_MAX+1]; - - r = dns_label_unescape(&name, label, sizeof label, 0); - if (r < 0) - return r; - if (r == 0) - break; - - q = dns_label_apply_idna(label, r, label, sizeof label); - if (q < 0) - return q; - if (q > 0) - r = q; - - if (!GREEDY_REALLOC(buf, n + !first + DNS_LABEL_ESCAPED_MAX)) - return -ENOMEM; - - r = dns_label_escape(label, r, buf + n + !first, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; - - if (first) - first = false; - else - buf[n++] = '.'; - - n += r; - } - - if (n > DNS_HOSTNAME_MAX) - return -EINVAL; - - if (!GREEDY_REALLOC(buf, n + 1)) - return -ENOMEM; - - buf[n] = 0; - *ret = TAKE_PTR(buf); - - return 1; #else *ret = NULL; return 0; diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 0491aa9370..f2fb2f0cea 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -16,11 +16,6 @@ int dns_label_escape_new(const char *p, size_t l, char **ret); int dns_name_parent(const char **name); -#if HAVE_LIBIDN -int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); -int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); -#endif - int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret); static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char **ret) { diff --git a/src/shared/idn-util.c b/src/shared/idn-util.c index 0f39b55942..aad0db1426 100644 --- a/src/shared/idn-util.c +++ b/src/shared/idn-util.c @@ -1,21 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#if HAVE_LIBIDN2 -# include -#elif HAVE_LIBIDN -# include -# include -#endif - -#include "dlfcn-util.h" #include "idn-util.h" #include "log.h" /* IWYU pragma: keep */ -#if HAVE_LIBIDN || HAVE_LIBIDN2 static void* idn_dl = NULL; -#endif -#if HAVE_LIBIDN2 DLSYM_PROTOTYPE(idn2_lookup_u8) = NULL; const char *(*sym_idn2_strerror)(int rc) _const_ = NULL; DLSYM_PROTOTYPE(idn2_to_unicode_8z8z) = NULL; @@ -32,56 +21,3 @@ int dlopen_idn(void) { DLSYM_ARG(idn2_strerror), DLSYM_ARG(idn2_to_unicode_8z8z)); } -#endif - -#if HAVE_LIBIDN -DLSYM_PROTOTYPE(idna_to_ascii_4i) = NULL; -DLSYM_PROTOTYPE(idna_to_unicode_44i) = NULL; -DLSYM_PROTOTYPE(stringprep_ucs4_to_utf8) = NULL; -DLSYM_PROTOTYPE(stringprep_utf8_to_ucs4) = NULL; - -int dlopen_idn(void) { - int r; - - ELF_NOTE_DLOPEN("idn", - "Support for internationalized domain names", - ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, - "libidn.so.12", "libidn.so.11"); - - if (idn_dl) - return 0; /* Already loaded */ - - r = check_dlopen_blocked("libidn.so.12"); - if (r < 0) - return r; - - _cleanup_(dlclosep) void *dl = NULL; - r = dlopen_safe("libidn.so.12", &dl, /* reterr_dlerror= */ NULL); - if (r < 0) { - /* libidn broke ABI in 1.34, but not in a way we care about (a new field got added to an - * open-coded struct we do not use), hence support both versions. */ - const char *dle = NULL; - r = dlopen_safe("libidn.so.11", &dl, &dle); - if (r < 0) { - log_debug_errno(r, "libidn support is not available: %s", dle ?: STRERROR(r)); - return -EOPNOTSUPP; /* turn into recognizable error */ - } - log_debug("Loaded 'libidn.so.11' via dlopen()"); - } else - log_debug("Loaded 'libidn.so.12' via dlopen()"); - - r = dlsym_many_or_warn( - dl, - LOG_DEBUG, - DLSYM_ARG(idna_to_ascii_4i), - DLSYM_ARG(idna_to_unicode_44i), - DLSYM_ARG(stringprep_ucs4_to_utf8), - DLSYM_ARG(stringprep_utf8_to_ucs4)); - if (r < 0) - return r; - - idn_dl = TAKE_PTR(dl); - - return 1; -} -#endif diff --git a/src/shared/idn-util.h b/src/shared/idn-util.h index 27213fb6c2..c971be9aef 100644 --- a/src/shared/idn-util.h +++ b/src/shared/idn-util.h @@ -1,34 +1,20 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#if HAVE_LIBIDN2 -# include -#elif HAVE_LIBIDN -# include -# include -#endif - #include "shared-forward.h" -#if HAVE_LIBIDN2 || HAVE_LIBIDN +#if HAVE_LIBIDN2 +#include + #include "dlfcn-util.h" +extern DLSYM_PROTOTYPE(idn2_lookup_u8); +extern const char *(*sym_idn2_strerror)(int rc) _const_; +extern DLSYM_PROTOTYPE(idn2_to_unicode_8z8z); + int dlopen_idn(void); #else static inline int dlopen_idn(void) { return -EOPNOTSUPP; } #endif - -#if HAVE_LIBIDN2 -extern DLSYM_PROTOTYPE(idn2_lookup_u8); -extern const char *(*sym_idn2_strerror)(int rc) _const_; -extern DLSYM_PROTOTYPE(idn2_to_unicode_8z8z); -#endif - -#if HAVE_LIBIDN -extern DLSYM_PROTOTYPE(idna_to_ascii_4i); -extern DLSYM_PROTOTYPE(idna_to_unicode_44i); -extern DLSYM_PROTOTYPE(stringprep_ucs4_to_utf8); -extern DLSYM_PROTOTYPE(stringprep_utf8_to_ucs4); -#endif diff --git a/src/shared/meson.build b/src/shared/meson.build index 36d38f4ed9..9fa976925a 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -92,7 +92,6 @@ shared_sources = files( 'hostname-setup.c', 'hwdb-util.c', 'id128-print.c', - 'idn-util.c', 'ima-util.c', 'image-policy.c', 'import-util.c', @@ -271,6 +270,10 @@ if conf.get('HAVE_LIBMOUNT') == 1 shared_sources += files('libmount-util.c') endif +if conf.get('HAVE_LIBIDN2') == 1 + shared_sources += files('idn-util.c') +endif + generate_ip_protocol_list = files('generate-ip-protocol-list.sh') ip_protocol_list_txt = custom_target( input : [generate_ip_protocol_list, ipproto_sources], @@ -374,7 +377,7 @@ libshared_deps = [threads, libelf_cflags, libfido2_cflags, libgcrypt_cflags, - libidn_cflags, + libidn2_cflags, libkmod_cflags, libmount_cflags, libopenssl, diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index 10b8da1e9c..4b80532698 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -47,7 +47,7 @@ static int run(int argc, char **argv) { ASSERT_DLOPEN(dlopen_dw, HAVE_ELFUTILS); ASSERT_DLOPEN(dlopen_elf, HAVE_ELFUTILS); ASSERT_DLOPEN(dlopen_gcrypt, HAVE_GCRYPT); - ASSERT_DLOPEN(dlopen_idn, HAVE_LIBIDN2 || HAVE_LIBIDN); + ASSERT_DLOPEN(dlopen_idn, HAVE_LIBIDN2); ASSERT_DLOPEN(dlopen_libacl, HAVE_ACL); ASSERT_DLOPEN(dlopen_libapparmor, HAVE_APPARMOR); ASSERT_DLOPEN(dlopen_libarchive, HAVE_LIBARCHIVE); diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index e041fb9cda..da67b2304b 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -788,7 +788,7 @@ static void test_dns_name_apply_idna_one(const char *s, int expected, const char } TEST(dns_name_apply_idna) { - const int ret = HAVE_LIBIDN2 | HAVE_LIBIDN; + const int ret = HAVE_LIBIDN2; /* IDNA2008 forbids names with hyphens in third and fourth positions * (https://tools.ietf.org/html/rfc5891#section-4.2.3.1). @@ -798,7 +798,6 @@ TEST(dns_name_apply_idna) { * labels. If registrars follow IDNA2008 we'll just be performing a * useless lookup. */ - const int ret2 = HAVE_LIBIDN; test_dns_name_apply_idna_one("", ret, ""); test_dns_name_apply_idna_one("foo", ret, "foo"); @@ -811,14 +810,13 @@ TEST(dns_name_apply_idna) { test_dns_name_apply_idna_one("föö.bär.", ret, "xn--f-1gaa.xn--br-via"); test_dns_name_apply_idna_one("xn--f-1gaa.xn--br-via", ret, "xn--f-1gaa.xn--br-via"); - test_dns_name_apply_idna_one("_443._tcp.fedoraproject.org", ret2, + test_dns_name_apply_idna_one("_443._tcp.fedoraproject.org", 0, "_443._tcp.fedoraproject.org"); - test_dns_name_apply_idna_one("_443", ret2, "_443"); - test_dns_name_apply_idna_one("gateway", ret, "gateway"); - test_dns_name_apply_idna_one("_gateway", ret2, "_gateway"); + test_dns_name_apply_idna_one("_443", 0, "_443"); + test_dns_name_apply_idna_one("gateway", 0, "gateway"); + test_dns_name_apply_idna_one("_gateway", 0, "_gateway"); - test_dns_name_apply_idna_one("r3---sn-ab5l6ne7.googlevideo.com", ret2, - ret2 ? "r3---sn-ab5l6ne7.googlevideo.com" : ""); + test_dns_name_apply_idna_one("r3---sn-ab5l6ne7.googlevideo.com", 0, ""); } TEST(dns_name_is_valid_or_address) {