aboutsummaryrefslogtreecommitdiffstats
path: root/smtpd/lka.c
diff options
context:
space:
mode:
Diffstat (limited to 'smtpd/lka.c')
-rw-r--r--smtpd/lka.c914
1 files changed, 914 insertions, 0 deletions
diff --git a/smtpd/lka.c b/smtpd/lka.c
new file mode 100644
index 00000000..6ac21245
--- /dev/null
+++ b/smtpd/lka.c
@@ -0,0 +1,914 @@
+/* $OpenBSD: lka.c,v 1.243 2019/12/21 10:23:37 gilles Exp $ */
+
+/*
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
+ * Copyright (c) 2012 Eric Faurot <eric@faurot.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <netdb.h>
+#include <grp.h> /* needed for setgroups */
+#include <imsg.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <pwd.h>
+#include <resolv.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "smtpd.h"
+#include "log.h"
+#include "ssl.h"
+
+static void lka_imsg(struct mproc *, struct imsg *);
+static void lka_shutdown(void);
+static void lka_sig_handler(int, short, void *);
+static int lka_authenticate(const char *, const char *, const char *);
+static int lka_credentials(const char *, const char *, char *, size_t);
+static int lka_userinfo(const char *, const char *, struct userinfo *);
+static int lka_addrname(const char *, const struct sockaddr *,
+ struct addrname *);
+static int lka_mailaddrmap(const char *, const char *, const struct mailaddr *);
+
+static void proc_timeout(int fd, short event, void *p);
+
+struct event ev_proc_ready;
+
+static void
+lka_imsg(struct mproc *p, struct imsg *imsg)
+{
+ struct table *table;
+ int ret;
+ struct sockaddr_storage ss;
+ struct userinfo userinfo;
+ struct addrname addrname;
+ struct envelope evp;
+ struct mailaddr maddr;
+ struct msg m;
+ union lookup lk;
+ char buf[LINE_MAX];
+ const char *tablename, *username, *password, *label, *procname;
+ uint64_t reqid;
+ int v;
+ struct timeval tv;
+ const char *direction;
+ const char *rdns;
+ const char *command;
+ const char *response;
+ const char *ciphers;
+ const char *address;
+ const char *domain;
+ const char *helomethod;
+ const char *heloname;
+ const char *filter_name;
+ const char *result;
+ struct sockaddr_storage ss_src, ss_dest;
+ int filter_response;
+ int filter_phase;
+ const char *filter_param;
+ uint32_t msgid;
+ uint32_t subsystems;
+ uint64_t evpid;
+ size_t msgsz;
+ int ok;
+ int fcrdns;
+
+ if (imsg == NULL)
+ lka_shutdown();
+
+ switch (imsg->hdr.type) {
+
+ case IMSG_GETADDRINFO:
+ case IMSG_GETNAMEINFO:
+ case IMSG_RES_QUERY:
+ resolver_dispatch_request(p, imsg);
+ return;
+
+ case IMSG_CERT_INIT:
+ case IMSG_CERT_CERTIFICATE:
+ case IMSG_CERT_VERIFY:
+ cert_dispatch_request(p, imsg);
+ return;
+
+ case IMSG_MTA_DNS_HOST:
+ case IMSG_MTA_DNS_MX:
+ case IMSG_MTA_DNS_MX_PREFERENCE:
+ dns_imsg(p, imsg);
+ return;
+
+ case IMSG_SMTP_CHECK_SENDER:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &tablename);
+ m_get_string(&m, &username);
+ m_get_mailaddr(&m, &maddr);
+ m_end(&m);
+
+ ret = lka_mailaddrmap(tablename, username, &maddr);
+
+ m_create(p, IMSG_SMTP_CHECK_SENDER, 0, 0, -1);
+ m_add_id(p, reqid);
+ m_add_int(p, ret);
+ m_close(p);
+ return;
+
+ case IMSG_SMTP_EXPAND_RCPT:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_envelope(&m, &evp);
+ m_end(&m);
+ lka_session(reqid, &evp);
+ return;
+
+ case IMSG_SMTP_LOOKUP_HELO:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &tablename);
+ m_get_sockaddr(&m, (struct sockaddr *)&ss);
+ m_end(&m);
+
+ ret = lka_addrname(tablename, (struct sockaddr*)&ss,
+ &addrname);
+
+ m_create(p, IMSG_SMTP_LOOKUP_HELO, 0, 0, -1);
+ m_add_id(p, reqid);
+ m_add_int(p, ret);
+ if (ret == LKA_OK)
+ m_add_string(p, addrname.name);
+ m_close(p);
+ return;
+
+ case IMSG_SMTP_AUTHENTICATE:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &tablename);
+ m_get_string(&m, &username);
+ m_get_string(&m, &password);
+ m_end(&m);
+
+ if (!tablename[0]) {
+ m_create(p_parent, IMSG_LKA_AUTHENTICATE,
+ 0, 0, -1);
+ m_add_id(p_parent, reqid);
+ m_add_string(p_parent, username);
+ m_add_string(p_parent, password);
+ m_close(p_parent);
+ return;
+ }
+
+ ret = lka_authenticate(tablename, username, password);
+
+ m_create(p, IMSG_SMTP_AUTHENTICATE, 0, 0, -1);
+ m_add_id(p, reqid);
+ m_add_int(p, ret);
+ m_close(p);
+ return;
+
+ case IMSG_MDA_LOOKUP_USERINFO:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &tablename);
+ m_get_string(&m, &username);
+ m_end(&m);
+
+ ret = lka_userinfo(tablename, username, &userinfo);
+
+ m_create(p, IMSG_MDA_LOOKUP_USERINFO, 0, 0, -1);
+ m_add_id(p, reqid);
+ m_add_int(p, ret);
+ if (ret == LKA_OK)
+ m_add_data(p, &userinfo, sizeof(userinfo));
+ m_close(p);
+ return;
+
+ case IMSG_MTA_LOOKUP_CREDENTIALS:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &tablename);
+ m_get_string(&m, &label);
+ m_end(&m);
+
+ lka_credentials(tablename, label, buf, sizeof(buf));
+
+ m_create(p, IMSG_MTA_LOOKUP_CREDENTIALS, 0, 0, -1);
+ m_add_id(p, reqid);
+ m_add_string(p, buf);
+ m_close(p);
+ return;
+
+ case IMSG_MTA_LOOKUP_SOURCE:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &tablename);
+ m_end(&m);
+
+ table = table_find(env, tablename);
+
+ m_create(p, IMSG_MTA_LOOKUP_SOURCE, 0, 0, -1);
+ m_add_id(p, reqid);
+
+ if (table == NULL) {
+ log_warn("warn: source address table %s missing",
+ tablename);
+ m_add_int(p, LKA_TEMPFAIL);
+ }
+ else {
+ ret = table_fetch(table, K_SOURCE, &lk);
+ if (ret == -1)
+ m_add_int(p, LKA_TEMPFAIL);
+ else if (ret == 0)
+ m_add_int(p, LKA_PERMFAIL);
+ else {
+ m_add_int(p, LKA_OK);
+ m_add_sockaddr(p,
+ (struct sockaddr *)&lk.source.addr);
+ }
+ }
+ m_close(p);
+ return;
+
+ case IMSG_MTA_LOOKUP_HELO:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &tablename);
+ m_get_sockaddr(&m, (struct sockaddr *)&ss);
+ m_end(&m);
+
+ ret = lka_addrname(tablename, (struct sockaddr*)&ss,
+ &addrname);
+
+ m_create(p, IMSG_MTA_LOOKUP_HELO, 0, 0, -1);
+ m_add_id(p, reqid);
+ m_add_int(p, ret);
+ if (ret == LKA_OK)
+ m_add_string(p, addrname.name);
+ m_close(p);
+ return;
+
+ case IMSG_MTA_LOOKUP_SMARTHOST:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &domain);
+ m_get_string(&m, &tablename);
+ m_end(&m);
+
+ table = table_find(env, tablename);
+
+ m_create(p, IMSG_MTA_LOOKUP_SMARTHOST, 0, 0, -1);
+ m_add_id(p, reqid);
+
+ if (table == NULL) {
+ log_warn("warn: smarthost table %s missing", tablename);
+ m_add_int(p, LKA_TEMPFAIL);
+ }
+ else {
+ if (domain == NULL)
+ ret = table_fetch(table, K_RELAYHOST, &lk);
+ else
+ ret = table_lookup(table, K_RELAYHOST, domain, &lk);
+
+ if (ret == -1)
+ m_add_int(p, LKA_TEMPFAIL);
+ else if (ret == 0)
+ m_add_int(p, LKA_PERMFAIL);
+ else {
+ m_add_int(p, LKA_OK);
+ m_add_string(p, lk.relayhost);
+ }
+ }
+ m_close(p);
+ return;
+
+ case IMSG_CONF_START:
+ return;
+
+ case IMSG_CONF_END:
+ if (tracing & TRACE_TABLES)
+ table_dump_all(env);
+
+ /* fork & exec tables that need it */
+ table_open_all(env);
+
+#if HAVE_PLEDGE
+ /* revoke proc & exec */
+ if (pledge("stdio rpath inet dns getpw recvfd sendfd",
+ NULL) == -1)
+ err(1, "pledge");
+#endif
+
+ /* setup proc registering task */
+ evtimer_set(&ev_proc_ready, proc_timeout, &ev_proc_ready);
+ tv.tv_sec = 0;
+ tv.tv_usec = 10;
+ evtimer_add(&ev_proc_ready, &tv);
+ return;
+
+ case IMSG_LKA_OPEN_FORWARD:
+ lka_session_forward_reply(imsg->data, imsg->fd);
+ return;
+
+ case IMSG_LKA_AUTHENTICATE:
+ imsg->hdr.type = IMSG_SMTP_AUTHENTICATE;
+ m_forward(p_pony, imsg);
+ return;
+
+ case IMSG_CTL_VERBOSE:
+ m_msg(&m, imsg);
+ m_get_int(&m, &v);
+ m_end(&m);
+ log_trace_verbose(v);
+ return;
+
+ case IMSG_CTL_PROFILE:
+ m_msg(&m, imsg);
+ m_get_int(&m, &v);
+ m_end(&m);
+ profiling = v;
+ return;
+
+ case IMSG_CTL_UPDATE_TABLE:
+ ret = 0;
+ table = table_find(env, imsg->data);
+ if (table == NULL) {
+ log_warnx("warn: Lookup table not found: "
+ "\"%s\"", (char *)imsg->data);
+ } else
+ ret = table_update(table);
+
+ m_compose(p_control,
+ (ret == 1) ? IMSG_CTL_OK : IMSG_CTL_FAIL,
+ imsg->hdr.peerid, 0, -1, NULL, 0);
+ return;
+
+ case IMSG_LKA_PROCESSOR_FORK:
+ m_msg(&m, imsg);
+ m_get_string(&m, &procname);
+ m_get_u32(&m, &subsystems);
+ m_end(&m);
+
+ m_create(p, IMSG_LKA_PROCESSOR_ERRFD, 0, 0, -1);
+ m_add_string(p, procname);
+ m_close(p);
+
+ lka_proc_forked(procname, subsystems, imsg->fd);
+ return;
+
+ case IMSG_LKA_PROCESSOR_ERRFD:
+ m_msg(&m, imsg);
+ m_get_string(&m, &procname);
+ m_end(&m);
+
+ lka_proc_errfd(procname, imsg->fd);
+ shutdown(imsg->fd, SHUT_WR);
+ return;
+
+ case IMSG_REPORT_SMTP_LINK_CONNECT:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &rdns);
+ m_get_int(&m, &fcrdns);
+ m_get_sockaddr(&m, (struct sockaddr *)&ss_src);
+ m_get_sockaddr(&m, (struct sockaddr *)&ss_dest);
+ m_end(&m);
+
+ lka_report_smtp_link_connect(direction, &tv, reqid, rdns, fcrdns, &ss_src, &ss_dest);
+ return;
+
+ case IMSG_REPORT_SMTP_LINK_GREETING:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &domain);
+ m_end(&m);
+
+ lka_report_smtp_link_greeting(direction, reqid, &tv, domain);
+ return;
+
+ case IMSG_REPORT_SMTP_LINK_DISCONNECT:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+
+ lka_report_smtp_link_disconnect(direction, &tv, reqid);
+ return;
+
+ case IMSG_REPORT_SMTP_LINK_IDENTIFY:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &helomethod);
+ m_get_string(&m, &heloname);
+ m_end(&m);
+
+ lka_report_smtp_link_identify(direction, &tv, reqid, helomethod, heloname);
+ return;
+
+ case IMSG_REPORT_SMTP_LINK_TLS:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &ciphers);
+ m_end(&m);
+
+ lka_report_smtp_link_tls(direction, &tv, reqid, ciphers);
+ return;
+
+ case IMSG_REPORT_SMTP_LINK_AUTH:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &username);
+ m_get_string(&m, &result);
+ m_end(&m);
+
+ lka_report_smtp_link_auth(direction, &tv, reqid, username, result);
+ return;
+
+ case IMSG_REPORT_SMTP_TX_RESET:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &msgid);
+ m_end(&m);
+
+ lka_report_smtp_tx_reset(direction, &tv, reqid, msgid);
+ return;
+
+ case IMSG_REPORT_SMTP_TX_BEGIN:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &msgid);
+ m_end(&m);
+
+ lka_report_smtp_tx_begin(direction, &tv, reqid, msgid);
+ return;
+
+ case IMSG_REPORT_SMTP_TX_MAIL:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &msgid);
+ m_get_string(&m, &address);
+ m_get_int(&m, &ok);
+ m_end(&m);
+
+ lka_report_smtp_tx_mail(direction, &tv, reqid, msgid, address, ok);
+ return;
+
+ case IMSG_REPORT_SMTP_TX_RCPT:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &msgid);
+ m_get_string(&m, &address);
+ m_get_int(&m, &ok);
+ m_end(&m);
+
+ lka_report_smtp_tx_rcpt(direction, &tv, reqid, msgid, address, ok);
+ return;
+
+ case IMSG_REPORT_SMTP_TX_ENVELOPE:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &msgid);
+ m_get_id(&m, &evpid);
+ m_end(&m);
+
+ lka_report_smtp_tx_envelope(direction, &tv, reqid, msgid, evpid);
+ return;
+
+ case IMSG_REPORT_SMTP_TX_DATA:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &msgid);
+ m_get_int(&m, &ok);
+ m_end(&m);
+
+ lka_report_smtp_tx_data(direction, &tv, reqid, msgid, ok);
+ return;
+
+ case IMSG_REPORT_SMTP_TX_COMMIT:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &msgid);
+ m_get_size(&m, &msgsz);
+ m_end(&m);
+
+ lka_report_smtp_tx_commit(direction, &tv, reqid, msgid, msgsz);
+ return;
+
+ case IMSG_REPORT_SMTP_TX_ROLLBACK:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_u32(&m, &msgid);
+ m_end(&m);
+
+ lka_report_smtp_tx_rollback(direction, &tv, reqid, msgid);
+ return;
+
+ case IMSG_REPORT_SMTP_PROTOCOL_CLIENT:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &command);
+ m_end(&m);
+
+ lka_report_smtp_protocol_client(direction, &tv, reqid, command);
+ return;
+
+ case IMSG_REPORT_SMTP_PROTOCOL_SERVER:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &response);
+ m_end(&m);
+
+ lka_report_smtp_protocol_server(direction, &tv, reqid, response);
+ return;
+
+ case IMSG_REPORT_SMTP_FILTER_RESPONSE:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_get_int(&m, &filter_phase);
+ m_get_int(&m, &filter_response);
+ m_get_string(&m, &filter_param);
+ m_end(&m);
+
+ lka_report_smtp_filter_response(direction, &tv, reqid,
+ filter_phase, filter_response, filter_param);
+ return;
+
+ case IMSG_REPORT_SMTP_TIMEOUT:
+ m_msg(&m, imsg);
+ m_get_string(&m, &direction);
+ m_get_timeval(&m, &tv);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+
+ lka_report_smtp_timeout(direction, &tv, reqid);
+ return;
+
+ case IMSG_FILTER_SMTP_PROTOCOL:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_int(&m, &filter_phase);
+ m_get_string(&m, &filter_param);
+ m_end(&m);
+
+ lka_filter_protocol(reqid, filter_phase, filter_param);
+ return;
+
+ case IMSG_FILTER_SMTP_BEGIN:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_get_string(&m, &filter_name);
+ m_end(&m);
+
+ lka_filter_begin(reqid, filter_name);
+ return;
+
+ case IMSG_FILTER_SMTP_END:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+
+ lka_filter_end(reqid);
+ return;
+
+ case IMSG_FILTER_SMTP_DATA_BEGIN:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+
+ lka_filter_data_begin(reqid);
+ return;
+
+ case IMSG_FILTER_SMTP_DATA_END:
+ m_msg(&m, imsg);
+ m_get_id(&m, &reqid);
+ m_end(&m);
+
+ lka_filter_data_end(reqid);
+ return;
+
+ }
+
+ errx(1, "lka_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
+}
+
+static void
+lka_sig_handler(int sig, short event, void *p)
+{
+ int status;
+ pid_t pid;
+
+ switch (sig) {
+ case SIGCHLD:
+ do {
+ pid = waitpid(-1, &status, WNOHANG);
+ } while (pid > 0 || (pid == -1 && errno == EINTR));
+ break;
+ default:
+ fatalx("lka_sig_handler: unexpected signal");
+ }
+}
+
+void
+lka_shutdown(void)
+{
+ log_debug("debug: lookup agent exiting");
+ _exit(0);
+}
+
+int
+lka(void)
+{
+ struct passwd *pw;
+ struct event ev_sigchld;
+
+ purge_config(PURGE_LISTENERS);
+
+ if ((pw = getpwnam(SMTPD_USER)) == NULL)
+ fatalx("unknown user " SMTPD_USER);
+
+ config_process(PROC_LKA);
+
+ if (initgroups(pw->pw_name, pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ fatal("lka: cannot drop privileges");
+
+ imsg_callback = lka_imsg;
+ event_init();
+
+ signal_set(&ev_sigchld, SIGCHLD, lka_sig_handler, NULL);
+ signal_add(&ev_sigchld, NULL);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+
+ config_peer(PROC_PARENT);
+ config_peer(PROC_QUEUE);
+ config_peer(PROC_CONTROL);
+ config_peer(PROC_PONY);
+
+ /* Ignore them until we get our config */
+ mproc_disable(p_pony);
+
+ lka_report_init();
+ lka_filter_init();
+
+#if HAVE_PLEDGE
+ /* proc & exec will be revoked before serving requests */
+ if (pledge("stdio rpath inet dns getpw recvfd sendfd proc exec", NULL) == -1)
+ err(1, "pledge");
+#endif
+
+ event_dispatch();
+ fatalx("exited event loop");
+
+ return (0);
+}
+
+static void
+proc_timeout(int fd, short event, void *p)
+{
+ struct event *ev = p;
+ struct timeval tv;
+
+ if (!lka_proc_ready())
+ goto reset;
+
+ lka_filter_ready();
+ mproc_enable(p_pony);
+ return;
+
+reset:
+ tv.tv_sec = 0;
+ tv.tv_usec = 10;
+ evtimer_add(ev, &tv);
+}
+
+
+static int
+lka_authenticate(const char *tablename, const char *user, const char *password)
+{
+ struct table *table;
+ union lookup lk;
+
+ log_debug("debug: lka: authenticating for %s:%s", tablename, user);
+ table = table_find(env, tablename);
+ if (table == NULL) {
+ log_warnx("warn: could not find table %s needed for authentication",
+ tablename);
+ return (LKA_TEMPFAIL);
+ }
+
+ switch (table_lookup(table, K_CREDENTIALS, user, &lk)) {
+ case -1:
+ log_warnx("warn: user credentials lookup fail for %s:%s",
+ tablename, user);
+ return (LKA_TEMPFAIL);
+ case 0:
+ return (LKA_PERMFAIL);
+ default:
+ if (crypt_checkpass(password, lk.creds.password) == 0)
+ return (LKA_OK);
+ return (LKA_PERMFAIL);
+ }
+}
+
+static int
+lka_credentials(const char *tablename, const char *label, char *dst, size_t sz)
+{
+ struct table *table;
+ union lookup lk;
+ char *buf;
+ int buflen, r;
+
+ table = table_find(env, tablename);
+ if (table == NULL) {
+ log_warnx("warn: credentials table %s missing", tablename);
+ return (LKA_TEMPFAIL);
+ }
+
+ dst[0] = '\0';
+
+ switch (table_lookup(table, K_CREDENTIALS, label, &lk)) {
+ case -1:
+ log_warnx("warn: credentials lookup fail for %s:%s",
+ tablename, label);
+ return (LKA_TEMPFAIL);
+ case 0:
+ log_warnx("warn: credentials not found for %s:%s",
+ tablename, label);
+ return (LKA_PERMFAIL);
+ default:
+ if ((buflen = asprintf(&buf, "%c%s%c%s", '\0',
+ lk.creds.username, '\0', lk.creds.password)) == -1) {
+ log_warn("warn");
+ return (LKA_TEMPFAIL);
+ }
+
+ r = base64_encode((unsigned char *)buf, buflen, dst, sz);
+ free(buf);
+
+ if (r == -1) {
+ log_warnx("warn: credentials parse error for %s:%s",
+ tablename, label);
+ return (LKA_TEMPFAIL);
+ }
+ return (LKA_OK);
+ }
+}
+
+static int
+lka_userinfo(const char *tablename, const char *username, struct userinfo *res)
+{
+ struct table *table;
+ union lookup lk;
+
+ log_debug("debug: lka: userinfo %s:%s", tablename, username);
+ table = table_find(env, tablename);
+ if (table == NULL) {
+ log_warnx("warn: cannot find user table %s", tablename);
+ return (LKA_TEMPFAIL);
+ }
+
+ switch (table_lookup(table, K_USERINFO, username, &lk)) {
+ case -1:
+ log_warnx("warn: failure during userinfo lookup %s:%s",
+ tablename, username);
+ return (LKA_TEMPFAIL);
+ case 0:
+ return (LKA_PERMFAIL);
+ default:
+ *res = lk.userinfo;
+ return (LKA_OK);
+ }
+}
+
+static int
+lka_addrname(const char *tablename, const struct sockaddr *sa,
+ struct addrname *res)
+{
+ struct table *table;
+ union lookup lk;
+ const char *source;
+
+ source = sa_to_text(sa);
+
+ log_debug("debug: lka: helo %s:%s", tablename, source);
+ table = table_find(env, tablename);
+ if (table == NULL) {
+ log_warnx("warn: cannot find helo table %s", tablename);
+ return (LKA_TEMPFAIL);
+ }
+
+ switch (table_lookup(table, K_ADDRNAME, source, &lk)) {
+ case -1:
+ log_warnx("warn: failure during helo lookup %s:%s",
+ tablename, source);
+ return (LKA_TEMPFAIL);
+ case 0:
+ return (LKA_PERMFAIL);
+ default:
+ *res = lk.addrname;
+ return (LKA_OK);
+ }
+}
+
+static int
+lka_mailaddrmap(const char *tablename, const char *username, const struct mailaddr *maddr)
+{
+ struct table *table;
+ struct maddrnode *mn;
+ union lookup lk;
+ int found;
+
+ log_debug("debug: lka: mailaddrmap %s:%s", tablename, username);
+ table = table_find(env, tablename);
+ if (table == NULL) {
+ log_warnx("warn: cannot find mailaddrmap table %s", tablename);
+ return (LKA_TEMPFAIL);
+ }
+
+ switch (table_lookup(table, K_MAILADDRMAP, username, &lk)) {
+ case -1:
+ log_warnx("warn: failure during mailaddrmap lookup %s:%s",
+ tablename, username);
+ return (LKA_TEMPFAIL);
+ case 0:
+ return (LKA_PERMFAIL);
+ default:
+ found = 0;
+ TAILQ_FOREACH(mn, &lk.maddrmap->queue, entries) {
+ if (!mailaddr_match(maddr, &mn->mailaddr))
+ continue;
+ found = 1;
+ break;
+ }
+ maddrmap_free(lk.maddrmap);
+ if (found)
+ return (LKA_OK);
+ return (LKA_PERMFAIL);
+ }
+ return (LKA_OK);
+}