From 379571c25966786b4852f0551a645f3b447c90f0 Mon Sep 17 00:00:00 2001 From: manuel Date: Fri, 18 Aug 2017 15:03:50 +0200 Subject: SMTPUTF8: convert UTF-8 domains to IDNA This isn't entirely correct according to RFC 6531 as it's better to not convert at all. However this would require we additionally add the UTF-8 form to qmails local recipient users/domains. Plus our SMTPUTF8 implementation doesn't convert outgoing UTF-8 mails if receiving MTA doesn't support SMTPUTF8. So mail forwarding might generate a bounce the user very likely doesn't understand. As MTAs who support SMTPUTF8 most likely also support the IDNA form, always converting is probably a good trade-off. --- Makefile | 2 +- qmail-smtpd.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a13882b..9ffde73 100644 --- a/Makefile +++ b/Makefile @@ -1626,7 +1626,7 @@ socket.lib dns.lib tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \ cdb.a fd.a wait.a datetime.a getln.a open.a sig.a case.a env.a \ stralloc.a alloc.a strerr.a substdio.a error.a str.a fs.a \ - `cat socket.lib` `cat dns.lib` + `cat socket.lib` `cat dns.lib` -lidn2 qmail-smtpd.0: \ qmail-smtpd.8 diff --git a/qmail-smtpd.c b/qmail-smtpd.c index db0e16b..95993eb 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c @@ -77,6 +77,11 @@ stralloc proto = {0}; int tls_before_auth = 0; #endif +#ifdef SMTPUTF8 +# include +int smtputf8 = 0; +#endif + int safewrite(fd,buf,len) int fd; char *buf; int len; { int r; @@ -385,6 +390,25 @@ char *arg; return 1; } +#ifdef SMTPUTF8 +static int idn_addr_convert(stralloc *addr) +{ + int i = byte_rchr(addr->s, addr->len, '@') + 1; + if (i < addr->len) { + char *asciihost = NULL; + switch (idn2_lookup_u8(addr->s + i, (uint8_t **)&asciihost, IDN2_NFC_INPUT)) { + case IDN2_OK: break; + case IDN2_MALLOC: die_nomem(); + default: err_smf(); return 0; + } + addr->len = i; + if (!stralloc_cats(addr, asciihost)) die_nomem(); + if (!stralloc_0(addr)) die_nomem(); + } + return 1; +} +#endif + static void log_deny(m,f,t) char *m,*f,*t; { enew(); eout(m); eout(" check failed ("); eout(f); eout(") -> ("); @@ -515,7 +539,6 @@ stralloc mailfrom = {0}; stralloc rcptto = {0}; stralloc fuser = {0}; stralloc mfparms = {0}; -int smtputf8 = 0; int recipcount; int mailfrom_size(arg) char *arg; @@ -630,6 +653,9 @@ void smtp_mail(arg) char *arg; flagsize = 0; mailfrom_parms(arg); if (flagsize) { err_size(); return; } +#ifdef SMTPUTF8 + if (smtputf8) { if (!idn_addr_convert(&addr)) return; } +#endif flagbarfbmf = 0; /* bmcheck is skipped for empty envelope senders */ if ((bmfok) && (addr.len != 1)) flagbarfbmf = bmcheck(BMCHECK_BMF); if ((!flagbarfbmf) && (bmfnrok) && (addr.len != 1) && (!relayclient)) { @@ -673,6 +699,9 @@ void smtp_rcpt(arg) char *arg; { err_bmf(); return; } +#ifdef SMTPUTF8 + if (smtputf8) { if (!idn_addr_convert(&addr)) return; } +#endif if (bmtok) flagbarfbmt = bmcheck(BMCHECK_BMT); if ((!flagbarfbmt) && (bmtnrok) && (!relayclient)) { flagbarfbmt = bmcheck(BMCHECK_BMTNR); -- cgit v1.2.3