diff options
| author | manuel <manuel@mausz.at> | 2017-08-18 15:03:50 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2017-08-18 15:03:50 +0200 |
| commit | 379571c25966786b4852f0551a645f3b447c90f0 (patch) | |
| tree | 702e4291f58c441d8a1ed75312e06617173d057f | |
| parent | 1cafb5eab0b30e5f5a05737a075123af53153cb1 (diff) | |
| download | qmail-379571c25966786b4852f0551a645f3b447c90f0.tar.gz qmail-379571c25966786b4852f0551a645f3b447c90f0.tar.bz2 qmail-379571c25966786b4852f0551a645f3b447c90f0.zip | |
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.
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | qmail-smtpd.c | 31 |
2 files changed, 31 insertions, 2 deletions
| @@ -1626,7 +1626,7 @@ socket.lib dns.lib | |||
| 1626 | tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \ | 1626 | tls.o ssl_timeoutio.o ndelay.a -L/usr/local/ssl/lib -lssl -lcrypto \ |
| 1627 | cdb.a fd.a wait.a datetime.a getln.a open.a sig.a case.a env.a \ | 1627 | cdb.a fd.a wait.a datetime.a getln.a open.a sig.a case.a env.a \ |
| 1628 | stralloc.a alloc.a strerr.a substdio.a error.a str.a fs.a \ | 1628 | stralloc.a alloc.a strerr.a substdio.a error.a str.a fs.a \ |
| 1629 | `cat socket.lib` `cat dns.lib` | 1629 | `cat socket.lib` `cat dns.lib` -lidn2 |
| 1630 | 1630 | ||
| 1631 | qmail-smtpd.0: \ | 1631 | qmail-smtpd.0: \ |
| 1632 | qmail-smtpd.8 | 1632 | 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}; | |||
| 77 | int tls_before_auth = 0; | 77 | int tls_before_auth = 0; |
| 78 | #endif | 78 | #endif |
| 79 | 79 | ||
| 80 | #ifdef SMTPUTF8 | ||
| 81 | # include <idn2.h> | ||
| 82 | int smtputf8 = 0; | ||
| 83 | #endif | ||
| 84 | |||
| 80 | int safewrite(fd,buf,len) int fd; char *buf; int len; | 85 | int safewrite(fd,buf,len) int fd; char *buf; int len; |
| 81 | { | 86 | { |
| 82 | int r; | 87 | int r; |
| @@ -385,6 +390,25 @@ char *arg; | |||
| 385 | return 1; | 390 | return 1; |
| 386 | } | 391 | } |
| 387 | 392 | ||
| 393 | #ifdef SMTPUTF8 | ||
| 394 | static int idn_addr_convert(stralloc *addr) | ||
| 395 | { | ||
| 396 | int i = byte_rchr(addr->s, addr->len, '@') + 1; | ||
| 397 | if (i < addr->len) { | ||
| 398 | char *asciihost = NULL; | ||
| 399 | switch (idn2_lookup_u8(addr->s + i, (uint8_t **)&asciihost, IDN2_NFC_INPUT)) { | ||
| 400 | case IDN2_OK: break; | ||
| 401 | case IDN2_MALLOC: die_nomem(); | ||
| 402 | default: err_smf(); return 0; | ||
| 403 | } | ||
| 404 | addr->len = i; | ||
| 405 | if (!stralloc_cats(addr, asciihost)) die_nomem(); | ||
| 406 | if (!stralloc_0(addr)) die_nomem(); | ||
| 407 | } | ||
| 408 | return 1; | ||
| 409 | } | ||
| 410 | #endif | ||
| 411 | |||
| 388 | static void log_deny(m,f,t) char *m,*f,*t; | 412 | static void log_deny(m,f,t) char *m,*f,*t; |
| 389 | { | 413 | { |
| 390 | enew(); eout(m); eout(" check failed ("); eout(f); eout(") -> ("); | 414 | enew(); eout(m); eout(" check failed ("); eout(f); eout(") -> ("); |
| @@ -515,7 +539,6 @@ stralloc mailfrom = {0}; | |||
| 515 | stralloc rcptto = {0}; | 539 | stralloc rcptto = {0}; |
| 516 | stralloc fuser = {0}; | 540 | stralloc fuser = {0}; |
| 517 | stralloc mfparms = {0}; | 541 | stralloc mfparms = {0}; |
| 518 | int smtputf8 = 0; | ||
| 519 | int recipcount; | 542 | int recipcount; |
| 520 | 543 | ||
| 521 | int mailfrom_size(arg) char *arg; | 544 | int mailfrom_size(arg) char *arg; |
| @@ -630,6 +653,9 @@ void smtp_mail(arg) char *arg; | |||
| 630 | flagsize = 0; | 653 | flagsize = 0; |
| 631 | mailfrom_parms(arg); | 654 | mailfrom_parms(arg); |
| 632 | if (flagsize) { err_size(); return; } | 655 | if (flagsize) { err_size(); return; } |
| 656 | #ifdef SMTPUTF8 | ||
| 657 | if (smtputf8) { if (!idn_addr_convert(&addr)) return; } | ||
| 658 | #endif | ||
| 633 | flagbarfbmf = 0; /* bmcheck is skipped for empty envelope senders */ | 659 | flagbarfbmf = 0; /* bmcheck is skipped for empty envelope senders */ |
| 634 | if ((bmfok) && (addr.len != 1)) flagbarfbmf = bmcheck(BMCHECK_BMF); | 660 | if ((bmfok) && (addr.len != 1)) flagbarfbmf = bmcheck(BMCHECK_BMF); |
| 635 | if ((!flagbarfbmf) && (bmfnrok) && (addr.len != 1) && (!relayclient)) { | 661 | if ((!flagbarfbmf) && (bmfnrok) && (addr.len != 1) && (!relayclient)) { |
| @@ -673,6 +699,9 @@ void smtp_rcpt(arg) char *arg; { | |||
| 673 | err_bmf(); | 699 | err_bmf(); |
| 674 | return; | 700 | return; |
| 675 | } | 701 | } |
| 702 | #ifdef SMTPUTF8 | ||
| 703 | if (smtputf8) { if (!idn_addr_convert(&addr)) return; } | ||
| 704 | #endif | ||
| 676 | if (bmtok) flagbarfbmt = bmcheck(BMCHECK_BMT); | 705 | if (bmtok) flagbarfbmt = bmcheck(BMCHECK_BMT); |
| 677 | if ((!flagbarfbmt) && (bmtnrok) && (!relayclient)) { | 706 | if ((!flagbarfbmt) && (bmtnrok) && (!relayclient)) { |
| 678 | flagbarfbmt = bmcheck(BMCHECK_BMTNR); | 707 | flagbarfbmt = bmcheck(BMCHECK_BMTNR); |
