From 5f61ac028e0930e7de9ea2a00864ccb6dc048f64 Mon Sep 17 00:00:00 2001 From: TJ Saunders Date: Sat, 7 Aug 2021 13:30:34 -0700 Subject: [PATCH] Issue #1286: Add support for libidn2, an alternative to libidna, for `mod_rewrite`. --- .github/workflows/ci.yml | 4 ++++ config.h.in | 6 ++++++ configure | 43 +++++++++++++++++++++++++++++++++++++++- configure.in | 26 +++++++++++++++++++++++- contrib/mod_rewrite.c | 29 +++++++++++++++++++++------ 5 files changed, 100 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3ac5acaf9..e95dbf574d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,8 @@ jobs: yum install -y GeoIP-devel # for mod_ldap yum install -y openldap-devel cyrus-sasl-devel + # for mod_rewrite + yum install -y libidn2-devel # for memcache support yum install -y libmemcached-devel # for redis support @@ -133,6 +135,8 @@ jobs: apt-get install -y libldap2-dev libsasl2-dev # for mod_ldap runtime support for SCRAM apt-get install -y libsasl2-modules-gssapi-mit + # for mod_rewrite + apt-get install -y libidn2-dev # for memcache support apt-get install -y libmemcached-dev # for redis support diff --git a/config.h.in b/config.h.in index ca81587017..fcd42d538a 100644 --- a/config.h.in +++ b/config.h.in @@ -399,6 +399,9 @@ /* Define if you have the iconv function. */ #undef HAVE_ICONV +/* Define if you have the idn2_to_ascii_8z function. */ +#undef HAVE_IDN2_TO_ASCII_8Z + /* Define if you have the idna_to_ascii_8z function. */ #undef HAVE_IDNA_TO_ASCII_8Z @@ -693,6 +696,9 @@ /* Define if you have the header file. */ #undef HAVE_ICONV_H +/* Define if you have the header file. */ +#undef HAVE_IDN2_H + /* Define if you have the header file. */ #undef HAVE_IDNA_H diff --git a/configure b/configure index a11949e37c..e0c400f567 100755 --- a/configure +++ b/configure @@ -19758,7 +19758,7 @@ fi done -for ac_header in netinet/tcp.h arpa/inet.h idna.h libintl.h +for ac_header in netinet/tcp.h arpa/inet.h idn2.h idna.h libintl.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -21285,6 +21285,47 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for idn2_to_ascii_8z" >&5 +$as_echo_n "checking for idn2_to_ascii_8z... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #ifdef HAVE_IDN2_H + # include + #endif + +int +main () +{ + + int flags = 0, res = 0; + const char *input = NULL; + char *output = NULL; + res = idn2_to_ascii_8z(input, &output, flags); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define HAVE_IDN2_TO_ASCII_8Z 1" >>confdefs.h + + MAIN_LIBS="$MAIN_LIBS -lidn2" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for idna_to_ascii_8z" >&5 $as_echo_n "checking for idna_to_ascii_8z... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext diff --git a/configure.in b/configure.in index 90425daba4..a1228a1397 100644 --- a/configure.in +++ b/configure.in @@ -1715,7 +1715,7 @@ AC_CHECK_HEADERS(netinet/ip.h,,, ] ]) -AC_CHECK_HEADERS(netinet/tcp.h arpa/inet.h idna.h libintl.h) +AC_CHECK_HEADERS(netinet/tcp.h arpa/inet.h idn2.h idna.h libintl.h) AC_CHECK_HEADERS(regex.h sys/stat.h errno.h sys/termios.h sys/termio.h) AC_CHECK_HEADERS(sys/statfs.h sys/statvfs.h sys/un.h sys/vfs.h sys/select.h) AC_CHECK_HEADERS(termios.h dirent.h ndir.h sys/ndir.h sys/dir.h vmsdir.h) @@ -1952,6 +1952,30 @@ AC_TRY_LINK( ] ) +AC_MSG_CHECKING([for idn2_to_ascii_8z]) +AC_TRY_COMPILE( + [ + #include + #ifdef HAVE_IDN2_H + # include + #endif + ], + [ + int flags = 0, res = 0; + const char *input = NULL; + char *output = NULL; + res = idn2_to_ascii_8z(input, &output, flags); + ], + [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IDN2_TO_ASCII_8Z, 1, [Define if you have idn2_to_ascii_8z]) + MAIN_LIBS="$MAIN_LIBS -lidn2" + ], + [ + AC_MSG_RESULT(no) + ] +) + AC_MSG_CHECKING([for idna_to_ascii_8z]) AC_TRY_COMPILE( [ diff --git a/contrib/mod_rewrite.c b/contrib/mod_rewrite.c index e73ed6a6a7..16cdd82736 100644 --- a/contrib/mod_rewrite.c +++ b/contrib/mod_rewrite.c @@ -1,6 +1,6 @@ /* * ProFTPD: mod_rewrite -- a module for rewriting FTP commands - * Copyright (c) 2001-2020 TJ Saunders + * Copyright (c) 2001-2021 TJ Saunders * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,11 +27,15 @@ #include "conf.h" #include "privs.h" -#ifdef HAVE_IDNA_H +#if defined(HAVE_IDNA_H) # include #endif /* HAVE_IDNA_H */ -#define MOD_REWRITE_VERSION "mod_rewrite/1.0" +#if defined(HAVE_IDN2_H) +# include +#endif /* HAVE_IDN2_H */ + +#define MOD_REWRITE_VERSION "mod_rewrite/1.1" /* Make sure the version of proftpd is as necessary. */ #if PROFTPD_VERSION_NUMBER < 0x0001030701 @@ -2034,7 +2038,8 @@ static char *rewrite_map_int_utf8trans(pool *map_pool, char *key) { return NULL; } -#if defined(HAVE_IDNA_H) && defined(HAVE_IDNA_TO_ASCII_8Z) +#if (defined(HAVE_IDNA_H) && defined(HAVE_IDNA_TO_ASCII_8Z)) || \ + (defined(HAVE_IDN2_H) && defined(HAVE_IDN2_TO_ASCII_8Z)) static char *rewrite_map_int_idnatrans(pool *map_pool, char *key) { int flags = 0, res; char *ascii_val = NULL, *map_val = NULL; @@ -2045,6 +2050,16 @@ static char *rewrite_map_int_idnatrans(pool *map_pool, char *key) { return NULL; } +# if defined(HAVE_IDN2_H) && defined(HAVE_IDN2_TO_ASCII_8Z) + flags = IDN2_NFC_INPUT|IDN2_NONTRANSITIONAL; + res = idn2_to_ascii_8z(key, &ascii_val, flags); + if (res != IDN2_OK) { + rewrite_log("rewrite_map_int_idnatrans(): failed transforming IDN2 " + "'%s' to ASCII: %s", key, idn2_strerror(res)); + return NULL; + } + +# elif defined(HAVE_IDNA_H) && defined(HAVE_IDNA_TO_ASCII_8Z) /* TODO: Should we enforce the use of e.g. the IDNA_USE_STD3_ASCII_RULES * flag? */ @@ -2054,13 +2069,14 @@ static char *rewrite_map_int_idnatrans(pool *map_pool, char *key) { "'%s' to ASCII: %s", key, idna_strerror(res)); return NULL; } +# endif /* IDNA support. */ map_val = pstrdup(map_pool, ascii_val); free(ascii_val); return map_val; } -#endif /* IDNA support */ +#endif /* IDNA or IDN2 support */ /* Rewrite logging functions */ @@ -2440,7 +2456,8 @@ MODRET set_rewritemap(cmd_rec *cmd) { map = (void *) rewrite_map_int_utf8trans; } else if (strcmp(mapsrc, "idnatrans") == 0) { -#if defined(HAVE_IDNA_H) && defined(HAVE_IDNA_TO_ASCII_8Z) +#if (defined(HAVE_IDNA_H) && defined(HAVE_IDNA_TO_ASCII_8Z)) || \ + (defined(HAVE_IDN2_H) && defined(HAVE_IDN2_TO_ASCII_8Z)) map = (void *) rewrite_map_int_idnatrans; #else CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,