33#include "timeoutconn.h"
43#define WHO "qmail-remote"
45#define MAX_SIZE 200000000
46#define HUGESMTPTEXT 1000
50#define PORT_SUBMISSION 587
51#define PORT_QMTPS 6209
73static stralloc sauninit = {0};
113 if (buffer_puts(&
bs,s) == -1)
118 if (buffer_put(&
bs,
"\0",1) == -1)
133 for (i = 0; i <
sa->len; ++i) {
135 if (ch == 0)
continue;
136 if (ch < 33) ch =
'?';
137 if (ch > 126) ch =
'?';
138 if (buffer_put(&
bs,&ch,1) == -1)
_exit(0);
144 out(
"ZInvalid ipaddr in control/domainips (#4.3.0)\n");
149 out(
"ZOut of memory. (#4.3.0)\n");
154 out(
"ZSystem resources temporarily unavailable. (#4.3.0)\n");
159 out(
"ZCan't bind to local ip address: ");
166 out(
"ZSorry, I wasn't able to establish an SMTP connection: ");
173 out(
"ZSorry, I wasn't able to establish an QMTP connection: ");
180 out(
"ZUnable to read message. (#4.3.0)\n");
185 out(
"ZCNAME lookup failed temporarily for: ");
192 out(
"ZSorry, I couldn't find any host named: ");
199 out(
"ZSorry, I couldn't find a mail exchanger or IP address for: ");
201 out(
". Will try again. (#4.1.2)\n");
206 out(
"ZUnable to switch to home directory. (#4.3.0)\n");
211 out(
"ZUnable to read control files. (#4.3.0)\n");
216 out(
"DSMTP cannot transfer messages with partial final lines. (#5.6.2)\n");
221 out(
"ZRecipient did not talk proper QMTP (#4.3.0)\n");
226 out(
"Dqmail-remote was invoked improperly. (#5.3.5)\n");
231 out(
"DSorry, I couldn't find any host named: ");
238 out(
"DSorry, I couldn't find a mail exchanger or IP address for: ");
245 out(
"DSorry. Although I'm listed as a best-preference MX or A for that host,\n\
246it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
251 out(
"KNo supported AUTH method found, continuing without authentication.\n");
272 out(
"ZConnected to ");
274 out(
" but connection died. ");
317static stralloc smtptext = {0};
318static stralloc header = {0};
322 buffer_get(&
bf,ch,1);
325 if (!stralloc_append(&smtptext,ch))
temp_nomem();
340 if (ch !=
'-')
break;
341 while (ch !=
'\n')
get(&ch);
346 while (ch !=
'\n')
get(&ch);
354 if (smtptext.s)
if (smtptext.len) {
355 out(
"Remote host said: ");
356 for (i = 0; i < smtptext.len; ++i)
357 if (!smtptext.s[i]) smtptext.s[i] =
'?';
358 if (buffer_put(&
bs,smtptext.s,smtptext.len) == -1)
_exit(0);
363void quit(
char *prepend,
char *append)
365 buffer_putsflush(&
bo,
"QUIT\r\n");
381 r = buffer_get(&
bi,&ch,1);
384 if (ch ==
'.') buffer_put(&
bo,
".",1);
388 buffer_put(&
bo,&ch,1);
389 r = buffer_get(&
bi,&ch,1);
393 buffer_put(&
bo,
"\r\n",2);
397 buffer_put(&
bo,
".\r\n",3);
463 while ((i += str_chr(smtptext.s+i,
'\n') + 1) &&
464 (i + 8 < smtptext.len) ) {
465 if (!str_diffn(smtptext.s + i + 4,
"STARTTLS",8))
return 1; }
473 STACK_OF(X509) *certs;
475 cert = SSL_get_peer_certificate(
ssl);
476 if (!cert) {
flagtls = 100;
return; }
478 if ((certs = SSL_get_peer_cert_chain(
ssl)) == NULL) {
479 certs = sk_X509_new_null();
480 sk_X509_push(certs, cert);
532 if (ch[i++] > 127)
return 1;
542 stralloc receivedline = {0};
547 r = buffer_get(&
bi,&ch,1);
550 if (ch ==
'\r')
continue;
553 if (!stralloc_append(&header,
"\r"))
temp_nomem();
554 if (!stralloc_append(&header,
"\n"))
temp_nomem();
555 if (case_starts(receivedline.s,
"Date:"))
return 0;
556 if (case_starts(receivedline.s,
"Received: from"))
received++;
558 if (case_starts(receivedline.s,
" by ")) {
559 for (i = 6; i < receivedline.len - 6; ++i)
560 if (*(receivedline.s + i) ==
' ')
561 if (case_starts(receivedline.s + i + 1,
"with UTF8"))
return 1;
567 if (!stralloc_append(&header,&ch))
temp_nomem();
568 if (!stralloc_catb(&receivedline,&ch,1))
temp_nomem();
582 if (smtptext.len > 10)
583 for (i = 0; i < smtptext.len; ++i) {
584 if (case_starts(smtptext.s + i,
"SIZE "))
return 1;
591 buffer_puts(&
bo,
"EHLO ");
593 buffer_puts(&
bo,
"\r\n");
597 buffer_puts(&
bo,
"HELO ");
599 buffer_puts(&
bo,
"\r\n");
604 if (
code >= 500)
quit(
"DConnected to ",
" but my name was rejected");
605 if (
code != 250)
quit(
"ZConnected to ",
" but my name was rejected");
612 buffer_puts(&
bo,
"STARTTLS\r\n");
622 quit(
"ZConnected to ",
" but STARTTLS was rejected");
628 buffer_puts(&
bo,
"MAIL FROM:<");
630 buffer_puts(&
bo,
">");
632 buffer_puts(&
bo,
" SMTPUTF8");
634 buffer_puts(&
bo,
" SIZE=");
637 buffer_puts(&
bo,
"\r\n");
654static const char hextab[] =
"0123456789abcdef";
664 for (i = 0; i < len; i++) {
666 if (c < 33 || c > 126 ||
c ==
'=' ||
c ==
'+') {
667 xch[0] = hextab[(
c >> 4) & 0x0f];
668 xch[1] = hextab[
c & 0x0f];
680 buffer_puts(&
bo,
"MAIL FROM:<");
682 buffer_puts(&
bo,
"> AUTH=");
685 buffer_puts(&
bo,
" SMTPUTF8");
687 buffer_puts(&
bo,
" SIZE=");
690 buffer_puts(&
bo,
"\r\n");
696 buffer_puts(&
bo,
"AUTH PLAIN\r\n");
699 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH PLAIN)");
708 buffer_puts(&
bo,
"\r\n");
713 case 432:
quit(
"DConnected to ",
" but password expired");
714 case 534:
quit(
"ZConnected to ",
" but authentication mechamism too weak (plain)");
715 default:
quit(
"ZConnected to ",
" but authentication was rejected (plain)");
722 buffer_puts(&
bo,
"AUTH LOGIN\r\n");
725 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH LOGIN)");
730 buffer_puts(&
bo,
"\r\n");
733 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (username)");
738 buffer_puts(&
bo,
"\r\n");
743 case 432:
quit(
"DConnected to ",
" but password expired");
744 case 534:
quit(
"ZConnected to ",
" but authentication mechanism is too weak (login)");
745 default:
quit(
"ZConnected to ",
" but authentication was rejected (login)");
753 unsigned char digest[16];
754 unsigned char digascii[33];
756 buffer_puts(&
bo,
"AUTH CRAM-MD5\r\n");
759 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH CRAM-MD5)");
760 if (str_chr(smtptext.s + 4,
' ')) {
762 if (!stralloc_copyb(&
slop,smtptext.s + 4,smtptext.len - 5))
temp_nomem();
768 for (
j = 0;
j < 16;
j++) {
769 digascii[2 *
j] = hextab[digest[
j] >> 4];
770 digascii[2 *
j + 1] = hextab[digest[
j] & 0x0f];
783 buffer_puts(&
bo,
"\r\n");
788 case 432:
quit(
"DConnected to ",
" but password expired");
789 case 534:
quit(
"ZConnected to ",
" but authentication mechamism too weak (cram)");
790 default:
quit(
"ZConnected to ",
" but authentication was rejected (cram)");
799 if (smtptext.len > 8)
800 for (i = 4; i < smtptext.len - 5; ++i) {
801 if (case_starts(smtptext.s + i,
"CRAM"))
803 if (case_starts(smtptext.s + i,
"LOGIN"))
805 if (case_starts(smtptext.s + i,
"PLAIN"))
825 if (
code >= 500)
quit(
"DConnected to ",
" but sender was rejected");
826 if (
code == 421 ||
code == 450)
quit(
"ZConnected to ",
" but probably greylisted");
827 if (
code >= 400)
quit(
"ZConnected to ",
" but sender was rejected");
828 if (
code != 220)
quit(
"ZConnected to ",
" but greeting failed");
846 if (
code >= 500)
quit(
"DConnected to ",
" but sender was rejected");
847 if (
code >= 400)
quit(
"ZConnected to ",
" but sender was probably greylisted");
851 buffer_puts(&
bo,
"RCPT TO:<");
853 buffer_puts(&
bo,
">\r\n");
858 if (
code == 552)
quit(
"DConnected to ",
" but message size is too large");
859 if (
code == 452)
quit(
"ZConnected to ",
" however insufficient storage space available");
864 }
else if (
code >= 500) {
867 }
else if (
code >= 400) {
875 if (!flagbother)
quit(
"DGiving up on ",
"");
877 buffer_putsflush(&
bo,
"DATA\r\n");
880 if (
code >= 500)
quit(
"D",
" failed on DATA command");
881 if (
code >= 400)
quit(
"Z",
" failed on DATA command");
883 buffer_putflush(&
bo,header.s,header.len);
888 if (
code >= 500)
quit(
"D",
" failed after I sent the message");
889 if (
code >= 400)
quit(
"Z",
" failed after I sent the message");
891 case 100:
case 110:
quit(
"K",
" TLS transmitted message accepted");
break;
892 case 101:
case 111:
quit(
"K",
" TLS (verified CA) transmitted message accepted");
break;
893 case 102:
case 112:
quit(
"K",
" TLS (validated CA+DN*) transmitted message accepted");
break;
894 case 103:
case 113:
quit(
"K",
" TLS (validated CA+DN) transmitted message accepted");
break;
895 case 104:
case 114:
quit(
"K",
" TLS (CERT pinning) transmitted message accepted");
break;
896 case 105:
case 115:
quit(
"K",
" TLS (TLSA EE validated) transmitted message accepted");
break;
897 case 106:
case 116:
quit(
"K",
" TLS (TLSA TA validated) transmitted message accepted");
break;
898 case 107:
case 117:
quit(
"K",
" TLS (TLSA PKIX verified) transmitted message accepted");
break;
899 default:
quit(
"K",
" accepted message");
break;
925 buffer_put(&
bo,
num,fmt_ulong(
num,len + 1));
926 buffer_put(&
bo,
":\n",2);
928 n = buffer_feed(&
bi);
929 if (n <= 0)
_exit(1);
930 x = buffer_PEEK(&
bi);
935 buffer_put(&
bo,
",",1);
938 buffer_put(&
bo,
num,fmt_ulong(
num,len));
939 buffer_put(&
bo,
":",1);
941 buffer_put(&
bo,
",",1);
946 buffer_put(&
bo,
num,fmt_ulong(
num,len));
947 buffer_put(&
bo,
":",1);
950 buffer_put(&
bo,
":",1);
952 buffer_put(&
bo,
",",1);
954 buffer_put(&
bo,
",",1);
963 if (ch ==
':')
break;
966 len = 10 * len + (ch -
'0');
970 if ((ch !=
'Z') && (ch !=
'D') && (ch !=
'K'))
temp_proto();
972 if (!stralloc_copyb(&smtptext,&ch,1))
temp_proto();
974 if (!stralloc_cats(&smtptext,
"qmtps:"))
temp_nomem();
976 if (!stralloc_cats(&smtptext,
"qmtp:"))
temp_nomem();
984 for (len = 0; len < smtptext.len; ++len) {
985 ch = smtptext.s[len];
986 if ((ch < 32) || (ch > 126)) smtptext.s[len] =
'?';
990 smtptext.s[smtptext.len - 1] =
'\n';
992 if (smtptext.s[0] ==
'K')
out(
"r");
993 else if (smtptext.s[0] ==
'D') {
1001 if (buffer_put(&
bs,smtptext.s + 1,smtptext.len - 1) == -1)
temp_qmtpnoc();
1040 switch ((r = dns_cname(&cn,&
canonhost))) {
1092 static ipalloc ip = {0};
1093 stralloc netif = {0};
1098 unsigned long random;
1100 unsigned long prefme;
1120 i = str_chr(
sender.s,
'@');
1138 j = str_chr(localip,
'%');
1139 if (localip[
j] !=
'%')
j = 0;
1140 k = str_chr(localip,
'|');
1141 if (localip[
k] !=
'|')
k = 0;
1156 for (i = 0; i <=
sender.len; ++i)
1196 if (relayhost && !*relayhost) relayhost = 0;
1199 for (i = 0; i <=
host.len; ++i) {
1200 if ((i == 0) || (i ==
host.len) || (
host.s[i] ==
'.'))
1209 if (relayhost && !*relayhost) relayhost = 0;
1212 i = str_chr(relayhost,
'|');
1213 if (relayhost[i] ==
'|') {
1214 j = str_chr(relayhost + i + 1,
'|');
1215 if (relayhost[i +
j + 1] ==
'|') {
1217 relayhost[i +
j + 1] = 0;
1221 k = str_chr(relayhost + i +
j + 2,
'|');
1222 if (relayhost[i +
j +
k + 2] ==
'|') {
1223 relayhost[i +
j +
k + 2] = 0;
1224 localip = relayhost + i +
j +
k + 3;
1229 p = str_chr(relayhost,
';');
1230 if (relayhost[
p] ==
';') {
1231 if (relayhost[
p + 1] ==
's') {
flagsmtps = 1;
p++; }
1232 scan_ulong(relayhost +
p + 1,&
port);
1239 char *asciihost = 0;
1241 switch (idn2_lookup_u8(
host.s,(uint8_t**)&asciihost,IDN2_NFC_INPUT)) {
1242 case IDN2_OK:
break;
1354 if (fstat(0,&st) == -1)
quit(
"Z",
" unable to fstat stdin");
1367 random =
now() + (getpid() << 16);
1377#ifdef DEFERREDBOUNCES
1385 for (i = 0; i < ip.len; ++i)
1387 if (ip.ix[i].pref < prefme)
1388 prefme = ip.ix[i].pref;
1390 if (relayhost) prefme = 300000;
1391 if (flagallaliases) prefme = 500000;
1394 i = str_chr(localip,
':');
1395 if (localip[i] ==
':') ip6flag = 1;
1399 for (i = 0; i < ip.len; ++i) {
1400 if (ip6flag == -1 && ip.ix[i].af == AF_INET6)
continue;
1401 if (ip6flag == 1 && ip.ix[i].af == AF_INET)
continue;
1402 if (ip.ix[i].pref < prefme)
break;
1411 for (i = 0; i < ip.len; ++i) {
1412 if (ip.ix[i].pref < prefme) {
1413 if (ip6flag == -1 && ip.ix[i].af == AF_INET6)
continue;
1414 if (ip6flag == 1 && ip.ix[i].af == AF_INET)
continue;
1415 if (
tcpto(&ip.ix[i]))
continue;
1417 smtpfd = socket(ip.ix[i].af,SOCK_STREAM,0);
1418 if (
smtpfd == -1)
continue;
1422 j = str_chr(localip,
':');
1423 if (localip[
j] ==
':') {
1425 if (byte_equal(ip.ix[i].addr.ip6.d,16,
ip6))
continue;
1426 ifidx = socket_getifidx(netif.s);
1430 if (byte_equal(ip.ix[i].addr.ip4.d,4,
ip4))
continue;
1437 if (ip.ix[i].af == AF_INET6)
1449 if (
flagtls == 9 && errno == EPROTO) {
1452 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(int *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)
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
char smallbuf[BUFFER_SMALL]
int utf8string(unsigned char *ch, int len)
struct constmap mapsmtproutes
char outbuf[BUFFER_MTUSIZE]
int quote(stralloc *, stralloc *)
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)