diff options
Diffstat (limited to 'usr.sbin/smtpd')
-rw-r--r-- | usr.sbin/smtpd/mfa.c | 397 | ||||
-rw-r--r-- | usr.sbin/smtpd/mfa_session.c | 821 |
2 files changed, 0 insertions, 1218 deletions
diff --git a/usr.sbin/smtpd/mfa.c b/usr.sbin/smtpd/mfa.c deleted file mode 100644 index 6372a4dd77c..00000000000 --- a/usr.sbin/smtpd/mfa.c +++ /dev/null @@ -1,397 +0,0 @@ -/* $OpenBSD: mfa.c,v 1.82 2014/04/04 16:10:42 eric Exp $ */ - -/* - * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> - * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> - * - * 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 <sys/types.h> -#include <sys/wait.h> -#include <sys/queue.h> -#include <sys/tree.h> -#include <sys/socket.h> - -#include <err.h> -#include <errno.h> -#include <event.h> -#include <imsg.h> -#include <inttypes.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "smtpd.h" -#include "log.h" - -struct mfa_tx { - uint64_t reqid; - struct io io; - struct iobuf iobuf; - FILE *ofile; - size_t datain; - size_t datalen; - int eom; - int error; -}; - -static void mfa_imsg(struct mproc *, struct imsg *); -static void mfa_shutdown(void); -static void mfa_sig_handler(int, short, void *); -static void mfa_tx_io(struct io *, int); -static int mfa_tx(uint64_t, int); -static void mfa_tx_done(struct mfa_tx *); - -struct tree tx_tree; - -static void -mfa_imsg(struct mproc *p, struct imsg *imsg) -{ - struct sockaddr_storage local, remote; - struct mailaddr maddr; - struct msg m; - const char *line, *hostname; - uint64_t reqid; - uint32_t datalen; /* XXX make it off_t? */ - int v, success, fdout; - - if (p->proc == PROC_PONY) { - switch (imsg->hdr.type) { - case IMSG_SMTP_REQ_CONNECT: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_get_sockaddr(&m, (struct sockaddr *)&local); - m_get_sockaddr(&m, (struct sockaddr *)&remote); - m_get_string(&m, &hostname); - m_end(&m); - mfa_filter_connect(reqid, (struct sockaddr *)&local, - (struct sockaddr *)&remote, hostname); - return; - - case IMSG_SMTP_REQ_HELO: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_get_string(&m, &line); - m_end(&m); - mfa_filter_line(reqid, HOOK_HELO, line); - return; - - case IMSG_SMTP_REQ_MAIL: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_get_mailaddr(&m, &maddr); - m_end(&m); - mfa_filter_mailaddr(reqid, HOOK_MAIL, &maddr); - return; - - case IMSG_SMTP_REQ_RCPT: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_get_mailaddr(&m, &maddr); - m_end(&m); - mfa_filter_mailaddr(reqid, HOOK_RCPT, &maddr); - return; - - case IMSG_SMTP_REQ_DATA: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_end(&m); - mfa_filter(reqid, HOOK_DATA); - return; - - case IMSG_SMTP_REQ_EOM: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_get_u32(&m, &datalen); - m_end(&m); - mfa_filter_eom(reqid, HOOK_EOM, datalen); - return; - - case IMSG_SMTP_EVENT_RSET: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_end(&m); - mfa_filter_event(reqid, HOOK_RESET); - return; - - case IMSG_SMTP_EVENT_COMMIT: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_end(&m); - mfa_filter_event(reqid, HOOK_COMMIT); - return; - - case IMSG_SMTP_EVENT_ROLLBACK: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_end(&m); - mfa_filter_event(reqid, HOOK_ROLLBACK); - return; - - case IMSG_SMTP_EVENT_DISCONNECT: - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_end(&m); - mfa_filter_event(reqid, HOOK_DISCONNECT); - return; - } - } - - if (p->proc == PROC_QUEUE) { - switch (imsg->hdr.type) { - case IMSG_SMTP_MESSAGE_OPEN: /* XXX bogus */ - m_msg(&m, imsg); - m_get_id(&m, &reqid); - m_get_int(&m, &success); - m_end(&m); - - fdout = mfa_tx(reqid, imsg->fd); - mfa_build_fd_chain(reqid, fdout); - return; - } - } - - if (p->proc == PROC_PARENT) { - switch (imsg->hdr.type) { - case IMSG_CONF_START: - return; - - case IMSG_CONF_END: - mfa_filter_init(); - return; - - case IMSG_CTL_VERBOSE: - m_msg(&m, imsg); - m_get_int(&m, &v); - m_end(&m); - log_verbose(v); - return; - - case IMSG_CTL_PROFILE: - m_msg(&m, imsg); - m_get_int(&m, &v); - m_end(&m); - profiling = v; - return; - } - } - - errx(1, "mfa_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); -} - -static void -mfa_sig_handler(int sig, short event, void *p) -{ - switch (sig) { - case SIGINT: - case SIGTERM: - mfa_shutdown(); - break; - - case SIGCHLD: - fatalx("unexpected SIGCHLD"); - break; - - default: - fatalx("mfa_sig_handler: unexpected signal"); - } -} - -static void -mfa_shutdown(void) -{ - pid_t pid; - - do { - pid = waitpid(WAIT_MYPGRP, NULL, 0); - } while (pid != -1 || (pid == -1 && errno == EINTR)); - - log_info("info: mail filter exiting"); - _exit(0); -} - -pid_t -mfa(void) -{ - pid_t pid; - struct passwd *pw; - struct event ev_sigint; - struct event ev_sigterm; - struct event ev_sigchld; - - switch (pid = fork()) { - case -1: - fatal("filter: cannot fork"); - case 0: - post_fork(PROC_MFA); - break; - default: - return (pid); - } - - mfa_filter_prepare(); - - purge_config(PURGE_EVERYTHING); - - if ((pw = getpwnam(SMTPD_USER)) == NULL) - fatalx("unknown user " SMTPD_USER); - - config_process(PROC_MFA); - - if (chroot(PATH_CHROOT) == -1) - fatal("scheduler: chroot"); - if (chdir("/") == -1) - fatal("scheduler: chdir(\"/\")"); - - if (setgroups(1, &pw->pw_gid) || - setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || - setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) - fatal("filter: cannot drop privileges"); - - imsg_callback = mfa_imsg; - event_init(); - - signal_set(&ev_sigint, SIGINT, mfa_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, mfa_sig_handler, NULL); - signal_set(&ev_sigchld, SIGCHLD, mfa_sig_handler, NULL); - signal_add(&ev_sigint, NULL); - signal_add(&ev_sigterm, NULL); - signal_add(&ev_sigchld, NULL); - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); - - config_peer(PROC_PARENT); - config_peer(PROC_CONTROL); - config_peer(PROC_PONY); - config_done(); - - mproc_disable(p_pony); - - if (event_dispatch() < 0) - fatal("event_dispatch"); - mfa_shutdown(); - - return (0); -} - -void -mfa_ready(void) -{ - log_debug("debug: mfa ready"); - mproc_enable(p_pony); -} - -static int -mfa_tx(uint64_t reqid, int fdout) -{ - struct mfa_tx *tx; - int sp[2]; - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) { - log_warn("warn: mfa: socketpair"); - return (-1); - } - - tx = xcalloc(1, sizeof(*tx), "mfa_tx"); - - if ((tx->ofile = fdopen(fdout, "w")) == NULL) { - log_warn("warn: mfa: fdopen"); - free(tx); - close(sp[0]); - close(sp[1]); - return (-1); - } - - iobuf_init(&tx->iobuf, 0, 0); - io_init(&tx->io, sp[0], tx, mfa_tx_io, &tx->iobuf); - io_set_read(&tx->io); - tx->reqid = reqid; - tree_xset(&tx_tree, reqid, tx); - - return (sp[1]); -} - -static void -mfa_tx_io(struct io *io, int evt) -{ - struct mfa_tx *tx = io->arg; - size_t len, n; - char *data; - - switch (evt) { - case IO_DATAIN: - data = iobuf_data(&tx->iobuf); - len = iobuf_len(&tx->iobuf); - log_debug("debug: mfa: tx data (%zu) for req %016"PRIx64, - len, tx->reqid); - n = fwrite(data, 1, len, tx->ofile); - if (n != len) { - tx->error = 1; - break; - } - tx->datain += n; - iobuf_drop(&tx->iobuf, n); - iobuf_normalize(&tx->iobuf); - return; - - case IO_DISCONNECTED: - log_debug("debug: mfa: tx done for req %016"PRIx64, - tx->reqid); - break; - - default: - log_debug("debug: mfa: tx error for req %016"PRIx64, - tx->reqid); - tx->error = 1; - break; - } - - io_clear(&tx->io); - iobuf_clear(&tx->iobuf); - fclose(tx->ofile); - tx->ofile = NULL; - if (tx->eom) - mfa_tx_done(tx); -} - -static void -mfa_tx_done(struct mfa_tx *tx) -{ - log_debug("debug: mfa: tx done for %016"PRIx64, tx->reqid); - - if (!tx->error && tx->datain != tx->datalen) { - log_debug("debug: mfa: tx datalen mismatch: %zu/%zu", - tx->datain, tx->datalen); - tx->error = 1; - } - - if (tx->error) { - log_debug("debug: mfa: tx error"); - - m_create(p_pony, IMSG_MFA_SMTP_RESPONSE, 0, 0, -1); - m_add_id(p_pony, tx->reqid); - m_add_int(p_pony, MFA_FAIL); - m_add_u32(p_pony, 0); - m_add_string(p_pony, "Internal server error"); - m_close(p_pony); - } -#if 0 - else - mfa_filter(tx->reqid, HOOK_EOM); -#endif - free(tx); -} diff --git a/usr.sbin/smtpd/mfa_session.c b/usr.sbin/smtpd/mfa_session.c deleted file mode 100644 index 7fe9a45d886..00000000000 --- a/usr.sbin/smtpd/mfa_session.c +++ /dev/null @@ -1,821 +0,0 @@ -/* $OpenBSD: mfa_session.c,v 1.22 2014/04/19 13:18:14 gilles Exp $ */ - -/* - * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> - * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> - * - * 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 <sys/types.h> -#include <sys/queue.h> -#include <sys/tree.h> -#include <sys/socket.h> -#include <sys/wait.h> - -#include <netinet/in.h> - -#include <ctype.h> -#include <errno.h> -#include <event.h> -#include <imsg.h> -#include <inttypes.h> -#include <resolv.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "smtpd.h" -#include "log.h" - -enum { - QT_QUERY, - QT_EVENT, -}; - -enum { - QUERY_READY, - QUERY_WAITING, - QUERY_RUNNING, - QUERY_DONE -}; - - -struct mfa_filterproc { - TAILQ_ENTRY(mfa_filterproc) entry; - struct mproc mproc; - int hooks; - int flags; - int ready; -}; - -struct mfa_filter { - TAILQ_ENTRY(mfa_filter) entry; - struct mfa_filterproc *proc; -}; -TAILQ_HEAD(mfa_filters, mfa_filter); - -struct mfa_session { - uint64_t id; - int terminate; - TAILQ_HEAD(mfa_queries, mfa_query) queries; - struct mfa_filters *filters; - struct mfa_filter *fcurr; -}; - -struct mfa_query { - uint64_t qid; - int type; - int hook; - struct mfa_session *session; - TAILQ_ENTRY(mfa_query) entry; - - int state; - int hasrun; - struct mfa_filter *current; - struct tree notify; /* list of filters to notify */ - - /* current data */ - union { - struct { - struct sockaddr_storage local; - struct sockaddr_storage remote; - char hostname[SMTPD_MAXHOSTNAMELEN]; - } connect; - char line[SMTPD_MAXLINESIZE]; - struct mailaddr maddr; - size_t datalen; - } u; - - /* current response */ - struct { - int status; - int code; - char *response; - } smtp; -}; - -static void mfa_filter_imsg(struct mproc *, struct imsg *); -static struct mfa_query *mfa_query(struct mfa_session *, int, int); -static void mfa_drain_query(struct mfa_query *); -static void mfa_run_query(struct mfa_filter *, struct mfa_query *); -static void mfa_set_fdout(struct mfa_session *, int); - -static TAILQ_HEAD(, mfa_filterproc) procs; -struct dict chains; - -static const char * mfa_query_to_text(struct mfa_query *); -static const char * mfa_filter_to_text(struct mfa_filter *); -static const char * mfa_filterproc_to_text(struct mfa_filterproc *); -static const char * type_to_str(int); -static const char * hook_to_str(int); -static const char * status_to_str(int); -static const char * filterimsg_to_str(int); - -struct tree sessions; -struct tree queries; - - -static void -mfa_extend_chain(struct mfa_filters *chain, const char *name) -{ - struct mfa_filter *n; - struct mfa_filters *fchain; - struct filter *fconf; - int i; - - fconf = dict_xget(&env->sc_filters, name); - if (fconf->chain) { - log_debug("mfa: extending with \"%s\"", name); - for (i = 0; i < MAX_FILTER_PER_CHAIN; i++) { - if (!fconf->filters[i][0]) - break; - mfa_extend_chain(chain, fconf->filters[i]); - } - } - else { - log_debug("mfa: adding filter \"%s\"", name); - n = xcalloc(1, sizeof(*n), "mfa_extend_chain"); - fchain = dict_get(&chains, name); - n->proc = TAILQ_FIRST(fchain)->proc; - TAILQ_INSERT_TAIL(chain, n, entry); - } -} - -void -mfa_filter_prepare(void) -{ - static int prepare = 0; - struct filter *filter; - void *iter; - struct mfa_filterproc *proc; - struct mfa_filters *fchain; - struct mfa_filter *f; - struct mproc *p; - int done, i; - - if (prepare) - return; - prepare = 1; - - TAILQ_INIT(&procs); - dict_init(&chains); - - log_debug("mfa: building simple chains..."); - - /* create all filter proc and associated chains */ - iter = NULL; - while (dict_iter(&env->sc_filters, &iter, NULL, (void **)&filter)) { - if (filter->chain) - continue; - - log_debug("mfa: building simple chain \"%s\"", filter->name); - - proc = xcalloc(1, sizeof(*proc), "mfa_filter_init"); - p = &proc->mproc; - p->handler = mfa_filter_imsg; - p->proc = PROC_FILTER; - p->name = xstrdup(filter->name, "mfa_filter_init"); - p->data = proc; - if (mproc_fork(p, filter->path, filter->name) < 0) - fatalx("mfa_filter_init"); - - log_debug("mfa: registering proc \"%s\"", filter->name); - - f = xcalloc(1, sizeof(*f), "mfa_filter_init"); - f->proc = proc; - - TAILQ_INSERT_TAIL(&procs, proc, entry); - fchain = xcalloc(1, sizeof(*fchain), "mfa_filter_prepare"); - TAILQ_INIT(fchain); - TAILQ_INSERT_TAIL(fchain, f, entry); - dict_xset(&chains, filter->name, fchain); - filter->done = 1; - } - - log_debug("mfa: building complex chains..."); - - /* resolve all chains */ - done = 0; - while (!done) { - done = 1; - iter = NULL; - while (dict_iter(&env->sc_filters, &iter, NULL, (void **)&filter)) { - if (filter->done) - continue; - done = 0; - filter->done = 1; - for (i = 0; i < MAX_FILTER_PER_CHAIN; i++) { - if (!filter->filters[i][0]) - break; - if (!dict_get(&chains, filter->filters[i])) { - filter->done = 0; - break; - } - } - if (filter->done == 0) - continue; - fchain = xcalloc(1, sizeof(*fchain), "mfa_filter_prepare"); - TAILQ_INIT(fchain); - log_debug("mfa: building chain \"%s\"...", filter->name); - for (i = 0; i < MAX_FILTER_PER_CHAIN; i++) { - if (!filter->filters[i][0]) - break; - mfa_extend_chain(fchain, filter->filters[i]); - } - log_debug("mfa: done building chain \"%s\"", filter->name); - dict_xset(&chains, filter->name, fchain); - } - } - log_debug("mfa: done building complex chains"); - - if (dict_get(&chains, "default") == NULL) { - log_debug("mfa: done building default chain"); - fchain = xcalloc(1, sizeof(*fchain), "mfa_filter_prepare"); - TAILQ_INIT(fchain); - dict_xset(&chains, "default", fchain); - } -} - -void -mfa_filter_init(void) -{ - static int init = 0; - struct mfa_filterproc *p; - - if (init) - return; - init = 1; - - tree_init(&sessions); - tree_init(&queries); - - TAILQ_FOREACH(p, &procs, entry) { - m_create(&p->mproc, IMSG_FILTER_REGISTER, 0, 0, -1); - m_add_u32(&p->mproc, FILTER_API_VERSION); - m_add_string(&p->mproc, p->mproc.name); - m_close(&p->mproc); - mproc_enable(&p->mproc); - } - - if (TAILQ_FIRST(&procs) == NULL) - mfa_ready(); -} - -void -mfa_filter_connect(uint64_t id, const struct sockaddr *local, - const struct sockaddr *remote, const char *host) -{ - struct mfa_session *s; - struct mfa_query *q; - - s = xcalloc(1, sizeof(*s), "mfa_query_connect"); - s->id = id; - s->filters = dict_xget(&chains, "default"); - TAILQ_INIT(&s->queries); - tree_xset(&sessions, s->id, s); - - q = mfa_query(s, QT_QUERY, HOOK_CONNECT); - - memmove(&q->u.connect.local, local, local->sa_len); - memmove(&q->u.connect.remote, remote, remote->sa_len); - if (strlcpy(q->u.connect.hostname, host, - sizeof(q->u.connect.hostname)) >= - sizeof(q->u.connect.hostname)) - fatalx("hostname too large"); - - q->smtp.status = MFA_OK; - q->smtp.code = 0; - q->smtp.response = NULL; - - mfa_drain_query(q); -} - -void -mfa_filter_event(uint64_t id, int hook) -{ - struct mfa_session *s; - struct mfa_query *q; - - /* On disconnect, the session is virtualy dead */ - if (hook == HOOK_DISCONNECT) - s = tree_xpop(&sessions, id); - else - s = tree_xget(&sessions, id); - q = mfa_query(s, QT_EVENT, hook); - - mfa_drain_query(q); -} - -void -mfa_filter_mailaddr(uint64_t id, int hook, const struct mailaddr *maddr) -{ - struct mfa_session *s; - struct mfa_query *q; - - s = tree_xget(&sessions, id); - q = mfa_query(s, QT_QUERY, hook); - - if (strlcpy(q->u.maddr.user, maddr->user, sizeof(q->u.maddr.user)) - >= sizeof(q.u.maddr.user)) - fatalx("username too large"); - if (strlcpy(q->u.maddr.domain, maddr->domain, sizeof(q->u.maddr.domain)) - >= sizeof(q.u.maddr.domain)) - fatalx("hostname too large"); - - mfa_drain_query(q); -} - -void -mfa_filter_line(uint64_t id, int hook, const char *line) -{ - struct mfa_session *s; - struct mfa_query *q; - - s = tree_xget(&sessions, id); - q = mfa_query(s, QT_QUERY, hook); - - if (strlcpy(q->u.line, line, sizeof(q->u.line)) - >= sizeof(q->u.line)) - fatalx("line too large"); - - mfa_drain_query(q); -} - -void -mfa_filter_eom(uint64_t id, int hook, size_t datalen) -{ - struct mfa_session *s; - struct mfa_query *q; - - s = tree_xget(&sessions, id); - q = mfa_query(s, QT_QUERY, hook); - q->u.datalen = datalen; - - mfa_drain_query(q); -} - -void -mfa_filter(uint64_t id, int hook) -{ - struct mfa_session *s; - struct mfa_query *q; - - s = tree_xget(&sessions, id); - q = mfa_query(s, QT_QUERY, hook); - - mfa_drain_query(q); -} - -static void -mfa_set_fdout(struct mfa_session *s, int fdout) -{ - struct mproc *p; - - while(s->fcurr) { - if (s->fcurr->proc->hooks & HOOK_DATALINE) { - log_trace(TRACE_MFA, "mfa: sending fd %d to %s", fdout, mfa_filter_to_text(s->fcurr)); - p = &s->fcurr->proc->mproc; - m_create(p, IMSG_FILTER_PIPE_SETUP, 0, 0, fdout); - m_add_id(p, s->id); - m_close(p); - return; - } - s->fcurr = TAILQ_PREV(s->fcurr, mfa_filters, entry); - } - - log_trace(TRACE_MFA, "mfa: chain input is %d", fdout); - - m_create(p_pony, IMSG_SMTP_MESSAGE_OPEN, 0, 0, fdout); /* XXX bogus */ - m_add_id(p_pony, s->id); - m_add_int(p_pony, 1); - m_close(p_pony); - return; -} - -void -mfa_build_fd_chain(uint64_t id, int fdout) -{ - struct mfa_session *s; - - s = tree_xget(&sessions, id); - s->fcurr = TAILQ_LAST(s->filters, mfa_filters); - mfa_set_fdout(s, fdout); -} - -static struct mfa_query * -mfa_query(struct mfa_session *s, int type, int hook) -{ - struct mfa_query *q; - - q = xcalloc(1, sizeof *q, "mfa_query"); - q->qid = generate_uid(); - q->session = s; - q->type = type; - q->hook = hook; - tree_init(&q->notify); - TAILQ_INSERT_TAIL(&s->queries, q, entry); - - q->state = QUERY_READY; - q->current = TAILQ_FIRST(s->filters); - q->hasrun = 0; - - log_trace(TRACE_MFA, "filter: new query %s %s", type_to_str(type), - hook_to_str(hook)); - - return (q); -} - -static void -mfa_drain_query(struct mfa_query *q) -{ - struct mfa_filterproc *proc; - struct mfa_query *prev; - - log_trace(TRACE_MFA, "filter: draining query %s", mfa_query_to_text(q)); - - /* - * The query must be passed through all filters that registered - * a hook, until one rejects it. - */ - while (q->state != QUERY_DONE) { - - /* Walk over all filters */ - while (q->current) { - - /* Trigger the current filter if not done yet. */ - if (!q->hasrun) { - mfa_run_query(q->current, q); - q->hasrun = 1; - } - if (q->state == QUERY_RUNNING) { - log_trace(TRACE_MFA, - "filter: waiting for running query %s", - mfa_query_to_text(q)); - return; - } - - /* - * Do not move forward if the query ahead of us is - * waiting on this filter. - */ - prev = TAILQ_PREV(q, mfa_queries, entry); - if (prev && prev->current == q->current) { - q->state = QUERY_WAITING; - log_trace(TRACE_MFA, - "filter: query blocked by previoius query %s", - mfa_query_to_text(prev)); - return; - } - - q->current = TAILQ_NEXT(q->current, entry); - q->hasrun = 0; - } - q->state = QUERY_DONE; - } - - if (q->type == QT_QUERY) { - - log_trace(TRACE_MFA, - "filter: query %016"PRIx64" done: " - "status=%s code=%d response=\"%s\"", - q->qid, - status_to_str(q->smtp.status), - q->smtp.code, - q->smtp.response); - - /* Done, notify all listeners and return smtp response */ - while (tree_poproot(&q->notify, NULL, (void**)&proc)) { - m_create(&proc->mproc, IMSG_FILTER_NOTIFY, 0, 0, -1); - m_add_id(&proc->mproc, q->qid); - m_add_int(&proc->mproc, q->smtp.status); - m_close(&proc->mproc); - } - - m_create(p_pony, IMSG_MFA_SMTP_RESPONSE, 0, 0, -1); - m_add_id(p_pony, q->session->id); - m_add_int(p_pony, q->smtp.status); - m_add_u32(p_pony, q->smtp.code); - if (q->smtp.response) - m_add_string(p_pony, q->smtp.response); - m_close(p_pony); - - free(q->smtp.response); - } - - TAILQ_REMOVE(&q->session->queries, q, entry); - /* If the query was a disconnect event, the session can be freed */ - if (q->hook == HOOK_DISCONNECT) { - /* XXX assert prev == NULL */ - log_trace(TRACE_MFA, "filter: freeing session %016" PRIx64, q->session->id); - free(q->session); - } - - log_trace(TRACE_MFA, "filter: freeing query %016" PRIx64, q->qid); - free(q); -} - -static void -mfa_run_query(struct mfa_filter *f, struct mfa_query *q) -{ - if ((f->proc->hooks & q->hook) == 0) { - log_trace(TRACE_MFA, "filter: skipping filter %s for query %s", - mfa_filter_to_text(f), mfa_query_to_text(q)); - return; - } - - log_trace(TRACE_MFA, "filter: running filter %s for query %s", - mfa_filter_to_text(f), mfa_query_to_text(q)); - - if (q->type == QT_QUERY) { - m_create(&f->proc->mproc, IMSG_FILTER_QUERY, 0, 0, -1); - m_add_id(&f->proc->mproc, q->session->id); - m_add_id(&f->proc->mproc, q->qid); - m_add_int(&f->proc->mproc, q->hook); - - switch (q->hook) { - case HOOK_CONNECT: - m_add_sockaddr(&f->proc->mproc, - (struct sockaddr *)&q->u.connect.local); - m_add_sockaddr(&f->proc->mproc, - (struct sockaddr *)&q->u.connect.remote); - m_add_string(&f->proc->mproc, q->u.connect.hostname); - break; - case HOOK_HELO: - m_add_string(&f->proc->mproc, q->u.line); - break; - case HOOK_MAIL: - case HOOK_RCPT: - m_add_mailaddr(&f->proc->mproc, &q->u.maddr); - break; - case HOOK_EOM: - m_add_u32(&f->proc->mproc, q->u.datalen); - break; - default: - break; - } - m_close(&f->proc->mproc); - - tree_xset(&queries, q->qid, q); - q->state = QUERY_RUNNING; - } - else { - m_create(&f->proc->mproc, IMSG_FILTER_EVENT, 0, 0, -1); - m_add_id(&f->proc->mproc, q->session->id); - m_add_int(&f->proc->mproc, q->hook); - m_close(&f->proc->mproc); - } -} - -static void -mfa_filter_imsg(struct mproc *p, struct imsg *imsg) -{ - struct mfa_filterproc *proc = p->data; - struct mfa_session *s; - struct mfa_query *q, *next; - struct msg m; - const char *line; - uint64_t qid; - uint32_t datalen; - int qhook, status, code, notify; - - if (imsg == NULL) { - log_warnx("warn: filter \"%s\" closed unexpectedly", p->name); - fatalx("exiting"); - } - - log_trace(TRACE_MFA, "filter: imsg %s from procfilter %s", - filterimsg_to_str(imsg->hdr.type), - mfa_filterproc_to_text(proc)); - - switch (imsg->hdr.type) { - - case IMSG_FILTER_REGISTER: - if (proc->ready) { - log_warnx("warn: filter \"%s\" already registered", - proc->mproc.name); - exit(1); - } - - m_msg(&m, imsg); - m_get_int(&m, &proc->hooks); - m_get_int(&m, &proc->flags); - m_end(&m); - proc->ready = 1; - - log_debug("debug: filter \"%s\": hooks 0x%08x flags 0x%04x", - proc->mproc.name, proc->hooks, proc->flags); - - TAILQ_FOREACH(proc, &procs, entry) - if (!proc->ready) - return; - mfa_ready(); - break; - - case IMSG_FILTER_RESPONSE: - m_msg(&m, imsg); - m_get_id(&m, &qid); - m_get_int(&m, &qhook); - if (qhook == HOOK_EOM) - m_get_u32(&m, &datalen); - m_get_int(&m, &status); - m_get_int(&m, &code); - m_get_int(&m, ¬ify); - if (m_is_eom(&m)) - line = NULL; - else - m_get_string(&m, &line); - m_end(&m); - - q = tree_xpop(&queries, qid); - if (q->hook != qhook) { - log_warnx("warn: mfa: hook mismatch %d != %d", q->hook, qhook); - fatalx("exiting"); - } - q->smtp.status = status; - if (code) - q->smtp.code = code; - if (line) { - free(q->smtp.response); - q->smtp.response = xstrdup(line, "mfa_filter_imsg"); - } - q->state = (status == FILTER_OK) ? QUERY_READY : QUERY_DONE; - if (notify) - tree_xset(&q->notify, (uintptr_t)(proc), proc); - if (qhook == HOOK_EOM) - q->u.datalen = datalen; - - next = TAILQ_NEXT(q, entry); - mfa_drain_query(q); - - /* - * If there is another query after this one which is waiting, - * make it move forward. - */ - if (next && next->state == QUERY_WAITING) - mfa_drain_query(next); - break; - - case IMSG_FILTER_PIPE_SETUP: - m_msg(&m, imsg); - m_get_id(&m, &qid); - m_end(&m); - - s = tree_xget(&sessions, qid); - s->fcurr = TAILQ_PREV(s->fcurr, mfa_filters, entry); - mfa_set_fdout(s, imsg->fd); - break; - - default: - log_warnx("warn: bad imsg from filter %s", p->name); - exit(1); - } -} - - -static const char * -mfa_query_to_text(struct mfa_query *q) -{ - static char buf[1024]; - char tmp[1024]; - int ret; - - tmp[0] = '\0'; - - switch(q->hook) { - - case HOOK_CONNECT: - (void)strlcat(tmp, "=", sizeof tmp); - (void)strlcat(tmp, ss_to_text(&q->u.connect.local), sizeof tmp); - (void)strlcat(tmp, " <-> ", sizeof tmp); - (void)strlcat(tmp, ss_to_text(&q->u.connect.remote), sizeof tmp); - (void)strlcat(tmp, "(", sizeof tmp); - (void)strlcat(tmp, q->u.connect.hostname, sizeof tmp); - if (strlcat(tmp, ")", sizeof tmp) >= sizeof tmp) - fatalx("line too large"); - break; - - case HOOK_MAIL: - case HOOK_RCPT: - ret = snprintf(tmp, sizeof tmp, "=%s@%s", - q->u.maddr.user, q->u.maddr.domain); - if (ret == -1 || ret >= sizeof tmp) - fatalx("line too large"); - break; - - case HOOK_HELO: - ret = snprintf(tmp, sizeof tmp, "=%s", q->u.line); - if (ret == -1 || ret >= sizeof tmp) - fatalx("line too large"); - break; - - default: - break; - } - - ret = snprintf(buf, sizeof buf, "%016"PRIx64"[%s,%s%s]", - q->qid, type_to_str(q->type), hook_to_str(q->hook), tmp); - if (ret == -1 || ret >= sizeof buf) - fatalx("line too large"); - return (buf); -} - -static const char * -mfa_filter_to_text(struct mfa_filter *f) -{ - static char buf[1024]; - int ret; - - ret = snprintf(buf, sizeof buf, "filter:%s", mfa_filterproc_to_text(f->proc)); - if (ret == -1 || ret >= sizeof buf) - fatalx("line too large"); - - return (buf); -} - -static const char * -mfa_filterproc_to_text(struct mfa_filterproc *proc) -{ - static char buf[1024]; - int ret; - - ret = snprintf(buf, sizeof buf, "%s[hooks=0x%08x,flags=0x%04x]", - proc->mproc.name, proc->hooks, proc->flags); - if (ret == -1 || ret >= sizeof buf) - fatalx("line too large"); - - return (buf); -} - -#define CASE(x) case x : return #x - -static const char * -filterimsg_to_str(int imsg) -{ - switch (imsg) { - CASE(IMSG_FILTER_REGISTER); - CASE(IMSG_FILTER_EVENT); - CASE(IMSG_FILTER_QUERY); - CASE(IMSG_FILTER_PIPE_SETUP); - CASE(IMSG_FILTER_PIPE_ABORT); - CASE(IMSG_FILTER_NOTIFY); - CASE(IMSG_FILTER_RESPONSE); - default: - return "IMSG_FILTER_???"; - } -} - -static const char * -hook_to_str(int hook) -{ - switch (hook) { - CASE(HOOK_CONNECT); - CASE(HOOK_HELO); - CASE(HOOK_MAIL); - CASE(HOOK_RCPT); - CASE(HOOK_DATA); - CASE(HOOK_EOM); - CASE(HOOK_RESET); - CASE(HOOK_DISCONNECT); - CASE(HOOK_COMMIT); - CASE(HOOK_ROLLBACK); - CASE(HOOK_DATALINE); - default: - return "HOOK_???"; - } -} - -static const char * -type_to_str(int type) -{ - switch (type) { - CASE(QT_QUERY); - CASE(QT_EVENT); - default: - return "QT_???"; - } -} - -static const char * -status_to_str(int status) -{ - switch (status) { - CASE(MFA_OK); - CASE(MFA_FAIL); - CASE(MFA_CLOSE); - default: - return "MFA_???"; - } -} |