summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd/mfa.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/smtpd/mfa.c')
-rw-r--r--usr.sbin/smtpd/mfa.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/usr.sbin/smtpd/mfa.c b/usr.sbin/smtpd/mfa.c
new file mode 100644
index 00000000000..5bfed1f68fe
--- /dev/null
+++ b/usr.sbin/smtpd/mfa.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.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/queue.h>
+#include <sys/tree.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <event.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "smtpd.h"
+
+__dead void mfa_shutdown(void);
+void mfa_sig_handler(int, short, void *);
+void mfa_dispatch_parent(int, short, void *);
+void mfa_dispatch_smtp(int, short, void *);
+void mfa_dispatch_lka(int, short, void *);
+void mfa_setup_events(struct smtpd *);
+void mfa_disable_events(struct smtpd *);
+void mfa_timeout(int, short, void *);
+
+void
+mfa_sig_handler(int sig, short event, void *p)
+{
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ mfa_shutdown();
+ break;
+ default:
+ fatalx("mfa_sig_handler: unexpected signal");
+ }
+}
+
+void
+mfa_dispatch_parent(int sig, short event, void *p)
+{
+ struct smtpd *env = p;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+
+ ibuf = env->sc_ibufs[PROC_PARENT];
+ switch (event) {
+ case EV_READ:
+ if ((n = imsg_read(ibuf)) == -1)
+ fatal("imsg_read_error");
+ if (n == 0) {
+ /* this pipe is dead, so remove the event handler */
+ event_del(&ibuf->ev);
+ event_loopexit(NULL);
+ return;
+ }
+ break;
+ case EV_WRITE:
+ if (msgbuf_write(&ibuf->w) == -1)
+ fatal("msgbuf_write");
+ imsg_event_add(ibuf);
+ return;
+ default:
+ fatalx("unknown event");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("parent_dispatch_mfa: imsg_read error");
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ default:
+ log_debug("parent_dispatch_mfa: unexpected imsg %d",
+ imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(ibuf);
+}
+
+void
+mfa_dispatch_smtp(int sig, short event, void *p)
+{
+ struct smtpd *env = p;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+
+ ibuf = env->sc_ibufs[PROC_SMTP];
+ switch (event) {
+ case EV_READ:
+ if ((n = imsg_read(ibuf)) == -1)
+ fatal("imsg_read_error");
+ if (n == 0) {
+ /* this pipe is dead, so remove the event handler */
+ event_del(&ibuf->ev);
+ event_loopexit(NULL);
+ return;
+ }
+ break;
+ case EV_WRITE:
+ if (msgbuf_write(&ibuf->w) == -1)
+ fatal("msgbuf_write");
+ imsg_event_add(ibuf);
+ return;
+ default:
+ fatalx("unknown event");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("mfa_dispatch_smtp: imsg_read error");
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_MFA_RPATH_SUBMIT: {
+ struct message *m;
+ struct submit_status ss;
+
+ m = imsg.data;
+ log_debug("mfa_dispatch_smtp: testing return path");
+ ss.id = m->id;
+ ss.code = 250;
+ ss.u.path = m->sender;
+
+ imsg_compose(env->sc_ibufs[PROC_LKA], IMSG_LKA_LOOKUP_MAIL, 0, 0, -1,
+ &ss, sizeof(ss));
+ break;
+ }
+ case IMSG_MFA_RCPT_SUBMIT: {
+ struct message_recipient *mr;
+ struct submit_status ss;
+
+ mr = imsg.data;
+ log_debug("mfa_dispatch_smtp: testing forward path");
+ ss.id = mr->id;
+ ss.code = 250;
+ ss.u.path = mr->path;
+ ss.ss = mr->ss;
+
+ imsg_compose(env->sc_ibufs[PROC_LKA], IMSG_LKA_LOOKUP_RCPT, 0, 0, -1,
+ &ss, sizeof(ss));
+ break;
+ }
+ case IMSG_MFA_DATA_SUBMIT:
+ break;
+ default:
+ log_debug("mfa_dispatch_smtp: unexpected imsg %d",
+ imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(ibuf);
+}
+
+void
+mfa_dispatch_lka(int sig, short event, void *p)
+{
+ struct smtpd *env = p;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+
+ ibuf = env->sc_ibufs[PROC_LKA];
+ switch (event) {
+ case EV_READ:
+ if ((n = imsg_read(ibuf)) == -1)
+ fatal("imsg_read_error");
+ if (n == 0) {
+ /* this pipe is dead, so remove the event handler */
+ event_del(&ibuf->ev);
+ event_loopexit(NULL);
+ return;
+ }
+ break;
+ case EV_WRITE:
+ if (msgbuf_write(&ibuf->w) == -1)
+ fatal("msgbuf_write");
+ imsg_event_add(ibuf);
+ return;
+ default:
+ fatalx("unknown event");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("mfa_dispatch_lka: imsg_read error");
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_MFA_LOOKUP_MAIL: {
+ struct submit_status *ss;
+
+ ss = imsg.data;
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_MFA_RPATH_SUBMIT, 0, 0, -1,
+ ss, sizeof(*ss));
+ break;
+ }
+ case IMSG_MFA_LOOKUP_RCPT: {
+ struct submit_status *ss;
+
+ ss = imsg.data;
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_MFA_RCPT_SUBMIT, 0, 0, -1,
+ ss, sizeof(*ss));
+ break;
+ }
+ default:
+ log_debug("mfa_dispatch_lka: unexpected imsg %d",
+ imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ imsg_event_add(ibuf);
+}
+
+void
+mfa_shutdown(void)
+{
+ log_info("mail filter exiting");
+ _exit(0);
+}
+
+void
+mfa_setup_events(struct smtpd *env)
+{
+ struct timeval tv;
+
+ evtimer_set(&env->sc_ev, mfa_timeout, env);
+ tv.tv_sec = 3;
+ tv.tv_usec = 0;
+ evtimer_add(&env->sc_ev, &tv);
+}
+
+void
+mfa_disable_events(struct smtpd *env)
+{
+ evtimer_del(&env->sc_ev);
+}
+
+void
+mfa_timeout(int fd, short event, void *p)
+{
+ struct smtpd *env = p;
+ struct timeval tv;
+
+ tv.tv_sec = 3;
+ tv.tv_usec = 0;
+ evtimer_add(&env->sc_ev, &tv);
+}
+
+pid_t
+mfa(struct smtpd *env)
+{
+ pid_t pid;
+ struct passwd *pw;
+
+ struct event ev_sigint;
+ struct event ev_sigterm;
+
+ struct peer peers[] = {
+ { PROC_PARENT, mfa_dispatch_parent },
+ { PROC_SMTP, mfa_dispatch_smtp },
+ { PROC_LKA, mfa_dispatch_lka },
+ };
+
+ switch (pid = fork()) {
+ case -1:
+ fatal("mfa: cannot fork");
+ case 0:
+ break;
+ default:
+ return (pid);
+ }
+
+// purge_config(env, PURGE_EVERYTHING);
+
+ pw = env->sc_pw;
+
+#ifndef DEBUG
+ if (chroot(pw->pw_dir) == -1)
+ fatal("mfa: chroot");
+ if (chdir("/") == -1)
+ fatal("mfa: chdir(\"/\")");
+#else
+#warning disabling privilege revocation and chroot in DEBUG MODE
+#endif
+
+ setproctitle("mail filter agent");
+ smtpd_process = PROC_MFA;
+
+#ifndef DEBUG
+ 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("mfa: cannot drop privileges");
+#endif
+
+ event_init();
+
+ signal_set(&ev_sigint, SIGINT, mfa_sig_handler, env);
+ signal_set(&ev_sigterm, SIGTERM, mfa_sig_handler, env);
+ signal_add(&ev_sigint, NULL);
+ signal_add(&ev_sigterm, NULL);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+
+ config_peers(env, peers, 3);
+
+ mfa_setup_events(env);
+ event_dispatch();
+ mfa_shutdown();
+
+ return (0);
+}
+
+int
+msg_cmp(struct message *m1, struct message *m2)
+{
+ /*
+ * do not return u_int64_t's
+ */
+ if (m1->id - m2->id > 0)
+ return (1);
+ else if (m1->id - m2->id < 0)
+ return (-1);
+ else
+ return (0);
+}
+
+SPLAY_GENERATE(msgtree, message, nodes, msg_cmp);