33#include "timeoutconn.h"
43#define WHO "qmail-remote"
45#define QMTP_MAX 200000000
46#define HUGESMTPTEXT 1000
50#define PORT_SUBMISSION 587
51#define PORT_QMTPS 6209
54#define SMTP_TIMEOUT 1200
75static stralloc sauninit = {0};
115 if (buffer_puts(&
bs,s) == -1)
120 if (buffer_put(&
bs,
"\0",1) == -1)
135 for (i = 0; i <
sa->len; ++i) {
137 if (ch == 0)
continue;
138 if (ch < 33) ch =
'?';
139 if (ch > 126) ch =
'?';
140 if (buffer_put(&
bs,&ch,1) == -1)
_exit(0);
146 out(
"ZInvalid ipaddr in control/domainips (#4.3.0)\n");
151 out(
"ZOut of memory. (#4.3.0)\n");
156 out(
"ZSystem resources temporarily unavailable. (#4.3.0)\n");
161 out(
"ZCan't bind to local ip address: ");
168 out(
"ZSorry, I wasn't able to establish a SMTP connection: ");
175 out(
"ZSorry, I wasn't able to establish a QMTP connection: ");
182 out(
"ZUnable to read message. (#4.3.0)\n");
187 out(
"ZCNAME lookup failed temporarily for: ");
194 out(
"ZSorry, I couldn't find any host named: ");
201 out(
"ZSorry, I couldn't find a mail exchanger or IP address for: ");
203 out(
". Will try again. (#4.1.2)\n");
208 out(
"ZUnable to switch to home directory. (#4.3.0)\n");
213 out(
"ZUnable to read control files. (#4.3.0)\n");
218 out(
"DSMTP cannot transfer messages with partial final line. (#5.6.2)\n");
223 out(
"ZRecipient did not talk proper QMTP. (#4.3.0)\n");
228 out(
"Dqmail-remote was invoked improperly. (#5.3.5)\n");
233 out(
"DSorry, I couldn't find any host named: ");
240 out(
"DSorry, I couldn't find a mail exchanger or IP address for: ");
247 out(
"DSorry, I could no deliver mail to MX: ");
249 out(
" ; domain does not accept mails. (#5.1.10)\n");
254 out(
"DSorry. Although I'm listed as a best-preference MX or A for that host,\n\
255it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
260 out(
"ZSorry, no supported AUTH method found, trying later again. (#4.7.1)\n");
282 out(
"ZConnected to ");
284 out(
" but connection died. ");
327static stralloc smtptext = {0};
328static stralloc header = {0};
332 buffer_get(&
bf,ch,1);
335 if (!stralloc_append(&smtptext,ch))
temp_nomem();
350 if (ch !=
'-')
break;
351 while (ch !=
'\n')
get(&ch);
356 while (ch !=
'\n')
get(&ch);
364 if (smtptext.s)
if (smtptext.len) {
365 out(
"Remote host said: ");
366 for (i = 0; i < smtptext.len; ++i)
367 if (!smtptext.s[i]) smtptext.s[i] =
'?';
368 if (buffer_put(&
bs,smtptext.s,smtptext.len) == -1)
_exit(0);
373void quit(
char *prepend,
char *append)
375 buffer_putsflush(&
bo,
"QUIT\r\n");
405 if (
inbuf[
in] ==
'\r') {
in++;
continue; }
421 buffer_put(&
bo,
".\r\n",3);
488 if (case_startb(smtptext.s + i + 4,8,
"STARTTLS"))
return 1;
489 }
while ((i += str_chr(smtptext.s + i,
'\n') + 1) &&
490 (i < smtptext.len - 12));
498 STACK_OF(X509) *certs;
501 cert = SSL_get_peer_certificate(
ssl);
502 if (!cert) {
flagtls = 100;
return; }
504 if ((certs = SSL_get_peer_cert_chain(
ssl)) == NULL) {
505 certs = sk_X509_new_null();
507 sk_X509_push(certs,cert);
547 if (ncerts) sk_X509_free(certs);
559 if (ch[i++] > 127)
return 1;
569 stralloc receivedline = {0};
574 r = buffer_get(&
bi,&ch,1);
577 if (ch ==
'\r')
continue;
580 if (!stralloc_append(&header,
"\r"))
temp_nomem();
581 if (!stralloc_append(&header,
"\n"))
temp_nomem();
582 if (case_starts(receivedline.s,
"Date:"))
return 0;
583 if (case_starts(receivedline.s,
"Received: from"))
received++;
585 if (case_starts(receivedline.s,
" by ")) {
586 for (i = 6; i < receivedline.len - 6; ++i)
587 if (*(receivedline.s + i) ==
' ')
588 if (case_starts(receivedline.s + i + 1,
"with UTF8"))
return 1;
594 if (!stralloc_append(&header,&ch))
temp_nomem();
595 if (!stralloc_catb(&receivedline,&ch,1))
temp_nomem();
611 if (case_startb(smtptext.s + i + 4,4,
"SIZE"))
return 1;
612 }
while ((i += str_chr(smtptext.s + i,
'\n') + 1) &&
613 (i < smtptext.len - 8));
620 buffer_puts(&
bo,
"EHLO ");
622 buffer_puts(&
bo,
"\r\n");
626 buffer_puts(&
bo,
"HELO ");
628 buffer_puts(&
bo,
"\r\n");
633 if (
code >= 500)
quit(
"DConnected to ",
" but my name was rejected");
634 if (
code != 250)
quit(
"ZConnected to ",
" but my name was rejected");
641 buffer_puts(&
bo,
"STARTTLS\r\n");
651 quit(
"ZConnected to ",
" but STARTTLS was rejected");
657 buffer_puts(&
bo,
"MAIL FROM:<");
659 buffer_puts(&
bo,
">");
661 buffer_puts(&
bo,
" SMTPUTF8");
663 buffer_puts(&
bo,
" SIZE=");
666 buffer_puts(&
bo,
"\r\n");
683static const char hextab[] =
"0123456789abcdef";
693 for (i = 0; i < len; i++) {
695 if (c < 33 || c > 126 ||
c ==
'=' ||
c ==
'+') {
696 xch[0] = hextab[(
c >> 4) & 0x0f];
697 xch[1] = hextab[
c & 0x0f];
709 buffer_puts(&
bo,
"MAIL FROM:<");
711 buffer_puts(&
bo,
"> AUTH=");
714 buffer_puts(&
bo,
" SMTPUTF8");
716 buffer_puts(&
bo,
" SIZE=");
719 buffer_puts(&
bo,
"\r\n");
725 buffer_puts(&
bo,
"AUTH PLAIN\r\n");
728 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH PLAIN)");
737 buffer_puts(&
bo,
"\r\n");
742 case 432:
quit(
"DConnected to ",
" but password expired");
743 case 534:
quit(
"ZConnected to ",
" but authentication mechamism too weak (plain)");
744 default:
quit(
"ZConnected to ",
" but authentication was rejected (plain)");
751 buffer_puts(&
bo,
"AUTH LOGIN\r\n");
754 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH LOGIN)");
759 buffer_puts(&
bo,
"\r\n");
762 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (username)");
767 buffer_puts(&
bo,
"\r\n");
772 case 432:
quit(
"DConnected to ",
" but password expired");
773 case 534:
quit(
"ZConnected to ",
" but authentication mechanism is too weak (login)");
774 default:
quit(
"ZConnected to ",
" but authentication was rejected (login)");
782 unsigned char digest[16];
783 unsigned char digascii[33];
785 buffer_puts(&
bo,
"AUTH CRAM-MD5\r\n");
788 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH CRAM-MD5)");
789 if (str_chr(smtptext.s + 4,
' ')) {
791 if (!stralloc_copyb(&
slop,smtptext.s + 4,smtptext.len - 5))
temp_nomem();
797 for (
j = 0;
j < 16;
j++) {
798 digascii[2 *
j] = hextab[digest[
j] >> 4];
799 digascii[2 *
j + 1] = hextab[digest[
j] & 0x0f];
812 buffer_puts(&
bo,
"\r\n");
817 case 432:
quit(
"DConnected to ",
" but password expired");
818 case 534:
quit(
"ZConnected to ",
" but authentication mechamism too weak (cram)");
819 default:
quit(
"ZConnected to ",
" but authentication was rejected (cram)");
829 if (case_startb(smtptext.s + i + 4,4,
"AUTH"))
830 for (i = 4; i < smtptext.len - 5; ++i) {
831 if (case_startb(smtptext.s + i,4,
"CRAM"))
833 if (case_startb(smtptext.s + i,5,
"LOGIN"))
835 if (case_startb(smtptext.s + i,5,
"PLAIN"))
838 }
while ((i += str_chr(smtptext.s + i,
'\n') + 1) &&
839 (i < smtptext.len - 12));
858 if (
code >= 500)
quit(
"DConnected to ",
" but sender was rejected");
859 if (
code == 421 ||
code == 450)
quit(
"ZConnected to ",
" but probably greylisted");
860 if (
code >= 400)
quit(
"ZConnected to ",
" but sender was rejected");
861 if (
code != 220)
quit(
"ZConnected to ",
" but greeting failed");
879 if (
code >= 500)
quit(
"DConnected to ",
" but sender was rejected");
880 if (
code >= 400)
quit(
"ZConnected to ",
" but sender was probably greylisted");
884 buffer_puts(&
bo,
"RCPT TO:<");
886 buffer_puts(&
bo,
">\r\n");
891 if (
code == 552)
quit(
"DConnected to ",
" but message size is too large");
892 if (
code == 452)
quit(
"ZConnected to ",
" however insufficient storage space available");
897 }
else if (
code >= 500) {
900 }
else if (
code >= 400) {
908 if (!flagbother)
quit(
"DGiving up on ",
"");
910 buffer_putsflush(&
bo,
"DATA\r\n");
913 if (
code >= 500)
quit(
"D",
" failed on DATA command");
914 if (
code >= 400)
quit(
"Z",
" failed on DATA command");
916 buffer_putflush(&
bo,header.s,header.len);
921 if (
code >= 500)
quit(
"D",
" failed after I sent the message");
922 if (
code >= 400)
quit(
"Z",
" failed after I sent the message");
924 case 100:
case 110:
quit(
"K",
" TLS transmitted message accepted");
break;
925 case 101:
case 111:
quit(
"K",
" TLS (verified CA) transmitted message accepted");
break;
926 case 102:
case 112:
quit(
"K",
" TLS (validated CA+DN*) transmitted message accepted");
break;
927 case 103:
case 113:
quit(
"K",
" TLS (validated CA+DN) transmitted message accepted");
break;
928 case 104:
case 114:
quit(
"K",
" TLS (CERT pinning) transmitted message accepted");
break;
929 case 105:
case 115:
quit(
"K",
" TLS (TLSA EE validated) transmitted message accepted");
break;
930 case 106:
case 116:
quit(
"K",
" TLS (TLSA TA validated) transmitted message accepted");
break;
931 case 107:
case 117:
quit(
"K",
" TLS (TLSA PKIX verified) transmitted message accepted");
break;
932 default:
quit(
"K",
" accepted message");
break;
942 unsigned long len = 0;
960 out(
"DMessage for: ");
outhost();
out(
" has zero bytes. Giving up.\n");
963 buffer_put(&
bo,
num,fmt_ulong(
num,len + 1));
964 buffer_put(&
bo,
":\n",2);
966 n = buffer_feed(&
bi);
967 if (n <= 0)
_exit(1);
968 x = buffer_PEEK(&
bi);
973 buffer_put(&
bo,
",",1);
976 buffer_put(&
bo,
num,fmt_ulong(
num,len));
977 buffer_put(&
bo,
":",1);
979 buffer_put(&
bo,
",",1);
984 buffer_put(&
bo,
num,fmt_ulong(
num,len));
985 buffer_put(&
bo,
":",1);
988 buffer_put(&
bo,
":",1);
990 buffer_put(&
bo,
",",1);
992 buffer_put(&
bo,
",",1);
1001 if (ch ==
':')
break;
1004 len = 10 * len + (ch -
'0');
1008 if ((ch !=
'Z') && (ch !=
'D') && (ch !=
'K'))
temp_proto();
1010 if (!stralloc_copyb(&smtptext,&ch,1))
temp_nomem();
1012 if (!stralloc_cats(&smtptext,
"qmtps:"))
temp_nomem();
1014 if (!stralloc_cats(&smtptext,
"qmtp:"))
temp_nomem();
1022 for (len = 0; len < smtptext.len; ++len) {
1023 ch = smtptext.s[len];
1024 if ((ch < 32) || (ch > 126)) smtptext.s[len] =
'?';
1028 smtptext.s[smtptext.len - 1] =
'\n';
1030 if (smtptext.s[0] ==
'K')
out(
"r");
1031 else if (smtptext.s[0] ==
'D') {
1039 if (buffer_put(&
bs,smtptext.s + 1,smtptext.len - 1) == -1)
temp_qmtpnoc();
1079 switch ((r = dns_cname(&cn,&
canonhost))) {
1129int main(
int argc,
char *
const *argv)
1131 static ipalloc ip = {0};
1132 stralloc netif = {0};
1137 unsigned long random;
1139 unsigned long prefme;
1159 i = str_chr(
sender.s,
'@');
1177 j = str_chr(localip,
'%');
1178 if (localip[
j] !=
'%')
j = 0;
1179 k = str_chr(localip,
'|');
1180 if (localip[
k] !=
'|')
k = 0;
1195 for (i = 0; i <=
sender.len; ++i)
1235 if (relayhost && !*relayhost) relayhost = 0;
1238 for (i = 0; i <=
host.len; ++i) {
1239 if ((i == 0) || (i ==
host.len) || (
host.s[i] ==
'.'))
1248 if (relayhost && !*relayhost) relayhost = 0;
1251 i = str_chr(relayhost,
'|');
1252 if (relayhost[i] ==
'|') {
1253 j = str_chr(relayhost + i + 1,
'|');
1254 if (relayhost[i +
j + 1] ==
'|') {
1256 relayhost[i +
j + 1] = 0;
1260 k = str_chr(relayhost + i +
j + 2,
'|');
1261 if (relayhost[i +
j +
k + 2] ==
'|') {
1262 relayhost[i +
j +
k + 2] = 0;
1263 localip = relayhost + i +
j +
k + 3;
1268 p = str_chr(relayhost,
';');
1269 if (relayhost[
p] ==
';') {
1270 if (relayhost[
p + 1] ==
's') {
flagsmtps = 1;
p++; }
1271 scan_ulong(relayhost +
p + 1,&
port);
1278 char *asciihost = 0;
1280 switch (idn2_lookup_u8(
host.s,(uint8_t**)&asciihost,IDN2_NFC_INPUT)) {
1281 case IDN2_OK:
break;
1393 if (fstat(0,&st) == -1)
quit(
"Z",
" unable to fstat stdin");
1406 random =
now() + (getpid() << 16);
1416#ifdef DEFERREDBOUNCES
1424 for (i = 0; i < ip.len; ++i)
1427 if (ip.ix[i].pref == 0 && ip.ix[i].mxh[0] ==
'.')
1430 if (ip.ix[i].pref < prefme)
1431 prefme = ip.ix[i].pref;
1434 if (relayhost) prefme = 300000;
1435 if (flagallaliases) prefme = 500000;
1438 i = str_chr(localip,
':');
1439 if (localip[i] ==
':') ip6flag = 1;
1443 for (i = 0; i < ip.len; ++i) {
1444 if (ip6flag == -1 && ip.ix[i].af == AF_INET6)
continue;
1445 if (ip6flag == 1 && ip.ix[i].af == AF_INET)
continue;
1446 if (ip.ix[i].pref < prefme)
break;
1454 for (i = 0; i < ip.len; ++i) {
1455 if (ip.ix[i].pref < prefme) {
1456 if (ip6flag == -1 && ip.ix[i].af == AF_INET6)
continue;
1457 if (ip6flag == 1 && ip.ix[i].af == AF_INET)
continue;
1458 if (
tcpto(&ip.ix[i]))
continue;
1460 smtpfd = socket(ip.ix[i].af,SOCK_STREAM,0);
1461 if (
smtpfd == -1)
continue;
1465 j = str_chr(localip,
':');
1466 if (localip[
j] ==
':') {
1468 if (byte_equal(ip.ix[i].addr.ip6.d,16,
ip6))
continue;
1469 ifidx = socket_getifidx(netif.s);
1473 if (byte_equal(ip.ix[i].addr.ip4.d,4,
ip4))
continue;
1480 if (ip.ix[i].af == AF_INET6)
1492 if (
flagtls == 9 && errno == EPROTO) {
1495 if (errno == ETIMEDOUT || errno == ECONNREFUSED || errno == EPROTO)
int b64encode(stralloc *in, stralloc *out)
int b64decode(const unsigned char *in, int l, stralloc *out)
int constmap_init(struct constmap *cm, char *s, int len, int flagcolon)
int control_readint(unsigned long *i, char *fn)
int control_rldef(stralloc *sa, char *fn, int flagme, char *def)
int control_readfile(stralloc *sa, char *fn, int flagme)
int stralloc_copys(stralloc *, char const *)
int dns_mxip(ipalloc *ia, stralloc *sa, unsigned long random)
int dns_ip(ipalloc *ia, stralloc *sa)
void c(char *, char *, char *, int, int, int)
void p(char *, char *, int, int, int)
void hmac_md5(unsigned char *text, int text_len, unsigned char *key, int key_len, unsigned char *digest)
int ipme_is(struct ip_mx *)
char tmpbuf[BUFSIZE_LINE]
GEN_ALLOC_readyplus(prioq, struct prioq_elt, p, len, a, i, n, x, 100, prioq_readyplus)
char inbuf[BUFFER_MTUSIZE]
ssize_t saferead(int fd, char *buf, int len)
struct constmap mapauthsenders
struct constmap mapqmtproutes
int xtext(stralloc *sa, char *s, int len)
char frombuf[BUFFER_SMALL]
void addrmangle(stralloc *saout, char *address, int *flagalias, int flagcname)
struct constmap mapdomainips
GEN_ALLOC_typedef(GEN_ALLOC_readyplus(saa, GEN_ALLOC_readyplus(stralloc, GEN_ALLOC_readyplus(sa, GEN_ALLOC_readyplus(len, GEN_ALLOC_readyplus(a)
struct constmap maptlsdestinations
void quit(char *prepend, char *append)
unsigned long verifydepth
void outsafe(stralloc *sa)
struct constmap mapdomaincerts
int utf8string(unsigned char *ch, int len)
char bufsmall[BUFFER_SMALL]
unsigned long timeoutconnect
ssize_t safewrite(int fd, char *buf, int len)
struct constmap mapsmtproutes
char outbuf[BUFFER_MTUSIZE]
int quote(stralloc *, stralloc *)
void tcpto_err(struct ip_mx *, int)
int tcpto(struct ip_mx *)
void temp_tlscipher(void)
void temp_tlsdigest(void)
void temp_tlspeerverify()
void temp_tlsamissing(void)
void temp_tlsainvalid(void)
void temp_tlscertfp(void)
void temp_invaliddigest(void)
int tlsa_check(const STACK_OF(X509) *, const stralloc, const unsigned long)
int tls_domaincerts(const stralloc)
int tls_destination(const stralloc)
tls_destination
int tls_fingerprint(X509 *, const char *, const int)
int tls_certkey(SSL_CTX *, const char *, const char *, char *)
int tls_checkpeer(SSL *, X509 *, const stralloc, const int, const int)
int tls_timeoutwrite(int t, int rfd, int wfd, SSL *tls, char *buf, int len)
int tls_timeoutread(int t, int rfd, int wfd, SSL *tls, char *buf, int len)
int tls_timeoutconn(int t, int rfd, int wfd, SSL *tls)
int ssl_ciphers(SSL_CTX *, const char *)
SSL * ssl_new(SSL_CTX *, int)
int ssl_ca(SSL_CTX *, const char *, const char *, int)