From 1cafb5eab0b30e5f5a05737a075123af53153cb1 Mon Sep 17 00:00:00 2001 From: manuel Date: Thu, 17 Aug 2017 13:17:22 +0200 Subject: add support for SMTPUTF8 --- Makefile | 13 +++++--- conf-cc | 2 +- qmail-remote.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- qmail-smtpd.c | 23 +++++++++++++- qmail-spp.h | 1 + qsutil.c | 4 +-- 6 files changed, 126 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index abf6a05..a13882b 100644 --- a/Makefile +++ b/Makefile @@ -221,9 +221,9 @@ compile byte_zero.c byte.h case.a: \ makelib case_diffb.o case_diffs.o case_lowerb.o case_lowers.o \ -case_starts.o +case_startb.o case_starts.o ./makelib case.a case_diffb.o case_diffs.o case_lowerb.o \ - case_lowers.o case_starts.o + case_lowers.o case_startb.o case_starts.o case_diffb.o: \ compile case_diffb.c case.h @@ -241,6 +241,10 @@ case_lowers.o: \ compile case_lowers.c case.h ./compile case_lowers.c +case_startb.o: \ +compile case_startb.c case.h + ./compile case_startb.c + case_starts.o: \ compile case_starts.c case.h ./compile case_starts.c @@ -1517,7 +1521,7 @@ dns.lib socket.lib ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ env.a str.a fs.a auto_qmail.o base64.o \ - `cat dns.lib` `cat socket.lib` -lval -lsres + `cat dns.lib` `cat socket.lib` -lval -lsres -lidn2 qmail-remote.0: \ qmail-remote.8 @@ -1633,7 +1637,8 @@ compile qmail-smtpd.c sig.h readwrite.h stralloc.h gen_alloc.h \ substdio.h alloc.h auto_qmail.h control.h received.h constmap.h \ error.h ipme.h ip.h ipalloc.h ip.h gen_alloc.h ip.h qmail.h qmail-spp.h \ substdio.h str.h fmt.h scan.h byte.h case.h env.h now.h datetime.h \ -exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h +exit.h rcpthosts.h timeoutread.h timeoutwrite.h commands.h base64.h open.h \ +fd.h fork.h ./compile qmail-smtpd.c qmail-start: \ diff --git a/conf-cc b/conf-cc index 245d8c5..a1f3fe6 100644 --- a/conf-cc +++ b/conf-cc @@ -1,3 +1,3 @@ -gcc -O2 -pipe -DTLS -fno-builtin-puts -fno-builtin-log2 +gcc -O2 -pipe -DTLS -DSMTPUTF8 -fno-builtin-puts -fno-builtin-log2 This will be used to compile .c files. diff --git a/qmail-remote.c b/qmail-remote.c index 94c6c0d..f8e60ad 100644 --- a/qmail-remote.c +++ b/qmail-remote.c @@ -46,6 +46,7 @@ stralloc helohost = {0}; stralloc routes = {0}; struct constmap maproutes; stralloc host = {0}; +stralloc idnhost = {0}; stralloc sender = {0}; stralloc auth_smtp_user = {0}; stralloc auth_smtp_pass = {0}; @@ -77,13 +78,19 @@ struct val_danestatus *dane_status = NULL; struct val_ssl_data *dane_ssl_data = NULL; #endif +#ifdef SMTPUTF8 +# include +int flagutf8 = 0; +stralloc header = {0}; +#endif + void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } void zeroflush() { zero(); substdio_flush(subfdoutsmall); } void zerodie() { zeroflush(); _exit(0); } -void outsafe(sa) stralloc *sa; { int i; char ch; +void outsafe(sa) stralloc *sa; { int i; unsigned char ch; for (i = 0;i < sa->len;++i) { -ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?'; +ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126 && ch <= 127) ch = '?'; if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } } void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); } @@ -346,6 +353,10 @@ void blast() int r; char ch; +#ifdef SMTPUTF8 + substdio_put(&smtpto,header.s,header.len); +#endif + for (;;) { r = substdio_get(&ssin,&ch,1); if (r == 0) break; @@ -634,11 +645,60 @@ int tls_init() stralloc recip = {0}; +#ifdef SMTPUTF8 +int utf8string(unsigned char *ch, int len) +{ + int i = 0; + while (i < len) + if (ch[i++] > 127) return 1; + return 0; +} + +int utf8received() +{ + int r, i, received = 0; + char ch; + stralloc receivedline = {0}; + + for (;;) { /* we consider only our own last written header */ + r = substdio_get(&ssin,&ch,1); + if (r == 0) break; + if (r == -1) temp_read(); + + if (ch == '\n') { + if (!stralloc_append(&header,"\r")) temp_nomem(); /* received.c does not add '\r' */ + if (!stralloc_append(&header,"\n")) temp_nomem(); + if (case_startb(receivedline.s,5,"Date:")) return 0; /* header to quit asap */ + if (case_startb(receivedline.s,14,"Received: from")) received++; /* found Received header */ + if (received) { + if (case_startb(receivedline.s,5," by ")) { + for (i = 6; i < receivedline.len-6; ++i) + if (*(receivedline.s+i) == ' ') + if (case_startb(receivedline.s+i+1,9,"with UTF8")) return 1; + return 0; + } + } + if (!stralloc_copys(&receivedline,"")) temp_nomem(); + receivedline.len = 0; + } else { + if (!stralloc_append(&header,&ch)) temp_nomem(); + if (!stralloc_catb(&receivedline,&ch,1)) temp_nomem(); + } + } + return 0; +} +#endif + void mail_without_auth() { substdio_puts(&smtpto,"MAIL FROM:<"); substdio_put(&smtpto,sender.s,sender.len); - substdio_puts(&smtpto,">\r\n"); + substdio_put(&smtpto,">",1); +#ifdef SMTPUTF8 + if (flagutf8 || utf8received()) + substdio_puts(&smtpto, " SMTPUTF8"); +#endif + substdio_puts(&smtpto,"\r\n"); substdio_flush(&smtpto); } @@ -730,7 +790,12 @@ void smtp() substdio_put(&smtpto,sender.s,sender.len); substdio_puts(&smtpto,"> AUTH=<"); substdio_put(&smtpto,sender.s,sender.len); - substdio_puts(&smtpto,">\r\n"); + substdio_put(&smtpto,">",1); +#ifdef SMTPUTF8 + if (flagutf8 || utf8received()) + substdio_puts(&smtpto, " SMTPUTF8"); +#endif + substdio_puts(&smtpto,"\r\n"); substdio_flush(&smtpto); if(!stralloc_copys(&auth_status, "Delivered with authenticated connection to \n")) temp_nomem(); if(!stralloc_0(&auth_status)) temp_nomem(); @@ -902,7 +967,12 @@ stralloc *saout; /* host has to be canonical, box has to be quoted */ char *s; { int j; - + +#ifdef SMTPUTF8 + if (!flagutf8) + flagutf8 = utf8string(s, str_len(s)); +#endif + j = str_rchr(s,'@'); if (!s[j]) { if (!stralloc_copys(saout,s)) temp_nomem(); @@ -983,6 +1053,18 @@ char **argv; relayhost[i] = 0; } if (!stralloc_copys(&host,relayhost)) temp_nomem(); + } else { +#ifdef SMTPUTF8 + char *asciihost = 0; + if (!stralloc_0(&host)) temp_nomem(); + switch (idn2_lookup_u8(host.s,(uint8_t**)&asciihost,IDN2_NFC_INPUT)) { + case IDN2_OK: break; + case IDN2_MALLOC: temp_nomem(); + default: perm_dns(); + } + if (!stralloc_copys(&idnhost,asciihost)) temp_nomem(); + if (!stralloc_0(&idnhost)) temp_nomem(); +#endif } @@ -1002,7 +1084,11 @@ char **argv; random = now() + (getpid() << 16); +#ifdef SMTPUTF8 + switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&idnhost,random)) { +#else switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random)) { +#endif case DNS_MEM: temp_nomem(); case DNS_SOFT: temp_dns(); case DNS_HARD: perm_dns(); diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 35630ac..db0e16b 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c @@ -29,6 +29,10 @@ #include "cdb.h" #include "qmail-spp.h" #include "dns.h" +#include "base64.h" +#include "open.h" +#include "fd.h" +#include "fork.h" int spp_val; @@ -511,6 +515,7 @@ stralloc mailfrom = {0}; stralloc rcptto = {0}; stralloc fuser = {0}; stralloc mfparms = {0}; +int smtputf8 = 0; int recipcount; int mailfrom_size(arg) char *arg; @@ -562,6 +567,9 @@ void mailfrom_parms(arg) char *arg; while (len) { arg++; len--; if (*arg == ' ' || *arg == '\0' ) { +#ifdef SMTPUTF8 + if (case_starts(mfparms.s,"SMTPUTF8")) smtputf8 = 1; +#endif if (case_starts(mfparms.s,"SIZE=")) if (mailfrom_size(mfparms.s+5)) { flagsize = 1; return; } if (case_starts(mfparms.s,"AUTH=")) mailfrom_auth(mfparms.s+5,mfparms.len-5); if (!stralloc_copys(&mfparms,"")) die_nomem; @@ -596,7 +604,11 @@ void smtp_ehlo(arg) char *arg; if (!ssl && (stat(servercert, &st) == 0)) out("\r\n250-STARTTLS"); #endif +#ifdef SMTPUTF8 + out("\r\n250-PIPELINING\r\n250-SMTPUTF8\r\n250-8BITMIME\r\n"); +#else out("\r\n250-PIPELINING\r\n250-8BITMIME\r\n"); +#endif #if defined(TLS) if(!tls_before_auth || (tls_before_auth && ssl)) smtp_authout(); #else @@ -827,7 +839,16 @@ void smtp_data(arg) char *arg; { if (qmail_open(&qqt) == -1) { err_qqt(); return; } qp = qmail_qp(&qqt); out("354 go ahead\r\n"); - + + if (smtputf8) { + stralloc utf8proto = {0}; + if (*protocol == 'E') ++protocol; + if (!stralloc_copys(&utf8proto, "UTF8")) die_nomem(); + if (!stralloc_cats(&utf8proto, protocol)) die_nomem(); + if (!stralloc_0(&utf8proto)) die_nomem(); + protocol = utf8proto.s; + } + received(&qqt,protocol,local,remoteip,remotehost,remoteinfo,fakehelo); qmail_put(&qqt,sppheaders.s,sppheaders.len); /* set in qmail-spp.c */ spp_rset(); diff --git a/qmail-spp.h b/qmail-spp.h index b4d7154..e2c03d8 100644 --- a/qmail-spp.h +++ b/qmail-spp.h @@ -8,6 +8,7 @@ extern int spp_helo(); extern void spp_rset(); extern int spp_mail(); extern int spp_rcpt(); +extern void spp_rcpt_accepted(); extern int spp_data(); extern int spp_auth(); diff --git a/qsutil.c b/qsutil.c index a769829..43890d0 100644 --- a/qsutil.c +++ b/qsutil.c @@ -24,11 +24,11 @@ void nomem() { log1("alert: out of memory, sleeping...\n"); sleep(10); } void pausedir(dir) char *dir; { log3("alert: unable to opendir ",dir,", sleeping...\n"); sleep(10); } -static int issafe(ch) char ch; +static int issafe(ch) unsigned char ch; { if (ch == '%') return 0; /* general principle: allman's code is crap */ if (ch < 33) return 0; - if (ch > 126) return 0; + if (ch > 126 && ch <= 127) return 0; return 1; } -- cgit v1.2.3