diff options
Diffstat (limited to 'smtpd/lka_session.c')
-rw-r--r-- | smtpd/lka_session.c | 556 |
1 files changed, 0 insertions, 556 deletions
diff --git a/smtpd/lka_session.c b/smtpd/lka_session.c deleted file mode 100644 index 999e01d6..00000000 --- a/smtpd/lka_session.c +++ /dev/null @@ -1,556 +0,0 @@ -/* $OpenBSD: lka_session.c,v 1.93 2019/09/20 17:46:05 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 "includes.h" - -#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 <resolv.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <limits.h> - -#include "smtpd.h" -#include "log.h" - -#define EXPAND_DEPTH 10 - -#define F_WAITING 0x01 - -struct lka_session { - uint64_t id; /* given by smtp */ - - TAILQ_HEAD(, envelope) deliverylist; - struct expand expand; - - int flags; - int error; - const char *errormsg; - struct envelope envelope; - struct xnodes nodes; - /* waiting for fwdrq */ - struct rule *rule; - struct expandnode *node; -}; - -static void lka_expand(struct lka_session *, struct rule *, - struct expandnode *); -static void lka_submit(struct lka_session *, struct rule *, - struct expandnode *); -static void lka_resume(struct lka_session *); - -static int init; -static struct tree sessions; - -void -lka_session(uint64_t id, struct envelope *envelope) -{ - struct lka_session *lks; - struct expandnode xn; - - if (init == 0) { - init = 1; - tree_init(&sessions); - } - - lks = xcalloc(1, sizeof(*lks)); - lks->id = id; - RB_INIT(&lks->expand.tree); - TAILQ_INIT(&lks->deliverylist); - tree_xset(&sessions, lks->id, lks); - - lks->envelope = *envelope; - - TAILQ_INIT(&lks->nodes); - memset(&xn, 0, sizeof xn); - xn.type = EXPAND_ADDRESS; - xn.u.mailaddr = lks->envelope.rcpt; - lks->expand.parent = NULL; - lks->expand.rule = NULL; - lks->expand.queue = &lks->nodes; - expand_insert(&lks->expand, &xn); - lka_resume(lks); -} - -void -lka_session_forward_reply(struct forward_req *fwreq, int fd) -{ - struct lka_session *lks; - struct dispatcher *dsp; - struct rule *rule; - struct expandnode *xn; - int ret; - - lks = tree_xget(&sessions, fwreq->id); - xn = lks->node; - rule = lks->rule; - - lks->flags &= ~F_WAITING; - - switch (fwreq->status) { - case 0: - /* permanent failure while lookup ~/.forward */ - log_trace(TRACE_EXPAND, "expand: ~/.forward failed for user %s", - fwreq->user); - lks->error = LKA_PERMFAIL; - break; - case 1: - if (fd == -1) { - dsp = dict_get(env->sc_dispatchers, lks->rule->dispatcher); - if (dsp->u.local.forward_only) { - log_trace(TRACE_EXPAND, "expand: no .forward " - "for user %s on forward-only rule", fwreq->user); - lks->error = LKA_TEMPFAIL; - } - else if (dsp->u.local.expand_only) { - log_trace(TRACE_EXPAND, "expand: no .forward " - "for user %s and no default action on rule", fwreq->user); - lks->error = LKA_PERMFAIL; - } - else { - log_trace(TRACE_EXPAND, "expand: no .forward for " - "user %s, just deliver", fwreq->user); - lka_submit(lks, rule, xn); - } - } - else { - dsp = dict_get(env->sc_dispatchers, rule->dispatcher); - - /* expand for the current user and rule */ - lks->expand.rule = rule; - lks->expand.parent = xn; - - /* forwards_get() will close the descriptor no matter what */ - ret = forwards_get(fd, &lks->expand); - if (ret == -1) { - log_trace(TRACE_EXPAND, "expand: temporary " - "forward error for user %s", fwreq->user); - lks->error = LKA_TEMPFAIL; - } - else if (ret == 0) { - if (dsp->u.local.forward_only) { - log_trace(TRACE_EXPAND, "expand: empty .forward " - "for user %s on forward-only rule", fwreq->user); - lks->error = LKA_TEMPFAIL; - } - else if (dsp->u.local.expand_only) { - log_trace(TRACE_EXPAND, "expand: empty .forward " - "for user %s and no default action on rule", fwreq->user); - lks->error = LKA_PERMFAIL; - } - else { - log_trace(TRACE_EXPAND, "expand: empty .forward " - "for user %s, just deliver", fwreq->user); - lka_submit(lks, rule, xn); - } - } - } - break; - default: - /* temporary failure while looking up ~/.forward */ - lks->error = LKA_TEMPFAIL; - } - - if (lks->error == LKA_TEMPFAIL && lks->errormsg == NULL) - lks->errormsg = "424 4.2.4 Mailing list expansion problem"; - if (lks->error == LKA_PERMFAIL && lks->errormsg == NULL) - lks->errormsg = "524 5.2.4 Mailing list expansion problem"; - - lka_resume(lks); -} - -static void -lka_resume(struct lka_session *lks) -{ - struct envelope *ep; - struct expandnode *xn; - - if (lks->error) - goto error; - - /* pop next node and expand it */ - while ((xn = TAILQ_FIRST(&lks->nodes))) { - TAILQ_REMOVE(&lks->nodes, xn, tq_entry); - lka_expand(lks, xn->rule, xn); - if (lks->flags & F_WAITING) - return; - if (lks->error) - goto error; - } - - /* delivery list is empty, reject */ - if (TAILQ_FIRST(&lks->deliverylist) == NULL) { - log_trace(TRACE_EXPAND, "expand: lka_done: expanded to empty " - "delivery list"); - lks->error = LKA_PERMFAIL; - lks->errormsg = "524 5.2.4 Mailing list expansion problem"; - } - error: - if (lks->error) { - m_create(p_pony, IMSG_SMTP_EXPAND_RCPT, 0, 0, -1); - m_add_id(p_pony, lks->id); - m_add_int(p_pony, lks->error); - - if (lks->errormsg) - m_add_string(p_pony, lks->errormsg); - else { - if (lks->error == LKA_PERMFAIL) - m_add_string(p_pony, "550 Invalid recipient"); - else if (lks->error == LKA_TEMPFAIL) - m_add_string(p_pony, "451 Temporary failure"); - } - - m_close(p_pony); - while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) { - TAILQ_REMOVE(&lks->deliverylist, ep, entry); - free(ep); - } - } - else { - /* Process the delivery list and submit envelopes to queue */ - while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) { - TAILQ_REMOVE(&lks->deliverylist, ep, entry); - m_create(p_queue, IMSG_LKA_ENVELOPE_SUBMIT, 0, 0, -1); - m_add_id(p_queue, lks->id); - m_add_envelope(p_queue, ep); - m_close(p_queue); - free(ep); - } - - m_create(p_queue, IMSG_LKA_ENVELOPE_COMMIT, 0, 0, -1); - m_add_id(p_queue, lks->id); - m_close(p_queue); - } - - expand_clear(&lks->expand); - tree_xpop(&sessions, lks->id); - free(lks); -} - -static void -lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn) -{ - struct forward_req fwreq; - struct envelope ep; - struct expandnode node; - struct mailaddr maddr; - struct dispatcher *dsp; - struct table *userbase; - int r; - union lookup lk; - char *tag; - const char *srs_decoded; - - if (xn->depth >= EXPAND_DEPTH) { - log_trace(TRACE_EXPAND, "expand: lka_expand: node too deep."); - lks->error = LKA_PERMFAIL; - lks->errormsg = "524 5.2.4 Mailing list expansion problem"; - return; - } - - switch (xn->type) { - case EXPAND_INVALID: - case EXPAND_INCLUDE: - fatalx("lka_expand: unexpected type"); - break; - - case EXPAND_ADDRESS: - - log_trace(TRACE_EXPAND, "expand: lka_expand: address: %s@%s " - "[depth=%d]", - xn->u.mailaddr.user, xn->u.mailaddr.domain, xn->depth); - - - ep = lks->envelope; - ep.dest = xn->u.mailaddr; - if (xn->parent) /* nodes with parent are forward addresses */ - ep.flags |= EF_INTERNAL; - - /* handle SRS */ - if (env->sc_srs_key != NULL && - ep.sender.user[0] == '\0' && - (strncasecmp(ep.rcpt.user, "SRS0=", 5) == 0 || - strncasecmp(ep.rcpt.user, "SRS1=", 5) == 0)) { - srs_decoded = srs_decode(mailaddr_to_text(&ep.rcpt)); - if (srs_decoded && - text_to_mailaddr(&ep.rcpt, srs_decoded)) { - /* flag envelope internal and override rcpt */ - ep.flags |= EF_INTERNAL; - xn->u.mailaddr = ep.rcpt; - lks->envelope = ep; - } - else { - log_warn("SRS failed to decode: %s", - mailaddr_to_text(&ep.rcpt)); - } - } - - /* Pass the node through the ruleset */ - rule = ruleset_match(&ep); - if (rule == NULL || rule->reject) { - lks->error = (errno == EAGAIN) ? - LKA_TEMPFAIL : LKA_PERMFAIL; - break; - } - - dsp = dict_xget(env->sc_dispatchers, rule->dispatcher); - if (dsp->type == DISPATCHER_REMOTE) { - lka_submit(lks, rule, xn); - } - else if (dsp->u.local.table_virtual) { - /* expand */ - lks->expand.rule = rule; - lks->expand.parent = xn; - - /* temporary replace the mailaddr with a copy where - * we eventually strip the '+'-part before lookup. - */ - maddr = xn->u.mailaddr; - xlowercase(maddr.user, xn->u.mailaddr.user, - sizeof maddr.user); - r = aliases_virtual_get(&lks->expand, &maddr); - if (r == -1) { - lks->error = LKA_TEMPFAIL; - log_trace(TRACE_EXPAND, "expand: lka_expand: " - "error in virtual alias lookup"); - } - else if (r == 0) { - lks->error = LKA_PERMFAIL; - log_trace(TRACE_EXPAND, "expand: lka_expand: " - "no aliases for virtual"); - } - if (lks->error == LKA_TEMPFAIL && lks->errormsg == NULL) - lks->errormsg = "424 4.2.4 Mailing list expansion problem"; - if (lks->error == LKA_PERMFAIL && lks->errormsg == NULL) - lks->errormsg = "524 5.2.4 Mailing list expansion problem"; - } - else { - lks->expand.rule = rule; - lks->expand.parent = xn; - xn->rule = rule; - - memset(&node, 0, sizeof node); - node.type = EXPAND_USERNAME; - xlowercase(node.u.user, xn->u.mailaddr.user, - sizeof node.u.user); - expand_insert(&lks->expand, &node); - } - break; - - case EXPAND_USERNAME: - log_trace(TRACE_EXPAND, "expand: lka_expand: username: %s " - "[depth=%d, sameuser=%d]", - xn->u.user, xn->depth, xn->sameuser); - - /* expand aliases with the given rule */ - dsp = dict_xget(env->sc_dispatchers, rule->dispatcher); - - lks->expand.rule = rule; - lks->expand.parent = xn; - - if (!xn->sameuser && - (dsp->u.local.table_alias || dsp->u.local.table_virtual)) { - if (dsp->u.local.table_alias) - r = aliases_get(&lks->expand, xn->u.user); - if (dsp->u.local.table_virtual) - r = aliases_virtual_get(&lks->expand, &xn->u.mailaddr); - if (r == -1) { - log_trace(TRACE_EXPAND, "expand: lka_expand: " - "error in alias lookup"); - lks->error = LKA_TEMPFAIL; - if (lks->errormsg == NULL) - lks->errormsg = "424 4.2.4 Mailing list expansion problem"; - } - if (r) - break; - } - - /* gilles+hackers@ -> gilles@ */ - if ((tag = strchr(xn->u.user, *env->sc_subaddressing_delim)) != NULL) { - *tag++ = '\0'; - (void)strlcpy(xn->subaddress, tag, sizeof xn->subaddress); - } - - userbase = table_find(env, dsp->u.local.table_userbase); - r = table_lookup(userbase, K_USERINFO, xn->u.user, &lk); - if (r == -1) { - log_trace(TRACE_EXPAND, "expand: lka_expand: " - "backend error while searching user"); - lks->error = LKA_TEMPFAIL; - break; - } - if (r == 0) { - log_trace(TRACE_EXPAND, "expand: lka_expand: " - "user-part does not match system user"); - lks->error = LKA_PERMFAIL; - break; - } - xn->realuser = 1; - - if (xn->sameuser && xn->parent->forwarded) { - log_trace(TRACE_EXPAND, "expand: lka_expand: same " - "user, submitting"); - lka_submit(lks, rule, xn); - break; - } - - /* no aliases found, query forward file */ - lks->rule = rule; - lks->node = xn; - xn->forwarded = 1; - - memset(&fwreq, 0, sizeof(fwreq)); - fwreq.id = lks->id; - (void)strlcpy(fwreq.user, lk.userinfo.username, sizeof(fwreq.user)); - (void)strlcpy(fwreq.directory, lk.userinfo.directory, sizeof(fwreq.directory)); - fwreq.uid = lk.userinfo.uid; - fwreq.gid = lk.userinfo.gid; - - m_compose(p_parent, IMSG_LKA_OPEN_FORWARD, 0, 0, -1, - &fwreq, sizeof(fwreq)); - lks->flags |= F_WAITING; - break; - - case EXPAND_FILENAME: - dsp = dict_xget(env->sc_dispatchers, rule->dispatcher); - if (dsp->u.local.forward_only) { - log_trace(TRACE_EXPAND, "expand: filename matched on forward-only rule"); - lks->error = LKA_TEMPFAIL; - break; - } - log_trace(TRACE_EXPAND, "expand: lka_expand: filename: %s " - "[depth=%d]", xn->u.buffer, xn->depth); - lka_submit(lks, rule, xn); - break; - - case EXPAND_ERROR: - dsp = dict_xget(env->sc_dispatchers, rule->dispatcher); - if (dsp->u.local.forward_only) { - log_trace(TRACE_EXPAND, "expand: error matched on forward-only rule"); - lks->error = LKA_TEMPFAIL; - break; - } - log_trace(TRACE_EXPAND, "expand: lka_expand: error: %s " - "[depth=%d]", xn->u.buffer, xn->depth); - if (xn->u.buffer[0] == '4') - lks->error = LKA_TEMPFAIL; - else if (xn->u.buffer[0] == '5') - lks->error = LKA_PERMFAIL; - lks->errormsg = xn->u.buffer; - break; - - case EXPAND_FILTER: - dsp = dict_xget(env->sc_dispatchers, rule->dispatcher); - if (dsp->u.local.forward_only) { - log_trace(TRACE_EXPAND, "expand: filter matched on forward-only rule"); - lks->error = LKA_TEMPFAIL; - break; - } - log_trace(TRACE_EXPAND, "expand: lka_expand: filter: %s " - "[depth=%d]", xn->u.buffer, xn->depth); - lka_submit(lks, rule, xn); - break; - } -} - -static struct expandnode * -lka_find_ancestor(struct expandnode *xn, enum expand_type type) -{ - while (xn && (xn->type != type)) - xn = xn->parent; - if (xn == NULL) { - log_warnx("warn: lka_find_ancestor: no ancestors of type %d", - type); - fatalx(NULL); - } - return (xn); -} - -static void -lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) -{ - struct envelope *ep; - struct dispatcher *dsp; - const char *user; - const char *format; - - ep = xmemdup(&lks->envelope, sizeof *ep); - (void)strlcpy(ep->dispatcher, rule->dispatcher, sizeof ep->dispatcher); - - dsp = dict_xget(env->sc_dispatchers, ep->dispatcher); - - switch (dsp->type) { - case DISPATCHER_REMOTE: - if (xn->type != EXPAND_ADDRESS) - fatalx("lka_deliver: expect address"); - ep->type = D_MTA; - ep->dest = xn->u.mailaddr; - break; - - case DISPATCHER_BOUNCE: - case DISPATCHER_LOCAL: - if (xn->type != EXPAND_USERNAME && - xn->type != EXPAND_FILENAME && - xn->type != EXPAND_FILTER) - fatalx("lka_deliver: wrong type: %d", xn->type); - - ep->type = D_MDA; - ep->dest = lka_find_ancestor(xn, EXPAND_ADDRESS)->u.mailaddr; - if (xn->type == EXPAND_USERNAME) { - (void)strlcpy(ep->mda_user, xn->u.user, sizeof(ep->mda_user)); - (void)strlcpy(ep->mda_subaddress, xn->subaddress, sizeof(ep->mda_subaddress)); - } - else { - user = !xn->parent->realuser ? - SMTPD_USER : - xn->parent->u.user; - (void)strlcpy(ep->mda_user, user, sizeof (ep->mda_user)); - - /* this battle needs to be fought ... */ - if (xn->type == EXPAND_FILTER && - strcmp(ep->mda_user, SMTPD_USER) == 0) - log_warnx("commands executed from aliases " - "run with %s privileges", SMTPD_USER); - - if (xn->type == EXPAND_FILENAME) - format = PATH_LIBEXEC"/mail.mboxfile -f %%{mbox.from} %s"; - else if (xn->type == EXPAND_FILTER) - format = "%s"; - (void)snprintf(ep->mda_exec, sizeof(ep->mda_exec), - format, xn->u.buffer); - } - break; - } - - TAILQ_INSERT_TAIL(&lks->deliverylist, ep, entry); -} |