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();
351 if (ch !=
'-')
break;
352 while (ch !=
'\n')
get(&ch);
357 while (ch !=
'\n')
get(&ch);
365 if (smtptext.s)
if (smtptext.len) {
366 out(
"Remote host said: ");
367 for (i = 0; i < smtptext.len; ++i)
368 if (!smtptext.s[i]) smtptext.s[i] =
'?';
369 if (buffer_put(&
bs,smtptext.s,smtptext.len) == -1)
_exit(0);
374void quit(
char *prepend,
char *append)
376 buffer_putsflush(&
bo,
"QUIT\r\n");
406 if (
inbuf[
in] ==
'\r') {
in++;
continue; }
422 buffer_put(&
bo,
".\r\n",3);
488 if (smtptext.len <= 12)
return 0;
489 while (n < smtptext.len - 12) {
490 if (case_startb(smtptext.s + n + 4,8,
"STARTTLS"))
return 1;
491 n += str_chr(smtptext.s + n,
'\n') + 1;
500 STACK_OF(X509) *certs;
503 cert = SSL_get_peer_certificate(
ssl);
504 if (!cert) {
flagtls = 100;
return; }
506 if ((certs = SSL_get_peer_cert_chain(
ssl)) == NULL) {
507 certs = sk_X509_new_null();
509 sk_X509_push(certs,cert);
549 if (ncerts) sk_X509_free(certs);
561 if ((
unsigned char) ch[i++] > 127)
return 1;
571 stralloc receivedline = {0};
576 r = buffer_get(&
bi,&ch,1);
579 if (ch ==
'\r')
continue;
582 if (!stralloc_append(&header,
"\r"))
temp_nomem();
583 if (!stralloc_append(&header,
"\n"))
temp_nomem();
584 if (case_starts(receivedline.s,
"Date:"))
return 0;
585 if (case_starts(receivedline.s,
"Received: from"))
received++;
587 if (case_starts(receivedline.s,
" by ")) {
588 for (i = 6; i < receivedline.len - 6; ++i)
589 if (*(receivedline.s + i) ==
' ')
590 if (case_starts(receivedline.s + i + 1,
"with UTF8"))
return 1;
596 if (!stralloc_append(&header,&ch))
temp_nomem();
597 if (!stralloc_catb(&receivedline,&ch,1))
temp_nomem();
612 if (smtptext.len <= 8)
return 0;
613 while (n < smtptext.len - 8) {
614 if (case_startb(smtptext.s + n + 4,4,
"SIZE"))
return 1;
615 n += str_chr(smtptext.s + n,
'\n') + 1;
623 buffer_puts(&
bo,
"EHLO ");
625 buffer_puts(&
bo,
"\r\n");
629 buffer_puts(&
bo,
"HELO ");
631 buffer_puts(&
bo,
"\r\n");
636 if (
code >= 500)
quit(
"DConnected to ",
" but my name was rejected");
637 if (
code != 250)
quit(
"ZConnected to ",
" but my name was rejected");
644 buffer_puts(&
bo,
"STARTTLS\r\n");
654 quit(
"ZConnected to ",
" but STARTTLS was rejected");
660 buffer_puts(&
bo,
"MAIL FROM:<");
662 buffer_puts(&
bo,
">");
664 buffer_puts(&
bo,
" SMTPUTF8");
666 buffer_puts(&
bo,
" SIZE=");
669 buffer_puts(&
bo,
"\r\n");
686static const char hextab[] =
"0123456789abcdef";
696 for (i = 0; i < len; i++) {
698 if (c < 33 || c > 126 ||
c ==
'=' ||
c ==
'+') {
699 xch[0] = hextab[(
c >> 4) & 0x0f];
700 xch[1] = hextab[
c & 0x0f];
712 buffer_puts(&
bo,
"MAIL FROM:<");
714 buffer_puts(&
bo,
"> AUTH=");
717 buffer_puts(&
bo,
" SMTPUTF8");
719 buffer_puts(&
bo,
" SIZE=");
722 buffer_puts(&
bo,
"\r\n");
728 buffer_puts(&
bo,
"AUTH PLAIN\r\n");
731 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH PLAIN)");
738 if (b64encode(&
plain,&
auth))
quit(
"ZConnected to ",
" but unable to base64encode (plain)");
740 buffer_puts(&
bo,
"\r\n");
745 case 432:
quit(
"DConnected to ",
" but password expired");
746 case 534:
quit(
"ZConnected to ",
" but authentication mechamism too weak (plain)");
747 default:
quit(
"ZConnected to ",
" but authentication was rejected (plain)");
754 buffer_puts(&
bo,
"AUTH LOGIN\r\n");
757 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH LOGIN)");
759 if (b64encode(&
user,&
auth))
quit(
"ZConnected to ",
" but unable to base64encode user");
762 buffer_puts(&
bo,
"\r\n");
765 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (username)");
768 if (b64encode(&
pass,&
auth))
quit(
"ZConnected to ",
" but unable to base64encode pass");
770 buffer_puts(&
bo,
"\r\n");
775 case 432:
quit(
"DConnected to ",
" but password expired");
776 case 534:
quit(
"ZConnected to ",
" but authentication mechanism is too weak (login)");
777 default:
quit(
"ZConnected to ",
" but authentication was rejected (login)");
788 buffer_puts(&
bo,
"AUTH CRAM-MD5\r\n");
791 if (
smtpcode() != 334)
quit(
"ZConnected to ",
" but authentication was rejected (AUTH CRAM-MD5)");
792 if (str_chr(smtptext.s + 4,
' ')) {
794 if (!stralloc_copyb(&
slop,smtptext.s + 4,smtptext.len - 5))
temp_nomem();
796 quit(
"ZConnected to ",
" but unable to base64decode challenge");
801 for (
j = 0;
j < 16;
j++) {
802 digascii[2 *
j] = hextab[(
unsigned char) digest[
j] >> 4];
803 digascii[2 *
j + 1] = hextab[(
unsigned char) digest[
j] & 0x0f];
813 if (b64encode(&
slop,&
auth))
quit(
"ZConnected to ",
" but unable to base64encode username+digest");
816 buffer_puts(&
bo,
"\r\n");
821 case 432:
quit(
"DConnected to ",
" but password expired");
822 case 534:
quit(
"ZConnected to ",
" but authentication mechamism too weak (cram)");
823 default:
quit(
"ZConnected to ",
" but authentication was rejected (cram)");
832 if (smtptext.len <= 12)
return;
833 while (n < smtptext.len - 12) {
834 if (case_startb(smtptext.s + n + 4,4,
"AUTH")) {
835 for (
int i = n + 4; i < smtptext.len - 5; ++i) {
836 if (case_startb(smtptext.s + i,4,
"CRAM"))
838 if (case_startb(smtptext.s + i,5,
"LOGIN"))
840 if (case_startb(smtptext.s + i,5,
"PLAIN"))
844 n += str_chr(smtptext.s + n,
'\n') + 1;
864 if (
code >= 500)
quit(
"DConnected to ",
" but sender was rejected");
865 if (
code == 421 ||
code == 450)
quit(
"ZConnected to ",
" but probably greylisted");
866 if (
code >= 400)
quit(
"ZConnected to ",
" but sender was rejected");
867 if (
code != 220)
quit(
"ZConnected to ",
" but greeting failed");
885 if (
code >= 500)
quit(
"DConnected to ",
" but sender was rejected");
886 if (
code >= 400)
quit(
"ZConnected to ",
" but sender was probably greylisted");
890 buffer_puts(&
bo,
"RCPT TO:<");
892 buffer_puts(&
bo,
">\r\n");
897 if (
code == 552)
quit(
"DConnected to ",
" but message size is too large");
898 if (
code == 452)
quit(
"ZConnected to ",
" however insufficient storage space available");
903 }
else if (
code >= 500) {
906 }
else if (
code >= 400) {
914 if (!flagbother)
quit(
"DGiving up on ",
"");
916 buffer_putsflush(&
bo,
"DATA\r\n");
919 if (
code >= 500)
quit(
"D",
" failed on DATA command");
920 if (
code >= 400)
quit(
"Z",
" failed on DATA command");
922 buffer_putflush(&
bo,header.s,header.len);
927 if (
code >= 500)
quit(
"D",
" failed after I sent the message");
928 if (
code >= 400)
quit(
"Z",
" failed after I sent the message");
930 case 100:
case 110:
quit(
"K",
" TLS transmitted message accepted");
break;
931 case 101:
case 111:
quit(
"K",
" TLS (verified CA) transmitted message accepted");
break;
932 case 102:
case 112:
quit(
"K",
" TLS (validated CA+DN*) transmitted message accepted");
break;
933 case 103:
case 113:
quit(
"K",
" TLS (validated CA+DN) transmitted message accepted");
break;
934 case 104:
case 114:
quit(
"K",
" TLS (CERT pinning) transmitted message accepted");
break;
935 case 105:
case 115:
quit(
"K",
" TLS (TLSA EE validated) transmitted message accepted");
break;
936 case 106:
case 116:
quit(
"K",
" TLS (TLSA TA validated) transmitted message accepted");
break;
937 case 107:
case 117:
quit(
"K",
" TLS (TLSA PKIX verified) transmitted message accepted");
break;
938 default:
quit(
"K",
" accepted message");
break;
948 unsigned long len = 0;
966 out(
"DMessage for: ");
outhost();
out(
" has zero bytes. Giving up.\n");
969 buffer_put(&
bo,
num,fmt_ulong(
num,len + 1));
970 buffer_put(&
bo,
":\n",2);
972 n = buffer_feed(&
bi);
973 if (n <= 0)
_exit(1);
974 x = buffer_PEEK(&
bi);
979 buffer_put(&
bo,
",",1);
982 buffer_put(&
bo,
num,fmt_ulong(
num,len));
983 buffer_put(&
bo,
":",1);
985 buffer_put(&
bo,
",",1);
990 buffer_put(&
bo,
num,fmt_ulong(
num,len));
991 buffer_put(&
bo,
":",1);
994 buffer_put(&
bo,
":",1);
996 buffer_put(&
bo,
",",1);
998 buffer_put(&
bo,
",",1);
1007 if (ch ==
':')
break;
1010 len = 10 * len + (ch -
'0');
1014 if ((ch !=
'Z') && (ch !=
'D') && (ch !=
'K'))
temp_proto();
1016 if (!stralloc_copyb(&smtptext,&ch,1))
temp_nomem();
1018 if (!stralloc_cats(&smtptext,
"qmtps:"))
temp_nomem();
1020 if (!stralloc_cats(&smtptext,
"qmtp:"))
temp_nomem();
1028 for (len = 0; len < smtptext.len; ++len) {
1029 ch = smtptext.s[len];
1030 if ((ch < 32) || (ch > 126)) smtptext.s[len] =
'?';
1034 smtptext.s[smtptext.len - 1] =
'\n';
1036 if (smtptext.s[0] ==
'K')
out(
"r");
1037 else if (smtptext.s[0] ==
'D') {
1045 if (buffer_put(&
bs,smtptext.s + 1,smtptext.len - 1) == -1)
temp_qmtpnoc();
1085 switch ((r = dns_cname(&cn,&
canonhost))) {
1135int main(
int argc,
char *
const argv[])
1137 static ipalloc ip = {0};
1138 stralloc netif = {0};
1143 unsigned long random;
1145 unsigned long prefme;
1165 i = str_chr(
sender.s,
'@');
1183 j = str_chr(localip,
'%');
1184 if (localip[
j] !=
'%')
j = 0;
1185 k = str_chr(localip,
'|');
1186 if (localip[
k] !=
'|')
k = 0;
1200 for (i = 0; i <=
sender.len; ++i)
1240 if (relayhost && !*relayhost) relayhost = 0;
1243 for (i = 0; i <=
host.len; ++i) {
1244 if ((i == 0) || (i ==
host.len) || (
host.s[i] ==
'.'))
1253 if (relayhost && !*relayhost) relayhost = 0;
1256 i = str_chr(relayhost,
'|');
1257 if (relayhost[i] ==
'|') {
1258 j = str_chr(relayhost + i + 1,
'|');
1259 if (relayhost[i +
j + 1] ==
'|') {
1261 relayhost[i +
j + 1] = 0;
1265 k = str_chr(relayhost + i +
j + 2,
'|');
1266 if (relayhost[i +
j +
k + 2] ==
'|') {
1267 relayhost[i +
j +
k + 2] = 0;
1268 localip = relayhost + i +
j +
k + 3;
1273 p = str_chr(relayhost,
';');
1274 if (relayhost[
p] ==
';') {
1275 if (relayhost[
p + 1] ==
's') {
flagsmtps = 1;
p++; }
1276 scan_ulong(relayhost +
p + 1,&
port);
1283 char *asciihost = 0;
1285 switch (idn2_lookup_u8(
host.s,(uint8_t**)&asciihost,IDN2_NFC_INPUT)) {
1286 case IDN2_OK:
break;
1398 if (fstat(0,&st) == -1)
quit(
"Z",
" unable to fstat stdin");
1411 random =
now() + (getpid() << 16);
1421#ifdef DEFERREDBOUNCES
1429 for (i = 0; i < ip.len; ++i)
1432 if (ip.ix[i].pref == 0 && ip.ix[i].mxh[0] ==
'.')
1435 if (ip.ix[i].pref < prefme)
1436 prefme = ip.ix[i].pref;
1439 if (relayhost) prefme = 300000;
1440 if (flagallaliases) prefme = 500000;
1443 i = str_chr(localip,
':');
1444 if (localip[i] ==
':') ip6flag = 1;
1448 for (i = 0; i < ip.len; ++i) {
1449 if (ip6flag == -1 && ip.ix[i].af == AF_INET6)
continue;
1450 if (ip6flag == 1 && ip.ix[i].af == AF_INET)
continue;
1451 if (ip.ix[i].pref < prefme)
break;
1459 for (i = 0; i < ip.len; ++i) {
1460 if (ip.ix[i].pref < prefme) {
1461 if (ip6flag == -1 && ip.ix[i].af == AF_INET6)
continue;
1462 if (ip6flag == 1 && ip.ix[i].af == AF_INET)
continue;
1463 if (
tcpto(&ip.ix[i]))
continue;
1465 smtpfd = socket(ip.ix[i].af,SOCK_STREAM,0);
1466 if (
smtpfd == -1)
continue;
1470 j = str_chr(localip,
':');
1471 if (localip[
j] ==
':') {
1473 if (byte_equal((
char *)ip.ix[i].addr.ip6.d,16,
ip6))
continue;
1474 ifidx = socket_getifidx(netif.s);
1478 if (byte_equal((
char *)ip.ix[i].addr.ip4.d,4,
ip4))
continue;
1485 if (ip.ix[i].af == AF_INET6)
1497 if (
flagtls == 9 && errno == EPROTO) {
1500 if (errno == ETIMEDOUT || errno == ECONNREFUSED || errno == EPROTO)
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(char *text, int text_len, char *key, int key_len, 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)
int utf8string(char *ch, int len)
ssize_t safewrite(int fd, char *buf, size_t len)
char inbuf[BUFFER_MTUSIZE]
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 bufsmall[BUFFER_SMALL]
unsigned long timeoutconnect
struct constmap mapsmtproutes
ssize_t saferead(int fd, char *buf, size_t len)
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_destination(stralloc)
tls_destination
int tls_domaincerts(stralloc)
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_timeoutconn(int, int, int, SSL *)
int tls_timeoutwrite(int, int, int, SSL *, char *, int)
int tls_timeoutread(int, int, int, SSL *, char *, int)
int ssl_ciphers(SSL_CTX *, const char *)
SSL * ssl_new(SSL_CTX *, int)
int ssl_ca(SSL_CTX *, const char *, const char *, int)