diff options
author | Jannis Hoffmann <jannis@fehcom.de> | 2024-07-09 11:44:11 +0200 |
---|---|---|
committer | Jannis Hoffmann <jannis@fehcom.de> | 2024-07-09 11:44:11 +0200 |
commit | f1b71c9fe7dbb4886588a036399cf5ebe16b7c47 (patch) | |
tree | e07786aa479c9fb6ee3e537078470aaab5454f80 /sqmail-4.3.07/src/qmail-remote.c | |
parent | a293489ee83c8b05d845a162dc2a4de026f3775d (diff) |
removed top level directory
Diffstat (limited to 'sqmail-4.3.07/src/qmail-remote.c')
-rw-r--r-- | sqmail-4.3.07/src/qmail-remote.c | 1476 |
1 files changed, 0 insertions, 1476 deletions
diff --git a/sqmail-4.3.07/src/qmail-remote.c b/sqmail-4.3.07/src/qmail-remote.c deleted file mode 100644 index d2f08dd..0000000 --- a/sqmail-4.3.07/src/qmail-remote.c +++ /dev/null @@ -1,1476 +0,0 @@ -#ifdef IDN2 -#include <idn2.h> -#endif -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <unistd.h> -#include "sig.h" -#include "stralloc.h" -#include "buffer.h" -#include "scan.h" -#include "case.h" -#include "byte.h" -#include "logmsg.h" -#include "qmail.h" -#include "auto_qmail.h" -#include "control.h" -#include "dns.h" -#include "alloc.h" -#include "genalloc.h" -#include "quote.h" -#include "fmt.h" -#include "ip.h" -#include "ipalloc.h" -#include "ipme.h" -#include "str.h" -#include "now.h" -#include "exit.h" -#include "constmap.h" -#include "tcpto.h" -#include "timeout.h" -#include "timeoutconn.h" -#include "base64.h" -#include "socket_if.h" -#include "ucspissl.h" -#include "hmac_md5.h" -#include "tls_remote.h" -#include "tls_errors.h" -#include "tls_timeoutio.h" -#include "uint_t.h" - -#define WHO "qmail-remote" - -#define QMTP_MAX 200000000 /* 190 MB for QMTP */ -#define HUGESMTPTEXT 1000 /* RFC 5322; was 5000 chars/line */ -#define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */ -#define PORT_QMTP 209 -#define PORT_SMTPS 465 -#define PORT_SUBMISSION 587 -#define PORT_QMTPS 6209 -#define VERIFYDEPTH 1 -#define TCP_TIMEOUT 60 -#define SMTP_TIMEOUT 1200 - -unsigned long port = PORT_SMTP; - -/** @file qmail-remote.c -- versatile SMTP(S)/QMTP(S) client */ - -int flagauth = 0; /* 1 = login; 2 = plain; 3 = crammd5 */ -int flagsmtps = 0; /* RFC 8314 - 'implicit TLS' */ -int flagtlsdomain = 0; /* 0 = no; 1 = yes; 2 = cert */ -int flagtls = 0; /* flagtls: XYZ - (mode) Z: -2 = rejected; -1 = not; 0 = no, default; Z > 0 see tls_remote.c - (prot) Y: 0 = StartTLS; 1 = SMTPS; 2 = QMTPS - (active) X: 1 = running TLS connection (after DNS lookup) - (done) Z: 1: CA chain; 2: Cert wildname; 3: Cert exactname; - 4: Cert fingerprint; 5: TLSA record */ -int flagverify = 0; /* 1 = verify Cert against CA; 2 = verify against Dir; 3 = triggerd by TLSA; - -2 = Cert pinning; -1 = no TLSA validation */ -int flagutf8 = 0; - -GEN_ALLOC_typedef(saa,stralloc,sa,len,a) -GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus) -static stralloc sauninit = {0}; - -stralloc helohost = {0}; -stralloc eaihost = {0}; -stralloc host = {0}; -stralloc idnhost = {0}; -stralloc sender = {0}; -stralloc canonhost = {0}; -stralloc remotehost = {0}; -stralloc canonbox = {0}; -stralloc senddomain = {0}; -stralloc sendip = {0}; - -stralloc domainips = {0}; -struct constmap mapdomainips; -char ip4[4]; -char ip6[16]; -uint32 ifidx = 0; -char *authsender = 0; - -stralloc smtproutes = {0}; -struct constmap mapsmtproutes; -stralloc qmtproutes = {0}; -struct constmap mapqmtproutes; - -saa reciplist = {0}; -stralloc recip = {0}; - -char msgsize[FMT_ULONG]; -unsigned long msize = 0; -struct ip_mx partner; - -SSL *ssl; -SSL_CTX *ctx; - -char bufsmall[BUFFER_SMALL]; -buffer bs = BUFFER_INIT(write,1,bufsmall,sizeof(bufsmall)); - -void out(char *s) -{ - if (buffer_puts(&bs,s) == -1) - _exit(0); - } -void zero() -{ - if (buffer_put(&bs,"\0",1) == -1) - _exit(0); -} -void zerodie() -{ - zero(); - buffer_flush(&bs); - if (ssl) tls_exit(ssl); - _exit(0); -} - -void outsafe(stralloc *sa) -{ - int i; - char ch; - for (i = 0; i < sa->len; ++i) { - ch = sa->s[i]; - if (ch == 0) continue; - if (ch < 33) ch = '?'; - if (ch > 126) ch = '?'; - if (buffer_put(&bs,&ch,1) == -1) _exit(0); - } -} - -void temp_noip() -{ - out("ZInvalid ipaddr in control/domainips (#4.3.0)\n"); - zerodie(); -} -void temp_nomem() -{ - out("ZOut of memory. (#4.3.0)\n"); - zerodie(); -} -void temp_oserr() -{ - out("ZSystem resources temporarily unavailable. (#4.3.0)\n"); - zerodie(); -} -void temp_osip() -{ - out("ZCan't bind to local ip address: "); - outsafe(&sendip); - out(". (#4.3.0)\n"); - zerodie(); -} -void temp_noconn() -{ - out("ZSorry, I wasn't able to establish an SMTP connection: "); - outsafe(&canonhost); - out(". (#4.3.0)\n"); - zerodie(); -} -void temp_qmtpnoc() -{ - out("ZSorry, I wasn't able to establish an QMTP connection: "); - outsafe(&canonhost); - out(". (#4.3.1)\n"); - zerodie(); -} -void temp_read() -{ - out("ZUnable to read message. (#4.3.0)\n"); - zerodie(); -} -void temp_dnscanon() -{ - out("ZCNAME lookup failed temporarily for: "); - outsafe(&canonhost); - out(". (#4.4.3)\n"); - zerodie(); -} -void temp_dns() -{ - out("ZSorry, I couldn't find any host named: "); - outsafe(&host); - out(". (#4.1.2)\n"); - zerodie(); -} -void temp_nomx() -{ - out("ZSorry, I couldn't find a mail exchanger or IP address for: "); - outsafe(&host); - out(". Will try again. (#4.1.2)\n"); - zerodie(); -} -void temp_chdir() -{ - out("ZUnable to switch to home directory. (#4.3.0)\n"); - zerodie(); -} -void temp_control() -{ - out("ZUnable to read control files. (#4.3.0)\n"); - zerodie(); -} -void perm_partialline() -{ - out("DSMTP cannot transfer messages with partial final line. (#5.6.2)\n"); - zerodie(); -} -void temp_proto() -{ - out("ZRecipient did not talk proper QMTP. (#4.3.0)\n"); - zerodie(); -} -void perm_usage() -{ - out("Dqmail-remote was invoked improperly. (#5.3.5)\n"); - zerodie(); -} -void perm_dns() -{ - out("DSorry, I couldn't find any host named: "); - outsafe(&host); - out(". (#5.1.2)\n"); - zerodie(); -} -void perm_nomx() -{ - out("DSorry, I couldn't find a mail exchanger or IP address for: "); - outsafe(&host); - out(". (#5.4.4)\n"); - zerodie(); -} -void perm_ambigmx() -{ - out("DSorry. Although I'm listed as a best-preference MX or A for that host,\n\ -it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n"); - zerodie(); -} -void err_authprot() -{ - out("ZSorry, no supported AUTH method found, trying later again. (#4.7.1)\n"); - zerodie(); -} - -void outhost() -{ - char ipaddr[IPFMT]; - int len; - - switch (partner.af) { - case AF_INET: - len = ip4_fmt(ipaddr,(char *)&partner.addr.ip4.d); break; - case AF_INET6: - len = ip6_fmt(ipaddr,(char *)&partner.addr.ip6.d); break; - } - if (buffer_put(&bs,ipaddr,len) == -1) _exit(0); -} - -int flagcritical = 0; - -void dropped() -{ - out("ZConnected to "); - outhost(); - out(" but connection died. "); - if (flagcritical) out("Possible duplicate! "); - out("(#4.4.2)\n"); - zerodie(); -} - -int timeoutconnect = TCP_TIMEOUT; -int smtpfd; -int timeout = SMTP_TIMEOUT; - -ssize_t saferead(int fd,char *buf,int len) -{ - int r; - if (ssl) { - r = tls_timeoutread(timeout,smtpfd,smtpfd,ssl,buf,len); - if (r < 0) temp_tlserr(); - } else { - r = timeoutread(timeout,smtpfd,buf,len); - } - if (r <= 0) dropped(); - return r; -} - -ssize_t safewrite(int fd,char *buf,int len) -{ - int r; - if (ssl) { - r = tls_timeoutwrite(timeout,smtpfd,smtpfd,ssl,buf,len); - if (r < 0) temp_tlserr(); - } else { - r = timeoutwrite(timeout,smtpfd,buf,len); - } - if (r <= 0) dropped(); - return r; -} - -char inbuf[BUFSIZE_LINE]; -buffer bi = BUFFER_INIT(read,0,inbuf,sizeof(inbuf)); -char outbuf[BUFSIZE_MESS]; -buffer bo = BUFFER_INIT(safewrite,-1,outbuf,sizeof(outbuf)); -char frombuf[BUFFER_SMALL]; -buffer bf = BUFFER_INIT(saferead,-1,frombuf,sizeof(frombuf)); - -static stralloc smtptext = {0}; -static stralloc header = {0}; - -void get(char *ch) -{ - buffer_get(&bf,ch,1); - if (*ch != '\r') - if (smtptext.len < HUGESMTPTEXT) - if (!stralloc_append(&smtptext,ch)) temp_nomem(); -} - -unsigned long smtpcode() -{ - unsigned char ch; - unsigned long code; - - if (!stralloc_copys(&smtptext,"")) temp_nomem(); - - get(&ch); code = ch - '0'; - get(&ch); code = code * 10 + (ch - '0'); - get(&ch); code = code * 10 + (ch - '0'); - for (;;) { - get(&ch); - if (ch != '-') break; - while (ch != '\n') get(&ch); - get(&ch); - get(&ch); - get(&ch); - } - while (ch != '\n') get(&ch); - - return code; -} - -void outsmtptext() -{ - int i; - if (smtptext.s) if (smtptext.len) { - out("Remote host said: "); - for (i = 0; i < smtptext.len; ++i) - if (!smtptext.s[i]) smtptext.s[i] = '?'; - if (buffer_put(&bs,smtptext.s,smtptext.len) == -1) _exit(0); - smtptext.len = 0; - } -} - -void quit(char *prepend,char *append) -{ - buffer_putsflush(&bo,"QUIT\r\n"); - /* waiting for remote side is just too ridiculous */ - out(prepend); - outhost(); - out(append); - out(".\n"); - outsmtptext(); - zerodie(); -} - -void blast() -{ - int r; - int in; - int out; - int eom = 1; // end-of-message <CRLF>.<CRLF> - char tmpbuf[BUFSIZE_MESS + 2]; // intermediate write buffer - -// New blast code; inspired by Bruce Guenter's 'fastremote patch' (2005) - - while ((r = buffer_get(&bi,inbuf,sizeof(inbuf)))) { // read into buffer - if (r == -1) temp_read(); - - for (in = out = 0; in < r;) { - if (eom && inbuf[in] == '.') { - tmpbuf[out++] = '.'; - tmpbuf[out++] = inbuf[in++]; - } - eom = 0; - while (in < r) { - if (inbuf[in] == '\r') { in++; continue; } // CR is DKIM input - if (inbuf[in] == '\n') { - eom = 1; - in++; - tmpbuf[out++] = '\r'; - tmpbuf[out++] = '\n'; - break; - } - tmpbuf[out++] = inbuf[in++]; - } - } - if (out) buffer_put(&bo,tmpbuf,out); - } - - if (!eom) perm_partialline(); - flagcritical = 1; - buffer_put(&bo,".\r\n",3); // LF seen; finish with .<CRLF> - buffer_flush(&bo); -} - -/* this file is too long -------------------------------------- client TLS */ - -stralloc cafile = {0}; -stralloc cadir = {0}; -stralloc certfile = {0}; -stralloc keyfile = {0}; -stralloc keypwd = {0}; -stralloc ciphers = {0}; - -char *tlsdestinfo = 0; -char *tlsdomaininfo = 0; - -stralloc domaincerts = {0}; -struct constmap mapdomaincerts; -stralloc tlsdestinations = {0}; -struct constmap maptlsdestinations; -unsigned long verifydepth = VERIFYDEPTH; - -void tls_init() -{ - ctx = ssl_client(); - ssl_errstr(); - if (!ctx) temp_tlsctx(); - -/* Fetch CA infos for dest */ - - if (flagverify > 0) - if (cafile.len || cadir.len) - if (!ssl_ca(ctx,cafile.s,cadir.s,(int) verifydepth)) temp_tlsca(); - - if (ciphers.len) - if (!ssl_ciphers(ctx,ciphers.s)) temp_tlscipher(); - -/* Prepare for Certificate Request */ - - if (flagtlsdomain == 2) - switch (tls_certkey(ctx,certfile.s,keyfile.s,keypwd.s)) { - case 0: break; - case -1: temp_tlscert(); - case -2: temp_tlskey(); - case -3: temp_tlschk(); - } - -/* Set SSL Context */ - - ssl = ssl_new(ctx,smtpfd); - if (!ssl) temp_tlsctx(); - -/* Setup SSL FDs */ - - if (!tls_conn(ssl,smtpfd)) temp_tlscon(); - -/* Go on in none-blocking mode */ - - if (tls_timeoutconn(timeout,smtpfd,smtpfd,ssl) <= 0) - temp_tlserr(); -} - -int starttls_peer() -{ - int i = 0; - - if (smtptext.len > 16) - for (i = 0; i < smtptext.len - 8; ++i) - if (case_starts(smtptext.s + i,"STARTTLS")) return 1; - - return 0; -} - -void tls_peercheck() -{ - X509 *cert; - STACK_OF(X509) *certs; - - cert = SSL_get_peer_certificate(ssl); - if (!cert) { flagtls = 100; return; } - - if ((certs = SSL_get_peer_cert_chain(ssl)) == NULL) { - certs = sk_X509_new_null(); - sk_X509_push(certs, cert); - } - - if (flagverify == -2) { // fingerprinting is silent - if (cafile.len) case_lowerb(cafile.s,cafile.len); - switch (tls_fingerprint(cert,cafile.s + 1,cafile.len - 2)) { - case -1: temp_tlspeercert(); - case -2: temp_tlsdigest(); - case -3: temp_invaliddigest(); - case 0: temp_tlscertfp(); - case 1: flagtls = 104; break; - } - } - - if (flagverify >= 0) { // TLSA is default - switch (tlsa_check(certs,remotehost,port)) { - case -4: temp_tlsamissing(); break; /* FIXME */ - case -3: temp_tlsainvalid(); break; - case -2: break; // unsupported type; may happen - case -1: break; // weird TLSA record - case 0: break; // no TLSA record given - case 1: case 2: flagtls = 107; flagverify = 3; break; // full certchain available (-PKIX) - case 3: flagtls = 106; flagverify = 0; break; // TA-CA; verify wont work - case 4: flagtls = 105; flagverify = 0; break; // Endpoint only - } - } - - if (flagverify > 0) { - switch (tls_checkpeer(ssl,cert,remotehost,flagtls,flagverify)) { - case -1: temp_tlspeercert(); - case -2: temp_tlspeerverify(); - case -3: temp_tlspeervalid(); - case 1: flagtls = 101; break; - case 2: flagtls = 102; break; - case 3: flagtls = 103; break; - } - } - - if (flagtls < 100) flagtls = 100; - - X509_free(cert); - X509_free(certs); - - return; -} - -/* this file is too long --------------------------------------- smtp UTF8 */ - -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; - int i; - int received = 0; - char ch; - stralloc receivedline = {0}; - -/* we consider only our own last written header */ - - for (;;) { - r = buffer_get(&bi,&ch,1); - if (r == 0) break; - if (r == -1) temp_read(); - if (ch == '\r') continue; // DKIM - - 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_starts(receivedline.s,"Date:")) return 0; /* header to quit asap */ - if (case_starts(receivedline.s,"Received: from")) received++; /* found Received header */ - if (received) { - if (case_starts(receivedline.s," by ")) { - for (i = 6; i < receivedline.len - 6; ++i) - if (*(receivedline.s + i) == ' ') - if (case_starts(receivedline.s + i + 1,"with UTF8")) return 1; - return 0; - } - } - if (!stralloc_copys(&receivedline,"")) temp_nomem(); - } else { - if (!stralloc_append(&header,&ch)) temp_nomem(); - if (!stralloc_catb(&receivedline,&ch,1)) temp_nomem(); - } - } - return 0; -} - -/* this file is too long -------------------------------------- smtp client */ - -unsigned long code; -int flagsize = 0; - -int smtp_size() -{ - int i; - if (smtptext.len > 10) - for (i = 0; i < smtptext.len; ++i) { - if (case_starts(smtptext.s + i,"SIZE ")) return 1; - } - return 0;; -} - -void smtp_greeting() -{ - buffer_puts(&bo,"EHLO "); - buffer_put(&bo,helohost.s,helohost.len); - buffer_puts(&bo,"\r\n"); - buffer_flush(&bo); - - if (smtpcode() != 250) { - buffer_puts(&bo,"HELO "); - buffer_put(&bo,helohost.s,helohost.len); - buffer_puts(&bo,"\r\n"); - buffer_flush(&bo); - - code = smtpcode(); - authsender = 0; - if (code >= 500) quit("DConnected to "," but my name was rejected"); - if (code != 250) quit("ZConnected to "," but my name was rejected"); - } - flagsize = smtp_size(); -} - -void smtp_starttls() -{ - buffer_puts(&bo,"STARTTLS\r\n"); - buffer_flush(&bo); - - if (smtpcode() == 220) { - tls_init(); - tls_peercheck(); - smtp_greeting(); - } - else { - flagtls = -2; - quit("ZConnected to "," but STARTTLS was rejected"); - } -} - -void mailfrom() -{ - buffer_puts(&bo,"MAIL FROM:<"); - buffer_put(&bo,sender.s,sender.len); - buffer_puts(&bo,">"); - if (flagutf8 || utf8received()) - buffer_puts(&bo," SMTPUTF8"); - if (flagsize && msize) { - buffer_puts(&bo," SIZE="); - buffer_puts(&bo,msgsize); - } - buffer_puts(&bo,"\r\n"); - buffer_flush(&bo); -} - -/* this file is too long -------------------------------------- client auth */ - -stralloc authsenders = {0}; -struct constmap mapauthsenders; - -stralloc user = {0}; -stralloc pass = {0}; -stralloc auth = {0}; -stralloc chal = {0}; -stralloc slop = {0}; -stralloc plain = {0}; -stralloc xuser = {0}; - -static const char hextab[] = "0123456789abcdef"; - -int xtext(stralloc *sa,char *s,int len) -{ - int i; - unsigned char c; - char xch[2]; - - if (!stralloc_copys(sa,"")) temp_nomem(); - - for (i = 0; i < len; i++) { - c = s[i]; - if (c < 33 || c > 126 || c == '=' || c == '+') { - xch[0] = hextab[(c >> 4) & 0x0f]; - xch[1] = hextab[c & 0x0f]; - if (!stralloc_catb(sa,xch,2)) temp_nomem(); - } else - if (!stralloc_catb(sa,s + i,1)) temp_nomem(); - } - - return sa->len; -} - -void mailfrom_xtext() -{ - if (!xtext(&xuser,user.s,user.len)) temp_nomem(); - buffer_puts(&bo,"MAIL FROM:<"); - buffer_put(&bo,sender.s,sender.len); - buffer_puts(&bo,"> AUTH="); - buffer_put(&bo,xuser.s,xuser.len); - if (flagutf8 || utf8received()) - buffer_puts(&bo," SMTPUTF8"); - if (flagsize && msize) { - buffer_puts(&bo," SIZE="); - buffer_puts(&bo,msgsize); - } - buffer_puts(&bo,"\r\n"); - buffer_flush(&bo); -} - -int mailfrom_plain() -{ - buffer_puts(&bo,"AUTH PLAIN\r\n"); - buffer_flush(&bo); - - if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (AUTH PLAIN)"); - - if (!stralloc_cats(&plain,"")) temp_nomem(); /* RFC 4616 section 2 */ - if (!stralloc_0(&plain)) temp_nomem(); - if (!stralloc_cat(&plain,&user)) temp_nomem(); /* user-id */ - if (!stralloc_0(&plain)) temp_nomem(); - if (!stralloc_cat(&plain,&pass)) temp_nomem(); /* password */ - if (b64encode(&plain,&auth)) quit("ZConnected to "," but unable to base64encode (plain)"); - buffer_put(&bo,auth.s,auth.len); - buffer_puts(&bo,"\r\n"); - buffer_flush(&bo); - - switch (smtpcode()) { - case 235: mailfrom_xtext(); break; - case 432: quit("DConnected to "," but password expired"); - case 534: quit("ZConnected to "," but authentication mechamism too weak (plain)"); - default: quit("ZConnected to "," but authentication was rejected (plain)"); - } - return 0; -} - -int mailfrom_login() -{ - buffer_puts(&bo,"AUTH LOGIN\r\n"); - buffer_flush(&bo); - - if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (AUTH LOGIN)"); - if (!stralloc_copys(&auth,"")) temp_nomem(); - if (b64encode(&user,&auth)) quit("ZConnected to "," but unable to base64encode user"); - - buffer_put(&bo,auth.s,auth.len); - buffer_puts(&bo,"\r\n"); - buffer_flush(&bo); - - if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (username)"); - - if (!stralloc_copys(&auth,"")) temp_nomem(); - if (b64encode(&pass,&auth)) quit("ZConnected to "," but unable to base64encode pass"); - buffer_put(&bo,auth.s,auth.len); - buffer_puts(&bo,"\r\n"); - buffer_flush(&bo); - - switch (smtpcode()) { - case 235: mailfrom_xtext(); break; - case 432: quit("DConnected to "," but password expired"); - case 534: quit("ZConnected to "," but authentication mechanism is too weak (login)"); - default: quit("ZConnected to "," but authentication was rejected (login)"); - } - return 0; -} - -int mailfrom_cram() -{ - int j; - unsigned char digest[16]; - unsigned char digascii[33]; - - buffer_puts(&bo,"AUTH CRAM-MD5\r\n"); - buffer_flush(&bo); - - if (smtpcode() != 334) quit("ZConnected to "," but authentication was rejected (AUTH CRAM-MD5)"); - if (str_chr(smtptext.s + 4,' ')) { /* Challenge */ - if (!stralloc_copys(&slop,"")) temp_nomem(); - if (!stralloc_copyb(&slop,smtptext.s + 4,smtptext.len - 5)) temp_nomem(); - if (b64decode(slop.s,slop.len,&chal)) quit("ZConnected to "," but unable to base64decode challenge"); - } - - hmac_md5((unsigned char *)chal.s,chal.len,pass.s,pass.len,digest); - - for (j = 0; j < 16; j++) { /* HEX => ASCII */ - digascii[2 * j] = hextab[digest[j] >> 4]; - digascii[2 * j + 1] = hextab[digest[j] & 0x0f]; - } - digascii[32]=0; - - if (!stralloc_copys(&slop,"")) temp_nomem(); - if (!stralloc_cat(&slop,&user)) temp_nomem(); /* user-id */ - if (!stralloc_cats(&slop," ")) temp_nomem(); - if (!stralloc_catb(&slop,digascii,32)) temp_nomem(); /* digest */ - - if (!stralloc_copys(&auth,"")) temp_nomem(); - if (b64encode(&slop,&auth)) quit("ZConnected to "," but unable to base64encode username+digest"); - - buffer_put(&bo,auth.s,auth.len); - buffer_puts(&bo,"\r\n"); - buffer_flush(&bo); - - switch (smtpcode()) { - case 235: mailfrom_xtext(); break; - case 432: quit("DConnected to "," but password expired"); - case 534: quit("ZConnected to "," but authentication mechamism too weak (cram)"); - default: quit("ZConnected to "," but authentication was rejected (cram)"); - } - return 0; -} - -void smtp_auth() -{ - int i; - - if (smtptext.len > 8) - for (i = 4; i < smtptext.len - 5; ++i) { - if (case_starts(smtptext.s + i,"CRAM")) - if (mailfrom_cram() >= 0) return; - if (case_starts(smtptext.s + i,"LOGIN")) - if (mailfrom_login() >= 0) return; - if (case_starts(smtptext.s + i,"PLAIN")) - if (mailfrom_plain() >= 0) return; - } - err_authprot(); - mailfrom(); -} - -/* this file is too long ------------------------------------------- GO ON */ - -void smtp() -{ - int flagbother; - int i; - - if (flagtls > 10 && flagtls < 20) { /* SMTPS */ - tls_init(); - tls_peercheck(); - } - - code = smtpcode(); - if (code >= 500) quit("DConnected to "," but sender was rejected"); - if (code == 421 || code == 450) quit("ZConnected to "," but probably greylisted"); /* RFC 6647 */ - if (code >= 400) quit("ZConnected to "," but sender was rejected"); - if (code != 220) quit("ZConnected to "," but greeting failed"); - - smtp_greeting(); - - if (flagtls > 0 && flagtls < 10) { /* STARTTLS */ - if (starttls_peer()) - smtp_starttls(); - else if (flagtls > 3 && flagtls != 9) { - if (!stralloc_0(&host)) temp_nomem(); - temp_tlshost(); - } - } - if (user.len && pass.len) /* AUTH */ - smtp_auth(); - else - mailfrom(); /* Mail From */ - - code = smtpcode(); - if (code >= 500) quit("DConnected to "," but sender was rejected"); - if (code >= 400) quit("ZConnected to "," but sender was probably greylisted"); - - flagbother = 0; /* Rcpt To */ - for (i = 0; i < reciplist.len; ++i) { - buffer_puts(&bo,"RCPT TO:<"); - buffer_put(&bo,reciplist.sa[i].s,reciplist.sa[i].len); - buffer_puts(&bo,">\r\n"); - buffer_flush(&bo); - - code = smtpcode(); /* Data */ - if (flagsize) { - if (code == 552) quit("DConnected to "," but message size is too large"); - if (code == 452) quit("ZConnected to "," however insufficient storage space available"); - } - if (code == 421 || code == 450) { // Postfix merde ;-) - out("s"); outhost(); out(" sender is greylisting.\n"); - outsmtptext(); zero(); - } else if (code >= 500) { - out("h"); outhost(); out(" does not like recipient.\n"); - outsmtptext(); zero(); - } else if (code >= 400) { - out("s"); outhost(); out(" does not like recipient.\n"); - outsmtptext(); zero(); - } else { - out("r"); zero(); - flagbother = 1; - } - } - if (!flagbother) quit("DGiving up on ",""); - - buffer_putsflush(&bo,"DATA\r\n"); - - code = smtpcode(); - if (code >= 500) quit("D"," failed on DATA command"); - if (code >= 400) quit("Z"," failed on DATA command"); - - buffer_putflush(&bo,header.s,header.len); - - blast(); - code = smtpcode(); - flagcritical = 0; - if (code >= 500) quit("D"," failed after I sent the message"); - if (code >= 400) quit("Z"," failed after I sent the message"); - switch (flagtls) { // StartTLS + SMTPS - case 100: case 110: quit("K"," TLS transmitted message accepted"); break; - case 101: case 111: quit("K"," TLS (verified CA) transmitted message accepted"); break; - case 102: case 112: quit("K"," TLS (validated CA+DN*) transmitted message accepted"); break; - case 103: case 113: quit("K"," TLS (validated CA+DN) transmitted message accepted"); break; - case 104: case 114: quit("K"," TLS (CERT pinning) transmitted message accepted"); break; - case 105: case 115: quit("K"," TLS (TLSA EE validated) transmitted message accepted"); break; - case 106: case 116: quit("K"," TLS (TLSA TA validated) transmitted message accepted"); break; - case 107: case 117: quit("K"," TLS (TLSA PKIX verified) transmitted message accepted"); break; - default: quit("K"," accepted message"); break; - } -} - -/* this file is too long -------------------------------------- qmtp client */ - -int qmtpsend = 0; - -void qmtp() -{ - unsigned long len; - char *x; - int i; - int n; - unsigned char ch; - char num[FMT_ULONG]; - int flagallok; - - if (qmtpsend == 2) { /* QMTPS */ - tls_init(); - tls_peercheck(); - } - -/* the following code was substantially taken from serialmail's serialqmtp.c */ - - scan_ulong(msgsize,&len); - buffer_put(&bo,num,fmt_ulong(num,len + 1)); - buffer_put(&bo,":\n",2); - while (len > 0) { - n = buffer_feed(&bi); - if (n <= 0) _exit(1); /* wise guy again */ - x = buffer_PEEK(&bi); - buffer_put(&bo,x,n); - buffer_SEEK(&bi,n); - len -= n; - } - buffer_put(&bo,",",1); - - len = sender.len; - buffer_put(&bo,num,fmt_ulong(num,len)); - buffer_put(&bo,":",1); - buffer_put(&bo,sender.s,sender.len); - buffer_put(&bo,",",1); - - len = 0; - for (i = 0; i < reciplist.len; ++i) - len += fmt_ulong(num,reciplist.sa[i].len) + 1 + reciplist.sa[i].len + 1; - buffer_put(&bo,num,fmt_ulong(num,len)); - buffer_put(&bo,":",1); - for (i = 0; i < reciplist.len; ++i) { - buffer_put(&bo,num,fmt_ulong(num,reciplist.sa[i].len)); - buffer_put(&bo,":",1); - buffer_put(&bo,reciplist.sa[i].s,reciplist.sa[i].len); - buffer_put(&bo,",",1); - } - buffer_put(&bo,",",1); - buffer_flush(&bo); - - flagallok = 1; - - for (i = 0; i < reciplist.len; ++i) { - len = 0; - for (;;) { - get(&ch); - if (ch == ':') break; - if (len > QMTP_MAX) temp_proto(); - if (ch - '0' > 9) temp_proto(); - len = 10 * len + (ch - '0'); - } - if (!len) temp_proto(); - get(&ch); --len; - if ((ch != 'Z') && (ch != 'D') && (ch != 'K')) temp_proto(); - - if (!stralloc_copyb(&smtptext,&ch,1)) temp_proto(); - if (flagtls == 100) { - if (!stralloc_cats(&smtptext,"qmtps:")) temp_nomem(); - } else { - if (!stralloc_cats(&smtptext,"qmtp:")) temp_nomem(); - } - - while (len > 0) { - get(&ch); - --len; - } - - for (len = 0; len < smtptext.len; ++len) { - ch = smtptext.s[len]; - if ((ch < 32) || (ch > 126)) smtptext.s[len] = '?'; - } - get(&ch); - if (ch != ',') temp_proto(); - smtptext.s[smtptext.len - 1] = '\n'; - - if (smtptext.s[0] == 'K') out("r"); - else if (smtptext.s[0] == 'D') { - out("h"); - flagallok = 0; - } - else { /* if (smtptext.s[0] == 'Z') */ - out("s"); - flagallok = 0; - } - if (buffer_put(&bs,smtptext.s + 1,smtptext.len - 1) == -1) temp_qmtpnoc(); - zero(); - } - if (!flagallok) { - out("DGiving up on "); outhost(); out("\n"); - } else { - out("KAll received okay by "); outhost(); out("\n"); - } - zerodie(); -} - -/* this file is too long -------------------------------------- common */ - -/* host has to be canonical [A/AAAA record], box has to be quoted */ - -void addrmangle(stralloc *saout,char *address,int *flagalias,int flagcname) -{ - int at; - int r = 0; - stralloc cn = {0}; - - *flagalias = flagcname; /* saout + flagalias are output */ - if (!flagutf8) - flagutf8 = utf8string(address,str_len(address)); - - at = str_rchr(address,'@'); - if (!address[at]) { - if (!stralloc_copys(saout,address)) temp_nomem(); - return; - } - - if (!stralloc_copys(&canonbox,address)) temp_nomem(); - canonbox.len = at; - if (!quote(saout,&canonbox)) temp_nomem(); /* saout = 'inbox' name without quotes ;-) */ - if (!stralloc_cats(saout,"@")) temp_nomem(); - - if (!stralloc_copys(&canonhost,address + at + 1)) temp_nomem(); - if (flagcname) { /* no relayhost */ - DNS_INIT - switch ((r = dns_cname(&cn,&canonhost))) { - case DNS_MEM: temp_nomem(); - case DNS_SOFT: temp_dnscanon(); - case DNS_HARD: ; /* alias loop, not our problem */ - default: if (r > 0) *flagalias = 0; - } - } - if (!stralloc_cat(saout,&canonhost)) temp_nomem(); -} - -void getcontrols() -{ - if (control_init() == -1) temp_control(); - if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control(); - if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1) - temp_control(); - if (control_rldef(&helohost,"control/helohost",1,(char *) 0) != 1) - temp_control(); - switch (control_readfile(&smtproutes,"control/smtproutes",0)) { - case -1: temp_control(); - case 0: if (!constmap_init(&mapsmtproutes,"",0,1)) temp_nomem(); break; - case 1: if (!constmap_init(&mapsmtproutes,smtproutes.s,smtproutes.len,1)) temp_nomem(); break; - } - switch (control_readfile(&domainips,"control/domainips",0)) { - case -1: temp_control(); - case 0: if (!constmap_init(&mapdomainips,"",0,1)) temp_nomem(); break; - case 1: if (!constmap_init(&mapdomainips,domainips.s,domainips.len,1)) temp_nomem(); break; - } - switch (control_readfile(&authsenders,"control/authsenders",0)) { - case -1: temp_control(); - case 0: if (!constmap_init(&mapauthsenders,"",0,1)) temp_nomem(); break; - case 1: if (!constmap_init(&mapauthsenders,authsenders.s,authsenders.len,1)) temp_nomem(); break; - } - switch (control_readfile(&qmtproutes,"control/qmtproutes",0)) { - case -1: temp_control(); - case 0: if (!constmap_init(&mapqmtproutes,"",0,1)) temp_nomem(); break; - case 1: if (!constmap_init(&mapqmtproutes,qmtproutes.s,qmtproutes.len,1)) temp_nomem(); break; - } - switch (control_readfile(&domaincerts,"control/domaincerts",0)) { - case -1: temp_control(); - case 0: if (!constmap_init(&mapdomaincerts,"",0,1)) temp_nomem(); break; - case 1: if (!constmap_init(&mapdomaincerts,domaincerts.s,domaincerts.len,1)) temp_nomem(); break; - } - switch (control_readfile(&tlsdestinations,"control/tlsdestinations",0)) { - case -1: temp_control(); - case 0: if (!constmap_init(&maptlsdestinations,"",0,1)) temp_nomem(); break; - case 1: if (!constmap_init(&maptlsdestinations,tlsdestinations.s,tlsdestinations.len,1)) temp_nomem(); break; - } -} - -int main(int argc,char **argv) -{ - static ipalloc ip = {0}; - stralloc netif = {0}; - struct stat st; - int i, j, k; - int p; /* reserved for port */ - int r; /* reserved for return code */ - unsigned long random; - char **recips; - unsigned long prefme; - int flagallaliases; - int flagalias; - char *relayhost; - char *localip; - int ip6flag = 0; - - sig_pipeignore(); - if (argc < 4) perm_usage(); - if (chdir(auto_qmail) == -1) temp_chdir(); - - getcontrols(); - if (!stralloc_copys(&host,argv[1])) temp_nomem(); - - authsender = 0; - relayhost = 0; - - addrmangle(&sender,argv[2],&flagalias,0); - - if (sender.len > 1) { - i = str_chr(sender.s,'@'); - if (sender.s[i] == '@') - if (!stralloc_copyb(&senddomain,sender.s + i + 1,sender.len - i - 1)) temp_nomem(); // un-terminated - } - -/* this file is too long -------------------------------------- set domain ip + helohost */ - - localip = 0; - - for (i = 0; i <= senddomain.len; ++i) - if ((i == 0) || (senddomain.s[i] == '.')) - if ((localip = constmap(&mapdomainips,senddomain.s + i,senddomain.len - i))) - break; - - if (!localip) - localip = constmap(&mapdomainips,"*",1); /* one for all */ - - if (localip) { - j = str_chr(localip,'%'); - if (localip[j] != '%') j = 0; - k = str_chr(localip,'|'); - if (localip[k] != '|') k = 0; - if (k) { /* helohost */ - if (!stralloc_copys(&helohost,localip + k + 1)) temp_nomem(); - if (!stralloc_0(&helohost)) temp_nomem(); - localip[k] = 0; - } - if (j) { /* IF index */ - localip[j] = 0; - if (!stralloc_copys(&netif,localip + j + 1)) temp_nomem(); - if (!stralloc_0(&netif)) temp_nomem(); - } - } - -/* this file is too long -------------------------------------- authsender routes */ - - for (i = 0; i <= sender.len; ++i) - if ((i == 0) || (i == sender.len) || (sender.s[i] == '.') || (sender.s[i] == '@')) - if ((authsender = constmap(&mapauthsenders,sender.s + i,sender.len - i))) - break; - - if (authsender && !*authsender) authsender = 0; - - if (authsender) { - i = str_chr(authsender,'|'); - if (authsender[i] == '|') { - j = str_chr(authsender + i + 1,'|'); - if (authsender[i + j + 1] == '|') { - authsender[i] = 0; - authsender[i + j + 1] = 0; - if (!stralloc_copys(&user,"")) temp_nomem(); - if (!stralloc_copys(&user,authsender + i + 1)) temp_nomem(); - if (!stralloc_copys(&pass,"")) temp_nomem(); - if (!stralloc_copys(&pass,authsender + i + j + 2)) temp_nomem(); - } - } - p = str_chr(authsender,';'); - if (authsender[p] == ';') { - if (authsender[p + 1] == 's') { flagsmtps = 1, p++; } - scan_ulong(authsender + p + 1,&port); - authsender[p] = 0; - } - relayhost = authsender; - if (!stralloc_copys(&host,authsender)) temp_nomem(); - } - -/* this file is too long -------------------------------------- standard routes */ - - if (!authsender) { - if (sender.len == 0) { /* bounce routes */ - if ((relayhost = constmap(&mapqmtproutes,"!@",2))) { - qmtpsend = 1; port = PORT_QMTP; - } else - relayhost = constmap(&mapsmtproutes,"!@",2); - } - - if (relayhost && !*relayhost) relayhost = 0; - - if (!relayhost) { - for (i = 0; i <= host.len; ++i) { /* qmtproutes */ - if ((i == 0) || (i == host.len) || (host.s[i] == '.')) - if ((relayhost = constmap(&mapqmtproutes,host.s + i,host.len - i))) { - qmtpsend = 1; port = PORT_QMTP; - break; - } /* default smtproutes */ - if ((relayhost = constmap(&mapsmtproutes,host.s + i,host.len - i))) - break; - } - } - if (relayhost && !*relayhost) relayhost = 0; - - if (relayhost) { /* default smtproutes -- authenticated */ - i = str_chr(relayhost,'|'); - if (relayhost[i] == '|') { - j = str_chr(relayhost + i + 1,'|'); // authenticate - if (relayhost[i + j + 1] == '|') { - relayhost[i] = 0; - relayhost[i + j + 1] = 0; - if (!stralloc_copys(&user,"")) temp_nomem(); - if (!stralloc_copys(&user,relayhost + i + 1)) temp_nomem(); - if (!stralloc_copys(&pass,"")) temp_nomem(); - k = str_chr(relayhost + i + j + 2,'|'); // local ip - if (relayhost[i + j + k + 2] == '|') { - relayhost[i + j + k + 2] = 0; - localip = relayhost + i + j + k + 3; - } - if (!stralloc_copys(&pass,relayhost + i + j + 2)) temp_nomem(); - } - } - p = str_chr(relayhost,';'); - if (relayhost[p] == ';') { - if (relayhost[p + 1] == 's') { flagsmtps = 1; p++; } // RFC 8314 - scan_ulong(relayhost + p + 1,&port); - if (qmtpsend && port == PORT_QMTPS) qmtpsend = 2; - relayhost[p] = 0; - } - if (!stralloc_copys(&host,relayhost)) temp_nomem(); -#ifdef IDN2 - } else { - 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(); -#endif - } - } - -/* this file is too long -------------------------------------- TLS destinations */ - - - flagtls = tls_destination((const stralloc) host); // host may not be 0-terminated - - if (flagtls > 0) { - if (tlsdestinfo) { - i = str_chr(tlsdestinfo,'|'); /* ca file/dir or cert fingerprint */ - if (tlsdestinfo[i] == '|') { - tlsdestinfo[i] = 0; - j = str_chr(tlsdestinfo + i + 1,'|'); /* cipher */ - if (tlsdestinfo[i + j + 1] == '|') { - tlsdestinfo[i + j + 1] = 0; - k = str_chr(tlsdestinfo + i + j + 2,'|'); /* cone domain */ - if (tlsdestinfo[i + j + k + 2] == '|') { - tlsdestinfo[i + j + k + 2] = 0; - if (str_diffn(tlsdestinfo + j + k + 3,canonhost.s,canonhost.len)) flagtls = 0; - } - p = str_chr(tlsdestinfo + i + j + 2,';'); /* verifydepth;port */ - if (tlsdestinfo[i + j + p + 2] == ';') { - tlsdestinfo[i + j + p + 2] = 0; - if (p > 0) scan_ulong(tlsdestinfo + i + j + 2,&verifydepth); - if (tlsdestinfo[i + j + p + 3] == 's') { flagsmtps = 1; p++; } /* RFC 8314 */ - scan_ulong(tlsdestinfo + i + j + p + 3,&port); - } - } - if (j) - if (!stralloc_copys(&ciphers,tlsdestinfo + i + 1)) temp_nomem(); - } - - /* either ':[=]cafile/cadir' -or- ':;port' */ - - if (tlsdestinfo[0] == ';') - scan_ulong(tlsdestinfo + 1,&port); - else - if (!stralloc_copys(&cafile,tlsdestinfo)) temp_nomem(); - } - -/* cafile starts with '=' => it is a fingerprint - cafile ends with '/' => consider it as cadir - cafile and cadir are now 0-terminated - ciphers are alway 0-terminated if given */ - - if (cafile.len > 2) { - flagverify = 1; - if (cafile.s[cafile.len] == '/') { - cafile.len = 0; - flagverify = 2; - if (!stralloc_copys(&cadir,tlsdestinfo)) temp_nomem(); - if (!stralloc_0(&cadir)) temp_nomem(); - } else { - if (cafile.s[0] == '=') flagverify = -2; - if (!stralloc_0(&cafile)) temp_nomem(); - } - } else - cafile.len = cadir.len = 0; - - if (ciphers.len > 4) /* otherwise garbage */ - if (!stralloc_0(&ciphers)) temp_nomem(); - else - ciphers.len = 0; - - if (port == PORT_SMTPS || flagsmtps) flagtls += 10; - if (port == PORT_QMTPS) flagtls += 20; - } - - if (flagtls == 8) flagverify = -1; - if (!flagtls && qmtpsend == 2) flagtls = 20; /* QMTPS */ - - -/* this file is too long -------------------------------------- Our Certs - per senddomain */ - - if (flagtls > 0) { - flagtlsdomain = tls_domaincerts((const stralloc) senddomain); // senddomain un-terminated - - if (flagtlsdomain && tlsdomaininfo) { - i = str_chr(tlsdomaininfo,'|'); - if (tlsdomaininfo[i] == '|') { - tlsdomaininfo[i] = 0; - j = str_chr(tlsdomaininfo + i + 1,'|'); - if (tlsdomaininfo[i + j + 1] == '|') { - tlsdomaininfo[i + j + 1] = 0; - if (!stralloc_copys(&keypwd,"")) temp_nomem(); - if (!stralloc_copys(&keypwd,tlsdomaininfo + i + j + 2)) temp_nomem(); - if (!stralloc_0(&keypwd)) temp_nomem(); - } - if (!stralloc_copys(&keyfile,tlsdomaininfo + i + 1)) temp_nomem(); - if (!stralloc_0(&keyfile)) temp_nomem(); - } - if (!stralloc_copys(&certfile,tlsdomaininfo)) temp_nomem(); - if (!stralloc_0(&certfile)) temp_nomem(); - flagtlsdomain = 2; - } - } - -/* this file is too long -------------------------------------- work thru reciplist */ - - if (!saa_readyplus(&reciplist,0)) temp_nomem(); - if (ipme_init() != 1) temp_oserr(); - - flagallaliases = 1; - recips = argv + 3; - - if (fstat(0,&st) == -1) quit("Z", " unable to fstat stdin"); - msize = st.st_size; - fmt_ulong(msgsize,msize); - - while (*recips) { - if (!saa_readyplus(&reciplist,1)) temp_nomem(); - reciplist.sa[reciplist.len] = sauninit; - addrmangle(reciplist.sa + reciplist.len,*recips,&flagalias,!relayhost); - if (!flagalias) flagallaliases = 0; - ++reciplist.len; - ++recips; - } - - random = now() + (getpid() << 16); -#ifdef IDN2 - 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_ERR: temp_dns(); - case DNS_COM: temp_dns(); - case DNS_SOFT: temp_dns(); -#ifdef DEFERREDBOUNCES - default: if (!ip.len) temp_nomx(); -#else - default: if (!ip.len) perm_nomx(); -#endif - } - - prefme = 100000; - for (i = 0; i < ip.len; ++i) - if (ipme_is(&ip.ix[i])) - if (ip.ix[i].pref < prefme) - prefme = ip.ix[i].pref; - - if (relayhost) prefme = 300000; - if (flagallaliases) prefme = 500000; - - if (localip) { - i = str_chr(localip,':'); - if (localip[i] == ':') ip6flag = 1; - else ip6flag = -1; - } - - for (i = 0; i < ip.len; ++i) { /* MX with smallest distance */ - if (ip6flag == -1 && ip.ix[i].af == AF_INET6) continue; - if (ip6flag == 1 && ip.ix[i].af == AF_INET) continue; - if (ip.ix[i].pref < prefme) break; - } - - if (i >= ip.len) - perm_ambigmx(); - - if (!stralloc_copys(&remotehost,ip.ix[i].mxh)) temp_nomem(); /* take MX hostname for TLSA */ - if (!stralloc_0(&remotehost)) temp_nomem(); - - for (i = 0; i < ip.len; ++i) { - if (ip.ix[i].pref < prefme) { - if (ip6flag == -1 && ip.ix[i].af == AF_INET6) continue; /* explicit binding */ - if (ip6flag == 1 && ip.ix[i].af == AF_INET) continue; - if (tcpto(&ip.ix[i])) continue; - - smtpfd = socket(ip.ix[i].af,SOCK_STREAM,0); - if (smtpfd == -1) continue; - - if (localip) { /* set domain ip */ - if (!stralloc_copyb(&sendip,localip,str_len(localip))) temp_nomem(); - j = str_chr(localip,':'); - if (localip[j] == ':') { - if (!ip6_scan(localip,ip6)) temp_noip(); /* IPv6 */ - if (byte_equal(ip.ix[i].addr.ip6.d,16,ip6)) continue; - ifidx = socket_getifidx(netif.s); - if (socket_bind6(smtpfd,ip6,0,ifidx) < 0) temp_osip(); - } else { - if (!ip4_scan(localip,ip4)) temp_noip(); /* IPv4 */ - if (byte_equal(ip.ix[i].addr.ip4.d,4,ip4)) continue; - if (socket_bind4(smtpfd,ip4,0) < 0) temp_osip(); - } - } - - - AGAIN: - if (ip.ix[i].af == AF_INET6) - r = timeoutconn6(smtpfd,(char *)&ip.ix[i].addr.ip6.d,(unsigned int) port,timeoutconnect,ifidx); - else - r = timeoutconn4(smtpfd,(char *)&ip.ix[i].addr.ip4.d,(unsigned int) port,timeoutconnect); - if (r == 0) { - tcpto_err(&ip.ix[i],0); - partner = ip.ix[i]; - if (qmtpsend) - qmtp(); - else - smtp(); /* read qmail/THOUGHTS; section 6 */ - } - if (flagtls == 9 && errno == EPROTO) { - flagtls = 0; goto AGAIN; - } - if (errno == ETIMEDOUT || errno == ECONNREFUSED || errno == EPROTO) - tcpto_err(&ip.ix[i],1); - close(smtpfd); - } - } - temp_noconn(); -} |