mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
resolved: support libidn2 in addition to libidn
libidn2 2.0.0 supports IDNA2008, in contrast to libidn which supports IDNA2003. https://bugzilla.redhat.com/show_bug.cgi?id=1449145 From that bug report: Internationalized domain names exist for quite some time (IDNA2003), although the protocols describing them have evolved in an incompatible way (IDNA2008). These incompatibilities will prevent applications written for IDNA2003 to access certain problematic domain names defined with IDNA2008, e.g., faß.de is translated to domain xn--fa-hia.de with IDNA2008, while in IDNA2003 it is translated to fass.de domain. That not only causes incompatibility problems, but may be used as an attack vector to redirect users to different web sites. v2: - keep libidn support - require libidn2 >= 2.0.0 v3: - keep dns_name_apply_idna caller dumb, and keep the #ifdefs inside of the function. - use both ±IDN and ±IDN2 in the version string
This commit is contained in:
parent
9bfc0df113
commit
87057e244b
@ -1137,6 +1137,7 @@ libshared_la_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
$(ACL_CFLAGS) \
|
||||
$(LIBIDN_CFLAGS) \
|
||||
$(LIBIDN2_CFLAGS) \
|
||||
$(SECCOMP_CFLAGS) \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(LIBCRYPTSETUP_CFLAGS)
|
||||
@ -1148,6 +1149,7 @@ libshared_la_LIBADD = \
|
||||
libudev-internal.la \
|
||||
$(ACL_LIBS) \
|
||||
$(LIBIDN_LIBS) \
|
||||
$(LIBIDN2_LIBS) \
|
||||
$(SECCOMP_LIBS) \
|
||||
$(BLKID_LIBS) \
|
||||
$(LIBCRYPTSETUP_LIBS)
|
||||
@ -1171,6 +1173,7 @@ libsystemd_shared_la_CFLAGS = \
|
||||
$(libudev_internal_la_CFLAGS) \
|
||||
$(ACL_CFLAGS) \
|
||||
$(LIBIDN_CFLAGS) \
|
||||
$(LIBIDN2_CFLAGS) \
|
||||
$(SECCOMP_CFLAGS) \
|
||||
$(BLKID_CFLAGS) \
|
||||
$(LIBCRYPTSETUP_CFLAGS) \
|
||||
@ -1185,6 +1188,7 @@ libsystemd_shared_la_LIBADD = \
|
||||
$(libudev_internal_la_LIBADD) \
|
||||
$(ACL_LIBS) \
|
||||
$(LIBIDN_LIBS) \
|
||||
$(LIBIDN2_LIBS) \
|
||||
$(SECCOMP_LIBS) \
|
||||
$(BLKID_LIBS) \
|
||||
$(LIBCRYPTSETUP_LIBS)
|
||||
|
2
README
2
README
@ -142,7 +142,7 @@ REQUIREMENTS:
|
||||
libqrencode (optional)
|
||||
libmicrohttpd (optional)
|
||||
libpython (optional)
|
||||
libidn (optional)
|
||||
libidn2 or libidn (optional)
|
||||
elfutils >= 158 (optional)
|
||||
make, gcc, and similar tools
|
||||
|
||||
|
33
configure.ac
33
configure.ac
@ -1015,16 +1015,32 @@ AM_CONDITIONAL(HAVE_LIBCURL, [test "$have_libcurl" = "yes"])
|
||||
AM_CONDITIONAL(HAVE_REMOTE, [test "$have_microhttpd" = "yes" -o "$have_libcurl" = "yes"])
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
have_libidn2=no
|
||||
AC_ARG_ENABLE(libidn2, AS_HELP_STRING([--disable-libidn2], [disable optional LIBIDN2 support]))
|
||||
if test "x$enable_libidn2" != "xno"; then
|
||||
PKG_CHECK_MODULES(LIBIDN2, [libidn2 >= 2.0.0],
|
||||
[AC_DEFINE(HAVE_LIBIDN2, 1, [Define if libidn2 is available])
|
||||
have_libidn2=yes
|
||||
M4_DEFINES="$M4_DEFINES -DHAVE_LIBIDN2"],
|
||||
[have_libidn2=no])
|
||||
if test "x$have_libidn2" = "xno" -a "x$enable_libidn2" = "xyes"; then
|
||||
AC_MSG_ERROR([*** libidn2 support requested but libraries not found])
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_LIBIDN2, [test "$have_libidn2" = "yes"])
|
||||
|
||||
have_libidn=no
|
||||
AC_ARG_ENABLE(libidn, AS_HELP_STRING([--disable-libidn], [disable optional LIBIDN support]))
|
||||
if test "x$enable_libidn" != "xno"; then
|
||||
PKG_CHECK_MODULES(LIBIDN, [libidn],
|
||||
[AC_DEFINE(HAVE_LIBIDN, 1, [Define if libidn is available])
|
||||
have_libidn=yes
|
||||
M4_DEFINES="$M4_DEFINES -DHAVE_LIBIDN"],
|
||||
[have_libidn=no])
|
||||
if test "x$have_libidn" = "xno" -a "x$enable_libidn" = "xyes"; then
|
||||
AC_MSG_ERROR([*** libidn support requested but libraries not found])
|
||||
if test "$have_libidn2" != "yes"; then
|
||||
if test "x$enable_libidn" != "xno"; then
|
||||
PKG_CHECK_MODULES(LIBIDN, [libidn],
|
||||
[AC_DEFINE(HAVE_LIBIDN, 1, [Define if libidn is available])
|
||||
have_libidn=yes
|
||||
M4_DEFINES="$M4_DEFINES -DHAVE_LIBIDN"],
|
||||
[have_libidn=no])
|
||||
if test "x$have_libidn" = "xno" -a "x$enable_libidn" = "xyes"; then
|
||||
AC_MSG_ERROR([*** libidn support requested but libraries not found])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_LIBIDN, [test "$have_libidn" = "yes"])
|
||||
@ -1715,6 +1731,7 @@ AC_MSG_RESULT([
|
||||
MICROHTTPD: ${have_microhttpd}
|
||||
GNUTLS: ${have_gnutls}
|
||||
libcurl: ${have_libcurl}
|
||||
libidn2: ${have_libidn2}
|
||||
libidn: ${have_libidn}
|
||||
libiptc: ${have_libiptc}
|
||||
ELFUTILS: ${have_elfutils}
|
||||
|
21
meson.build
21
meson.build
@ -791,15 +791,29 @@ else
|
||||
endif
|
||||
|
||||
want_libidn = get_option('libidn')
|
||||
if want_libidn != 'false'
|
||||
want_libidn2 = get_option('libidn2')
|
||||
if want_libidn == 'true' and want_libidn2 == 'true'
|
||||
error('libidn and libidn2 cannot be requested simultaneously')
|
||||
endif
|
||||
|
||||
if want_libidn2 != 'false' and want_libidn != 'true'
|
||||
libidn = dependency('libidn2',
|
||||
required : want_libidn2 == 'true')
|
||||
# libidn is used for both libidn and libidn2 objects
|
||||
if libidn.found()
|
||||
conf.set('HAVE_LIBIDN2', true)
|
||||
m4_defines += ['-DHAVE_LIBIDN2']
|
||||
endif
|
||||
else
|
||||
libidn = []
|
||||
endif
|
||||
if not conf.get('HAVE_LIBIDN2', false) and want_libidn != 'false'
|
||||
libidn = dependency('libidn',
|
||||
required : want_libidn == 'true')
|
||||
if libidn.found()
|
||||
conf.set('HAVE_LIBIDN', true)
|
||||
m4_defines += ['-DHAVE_LIBIDN']
|
||||
endif
|
||||
else
|
||||
libidn = []
|
||||
endif
|
||||
|
||||
want_libiptc = get_option('libiptc')
|
||||
@ -2428,6 +2442,7 @@ foreach tuple : [
|
||||
['microhttpd'],
|
||||
['gnutls'],
|
||||
['libcurl'],
|
||||
['libidn2'],
|
||||
['libidn'],
|
||||
['libiptc'],
|
||||
['elfutils'],
|
||||
|
@ -195,6 +195,8 @@ option('libcryptsetup', type : 'combo', choices : ['auto', 'true', 'false'],
|
||||
description : 'libcryptsetup support')
|
||||
option('libcurl', type : 'combo', choices : ['auto', 'true', 'false'],
|
||||
description : 'libcurl support')
|
||||
option('libidn2', type : 'combo', choices : ['auto', 'true', 'false'],
|
||||
description : 'libidn2 support')
|
||||
option('libidn', type : 'combo', choices : ['auto', 'true', 'false'],
|
||||
description : 'libidn support')
|
||||
option('libiptc', type : 'combo', choices : ['auto', 'true', 'false'],
|
||||
|
@ -127,6 +127,12 @@
|
||||
#define _KMOD_FEATURE_ "-KMOD"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBIDN2
|
||||
#define _IDN2_FEATURE_ "+IDN2"
|
||||
#else
|
||||
#define _IDN2_FEATURE_ "-IDN2"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBIDN
|
||||
#define _IDN_FEATURE_ "+IDN"
|
||||
#else
|
||||
@ -154,5 +160,6 @@
|
||||
_BLKID_FEATURE_ " " \
|
||||
_ELFUTILS_FEATURE_ " " \
|
||||
_KMOD_FEATURE_ " " \
|
||||
_IDN2_FEATURE_ " " \
|
||||
_IDN_FEATURE_ " " \
|
||||
_CGROUP_HIEARCHY_
|
||||
|
@ -309,8 +309,8 @@ int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bo
|
||||
r = dns_name_apply_idna(name, &buf);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
name = buf;
|
||||
if (r > 0)
|
||||
name = buf;
|
||||
}
|
||||
|
||||
q = dns_question_new(family == AF_UNSPEC ? 2 : 1);
|
||||
@ -422,8 +422,8 @@ int dns_question_new_service(
|
||||
r = dns_name_apply_idna(domain, &buf);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
domain = buf;
|
||||
if (r > 0)
|
||||
domain = buf;
|
||||
}
|
||||
|
||||
r = dns_service_join(service, type, domain, &joined);
|
||||
|
@ -21,6 +21,10 @@
|
||||
#include <poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifdef HAVE_LIBIDN2
|
||||
#include <idn2.h>
|
||||
#endif
|
||||
|
||||
#include "af-list.h"
|
||||
#include "alloc-util.h"
|
||||
#include "dirent-util.h"
|
||||
@ -324,9 +328,14 @@ static int manager_network_monitor_listen(Manager *m) {
|
||||
|
||||
static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
|
||||
_cleanup_free_ char *h = NULL, *n = NULL;
|
||||
#if defined(HAVE_LIBIDN2)
|
||||
_cleanup_free_ char *utf8 = NULL;
|
||||
#elif defined(HAVE_LIBIDN)
|
||||
int k;
|
||||
#endif
|
||||
char label[DNS_LABEL_MAX];
|
||||
const char *p;
|
||||
int r, k;
|
||||
const char *p, *decoded;
|
||||
int r;
|
||||
|
||||
assert(full_hostname);
|
||||
assert(llmnr_hostname);
|
||||
@ -339,7 +348,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
|
||||
return log_debug_errno(r, "Can't determine system hostname: %m");
|
||||
|
||||
p = h;
|
||||
r = dns_label_unescape(&p, label, sizeof(label));
|
||||
r = dns_label_unescape(&p, label, sizeof label);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to unescape host name: %m");
|
||||
if (r == 0) {
|
||||
@ -347,7 +356,16 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
k = dns_label_undo_idna(label, r, label, sizeof(label));
|
||||
#if defined(HAVE_LIBIDN2)
|
||||
r = idn2_to_unicode_8z8z(label, &utf8, 0);
|
||||
if (r != IDN2_OK)
|
||||
return log_error("Failed to undo IDNA: %s", idn2_strerror(r));
|
||||
assert(utf8_is_valid(utf8));
|
||||
|
||||
r = strlen(utf8);
|
||||
decoded = utf8;
|
||||
#elif defined(HAVE_LIBIDN)
|
||||
k = dns_label_undo_idna(label, r, label, sizeof label);
|
||||
if (k < 0)
|
||||
return log_error_errno(k, "Failed to undo IDNA: %m");
|
||||
if (k > 0)
|
||||
@ -357,8 +375,12 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
|
||||
log_error("System hostname is not UTF-8 clean.");
|
||||
return -EINVAL;
|
||||
}
|
||||
decoded = label;
|
||||
#else
|
||||
decoded = label; /* no decoding */
|
||||
#endif
|
||||
|
||||
r = dns_label_escape_new(label, r, &n);
|
||||
r = dns_label_escape_new(decoded, r, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to escape host name: %m");
|
||||
|
||||
|
@ -218,7 +218,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);
|
||||
|
||||
#ifdef HAVE_LIBIDN
|
||||
#if defined(HAVE_LIBIDN2) || defined(HAVE_LIBIDN)
|
||||
/* 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);
|
||||
|
@ -17,9 +17,11 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#ifdef HAVE_LIBIDN
|
||||
#include <idna.h>
|
||||
#include <stringprep.h>
|
||||
#if defined(HAVE_LIBIDN2)
|
||||
# include <idn2.h>
|
||||
#elif defined(HAVE_LIBIDN)
|
||||
# include <idna.h>
|
||||
# include <stringprep.h>
|
||||
#endif
|
||||
|
||||
#include <endian.h>
|
||||
@ -299,8 +301,8 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
|
||||
#ifdef 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;
|
||||
const char *p;
|
||||
@ -348,13 +350,9 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
|
||||
decoded[l] = 0;
|
||||
|
||||
return (int) l;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
|
||||
#ifdef HAVE_LIBIDN
|
||||
size_t input_size, output_size;
|
||||
_cleanup_free_ uint32_t *input = NULL;
|
||||
_cleanup_free_ char *result = NULL;
|
||||
@ -399,10 +397,8 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
|
||||
decoded[w] = 0;
|
||||
|
||||
return w;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int dns_name_concat(const char *a, const char *b, char **_ret) {
|
||||
_cleanup_free_ char *ret = NULL;
|
||||
@ -1274,6 +1270,23 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
|
||||
}
|
||||
|
||||
int dns_name_apply_idna(const char *name, char **ret) {
|
||||
/* Return negative on error, 0 if not implemented, positive on success. */
|
||||
|
||||
#if defined(HAVE_LIBIDN2)
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
assert(ret);
|
||||
|
||||
r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) ret,
|
||||
IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
|
||||
if (r == IDN2_OK)
|
||||
return 1; /* *ret has been written */
|
||||
else if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
|
||||
return -ENOSPC;
|
||||
else
|
||||
return -EINVAL;
|
||||
#elif defined(HAVE_LIBIDN)
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
size_t n = 0, allocated = 0;
|
||||
bool first = true;
|
||||
@ -1323,6 +1336,9 @@ int dns_name_apply_idna(const char *name, char **ret) {
|
||||
buf = NULL;
|
||||
|
||||
return (int) n;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int dns_name_is_valid_or_address(const char *name) {
|
||||
|
@ -51,8 +51,10 @@ static inline int dns_name_parent(const char **name) {
|
||||
return dns_label_unescape(name, NULL, DNS_LABEL_MAX);
|
||||
}
|
||||
|
||||
#if defined(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, char **ret);
|
||||
|
||||
|
@ -608,7 +608,7 @@ static void test_dns_name_common_suffix(void) {
|
||||
}
|
||||
|
||||
static void test_dns_name_apply_idna_one(const char *s, const char *result) {
|
||||
#ifdef HAVE_LIBIDN
|
||||
#if defined(HAVE_LIBIDN2) || defined(HAVE_LIBIDN)
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
assert_se(dns_name_apply_idna(s, &buf) >= 0);
|
||||
assert_se(dns_name_equal(buf, result) > 0);
|
||||
|
Loading…
Reference in New Issue
Block a user