diff options
Diffstat (limited to 'src/qmail-remote')
| -rw-r--r-- | src/qmail-remote/deps-exe/qmail-remote-io | 2 | ||||
| -rw-r--r-- | src/qmail-remote/deps-lib/qmailr | 1 | ||||
| -rw-r--r-- | src/qmail-remote/dns.c | 57 | ||||
| -rw-r--r-- | src/qmail-remote/qmail-remote-io.c | 245 | ||||
| -rw-r--r-- | src/qmail-remote/qmail-remote.c | 262 | ||||
| -rw-r--r-- | src/qmail-remote/qmail-remote.h | 4 | ||||
| -rw-r--r-- | src/qmail-remote/qmailr.h | 35 | ||||
| -rw-r--r-- | src/qmail-remote/qmailr_error.c | 33 | ||||
| -rw-r--r-- | src/qmail-remote/qmailr_smtp.c | 53 | ||||
| -rw-r--r-- | src/qmail-remote/qmailr_tls.c | 2 | ||||
| -rw-r--r-- | src/qmail-remote/smtproutes.c | 42 |
11 files changed, 637 insertions, 99 deletions
diff --git a/src/qmail-remote/deps-exe/qmail-remote-io b/src/qmail-remote/deps-exe/qmail-remote-io new file mode 100644 index 0000000..7dcdb19 --- /dev/null +++ b/src/qmail-remote/deps-exe/qmail-remote-io @@ -0,0 +1,2 @@ +libqmailr.a.xyzzy +-lskarnet diff --git a/src/qmail-remote/deps-lib/qmailr b/src/qmail-remote/deps-lib/qmailr index c1095ed..8ba0674 100644 --- a/src/qmail-remote/deps-lib/qmailr +++ b/src/qmail-remote/deps-lib/qmailr @@ -1,5 +1,6 @@ qmailr_control.o qmailr_error.o +qmailr_smtp.o qmailr_tcpto.o qmailr_tls.o qmailr_utils.o diff --git a/src/qmail-remote/dns.c b/src/qmail-remote/dns.c index 4649fc7..fb01a0d 100644 --- a/src/qmail-remote/dns.c +++ b/src/qmail-remote/dns.c @@ -51,13 +51,13 @@ static unsigned int use_host_as_mx (skadns_t *a, char const *host, genalloc *mxi mxipinfo info = MXIPINFO_ZERO ; s6dns_domain_t q ; if (!s6dns_domain_fromstring_noqualify_encode(&q, host, strlen(host))) - qmailr_tempsys("Unable to DNS-encode host domain") ; + qmailr_tempusys("DNS-encode host domain") ; if (!skadns_send_g(a, &info.id4, &q, S6DNS_T_A, deadline, deadline)) - qmailr_tempsys("Unable to send A DNS query") ; + qmailr_tempusys("send ", "A", " DNS query") ; newreqs++ ; #ifdef SKALIBS_IPV6_ENABLED if (!skadns_send_g(a, &info.id6, &q, S6DNS_T_AAAA, deadline, deadline)) - qmailr_tempsys("Unable to send AAAA DNS query") ; + qmailr_tempusys("send ", "AAAA", " DNS query") ; newreqs++ ; #endif if (!genalloc_catb(mxipinfo, mxip, &info, 1)) dienomem() ; @@ -67,14 +67,14 @@ static unsigned int use_host_as_mx (skadns_t *a, char const *host, genalloc *mxi /* The point of this monster here is to do all the DNS resolutions in parallel, to avoid compounding network latency. One of the many things that could never - be done by patching qmail-remote. + be done by patching the original qmail-remote. 1 sender + n-1 recipients are given in eaddr. - loop around CNAME until we get the canonical name, for the n eaddrs - either lookup the MX for the host then find all the A and AAAAs of all the MXes, or get the A and AAAAs of the host directly (if smtproutes) - do not keep the As and AAAAs listed in ipme - sort the set of IPs by MX preference - When done, quote all the boxnames in eaddr. + When done, addrmangle (i.e. quote if needed) all the boxnames in eaddr. Shove everything in storage and return the indices: in eaddrpos for sender+recipients, in mxipind for the IPs to connect to. @@ -83,19 +83,19 @@ static unsigned int use_host_as_mx (skadns_t *a, char const *host, genalloc *mxi Also, fuck DNS. */ -void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size_t *eaddrpos, genalloc *mxipind, stralloc *storage, unsigned int timeoutdns, char const *ipme4, unsigned int n4, char const *ipme6, unsigned int n6, uint32_t flags) +unsigned int dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size_t *eaddrpos, genalloc *mxipind, stralloc *storage, unsigned int timeoutdns, char const *ipme4, unsigned int n4, char const *ipme6, unsigned int n6, uint32_t flags) { skadns_t a = SKADNS_ZERO ; genalloc mxipi = GENALLOC_ZERO ; /* mxipinfo */ - tain deadline ; unsigned int pending = 0 ; - uint16_t mxn = 0 ; + unsigned int mxn = 0 ; uint16_t mxid = UINT16_MAX ; + tain deadline ; cnameinfo cnames[n] ; tain_addsec_g(&deadline, timeoutdns) ; if (!skadns_startf_g(&a, &deadline)) - qmailr_tempsys("Unable to start asynchronous DNS helper") ; + qmailr_tempusys("start asynchronous DNS helper") ; for (unsigned int i = 0 ; i < n ; i++) { @@ -108,9 +108,9 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size cnames[i].atpos = at - eaddr[i] ; if (!stralloc_catb(&cnames[i].sa, at+1, len)) dienomem() ; if (!s6dns_domain_fromstring_noqualify_encode(&q, at+1, len)) - qmailr_tempsys("Unable to DNS-encode recipient domain") ; + qmailr_tempusys("DNS-encode recipient domain") ; if (!skadns_send_g(&a, &cnames[i].id, &q, S6DNS_T_CNAME, &deadline, &deadline)) - qmailr_tempsys("Unable to send CNAME DNS query") ; + qmailr_tempusys("send ", "CNAME", " DNS query") ; cnames[i].count = 1 ; pending++ ; } @@ -126,9 +126,9 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size { s6dns_domain_t q ; if (!s6dns_domain_fromstring_noqualify_encode(&q, host, strlen(host))) - qmailr_tempsys("Unable to DNS-encode host domain") ; + qmailr_tempusys("DNS-encode host domain") ; if (!skadns_send_g(&a, &mxid, &q, S6DNS_T_MX, &deadline, &deadline)) - qmailr_tempsys("Unable to send MX DNS query") ; + qmailr_tempusys("send ", "MX", " DNS query") ; pending++ ; } else @@ -142,10 +142,10 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size uint16_t *ids ; iopause_fd x = { .fd = skadns_fd(&a), .events = IOPAUSE_READ } ; int r = iopause_g(&x, 1, &deadline) ; - if (r == -1) qmailr_tempsys("Unable to iopause") ; + if (r == -1) qmailr_tempusys("iopause") ; if (!r) qmailr_tempsys("Timed out waiting for DNS") ; r = skadns_update(&a) ; - if (r == -1) qmailr_tempsys("Unable to read DNS answers") ; + if (r == -1) qmailr_tempusys("read DNS answers") ; ids = genalloc_s(uint16_t, &a.list) ; for (size_t j = 0 ; j < genalloc_len(uint16_t, &a.list) ; j++) { @@ -161,8 +161,8 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size if (r == -1) qmailr_tempsys("DNS packet parsing error") ; if (!r) { - if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving MX") ; - else qmailr_perm("DNS CNAME resolution error") ; + if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving ", "MX") ; + else qmailr_perm("DNS ", "CNAME", " resolution error") ; } skadns_release(&a, ids[j]) ; pending-- ; @@ -178,11 +178,11 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size mxipinfo *p = genalloc_s(mxipinfo, &mxipi) + i ; p->ip4 = p->ip6 = stralloc_zero ; if (!skadns_send_g(&a, &p->id4, &mxs[i].exchange, S6DNS_T_A, &deadline, &deadline)) - qmailr_tempsys("Unable to send A DNS query") ; + qmailr_tempusys("send ", "A", " DNS query") ; pending++ ; #ifdef SKALIBS_IPV6_ENABLED if (!skadns_send_g(&a, &p->id6, &mxs[i].exchange, S6DNS_T_AAAA, &deadline, &deadline)) - qmailr_tempsys("Unable to send AAAA DNS query") ; + qmailr_tempusys("send ", "AAAA", " DNS query") ; pending++ ; #endif } @@ -204,8 +204,8 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size if (r == -1) qmailr_tempsys("DNS packet parsing error") ; if (!r) { - if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving CNAME") ; - else qmailr_perm("DNS CNAME resolution error") ; + if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving ", "CNAME") ; + else qmailr_perm("DNS ", "CNAME", " resolution error") ; } skadns_release(&a, ids[j]) ; pending-- ; @@ -214,14 +214,14 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size s6dns_domain_t *domain = genalloc_s(s6dns_domain_t, &dlist.ds) ; if (cnames[i].count++ >= 100) qmailr_temp("DNS CNAME loop") ; if (!skadns_send_g(&a, &cnames[i].id, domain, S6DNS_T_CNAME, &deadline, &deadline)) - qmailr_tempsys("Unable to send CNAME DNS query") ; + qmailr_tempusys("send ", "CNAME", " DNS query") ; pending++ ; if (!stralloc_ready(&cnames[i].sa, 256)) dienomem() ; s6dns_domain_decode(domain) ; cnames[i].sa.len = s6dns_domain_tostring(cnames[i].sa.s, 256, domain) ; genalloc_free(s6dns_domain_t, &dlist.ds) ; } - else cnames[i].id = UINT16_MAX ; /* that's the canonical host in cnames[i].sa */ + else cnames[i].id = UINT16_MAX ; /* we have the canonical host in cnames[i].sa */ continue ; } @@ -235,8 +235,8 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size if (r == -1) qmailr_tempsys("DNS packet parsing error") ; if (!r) { - if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving A") ; - else qmailr_perm("DNS A resolution error") ; + if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving ", "A") ; + else qmailr_perm("DNS ", "A", " resolution error") ; } skadns_release(&a, ids[j]) ; pending-- ; @@ -259,8 +259,8 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size if (r == -1) qmailr_tempsys("DNS packet parsing error") ; if (!r) { - if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving AAAA") ; - else qmailr_perm("DNS AAAA resolution error") ; + if (errno == EBUSY || errno == EIO) qmailr_temp("Temporary DNS error while resolving ", "AAAA") ; + else qmailr_perm("DNS ", "AAAA", " resolution error") ; } skadns_release(&a, ids[j]) ; pending-- ; @@ -279,7 +279,7 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size } } } - skadns_end(&a) ; /* we done buddy */ + skadns_end(&a) ; /* we done, buddy */ for (unsigned int i = 0 ; i < n ; i++) { @@ -312,4 +312,5 @@ void dns_stuff (char const *host, char const *const *eaddr, unsigned int n, size #endif } genalloc_free(mxipinfo, &mxipi) ; + return mxn ; } diff --git a/src/qmail-remote/qmail-remote-io.c b/src/qmail-remote/qmail-remote-io.c new file mode 100644 index 0000000..3f55f87 --- /dev/null +++ b/src/qmail-remote/qmail-remote-io.c @@ -0,0 +1,245 @@ +/* ISC license. */ + +#include <unistd.h> + +#include <skalibs/gccattributes.h> +#include <skalibs/types.h> +#include <skalibs/buffer.h> +#include <skalibs/gol.h> +#include <skalibs/tai.h> +#include <skalibs/unix-timed.h> + +#include "qmailr.h" + +enum gola_e +{ + GOLA_TIMEOUT, + GOLA_FDR, + GOLA_FDW, + GOLA_N +} ; + +static inline unsigned int qgol_argv (char const *const *argv, gol_bool const *b, unsigned int bn, gol_arg const *a, unsigned int an, uint64_t *br, char const **ar) +{ + int problem = 0 ; + int r = gol(argv, b, bn, a, an, br, ar, &problem) ; + + if (r < 0) + { + if (problem > 0) + { + char s[2] = { argv[-r-1][problem], 0 } ; + qmailr_perm("qmail-remote-io: ", "unrecognized ", "short ", "option: ", s) ; + } + else if (!problem) + qmailr_perm("qmail-remote-io: ", "invalid ", "option: ", argv[-r-1]) ; + else if (problem == -1) + qmailr_perm("qmail-remote-io: ", "unrecognized ", "boolean ", "option: ", argv[-r-1]) ; + else + qmailr_perm("qmail-remote-io: ", "unrecognized ", "option with argument: ", argv[-r-1]) ; + } + else return r ; +} + +static inline unsigned int qgol_main (int argc, char const *const *argv, gol_bool const *b, unsigned int bn, gol_arg const *a, unsigned int an, uint64_t *br, char const **ar) +{ + if (argc < 1 || argv[argc]) qmailr_perm("qmail-remote-io: ", "invalid argc/argv") ; + if (argc == 1) return 1 ; + return 1 + qgol_argv(argv + 1, b, bn, a, an, br, ar) ; +} + +static unsigned int read_answer_options (buffer *in, unsigned int timeout, char *buf, size_t buflen, char const *fmtip, unsigned int flags) +{ + int r = qmailr_smtp_read_answer(in, buf, buflen, timeout) ; + if (r == -1) qmailr_tempsys("qmail-remote-io: ", "unable to ", "read SMTP answer from ", fmtip, flags & 1 ? " (Possible duplicate!)" : "") ; + if (!r) qmailr_tempsys("qmail-remote-io: ", fmtip, " closed the connection early", flags & 1 ? " (Possible duplicate!)" : "") ; + return r ; +} + +static unsigned read_answer (buffer *in, unsigned int timeout, char *buf, size_t buflen, char const *fmtip) +{ + return read_answer_options(in, timeout, buf, buflen, fmtip, 0) ; +} + +static void put (buffer *out, char const *s) +{ + if (buffer_puts(out, s) < 0) + qmailr_tempsys("qmail-remote-io: ", "unable to ", "queue SMTP command") ; +} + +static void datachar (buffer *out, char c) +{ + if (buffer_put(out, &c, 1) < 1) + qmailr_tempsys("qmail-remote-io: ", "unable to ", "send character after DATA") ; +} + +/* + small DFA for blast() to quote dots and newlines + + 0 1 2 3 +st\ev EOF . \n other + +0 qp rp p +START END INLINE START INLINE + +1 p rp p +INLINE X INLINE START INLINE + +END=2 X=3 + +0x10 q quote with . +0x20 r quote with \r +0x40 p print char + +*/ + +static inline uint8_t cclass (char c) +{ + return c == '.' ? 1 : c == '\n' ? 2 : 3 ; +} + +static void blast (buffer *out, unsigned int timeout) +{ + static uint8_t const table[2][4] = + { + { 0x02, 0x51, 0x60, 0x41 }, + { 0x03, 0x41, 0x60, 0x41 } + } ; + uint8_t state = 0 ; + while (state < 2) + { + char c ; + uint8_t val ; + ssize_t r = buffer_get(buffer_0, &c, 1) ; + if (r == -1) qmailr_tempsys("qmail-remote-io: ", "unable to ", "read message") ; + val = r ? table[state][cclass(c)] : table[state][0] ; + state = val & 3 ; + if (val & 0x10) datachar(out, '.') ; + if (val & 0x20) datachar(out, '\r') ; + if (val & 0x40) datachar(out, c) ; + } + if (state > 2) qmailr_perm("qmail-remote-io: ", "SMTP cannot transfer messages with partial final lines") ; + if (buffer_putflush(out, ".\r\n", 3) < 0) qmailr_tempsys("qmail-remote-io: ", "unable to ", "finalize message data") ; +} + +static void smtp_body (buffer *in, buffer *out, char const *fmtip, char const *sender, char const *const *recip, unsigned int n, unsigned int timeout) gccattr_noreturn ; +static void smtp_body (buffer *in, buffer *out, char const *fmtip, char const *sender, char const *const *recip, unsigned int n, unsigned int timeout) +{ + tain deadline ; + unsigned int code ; + int flagbother = 0 ; + char buf[4096] ; + + put(out, "MAIL FROM:<") ; + put(out, sender) ; + put(out, ">\r\n") ; + tain_addsec_g(&deadline, timeout) ; + if (!buffer_timed_flush_g(out, &deadline)) + qmailr_tempsys("qmail-remote-io: ", "unable to ", "send command to ", fmtip) ; + code = read_answer(in, timeout, buf, 4096, fmtip) ; + if (code >= 500) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_perm("qmail-remote-io: ", "connected to ", fmtip, " but sender was rejected") ; + } + else if (code >= 400) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_temp("qmail-remote-io: ", "connected to ", fmtip, " but sender was rejected") ; + } + + for (unsigned int i = 0 ; i < n ; i++) + { + put(out, "RCPT TO:<") ; + put(out, recip[i]) ; + put(out, ">\r\n") ; + tain_addsec_g(&deadline, timeout) ; + if (!buffer_timed_flush_g(out, &deadline)) + qmailr_tempsys("qmail-remote-io: ", "unable to ", "send command to ", fmtip) ; + code = read_answer(in, timeout, buf, 4096, fmtip) ; + if (code >= 500) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_die('h', fmtip, " does not like recipient.\n", "Remote host said: ", buf+4) ; + } + else if (code >= 400) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_die('s', fmtip, " does not like recipient.\n", "Remote host said: ", buf+4) ; + } + else + { + buffer_put(buffer_1, "r", 2) ; + flagbother = 1 ; + } + } + if (!flagbother) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_perm("Giving up on ", fmtip) ; + } + + put(out, "DATA\r\n") ; + tain_addsec_g(&deadline, timeout) ; + if (!buffer_timed_flush_g(out, &deadline)) + qmailr_tempsys("qmail-remote-io: ", "unable to ", "send command to ", fmtip) ; + code = read_answer(in, timeout, buf, 4096, fmtip) ; + if (code >= 500) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_perm(fmtip, " failed on DATA command") ; + } + else if (code >= 400) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_temp(fmtip, " failed on DATA command") ; + } + + blast(out, timeout) ; + code = read_answer_options(in, timeout, buf, 4096, fmtip, 1) ; + if (code >= 500) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_perm(fmtip, " failed after I sent the message") ; + } + else if (code >= 400) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_temp(fmtip, " failed after I sent the message") ; + } + + qmailr_smtp_quit(out, timeout) ; + qmailr_die('K', fmtip, " accepted message") ; +} + +int main (int argc, char const *const *argv) +{ + static gol_arg const rgola[] = + { + { .so = 't', .lo = "timeoutremote", .i = GOLA_TIMEOUT }, + { .so = '6', .lo = "fdr", .i = GOLA_FDR }, + { .so = '7', .lo = "fdw", .i = GOLA_FDW }, + } ; + char const *wgola[GOLA_N] = { 0 } ; + unsigned int fdr = 6, fdw = 7 ; + unsigned int timeoutremote = 1200 ; + buffer in, out ; + char inbuf[1024] ; + char outbuf[BUFFER_OUTSIZE] ; + unsigned int golc = qgol_main(argc, argv, 0, 0, rgola, 3, 0, wgola) ; + argc -= golc ; argv += golc ; + if (argc < 3) qmailr_perm("qmail-remote-io: ", "too few arguments") ; + + if (wgola[GOLA_TIMEOUT] && !uint0_scan(wgola[GOLA_TIMEOUT], &timeoutremote)) + qmailr_perm("qmail-remote-io: ", "invalid timeoutremote") ; + if (wgola[GOLA_FDR] && !uint0_scan(wgola[GOLA_FDR], &fdr)) + qmailr_perm("qmail-remote-io: ", "invalid fdr") ; + if (wgola[GOLA_FDW] && !uint0_scan(wgola[GOLA_FDW], &fdw)) + qmailr_perm("qmail-remote-io: ", "invalid fdw") ; + + buffer_init(&in, &buffer_read, fdr, inbuf, 1024) ; + buffer_init(&out, &buffer_write, fdw, outbuf, BUFFER_OUTSIZE) ; + + tain_now_set_stopwatch_g() ; + smtp_body(&in, &out, argv[0], argv[1], argv + 2, argc - 2, timeoutremote) ; +} diff --git a/src/qmail-remote/qmail-remote.c b/src/qmail-remote/qmail-remote.c index 870c797..2fa98ab 100644 --- a/src/qmail-remote/qmail-remote.c +++ b/src/qmail-remote/qmail-remote.c @@ -1,29 +1,197 @@ /* ISC license. */ #include <string.h> +#include <strings.h> #include <stdint.h> #include <unistd.h> +#include <errno.h> +#include <limits.h> +#include <skalibs/types.h> +#include <skalibs/env.h> +#include <skalibs/exec.h> +#include <skalibs/fmtscan.h> +#include <skalibs/buffer.h> #include <skalibs/cdb.h> #include <skalibs/stralloc.h> #include <skalibs/sig.h> #include <skalibs/tai.h> +#include <skalibs/djbunix.h> +#include <skalibs/socket.h> #include <skalibs/ip46.h> +#include <skalibs/unix-timed.h> +#include <s6-networking/config.h> #include <smtpd-starttls-proxy/config.h> #include "qmailr.h" #include "qmail-remote.h" #define dieusage() qmailr_perm("qmail-remote was invoked improperly") +static inline void exec_tls (int fd, char const *fmtip, unsigned int timeoutconnect, unsigned int timeoutremote, qmailr_tls const *qtls, size_t helopos, size_t const *eaddrpos, unsigned int n, char const *storage) gccattr_noreturn ; +static inline void exec_tls (int fd, char const *fmtip, unsigned int timeoutconnect, unsigned int timeoutremote, qmailr_tls const *qtls, size_t helopos, size_t const *eaddrpos, unsigned int n, char const *storage) +{ + unsigned int m = 0 ; + char fmtfd[UINT_FMT] ; + char fmtt[UINT_FMT] ; + char fmtk[UINT_FMT] ; + char const *argv[20 + n] ; + + if (!env_mexec("TLS_UID", 0) || !env_mexec("TLS_GID", 0) + || !env_mexec(qtls->flagtadir ? "CADIR" : "CAFILE", storage + qtls->tapos)) dienomem() ; + if (qtls->flagclientcert) + { + if (!env_mexec("CERTFILE", storage + qtls->certpos) + || !env_mexec("KEYFILE", storage + qtls->keypos)) dienomem() ; + } + + { + int devnull = open_readb("/dev/null") ; + if (devnull >= 0) + { + if (devnull < 3) qmailr_temp("weird fd configuration") ; + fd_move(2, devnull) ; + } + } + + fmtfd[uint_fmt(fmtfd, (unsigned int)fd)] = 0 ; + fmtt[uint_fmt(fmtt, timeoutremote)] = 0 ; + fmtk[uint_fmt(fmtk, timeoutconnect > UINT_MAX/1000 ? UINT_MAX : timeoutconnect * 1000)] = 0 ; + + argv[m++] = S6_NETWORKING_EXTBINPREFIX "s6-tlsc" ; + argv[m++] = "-Sjzv0" ; + argv[m++] = "-K" ; + argv[m++] = fmtk ; + argv[m++] = "-6" ; + argv[m++] = fmtfd ; + argv[m++] = "-7" ; + argv[m++] = fmtfd ; + argv[m++] = "--" ; + + argv[m++] = SMTPD_STARTTLS_PROXY_LIBEXECPREFIX "qmail-remote-io" ; + argv[m++] = "-t" ; + argv[m++] = fmtt ; + argv[m++] = "-6" ; + argv[m++] = fmtfd ; + argv[m++] = "-7" ; + argv[m++] = fmtfd ; + argv[m++] = "--" ; + argv[m++] = fmtip ; + argv[m++] = storage + helopos ; + for (unsigned int i = 0 ; i < n ; i++) argv[m++] = storage + eaddrpos[i] ; + argv[m++] = 0 ; + mexec(argv) ; + qmailr_tempusys("exec ", argv[0]) ; +} + +static inline void exec_notls (int fd, char const *fmtip, unsigned int timeoutremote, size_t helopos, size_t const *eaddrpos, unsigned int n, char const *storage) gccattr_noreturn ; +static inline void exec_notls (int fd, char const *fmtip, unsigned int timeoutremote, size_t helopos, size_t const *eaddrpos, unsigned int n, char const *storage) +{ + unsigned int m = 0 ; + char fmtfd[UINT_FMT] ; + char fmtt[UINT_FMT] ; + char const *argv[11 + n] ; + + fmtfd[uint_fmt(fmtfd, (unsigned int)fd)] = 0 ; + fmtt[uint_fmt(fmtt, timeoutremote)] = 0 ; + argv[m++] = SMTPD_STARTTLS_PROXY_LIBEXECPREFIX "qmail-remote-io" ; + argv[m++] = "-t" ; + argv[m++] = fmtt ; + argv[m++] = "-6" ; + argv[m++] = fmtfd ; + argv[m++] = "-7" ; + argv[m++] = fmtfd ; + argv[m++] = "--" ; + argv[m++] = fmtip ; + argv[m++] = storage + helopos ; + for (unsigned int i = 0 ; i < n ; i++) argv[m++] = storage + eaddrpos[i] ; + argv[m++] = 0 ; + exec(argv) ; + qmailr_tempusys("exec ", argv[0]) ; +} + +static int smtp_start (buffer *in, buffer *out, char const *helohost, unsigned int timeout, char const *fmtip) +{ + int hastls = 0 ; + tain deadline ; + char line[1024] ; + + int r = qmailr_smtp_read_answer(in, line, 1024, timeout) ; + if (r == -1) qmailr_tempusys("read from ", fmtip) ; + if (!r) qmailr_temp("Connected to ", fmtip, " but connection died") ; + if (r != 220) + { + qmailr_smtp_quit(out, timeout) ; + qmailr_temp("Connected to ", fmtip, " but greeting failed") ; + } + + buffer_putnoflush(out, "EHLO ", 5) ; + buffer_putsnoflush(out, helohost) ; + buffer_putnoflush(out, "\r\n", 2) ; + + tain_addsec_g(&deadline, timeout) ; + if (!buffer_timed_flush_g(out, &deadline)) + qmailr_tempusys("send ", "EHLO", " to ", fmtip) ; + + tain_addsec_g(&deadline, timeout) ; + for (;;) + { + unsigned int code = 250 ; + int r = qmailr_smtp_read_line(in, line, 1024, &code, &deadline) ; + if (r == -1) qmailr_tempusys("read from ", fmtip) ; + if (!r) qmailr_temp("Connected to ", fmtip, " but connection died") ; + if (code != 250) qmailr_temp("Connected to ", fmtip, " but it speaks a weird protocol") ; + if (!strcasecmp(line + 4, "STARTTLS")) hastls = 1 ; + if (r == 1) break ; + } + return hastls ; +} + +static void attempt_smtp (int fd, char const *ip, int is6, unsigned int timeoutconnect, unsigned int timeoutremote, qmailr_tls const *qtls, size_t helopos, size_t const *eaddrpos, unsigned int n, char const *storage) +{ + int hastls ; + char inbuf[2048] ; + char outbuf[2048] ; + char fmtip[IP6_FMT] ; + buffer in = BUFFER_INIT(&buffer_read, fd, inbuf, 2048) ; + buffer out = BUFFER_INIT(&buffer_write, fd, outbuf, 2048) ; + if (is6) fmtip[ip6_fmt(fmtip, ip)] = 0 ; + else fmtip[ip4_fmt(fmtip, ip)] = 0 ; + + hastls = smtp_start(&in, &out, storage + helopos, timeoutremote, fmtip) ; + if (qtls->flagwanttls) + { + if (hastls) + { + int r ; + tain deadline ; + char line[1024] ; + buffer_putsnoflush(&out, "STARTTLS\r\n") ; + tain_addsec_g(&deadline, timeoutremote) ; + if (!buffer_timed_flush_g(&out, &deadline)) qmailr_tempusys("send ", "STARTTLS", " to ", fmtip) ; + r = qmailr_smtp_read_answer(&in, line, 1024, timeoutremote) ; + if (r == -1) qmailr_tempusys("read from ", fmtip) ; + else if (!r) + { + qmailr_smtp_quit(&out, timeoutremote) ; + qmailr_temp("Connected to ", fmtip, " but connection died") ; + } + else if (r == 220) exec_tls(fd, fmtip, timeoutconnect, timeoutremote, qtls, helopos, eaddrpos, n, storage) ; + if (qtls->strictness) return ; + } + else if (qtls->strictness >= 2) return ; + } + exec_notls(fd, fmtip, timeoutremote, helopos, eaddrpos, n, storage) ; +} + int main (int argc, char const *const *argv) { stralloc storage = STRALLOC_ZERO ; stralloc ipme4 = STRALLOC_ZERO ; stralloc ipme6 = STRALLOC_ZERO ; - qmailr_tls qt = QMAILR_TLS_ZERO ; + qmailr_tls qtls = QMAILR_TLS_ZERO ; smtproutes routes = SMTPROUTES_ZERO ; - unsigned int timeoutconnect = 60, timeoutremote = 1200 ; + unsigned int timeoutconnect = 60, timeoutremote = 1200, timeoutdns = 0 ; char const *host ; size_t mepos, helopos, hostpos = 0 ; uint16_t port = 25 ; @@ -31,8 +199,8 @@ int main (int argc, char const *const *argv) if (argc-- < 4) dieusage() ; argv++ ; - if (chdir(SMTPD_STARTTLS_PROXY_QMAIL_HOME) == -1) qmailr_temp("Unable to chdir to " SMTPD_STARTTLS_PROXY_QMAIL_HOME) ; - if (sig_altignore(SIGPIPE) == -1) qmailr_tempsys("Unable to ignore SIGPIPE") ; + if (chdir(SMTPD_STARTTLS_PROXY_QMAIL_HOME) == -1) qmailr_tempusys("chdir to ", SMTPD_STARTTLS_PROXY_QMAIL_HOME) ; + if (sig_altignore(SIGPIPE) == -1) qmailr_tempusys("ignore SIGPIPE") ; host = *argv++ ; argc-- ; tain_now_set_stopwatch_g() ; @@ -40,27 +208,27 @@ int main (int argc, char const *const *argv) /* init control */ r = qmailr_control_read("control/me", &storage, &mepos) ; - if (r == -1) qmailr_tempsys("Unable to read control/me") ; - else if (!r) qmailr_temp("Invalid control/me") ; + if (r == -1) qmailr_tempusys("read ", "control/me") ; + else if (!r) qmailr_temp("Invalid ", "control/me") ; r = qmailr_control_read("control/helohost", &storage, &helopos) ; - if (r == -1) qmailr_tempsys("Unable to read control/helohost") ; + if (r == -1) qmailr_tempusys("read ", "control/helohost") ; else if (!r) helopos = mepos ; r = qmailr_control_readint("control/timeoutconnect", &timeoutconnect, &storage) ; - if (r == -1) qmailr_tempsys("Unable to read control/timeoutconnect") ; + if (r == -1) qmailr_tempusys("read ", "control/timeoutconnect") ; r = qmailr_control_readint("control/timeoutremote", &timeoutremote, &storage) ; - if (r == -1) qmailr_tempsys("Unable to read control/timeoutremote") ; + if (r == -1) qmailr_tempusys("read ", "control/timeoutremote") ; + r = qmailr_control_readint("control/timeoutdns", &timeoutdns, &storage) ; + if (r == -1) qmailr_tempusys("read ", "control/timeoutdns") ; if (!qmailr_control_readiplist("control/ipme", &ipme4, &ipme6)) - qmailr_tempsys("Unable to read control/ipme") ; - stralloc_shrink(&ipme4) ; - stralloc_shrink(&ipme6) ; + qmailr_tempusys("read ", "control/ipme") ; qsort(ipme4.s, ipme4.len >> 2, 4, &qmailr_memcmp4) ; qsort(ipme6.s, ipme6.len >> 4, 16, &qmailr_memcmp16) ; - if (!qmailr_tls_init(&qt, &storage)) - qmailr_tempsys("Unable to read TLS control files") ; + if (!qmailr_tls_init(&qtls, &storage)) + qmailr_tempusys("read ", "TLS control files") ; if (smtproutes_init(&routes)) { @@ -76,11 +244,69 @@ int main (int argc, char const *const *argv) { genalloc mxipind = GENALLOC_ZERO ; + mxip const *mxs ; size_t eaddrpos[argc] ; - dns_stuff(hostpos ? storage.s + hostpos : host, argv, argc, eaddrpos, &mxipind, &storage, timeoutconnect, ipme4.s, ipme4.len >> 2, ipme6.s, ipme6.len >> 4, !hostpos) ; - - } + size_t ntot = 0 ; + unsigned int mxn = dns_stuff(hostpos ? storage.s + hostpos : host, argv, argc, eaddrpos, &mxipind, &storage, timeoutdns, ipme4.s, ipme4.len >> 2, ipme6.s, ipme6.len >> 4, !hostpos) ; + if (!mxn) qmailr_perm("No suitable MX found for remote host") ; + stralloc_free(&ipme4) ; + stralloc_free(&ipme6) ; + mxs = genalloc_s(mxip, &mxipind) ; + for (unsigned int i = 0 ; i < mxn ; i++) ntot += mxs[i].n4 + mxs[i].n6 ; + if (!ntot) qmailr_perm("No suitable IP addresses for the MX") ; - _exit(0) ; + for (; qtls.flagwanttls && qtls.strictness == 1 ; qtls.flagwanttls = 0) + { + for (unsigned int i = 0 ; i < mxn ; i++) + { +#ifdef SKALIBS_IPV6_ENABLED + for (unsigned int j = 0 ; j < mxs[i].n6 ; j++) + { + char const *ip = storage.s + mxs[i].pos6 + (j << 4) ; + tain deadline ; + int fd ; + if (qmailr_tcpto_match(ip, 1)) continue ; + fd = socket_tcp6() ; + if (fd == -1) qmailr_tempusys("create socket") ; + tain_addsec_g(&deadline, timeoutconnect) ; + if (!socket_deadlineconnstamp6_g(fd, ip, port, &deadline)) + { + if (!qmailr_tcpto_update(ip, 1, errno == ETIMEDOUT)) + qmailr_tempusys("update ", "tcpto6") ; + fd_close(fd) ; + continue ; + } + if (!qmailr_tcpto_update(ip, 1, 0)) + qmailr_tempusys("update ", "tcpto6") ; + attempt_smtp(fd, ip, 1, timeoutconnect, timeoutremote, &qtls, helopos, eaddrpos, argc, storage.s) ; + fd_close(fd) ; + } +#endif + for (unsigned int j = 0 ; j < mxs[i].n4 ; j++) + { + char const *ip = storage.s + mxs[i].pos4 + (j << 2) ; + tain deadline ; + int fd ; + if (qmailr_tcpto_match(ip, 0)) continue ; + fd = socket_tcp4() ; + if (fd == -1) qmailr_tempusys("create socket") ; + tain_addsec_g(&deadline, timeoutconnect) ; + if (!socket_deadlineconnstamp4_g(fd, ip, port, &deadline)) + { + if (!qmailr_tcpto_update(ip, 0, errno == ETIMEDOUT)) + qmailr_tempusys("update ", "tcpto") ; + fd_close(fd) ; + continue ; + } + if (!qmailr_tcpto_update(ip, 0, 0)) + qmailr_tempusys("update ", "tcpto") ; + attempt_smtp(fd, ip, 0, timeoutconnect, timeoutremote, &qtls, helopos, eaddrpos, argc, storage.s) ; + fd_close(fd) ; + } + } + } + } + qmailr_tempusys("establish an SMTP connection") ; + _exit(101) ; /* not reached */ } diff --git a/src/qmail-remote/qmail-remote.h b/src/qmail-remote/qmail-remote.h index 8059344..afe4323 100644 --- a/src/qmail-remote/qmail-remote.h +++ b/src/qmail-remote/qmail-remote.h @@ -12,7 +12,7 @@ #include "qmailr.h" -#define dienomem() qmailr_tempsys("Unable to grow stralloc") +#define dienomem() qmailr_tempusys("stralloc_catb") /* dns */ @@ -27,7 +27,7 @@ struct mxip_s } ; #define MXIP_ZERO { 0 } -extern void dns_stuff (char const *, char const *const *, unsigned int, size_t *, genalloc *, stralloc *, unsigned int, char const *, unsigned int, char const *, unsigned int, uint32_t) ; +extern unsigned int dns_stuff (char const *, char const *const *, unsigned int, size_t *, genalloc *, stralloc *, unsigned int, char const *, unsigned int, char const *, unsigned int, uint32_t) ; /* smtproutes */ diff --git a/src/qmail-remote/qmailr.h b/src/qmail-remote/qmailr.h index 08c4f41..451824a 100644 --- a/src/qmail-remote/qmailr.h +++ b/src/qmail-remote/qmailr.h @@ -7,23 +7,30 @@ #include <stdint.h> #include <skalibs/gccattributes.h> +#include <skalibs/buffer.h> #include <skalibs/tai.h> #include <skalibs/stralloc.h> /* qmailr_error */ -extern void qmailr_diev (int, char const *const *, unsigned int) gccattr_noreturn ; +extern void qmailr_warnv (char, char const *const *, unsigned int) gccattr_noreturn ; +extern void qmailr_diev (char, char const *const *, unsigned int) gccattr_noreturn ; extern void qmailr_dievsys (char const *const *, unsigned int) gccattr_noreturn ; -extern void qmailr_die (int, char const *) gccattr_noreturn ; -extern void qmailr_diesys (char const *) gccattr_noreturn ; -#define qmailr_temp(s) qmailr_die(0, (s)) -#define qmailr_tempv(v, n) qmailr_diev(0, (v), n) -#define qmailr_tempsys(s) qmailr_diesys(s) -#define qmailr_tempvsys(v, n) qmailr_dievsys(v, n) -#define qmailr_perm(s) qmailr_die(1, (s)) -#define qmailr_permv(v, n) qmailr_diev(1, (v), n) +#define qmailr_array(...) ((char const *const[]){__VA_ARGS__}) +#define qmailr_dien(e, n, ...) qmailr_diev(e, qmailr_array(__VA_ARGS__), (n)) +#define qmailr_diensys(n, ...) qmailr_dievsys(qmailr_array(__VA_ARGS__), (n)) + +#define qmailr_die(c, ...) qmailr_dien(c, sizeof(qmailr_array(__VA_ARGS__))/sizeof(char const *), __VA_ARGS__) +#define qmailr_diesys(...) qmailr_diensys(sizeof(qmailr_array(__VA_ARGS__))/sizeof(char const *), __VA_ARGS__) + +#define qmailr_temp(...) qmailr_die('Z', __VA_ARGS__) +#define qmailr_tempsys(...) qmailr_diesys(__VA_ARGS__) +#define qmailr_perm(...) qmailr_die(1, __VA_ARGS__) + +#define qmailr_tempu(...) qmailr_die('D', "Unable to ", __VA_ARGS__) +#define qmailr_tempusys(...) qmailr_diesys("Unable to ", __VA_ARGS__) /* qmailr_utils */ @@ -46,6 +53,14 @@ extern int qmailr_control_readint (char const *file, unsigned int *, stralloc *) extern int qmailr_control_readiplist (char const *, stralloc *, stralloc *) ; + /* qmailr_smtp */ + +extern int qmailr_smtp_read_line (buffer *, char *, size_t, unsigned int *, tain const *) ; +extern int qmailr_smtp_read_answer (buffer *, char *, size_t, unsigned int) ; +extern int qmailr_smtp_start (buffer *, buffer *, char const *, unsigned int) ; +extern void qmailr_smtp_quit (buffer *b, unsigned int) ; + + /* qmailr_tls */ typedef struct qmailr_tls_s qmailr_tls, *qmailr_tls_ref ; @@ -55,7 +70,7 @@ struct qmailr_tls_s size_t certpos ; size_t keypos ; uint8_t strictness : 2 ; - uint8_t flagtls : 1 ; + uint8_t flagwanttls : 1 ; uint8_t flagtadir : 1 ; uint8_t flagclientcert : 1 ; } ; diff --git a/src/qmail-remote/qmailr_error.c b/src/qmail-remote/qmailr_error.c index fcdce54..0f500e2 100644 --- a/src/qmail-remote/qmailr_error.c +++ b/src/qmail-remote/qmailr_error.c @@ -8,31 +8,26 @@ #include <smtpd-starttls-proxy/config.h> -void qmailr_diev (int permanent, char const *const *v, unsigned int n) +void qmailr_warnv (char code, char const *const *v, unsigned int n) { - buffer_put(buffer_1small, permanent ? "D" : "Z", 1) ; - while (n--) buffer_puts(buffer_1small, *v++) ; - buffer_putflush(buffer_1small, "\n", 2) ; - _exit(0) ; + buffer_put(buffer_1, &code, 1) ; + while (n--) buffer_puts(buffer_1, *v++) ; + buffer_putflush(buffer_1, "\n", 2) ; } -void qmailr_dievsys (char const *const *v, unsigned int n) +void qmailr_diev (char code, char const *const *v, unsigned int n) { - char const *se = strerror(errno) ; - buffer_put(buffer_1small, "Z", 1) ; - while (n--) buffer_puts(buffer_1small, *v++) ; - buffer_put(buffer_1small, ": ", 2) ; - buffer_puts(buffer_1small, se) ; - buffer_putflush(buffer_1small, "\n", 2) ; + qmailr_warnv(code, v, n) ; _exit(0) ; } -void qmailr_die (int permanent, char const *msg) -{ - qmailr_diev(permanent, &msg, 1) ; -} - -void qmailr_diesys (char const *msg) +void qmailr_dievsys (char const *const *v, unsigned int n) { - qmailr_dievsys(&msg, 1) ; + char const *se = strerror(errno) ; + buffer_put(buffer_1, "Z", 1) ; + while (n--) buffer_puts(buffer_1, *v++) ; + buffer_put(buffer_1, ": ", 2) ; + buffer_puts(buffer_1, se) ; + buffer_putflush(buffer_1, "\n", 2) ; + _exit(0) ; } diff --git a/src/qmail-remote/qmailr_smtp.c b/src/qmail-remote/qmailr_smtp.c new file mode 100644 index 0000000..5a778f4 --- /dev/null +++ b/src/qmail-remote/qmailr_smtp.c @@ -0,0 +1,53 @@ +/* ISC license. */ + +#include <strings.h> +#include <errno.h> + +#include <skalibs/types.h> +#include <skalibs/buffer.h> +#include <skalibs/tai.h> +#include <skalibs/unix-timed.h> + +#include "qmailr.h" + +#include <skalibs/posixishard.h> + +int qmailr_smtp_read_line (buffer *in, char *line, size_t max, unsigned int *code, tain const *deadline) +{ + unsigned int c ; + size_t w = 0 ; + ssize_t r = timed_getlnmax_g(in, line, max, &w, '\n', deadline) ; + if (r <= 0) return r ; + if (w < 4) return (errno = EPROTO, -1) ; + line[--w] = 0 ; + if (line[w-1] == '\r') line[--w] = 0 ; + while (w >= 3 && line[w-1] == ' ') line[--w] = 0 ; + if (uint_scan(line, &c) != 3) return (errno = EPROTO, -1) ; + *code = c ; + return 1 + (line[3] == '-') ; +} + +int qmailr_smtp_read_answer (buffer *in, char *line, size_t max, unsigned int timeout) +{ + unsigned int code = 1000 ; + tain deadline ; + tain_addsec_g(&deadline, timeout) ; + for (;;) + { + unsigned int c ; + int r = qmailr_smtp_read_line(in, line, max, &c, &deadline) ; + if (r <= 0) return r ; + if (code == 1000) code = c ; + else if (code != c) return (errno = EPROTO, -1) ; + if (r == 1) break ; + } + return code ; +} + +void qmailr_smtp_quit (buffer *out, unsigned int timeout) +{ + tain deadline ; + buffer_puts(out, "QUIT\r\n") ; + tain_addsec_g(&deadline, timeout) ; + buffer_timed_flush_g(out, &deadline) ; +} diff --git a/src/qmail-remote/qmailr_tls.c b/src/qmail-remote/qmailr_tls.c index 6e09a82..351401e 100644 --- a/src/qmail-remote/qmailr_tls.c +++ b/src/qmail-remote/qmailr_tls.c @@ -19,7 +19,7 @@ int qmailr_tls_init (qmailr_tls *qt, stralloc *sa) if (r) { unsigned int strictness = 0 ; - tmp.flagtls = 1 ; + tmp.flagwanttls = 1 ; if (sa->s[sa->len - 2] == '/') { sa->s[--sa->len - 1] = 0 ; diff --git a/src/qmail-remote/smtproutes.c b/src/qmail-remote/smtproutes.c index 7467031..987961c 100644 --- a/src/qmail-remote/smtproutes.c +++ b/src/qmail-remote/smtproutes.c @@ -96,7 +96,7 @@ static inline char getnext (buffer *b) { char c ; ssize_t r = buffer_get(b, &c, 1) ; - if (r == -1) qmailr_tempsys("Unable to read from control/smtproutes") ; + if (r == -1) qmailr_tempusys("read ", "control/smtproutes") ; return r ? c : 0 ; } @@ -121,7 +121,7 @@ static inline void smtproutes_compile (int fdr, int fdw) buffer b = BUFFER_INIT(&buffer_read, fdr, buf, 2048) ; uint32_t relaypos = 0, relayend = 0 ; uint8_t state = 0 ; - if (!cdbmake_start(&cm, fdw)) qmailr_tempsys("Unable to cdbmake_start") ; + if (!cdbmake_start(&cm, fdw)) qmailr_tempusys("cdbmake_start") ; while (state < 0x0a) { @@ -130,36 +130,36 @@ static inline void smtproutes_compile (int fdr, int fdw) state = val & 0x000f ; if (val & 0x0100) { - if (!stralloc_catb(&sa, &c, 1)) qmailr_tempsys("Unable to grow stralloc") ; + if (!stralloc_catb(&sa, &c, 1)) dienomem() ; } if (val & 0x0200) { relaypos = sa.len + 1 ; - if (!stralloc_catb(&sa, "\0\0\31", 3)) qmailr_tempsys("Unable to grow stralloc") ; + if (!stralloc_catb(&sa, "\0\0\31", 3)) dienomem() ; } if (val & 0x0400) { - if (!stralloc_0(&sa)) qmailr_tempsys("Unable to grow stralloc") ; + if (!stralloc_0(&sa)) dienomem() ; relayend = sa.len ; } if (val & 0x0800) { uint16_t port ; - if (!stralloc_0(&sa)) qmailr_tempsys("Unable to grow stralloc") ; - if (!uint160_scan(sa.s + relayend, &port)) qmailr_temp("Invalid port in control/smtproutes") ; + if (!stralloc_0(&sa)) dienomem() ; + if (!uint160_scan(sa.s + relayend, &port)) qmailr_temp("Invalid port in ", "control/smtproutes") ; uint16_pack_big(sa.s + relaypos, port) ; } if (val & 0x0100) { if (relaypos > 1 || relayend > 2 + relaypos) if (!cdbmake_add(&cm, sa.s, relaypos, sa.s + relaypos, relayend - relaypos)) - qmailr_tempsys("Unable to cdbmake_add") ; + qmailr_tempusys("cdbmake_add") ; sa.len = 0 ; } } - if (state != 0x0a) qmailr_temp("Syntax error in control/smtproutes") ; + if (state != 0x0a) qmailr_temp("Syntax error in ", "control/smtproutes") ; stralloc_free(&sa) ; - if (!cdbmake_finish(&cm)) qmailr_tempsys("Unable to cdbmake_finish") ; + if (!cdbmake_finish(&cm)) qmailr_tempusys("cdbmake_finish") ; } int smtproutes_init (smtproutes *routes) @@ -169,17 +169,17 @@ int smtproutes_init (smtproutes *routes) static char const *txtfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/smtproutes" ; static size_t const cdblen = sizeof(cdbfile) - 1 ; int fdl = openc_create(lckfile) ; - if (fdl == -1) qmailr_tempsys("Unable to open run/qmail-remote/smtproutes.lock") ; - if (fd_lock(fdl, 1, 0) == -1) qmailr_tempsys("Unable to lock run/qmail-remote/smtproutes.lock") ; + if (fdl == -1) qmailr_tempusys("open ", "run/qmail-remote/smtproutes.lock") ; + if (fd_lock(fdl, 1, 0) == -1) qmailr_tempusys("lock ", "run/qmail-remote/smtproutes.lock") ; int fdc = openc_read(cdbfile) ; if (fdc >= 0) { struct stat stc, str ; - if (fstat(fdc, &stc) == -1) qmailr_tempsys("Unable to fstat run/qmail-remote/smtproutes.cdb") ; + if (fstat(fdc, &stc) == -1) qmailr_tempusys("fstat ", "run/qmail-remote/smtproutes.cdb") ; if (stat(txtfile, &str) == -1) { - if (errno != ENOENT) qmailr_tempsys("Unable to fstat control/smtproutes") ; + if (errno != ENOENT) qmailr_tempusys("fstat ", "control/smtproutes") ; unlink_void(cdbfile) ; fd_close(fdc) ; goto zero ; @@ -191,7 +191,7 @@ int smtproutes_init (smtproutes *routes) int fdr = openc_read(txtfile) ; if (fdr == -1) { - if (errno != ENOENT) qmailr_tempsys("Unable to open control/smtproutes") ; + if (errno != ENOENT) qmailr_tempusys("open ", "control/smtproutes") ; goto zero ; } @@ -200,16 +200,16 @@ int smtproutes_init (smtproutes *routes) memcpy(tmp, cdbfile, cdblen) ; memcpy(tmp + cdblen, ":XXXXXX", 8) ; fdc = mkstemp(tmp) ; - if (fdc == -1) qmailr_tempsys("Unable to mkstemp") ; + if (fdc == -1) qmailr_tempusys("mkstemp") ; smtproutes_compile(fdr, fdc) ; - if (lseek(fdc, 0, SEEK_SET) == -1) qmailr_tempsys("Unable to lseek") ; - if (fsync(fdc) == -1) qmailr_tempsys("Unable to fsync run/qmail-remote/smtproutes.cdb") ; + if (lseek(fdc, 0, SEEK_SET) == -1) qmailr_tempusys("lseek") ; + if (fsync(fdc) == -1) qmailr_tempusys("fsync ", "run/qmail-remote/smtproutes.cdb") ; fd_close(fdr) ; if (rename(tmp, cdbfile) == -1) unlink_void(tmp) ; } useit: - if (!cdb_init_fromfd(&routes->map, fdc)) qmailr_tempsys("Unable to mmap run/qmail-remote/smtproutes.cdb") ; + if (!cdb_init_fromfd(&routes->map, fdc)) qmailr_tempusys("mmap ", "run/qmail-remote/smtproutes.cdb") ; fd_close(fdc) ; fd_close(fdl) ; return 1 ; @@ -227,10 +227,10 @@ int smtproutes_match (smtproutes const *routes, char const *s, stralloc *sa, siz if (r == -1) qmailr_temp("Invalid run/qmail-remote/smtproutes.cdb") ; if (!r) return 0 ; if (data.len < 3) return 0 ; - if (data.s[data.len - 1]) qmailr_temp("Invalid run/qmail-remote/smtproutes.cdb") ; + if (data.s[data.len - 1]) qmailr_temp("Invalid ", "run/qmail-remote/smtproutes.cdb") ; *pos = sa->len ; uint16_unpack_big(data.s, port) ; - if (!stralloc_catb(sa, data.s + 2, data.len - 2)) qmailr_tempsys("Unable to grow stralloc") ; + if (!stralloc_catb(sa, data.s + 2, data.len - 2)) dienomem() ; return 1 ; } |
