From 5ca4a0e5b65066f41af7c670e8200b0d0eba41dd Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Fri, 6 Feb 2026 02:16:08 +0000 Subject: Just name it qmail-remote after all --- src/qmail-smtpc/deps-exe/qmail-smtpc | 6 - src/qmail-smtpc/deps-lib/qmailr | 6 - src/qmail-smtpc/dns.c | 315 ----------------------------------- src/qmail-smtpc/qmail-smtpc.c | 86 ---------- src/qmail-smtpc/qmail-smtpc.h | 46 ----- src/qmail-smtpc/qmailr.h | 66 -------- src/qmail-smtpc/qmailr_control.c | 82 --------- src/qmail-smtpc/qmailr_error.c | 38 ----- src/qmail-smtpc/qmailr_tcpto.c | 157 ----------------- src/qmail-smtpc/qmailr_tls.c | 47 ------ src/qmail-smtpc/qmailr_utils.c | 60 ------- src/qmail-smtpc/smtproutes.c | 240 -------------------------- 12 files changed, 1149 deletions(-) delete mode 100644 src/qmail-smtpc/deps-exe/qmail-smtpc delete mode 100644 src/qmail-smtpc/deps-lib/qmailr delete mode 100644 src/qmail-smtpc/dns.c delete mode 100644 src/qmail-smtpc/qmail-smtpc.c delete mode 100644 src/qmail-smtpc/qmail-smtpc.h delete mode 100644 src/qmail-smtpc/qmailr.h delete mode 100644 src/qmail-smtpc/qmailr_control.c delete mode 100644 src/qmail-smtpc/qmailr_error.c delete mode 100644 src/qmail-smtpc/qmailr_tcpto.c delete mode 100644 src/qmail-smtpc/qmailr_tls.c delete mode 100644 src/qmail-smtpc/qmailr_utils.c delete mode 100644 src/qmail-smtpc/smtproutes.c (limited to 'src/qmail-smtpc') diff --git a/src/qmail-smtpc/deps-exe/qmail-smtpc b/src/qmail-smtpc/deps-exe/qmail-smtpc deleted file mode 100644 index 4484f9b..0000000 --- a/src/qmail-smtpc/deps-exe/qmail-smtpc +++ /dev/null @@ -1,6 +0,0 @@ -dns.o -smtproutes.o -libqmailr.a.xyzzy --lskadns --ls6dns --lskarnet diff --git a/src/qmail-smtpc/deps-lib/qmailr b/src/qmail-smtpc/deps-lib/qmailr deleted file mode 100644 index c1095ed..0000000 --- a/src/qmail-smtpc/deps-lib/qmailr +++ /dev/null @@ -1,6 +0,0 @@ -qmailr_control.o -qmailr_error.o -qmailr_tcpto.o -qmailr_tls.o -qmailr_utils.o --lskarnet diff --git a/src/qmail-smtpc/dns.c b/src/qmail-smtpc/dns.c deleted file mode 100644 index 90aade4..0000000 --- a/src/qmail-smtpc/dns.c +++ /dev/null @@ -1,315 +0,0 @@ -/* ISC license. */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "qmailr.h" -#include "qmail-smtpc.h" - -typedef struct cnameinfo_s cnameinfo, *cnameinfo_ref ; -struct cnameinfo_s -{ - stralloc sa ; - size_t atpos ; - uint16_t id ; - uint16_t count ; -} ; - -typedef struct mxipinfo_s mxipinfo, mxipinfo_ref ; -struct mxipinfo_s -{ - stralloc ip4 ; - stralloc ip6 ; - uint16_t id4 ; - uint16_t id6 ; -} ; -#define MXIPINFO_ZERO { .ip4 = STRALLOC_ZERO, .ip6 = STRALLOC_ZERO, .id4 = UINT16_MAX, .id6 = UINT16_MAX } - -static int mx_cmp (void const *a, void const *b) -{ - s6dns_message_rr_mx_t const *aa = a ; - s6dns_message_rr_mx_t const *bb = b ; - return aa->preference < bb-> preference ? -1 : aa->preference > bb->preference ; -} - -static unsigned int use_host_as_mx (skadns_t *a, char const *host, genalloc *mxip, tain const *deadline) -{ - unsigned int newreqs = 0 ; - 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") ; - if (!skadns_send_g(a, &info.id4, &q, S6DNS_T_A, deadline, deadline)) - qmailr_tempsys("Unable to 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") ; - newreqs++ ; -#endif - if (!genalloc_catb(mxipinfo, mxip, &info, 1)) dienomem() ; - return newreqs ; -} - - /* - 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. - 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. - Shove everything in storage and return the indices: - in eaddrpos for sender+recipients, in mxipind for the IPs to connect to. - - Also, fuck DNS for requiring so many small allocations and data copies. - - 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) -{ - skadns_t a = SKADNS_ZERO ; - genalloc mxipi = GENALLOC_ZERO ; /* mxipinfo */ - tain deadline ; - unsigned int pending = 0 ; - uint16_t mxn = 0 ; - uint16_t mxid = UINT16_MAX ; - cnameinfo cnames[n] ; - - tain_addsec_g(&deadline, timeoutdns) ; - if (!skadns_startf_g(&a, &deadline)) - qmailr_tempsys("Unable to start asynchronous DNS helper") ; - - for (unsigned int i = 0 ; i < n ; i++) - { - char const *at = strrchr(eaddr[i], '@') ; - cnames[i].sa = stralloc_zero ; - if (at) - { - s6dns_domain_t q ; - size_t len = strlen(at+1) ; - 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") ; - if (!skadns_send_g(&a, &cnames[i].id, &q, S6DNS_T_CNAME, &deadline, &deadline)) - qmailr_tempsys("Unable to send CNAME DNS query") ; - cnames[i].count = 1 ; - pending++ ; - } - else - { - cnames[i].id = UINT16_MAX ; - cnames[i].count = 0 ; - cnames[i].atpos = strlen(eaddr[i]) ; - } - } - - if (flags & 1) - { - s6dns_domain_t q ; - if (!s6dns_domain_fromstring_noqualify_encode(&q, host, strlen(host))) - qmailr_tempsys("Unable to DNS-encode host domain") ; - if (!skadns_send_g(&a, &mxid, &q, S6DNS_T_MX, &deadline, &deadline)) - qmailr_tempsys("Unable to send MX DNS query") ; - pending++ ; - } - else - { - mxn = 1 ; - pending += use_host_as_mx(&a, host, &mxipi, &deadline) ; - } - - while (pending) - { - 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) qmailr_tempsys("Timed out waiting for DNS") ; - r = skadns_update(&a) ; - if (r == -1) qmailr_tempsys("Unable to read DNS answers") ; - ids = genalloc_s(uint16_t, &a.list) ; - for (size_t j = 0 ; j < genalloc_len(uint16_t, &a.list) ; j++) - { - char const *packet = skadns_packet(&a, ids[j]) ; - uint16_t packetlen = skadns_packetlen(&a, ids[j]) ; - if (!packet) qmailr_tempsys("DNS packet reading error") ; - - if (ids[j] == mxid) /* return from MX query */ - { - s6dns_message_header_t h ; - genalloc mxes = GENALLOC_ZERO ; /* s6dns_message_rr_mx_t */ - r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_mx, &mxes) ; - 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") ; - } - skadns_release(&a, ids[j]) ; - pending-- ; - mxid = UINT16_MAX ; - if (r >= 2) /* we have MXes, ask for their IPs */ - { - s6dns_message_rr_mx_t *mxs = genalloc_s(s6dns_message_rr_mx_t, &mxes) ; - mxn = genalloc_len(s6dns_message_rr_mx_t, &mxes) ; - if (!genalloc_readyplus(mxipinfo, &mxipi, mxn)) dienomem() ; - qsort(mxs, mxn, sizeof(s6dns_message_rr_mx_t), &mx_cmp) ; - for (unsigned int i = 0 ; i < mxn ; i++) - { - 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") ; - 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") ; - pending++ ; -#endif - } - genalloc_free(s6dns_message_rr_mx_t, &mxes) ; - } - else - { - mxn = 1 ; - pending += use_host_as_mx(&a, host, &mxipi, &deadline) ; - } - continue ; - } - - for (unsigned int i = 0 ; i < n ; i++) if (ids[j] == cnames[i].id) /* return from CNAME query */ - { - s6dns_message_header_t h ; - s6dns_dpag_t dlist = { .ds = GENALLOC_ZERO, .rtype = S6DNS_T_CNAME } ; - r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_domain, &dlist) ; - 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") ; - } - skadns_release(&a, ids[j]) ; - pending-- ; - if (r >= 2) /* it's a CNAME, loop on it */ - { - 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") ; - 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 */ - continue ; - } - - for (unsigned int i = 0 ; i < mxn ; i++) - { - mxipinfo *p = genalloc_s(mxipinfo, &mxipi) + i ; - if (ids[j] == p->id4) - { - s6dns_message_header_t h ; - r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_a, &p->ip4) ; - 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") ; - } - skadns_release(&a, ids[j]) ; - pending-- ; - p->id4 = UINT16_MAX ; - for (unsigned int k = 0 ; k < p->ip4.len ; k += 4) - { - if (bsearch(p->ip4.s + k, ipme4, n4, 4, &qmailr_memcmp4)) - { - memmove(p->ip4.s + k, p->ip4.s + p->ip4.len - 4, 4) ; - p->ip4.len -= 4 ; - k -= 4 ; - } - } - } -#ifdef SKALIBS_IPV6_ENABLED - else if (ids[j] == p->id6) - { - s6dns_message_header_t h ; - r = s6dns_message_parse(&h, packet, packetlen, &s6dns_message_parse_answer_aaaa, &p->ip6) ; - 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") ; - } - skadns_release(&a, ids[j]) ; - pending-- ; - p->id6 = UINT16_MAX ; - for (unsigned int k = 0 ; k < p->ip6.len ; k += 16) - { - if (bsearch(p->ip6.s + k, ipme6, n6, 16, &qmailr_memcmp16)) - { - memmove(p->ip6.s + k, p->ip6.s + p->ip6.len - 16, 16) ; - p->ip6.len -= 16 ; - k -= 16 ; - } - } - } -#endif - } - } - } - skadns_end(&a) ; /* we done buddy */ - - for (unsigned int i = 0 ; i < n ; i++) - { - eaddrpos[i] = storage->len ; - if (!qmailr_box_encode(eaddr[i], cnames[i].atpos, storage)) dienomem() ; - if (cnames[i].count) - { - if (!stralloc_catb(storage, "@", 1)) dienomem() ; - if (!stralloc_catb(storage, cnames[i].sa.s, cnames[i].sa.len)) dienomem() ; - stralloc_free(&cnames[i].sa) ; - } - if (!stralloc_0(storage)) dienomem() ; - } - - if (!genalloc_readyplus(mxip, mxipind, mxn)) dienomem() ; - for (unsigned int i = 0 ; i < mxn ; i++) - { - mxip data ; - mxipinfo *p = genalloc_s(mxipinfo, &mxipi) + i ; - data.n4 = p->ip4.len >> 2 ; - data.pos4 = storage->len ; - if (!stralloc_catb(storage, p->ip4.s, p->ip4.len)) dienomem() ; - stralloc_free(&p->ip4) ; -#ifdef SKALIBS_IPV6_ENABLED - data.n6 = p->ip6.len >> 4 ; - data.pos6 = storage->len ; - if (!stralloc_catb(storage, p->ip6.s, p->ip6.len)) dienomem() ; - stralloc_free(&p->ip6) ; - genalloc_catb(mxip, mxipind, &data, 1) ; -#endif - } - genalloc_free(mxipinfo, &mxipi) ; -} diff --git a/src/qmail-smtpc/qmail-smtpc.c b/src/qmail-smtpc/qmail-smtpc.c deleted file mode 100644 index 0e0b11b..0000000 --- a/src/qmail-smtpc/qmail-smtpc.c +++ /dev/null @@ -1,86 +0,0 @@ -/* ISC license. */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include "qmailr.h" -#include "qmail-smtpc.h" - -#define dieusage() qmailr_perm("qmail-remote was invoked improperly") - -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 ; - smtproutes routes = SMTPROUTES_ZERO ; - unsigned int timeoutconnect = 60, timeoutremote = 1200 ; - char const *host ; - size_t mepos, helopos, hostpos = 0 ; - uint16_t port = 25 ; - int r ; - - 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") ; - host = *argv++ ; argc-- ; - tain_now_set_stopwatch_g() ; - - - /* 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") ; - - r = qmailr_control_read("control/helohost", &storage, &helopos) ; - if (r == -1) qmailr_tempsys("Unable to 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") ; - r = qmailr_control_readint("control/timeoutremote", &timeoutremote, &storage) ; - if (r == -1) qmailr_tempsys("Unable to read control/timeoutremote") ; - - if (!qmailr_control_readiplist("control/ipme", &ipme4, &ipme6)) - qmailr_tempsys("Unable to read control/ipme") ; - stralloc_shrink(&ipme4) ; - stralloc_shrink(&ipme6) ; - 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 (smtproutes_init(&routes)) - { - if (!smtproutes_match(&routes, host, &storage, &hostpos, &port)) - { - size_t hostlen = strlen(host) ; - for (size_t i = 0 ; i < hostlen ; i++) if (host[i] == '.') - if (smtproutes_match(&routes, argv[1], &storage, &hostpos, &port)) break ; - if (!hostpos) smtproutes_match(&routes, "", &storage, &hostpos, &port) ; - } - smtproutes_free(&routes) ; - } - - { - genalloc mxipind = GENALLOC_ZERO ; - 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) ; - - } - - - _exit(0) ; -} diff --git a/src/qmail-smtpc/qmail-smtpc.h b/src/qmail-smtpc/qmail-smtpc.h deleted file mode 100644 index 29aa792..0000000 --- a/src/qmail-smtpc/qmail-smtpc.h +++ /dev/null @@ -1,46 +0,0 @@ -/* ISC license. */ - -#ifndef QMAIL_SMTPC_H -#define QMAIL_SMTPC_H - -#include -#include - -#include -#include -#include - -#include "qmailr.h" - -#define dienomem() qmailr_tempsys("Unable to grow stralloc") - - -/* dns */ - -typedef struct mxip_s mxip, *mxip_ref ; -struct mxip_s -{ - size_t pos4 ; - size_t pos6 ; - uint16_t n4 ; - uint16_t n6 ; -} ; -#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) ; - - -/* smtproutes */ - -typedef struct smtproutes_s smtproutes ; -struct smtproutes_s -{ - cdb map ; -} ; -#define SMTPROUTES_ZERO { .map = CDB_ZERO } - -extern int smtproutes_init (smtproutes *) ; -extern int smtproutes_match (smtproutes const *, char const *, stralloc *, size_t *, uint16_t *) ; -extern void smtproutes_free (smtproutes *) ; - -#endif diff --git a/src/qmail-smtpc/qmailr.h b/src/qmail-smtpc/qmailr.h deleted file mode 100644 index 08c4f41..0000000 --- a/src/qmail-smtpc/qmailr.h +++ /dev/null @@ -1,66 +0,0 @@ -/* ISC license. */ - -#ifndef QMAILR_H -#define QMAILR_H - -#include -#include - -#include -#include -#include - - -/* qmailr_error */ - -extern void qmailr_diev (int, 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) - - -/* qmailr_utils */ - -extern int qmailr_memcmp4 (void const *, void const *) ; -extern int qmailr_memcmp16 (void const *, void const *) ; -extern int qmailr_box_encode (char const *, size_t, stralloc *) ; - - -/* qmailr_tcpto */ - -extern int qmailr_tcpto_match (char const *, int) ; -extern int qmailr_tcpto_update (char const *, int, int) ; - - -/* qmailr_control */ - -extern int qmailr_control_read (char const *, stralloc *, size_t *) ; -extern int qmailr_control_readint (char const *file, unsigned int *, stralloc *) ; -extern int qmailr_control_readiplist (char const *, stralloc *, stralloc *) ; - - -/* qmailr_tls */ - -typedef struct qmailr_tls_s qmailr_tls, *qmailr_tls_ref ; -struct qmailr_tls_s -{ - size_t tapos ; - size_t certpos ; - size_t keypos ; - uint8_t strictness : 2 ; - uint8_t flagtls : 1 ; - uint8_t flagtadir : 1 ; - uint8_t flagclientcert : 1 ; -} ; -#define QMAILR_TLS_ZERO { 0 } - -extern int qmailr_tls_init (qmailr_tls *, stralloc *) ; - -#endif diff --git a/src/qmail-smtpc/qmailr_control.c b/src/qmail-smtpc/qmailr_control.c deleted file mode 100644 index 706b0d9..0000000 --- a/src/qmail-smtpc/qmailr_control.c +++ /dev/null @@ -1,82 +0,0 @@ -/* ISC license. */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "qmailr.h" - -#include - -int qmailr_control_read (char const *file, stralloc *sa, size_t *pos) -{ - int fd = openc_readb(file) ; - if (fd == -1) return errno == ENOENT ? (errno = 0, 0) : -1 ; - - char buf[4096] ; - size_t r = allread(fd, buf, 4096) ; - fd_close(fd) ; - if (r == 4096) return (errno = ENAMETOOLONG, -1) ; - if (!r) return 0 ; - if (buf[r-1] == '\n') r-- ; - if (!r) return 0 ; - if (!stralloc_readyplus(sa, r+1)) return -1 ; - *pos = sa->len ; - stralloc_catb(sa, buf, r) ; stralloc_0(sa) ; - return 1 ; -} - -int qmailr_control_readint (char const *file, unsigned int *x, stralloc *sa) -{ - size_t pos ; - int r = qmailr_control_read(file, sa, &pos) ; - if (r <= 0) return r ; - sa->len = pos ; - if (!uint0_scan(sa->s + sa->len, x)) return (errno = EPROTO, 0) ; - return 1 ; -} - -int qmailr_control_readiplist (char const *file, stralloc *ip4, stralloc *ip6) -{ - int fd = openc_readb(file) ; - if (fd == -1) return errno == ENOENT ? (errno = 0, 0) : -1 ; - - size_t pos4 = ip4->len, pos6 = ip6->len ; - char buf[4096] ; - buffer b = BUFFER_INIT(&buffer_read, fd, buf, 4096) ; - - for (;;) - { - char line[128] ; - char ip[16] ; - size_t len = 0 ; - int r = getlnmax(&b, line, 127, &len, '\n') ; - if (r == -1) goto err ; - if (!r) break ; - if (!len) continue ; - if (line[len-1] != '\n') line[len++] = '\n' ; - if (ip6_scan(line, ip) == len-1) - { - if (!stralloc_catb(ip6, ip, 16)) goto err ; - } - else if (ip4_scan(line, ip) == len-1) - { - if (!stralloc_catb(ip4, ip, 4)) goto err ; - } - else goto errinval ; - } - return 1 ; - - errinval: - errno = EINVAL ; - err: - ip4->len = pos4 ; ip6->len = pos6 ; - return 0 ; -} diff --git a/src/qmail-smtpc/qmailr_error.c b/src/qmail-smtpc/qmailr_error.c deleted file mode 100644 index fcdce54..0000000 --- a/src/qmail-smtpc/qmailr_error.c +++ /dev/null @@ -1,38 +0,0 @@ -/* ISC license. */ - -#include -#include -#include - -#include - -#include - -void qmailr_diev (int permanent, 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) ; -} - -void qmailr_dievsys (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) ; - _exit(0) ; -} - -void qmailr_die (int permanent, char const *msg) -{ - qmailr_diev(permanent, &msg, 1) ; -} - -void qmailr_diesys (char const *msg) -{ - qmailr_dievsys(&msg, 1) ; -} diff --git a/src/qmail-smtpc/qmailr_tcpto.c b/src/qmail-smtpc/qmailr_tcpto.c deleted file mode 100644 index f90d1d0..0000000 --- a/src/qmail-smtpc/qmailr_tcpto.c +++ /dev/null @@ -1,157 +0,0 @@ -/* ISC license. */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include "qmailr.h" - -#include - - -/* - tcpto implementation, should be compatible with qmail-tcpto. - Assumes the 4 unused bytes at the end of a record are there to - accommodate 64-bit time_t. Which we use. But qmail-tcpto does - not, so you should patch that before 2038. - Has ipv6 support, storing v6 records in a different file. - Unlike qmail's tcpto, we assume the records are sorted by IP. - This makes it easy to look for a record with bsearch. We - keep records sorted with every modification, and we aggressively - cut empty ones from the file. - For the match function, not sure what is faster between mmapping and - simple reading. Currently we mmap to save private/dirty RAM, but - that holds the lock longer; it should be ok because we switched to - a shared lock for this (unsure why djb didn't). -*/ - -int qmailr_tcpto_match (char const *ip, int is6) -{ - char const *file = is6 ? SMTPD_STARTTLS_PROXY_QMAIL_HOME "/run/qmail-remote/tcpto6" : SMTPD_STARTTLS_PROXY_QMAIL_HOME "/queue/lock/tcpto" ; - uint32_t iplen = is6 ? 16 : 4 ; - uint32_t width = iplen + 12 ; - int r = 0 ; - char const *p ; - cdb c ; /* XXX: not a cdb, we're just using the mmap wrapper */ - int fd = openc_read(file) ; - - if (fd == -1) return -1 ; - if (fd_lock(fd, 0, 0) == -1) goto err ; - if (!cdb_init_fromfd(&c, fd)) goto err ; - if (c.size % width) goto errproto ; - p = bsearch(ip, c.map, c.size / width, width, is6 ? &qmailr_memcmp16 : &qmailr_memcmp4) ; - if (p) - { - if (p[iplen] >= 2) - { - tai when ; - uint64_t x ; - uint64_unpack(p + iplen + 4, &x) ; - tai_u64(&when, x) ; - tai_sub(&when, tain_secp(&STAMP), &when) ; - r = tai_sec(&when) < ((60 + (getpid() & 31)) << 6) ; /* don't ask me, ask djb */ - } - } - cdb_free(&c) ; - fd_close(fd) ; - return r ; - - errproto: - errno = EPROTO ; - err: - fd_close(fd) ; - return -1 ; -} - -int qmailr_tcpto_update (char const *ip, int is6, int problem) -{ - char const *file = is6 ? SMTPD_STARTTLS_PROXY_QMAIL_HOME "/run/qmail-remote/tcpto6" : SMTPD_STARTTLS_PROXY_QMAIL_HOME "/queue/lock/tcpto" ; - uint32_t iplen = is6 ? 16 : 4 ; - uint32_t width = iplen + 12 ; - uint32_t n ; - char *p = 0 ; - struct stat st ; - int fdr ; - int fdw = openc_create(file) ; - - if (fdw == -1) return 0 ; - if (fd_lock(fdw, 1, 0) == -1) goto err ; - fdr = openc_read(file) ; - if (fdr == -1) goto err ; - if (fstat(fdr, &st) == -1) goto err0 ; - if (st.st_size % width) goto errproto ; - n = st.st_size / width ; - - { - char buf[(n+1) * width] ; /* relax, it won't bite */ - if (n) - { - if (allread(fdr, buf, st.st_size) < st.st_size) goto err0 ; - memset(buf + st.st_size, 0, width) ; - p = bsearch(ip, buf, n, width, is6 ? &qmailr_memcmp16 : &qmailr_memcmp4) ; - if (p) - { - if (problem) - { - tai when ; - uint64_t x ; - uint64_unpack(p + iplen + 4, &x) ; - tai_u64(&when, x) ; - tai_sub(&when, tain_secp(&STAMP), &when) ; - if (tai_sec(&when) < 120) p = 0 ; - else - { - if (++p[iplen] > 10) p[iplen] = 10 ; - x = tai_sec(tain_secp(&STAMP)) - TAI_MAGIC ; - uint64_pack(p + iplen + 4, x) ; - } - } - else p[iplen] = 0 ; - } - } - else if (problem) - { - uint64_t x = tai_sec(tain_secp(&STAMP)) - TAI_MAGIC ; - p = buf + n++ * width ; - memcpy(p, ip, iplen) ; - p[iplen] = 1 ; - memset(p + iplen + 1, 0, 3) ; - uint64_pack(p + iplen + 4, x) ; - } - fd_close(fdr) ; - - if (p) - { - for (uint32_t i = 0 ; i < n ; i++) - if (!buf[i * width + iplen]) - memcpy(buf + i * width, buf + --n * width, width) ; - if (n) - { - qsort(buf, n, width, is6 ? &qmailr_memcmp16 : &qmailr_memcmp4) ; - if (allwrite(fdw, buf, n * width) < n * width) goto err ; - } - if (ftruncate(fdw, n * width) == -1) goto err ; - } - } - - fd_close(fdw) ; - return 1 ; - - errproto: - errno = EPROTO ; - err0: - fd_close(fdr) ; - err: - fd_close(fdw) ; - return 0 ; -} diff --git a/src/qmail-smtpc/qmailr_tls.c b/src/qmail-smtpc/qmailr_tls.c deleted file mode 100644 index 6e09a82..0000000 --- a/src/qmail-smtpc/qmailr_tls.c +++ /dev/null @@ -1,47 +0,0 @@ -/* ISC license. */ - -#include - -#include -#include "qmailr.h" - -int qmailr_tls_init (qmailr_tls *qt, stralloc *sa) -{ - static char const *tafile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/trustanchors" ; - static char const *certfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/clientcert" ; - static char const *keyfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/clientkey" ; - static char const *strictfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/control/tlsstrictness" ; - - qmailr_tls tmp = QMAILR_TLS_ZERO ; - size_t sabase = sa->len ; - int r = qmailr_control_read(tafile, sa, &tmp.tapos) ; - if (r == -1) return 0 ; - if (r) - { - unsigned int strictness = 0 ; - tmp.flagtls = 1 ; - if (sa->s[sa->len - 2] == '/') - { - sa->s[--sa->len - 1] = 0 ; - tmp.flagtadir = 1 ; - } - r = qmailr_control_read(certfile, sa, &tmp.certpos) ; - if (r == -1) goto err ; - if (r) - { - r = qmailr_control_read(keyfile, sa, &tmp.keypos) ; - if (r == -1) goto err ; - if (r) tmp.flagclientcert = 1 ; - } - r = qmailr_control_readint(strictfile, &strictness, sa) ; - if (r == -1) goto err ; - tmp.strictness = strictness & 3 ; - } - - *qt = tmp ; - return 1 ; - - err: - sa->len = sabase ; - return 0 ; -} diff --git a/src/qmail-smtpc/qmailr_utils.c b/src/qmail-smtpc/qmailr_utils.c deleted file mode 100644 index deeff46..0000000 --- a/src/qmail-smtpc/qmailr_utils.c +++ /dev/null @@ -1,60 +0,0 @@ -/* ISC license. */ - -#include - -#include -#include - -#include "qmailr.h" - -int qmailr_memcmp4 (void const *a, void const *b) -{ - return memcmp(a, b, 4) ; -} - -int qmailr_memcmp16 (void const *a, void const *b) -{ - return memcmp(a, b, 16) ; -} - -static inline int needsquoting (char const *s, size_t len) -{ - static unsigned char const badchar[32] = - { - 0xff, 0xff, 0xff, 0xff, - 0x05, 0x13, 0x00, 0x5c, - 0x01, 0x00, 0x00, 0x38, - 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - } ; - if (!len) return 1 ; - if (s[0] == '.' || s[len - 1] == '.') return 1 ; - for (size_t i = 0 ; i < len ; i++) - { - if (bitarray_peek(badchar, (unsigned char)s[i])) return 1 ; - if (i + 2 < len && s[i] == '.' && s[i+1] == '.') return 1 ; - } - return 0 ; -} - -int qmailr_box_encode (char const *s, size_t len, stralloc *storage) -{ - if (needsquoting(s, len)) - { - size_t j = storage->len ; - if (!stralloc_readyplus(storage, 2 + (len << 1))) return 0 ; - storage->s[j++] = '"' ; - for (size_t i = 0 ; i < len ; i++) - { - if (strchr("\"\\\r\n", s[i])) storage->s[j++] = '\\' ; - storage->s[j++] = s[i] ; - } - storage->s[j++] = '"' ; - storage->len = j ; - } - else if (!stralloc_catb(storage, s, len)) return 0 ; - return 1 ; -} diff --git a/src/qmail-smtpc/smtproutes.c b/src/qmail-smtpc/smtproutes.c deleted file mode 100644 index d5b1fac..0000000 --- a/src/qmail-smtpc/smtproutes.c +++ /dev/null @@ -1,240 +0,0 @@ -/* ISC license. */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "qmailr.h" -#include "qmail-smtpc.h" - - -/* - qmail-remote uses a "constmap" for smtproutes, which is - basically a cdb in RAM. Every instance of qmail-remote - parses control/smtproutes to make the constmap. - We replace it with a real cdb, stored in the filesystem. - It saves CPU (N-1 instances of qmail-remote use the cdb - directly) and RAM (the cdb is read-only and shared). - The cdb is updated whenever control/smtproutes is newer. - We have to lock around the test to avoid several - concurrent compilations; the current lock feels too big, - the crit section can probably be made smaller, but the - behaviour is safe and avoids retry heuristics. -*/ - -/* - Key to the control/smtproutes parser - [host]:[relay[:port]] - An ip in square brackets is acceptable in host and relay, even ipv6 - - - 0 1 2 3 4 5 6 7 8 9 -st\ev EOF # \n : [ ] 0-9 a-f other special - -0 h n n n -START END COMMENT START RELAY QHOST X HOST HOST HOST X - -1 -COMMENT END COMMENT START COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT - -2 n n n -QHOST X X X QHOST X EHOST QHOST QHOST X X - -3 n h n n n -HOST X HOST X RELAY X X HOST HOST HOST X - -4 h -EHOST X X X RELAY X X X X X X - -5 ra n ra r n n n -RELAY END INRELAY START PORT QRELAY X INRELAY INRELAY INRELAY X - -6 n n n -QRELAY X X X QRELAY X ERELAY QRELAY QRELAY X X - -7 ra ra r n n n -INRELAY END X START PORT X X INRELAY INRELAY INRELAY X - -8 ra ra r -ERELAY END X START PORT X X X X X X - -9 pa pa n -PORT END X START X X X PORT X X X - -END=a, X=b - -0x0100 n push character -0x0200 h compute host length -0x0400 r compute relay length -0x0800 p compute port -0x1000 a add route entry -*/ - -static inline uint8_t cclass (char c) -{ - static uint8_t const table[128] = "0999999999299999999999999999999998918889999898786666666666399898877777788888888888888888884958898888888888888888888888888899999" ; - return c & 0x80 ? 9 : table[(uint8_t)c] - '0' ; -} - -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") ; - return r ? c : 0 ; -} - -static inline void smtproutes_compile (int fdr, int fdw) -{ - static uint16_t const table[10][10] = - { - { 0x000a, 0x0001, 0x0000, 0x0205, 0x0002, 0x000b, 0x0103, 0x0103, 0x0103, 0x000b }, - { 0x000a, 0x0001, 0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 }, - { 0x000b, 0x000b, 0x000b, 0x0102, 0x000b, 0x0004, 0x0102, 0x0102, 0x0102, 0x000b }, - { 0x000b, 0x0103, 0x000b, 0x0205, 0x000b, 0x000b, 0x0103, 0x0103, 0x0103, 0x000b }, - { 0x000b, 0x000b, 0x000b, 0x0205, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, - { 0x140a, 0x0107, 0x1400, 0x0409, 0x0006, 0x000b, 0x0107, 0x0107, 0x0107, 0x000b }, - { 0x000b, 0x000b, 0x000b, 0x0106, 0x000b, 0x0008, 0x0106, 0x0106, 0x0106, 0x000b }, - { 0x140a, 0x000b, 0x1400, 0x0409, 0x000b, 0x000b, 0x0107, 0x0107, 0x0107, 0x000b }, - { 0x140a, 0x000b, 0x1400, 0x0409, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, - { 0x180a, 0x000b, 0x1800, 0x000b, 0x000b, 0x000b, 0x0109, 0x000b, 0x000b, 0x000b } - } ; - cdbmaker cm = CDBMAKER_ZERO ; - stralloc sa = STRALLOC_ZERO ; - char buf[2048] ; - 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") ; - - while (state < 0x0a) - { - char c = getnext(&b) ; - uint16_t val = table[state][cclass(c)] ; - state = val & 0x000f ; - if (val & 0x0100) - { - if (!stralloc_catb(&sa, &c, 1)) qmailr_tempsys("Unable to grow stralloc") ; - } - if (val & 0x0200) - { - relaypos = sa.len + 1 ; - if (!stralloc_catb(&sa, "\0\0\31", 3)) qmailr_tempsys("Unable to grow stralloc") ; - } - if (val & 0x0400) - { - if (!stralloc_0(&sa)) qmailr_tempsys("Unable to grow stralloc") ; - 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") ; - 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") ; - sa.len = 0 ; - } - } - if (state != 0x0a) qmailr_temp("Syntax error in control/smtproutes") ; - stralloc_free(&sa) ; - if (!cdbmake_finish(&cm)) qmailr_tempsys("Unable to cdbmake_finish") ; -} - -int smtproutes_init (smtproutes *routes) -{ - static char const *cdbfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/run/qmail-remote/smtproutes.cdb" ; - static char const *lckfile = SMTPD_STARTTLS_PROXY_QMAIL_HOME "/run/qmail-remote/smtproutes.lock" ; - 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") ; - - 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 (stat(txtfile, &str) == -1) - { - if (errno != ENOENT) qmailr_tempsys("Unable to fstat control/smtproutes") ; - unlink_void(cdbfile) ; - fd_close(fdc) ; - goto zero ; - } - if (timespec_cmp(&stc.st_mtim, &str.st_mtim) > 0) goto useit ; - fd_close(fdc) ; - } - - int fdr = openc_read(txtfile) ; - if (fdr == -1) - { - if (errno != ENOENT) qmailr_tempsys("Unable to open control/smtproutes") ; - goto zero ; - } - - { - char tmp[cdblen + 8] ; - memcpy(tmp, cdbfile, cdblen) ; - memcpy(tmp + cdblen, ":XXXXXX", 8) ; - fdc = mkstemp(tmp) ; - if (fdc == -1) qmailr_tempsys("Unable to 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") ; - 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") ; - fd_close(fdc) ; - fd_close(fdl) ; - return 1 ; - - zero: - fd_close(fdl) ; - errno = 0 ; - return 0 ; -} - -int smtproutes_match (smtproutes const *routes, char const *s, stralloc *sa, size_t *pos, uint16_t *port) -{ - cdb_data data ; - int r = cdb_find(&routes->map, &data, s, strlen(s)) ; - 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") ; - *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") ; - return 1 ; -} - -void smtproutes_free (smtproutes *routes) -{ - cdb_free(&routes->map) ; -} -- cgit v1.3.1