summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/smtpd/expand.c30
-rw-r--r--usr.sbin/smtpd/lka_session.c628
-rw-r--r--usr.sbin/smtpd/smtpd.h30
3 files changed, 298 insertions, 390 deletions
diff --git a/usr.sbin/smtpd/expand.c b/usr.sbin/smtpd/expand.c
index c7798e08bdf..4900157be70 100644
--- a/usr.sbin/smtpd/expand.c
+++ b/usr.sbin/smtpd/expand.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: expand.c,v 1.16 2012/09/21 19:37:08 eric Exp $ */
+/* $OpenBSD: expand.c,v 1.17 2012/09/27 18:57:25 eric Exp $ */
/*
* Copyright (c) 2009 Gilles Chehade <gilles@openbsd.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
@@ -42,15 +43,25 @@ expand_insert(struct expand *expand, struct expandnode *node)
{
struct expandnode *xn;
+ if (node->type == EXPAND_USERNAME &&
+ expand->parent &&
+ expand->parent->type == EXPAND_USERNAME &&
+ !strcmp(expand->parent->u.user, node->u.user))
+ node->sameuser = 1;
+
if (expand_lookup(expand, node))
return;
xn = xmemdup(node, sizeof *xn, "expand_insert");
-
- /* copy expansion context on node */
- strlcpy(xn->as_user, expand->user, sizeof xn->as_user);
-
+ xn->rule = expand->rule;
+ xn->parent = expand->parent;
+ if (xn->parent)
+ xn->depth = xn->parent->depth + 1;
+ else
+ xn->depth = 0;
RB_INSERT(expandtree, &expand->tree, xn);
+ if (expand->queue)
+ TAILQ_INSERT_TAIL(expand->queue, xn, tq_entry);
}
void
@@ -58,6 +69,10 @@ expand_free(struct expand *expand)
{
struct expandnode *xn;
+ if (expand->queue)
+ while ((xn = TAILQ_FIRST(expand->queue)))
+ TAILQ_REMOVE(expand->queue, xn, tq_entry);
+
while ((xn = RB_ROOT(&expand->tree)) != NULL) {
RB_REMOVE(expandtree, &expand->tree, xn);
free(xn);
@@ -69,9 +84,12 @@ expand_cmp(struct expandnode *e1, struct expandnode *e2)
{
if (e1->type < e2->type)
return -1;
-
if (e1->type > e2->type)
return 1;
+ if (e1->sameuser < e2->sameuser)
+ return -1;
+ if (e1->sameuser > e2->sameuser)
+ return 1;
return memcmp(&e1->u, &e2->u, sizeof(e1->u));
}
diff --git a/usr.sbin/smtpd/lka_session.c b/usr.sbin/smtpd/lka_session.c
index 2b5cf095a82..9afa1bb731f 100644
--- a/usr.sbin/smtpd/lka_session.c
+++ b/usr.sbin/smtpd/lka_session.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: lka_session.c,v 1.35 2012/09/26 19:52:20 eric Exp $ */
+/* $OpenBSD: lka_session.c,v 1.36 2012/09/27 18:57:25 eric Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.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
@@ -39,42 +40,40 @@
#include "smtpd.h"
#include "log.h"
-enum lka_session_flags {
- F_ERROR = 0x1
-};
+#define F_ERROR 0x01
+#define F_WAITING 0x02
struct lka_session {
- SPLAY_ENTRY(lka_session) nodes;
- uint64_t id;
+ uint64_t id;
+
+ TAILQ_HEAD(, envelope) deliverylist;
+ struct expand expand;
+
+ int flags;
+ struct submit_status ss;
- TAILQ_HEAD(, envelope) deliverylist;
- struct expand expand;
+ struct envelope envelope;
- uint8_t iterations;
- uint32_t pending;
- enum lka_session_flags flags;
- struct submit_status ss;
+ struct xnodes nodes;
+ /* waiting for fwdrq */
+ struct rule *rule;
+ struct expandnode *node;
};
-static void lka_session_fail(struct lka_session *);
-static void lka_session_destroy(struct lka_session *);
-static void lka_session_pickup(struct lka_session *, struct envelope *);
-static int lka_session_envelope_expand(struct lka_session *, struct envelope *);
-static int lka_session_resume(struct lka_session *, struct envelope *);
-static void lka_session_done(struct lka_session *);
-static size_t lka_session_expand_format(char *, size_t, struct envelope *);
-static void lka_session_request_forwardfile(struct lka_session *,
- struct envelope *, char *);
-static void lka_session_deliver(struct lka_session *, struct envelope *);
-static int lka_session_resolve_node(struct envelope *, struct expandnode *);
-static int lka_session_rcpt_action(struct envelope *);
+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 size_t lka_expand_format(char *, size_t, const struct envelope *);
+static void mailaddr_to_username(const struct mailaddr *, char *, size_t);
+static const char * mailaddr_tag(const struct mailaddr *);
static struct tree sessions = SPLAY_INITIALIZER(&sessions);
void
lka_session(struct submit_status *ss)
{
- struct lka_session *lks;
+ struct lka_session *lks;
+ struct expandnode xn;
lks = xcalloc(1, sizeof(*lks), "lka_session");
lks->id = generate_uid();
@@ -84,256 +83,103 @@ lka_session(struct submit_status *ss)
TAILQ_INIT(&lks->deliverylist);
tree_xset(&sessions, lks->id, lks);
- if (! lka_session_envelope_expand(lks, &ss->envelope))
- lka_session_fail(lks);
- else
- lka_session_pickup(lks, &ss->envelope);
-}
-
-static int
-lka_session_envelope_expand(struct lka_session *lks, struct envelope *ep)
-{
- char *user;
- char *tag;
- struct user_backend *ub;
- struct mta_user u;
- char username[MAX_LOCALPART_SIZE];
-
- /* remote delivery, no need to process further */
- if (ep->type == D_MTA) {
- lka_session_deliver(lks, ep);
- return 1;
- }
-
- switch (ep->rule.r_condition.c_type) {
- case C_ALL:
- case C_DOM:
- if (ep->agent.mda.user[0] == '\0')
- user = ep->dest.user;
- else
- user = ep->agent.mda.user;
- xlowercase(username, user, sizeof(username));
-
- /* gilles+hackers@ -> gilles@ */
- if ((tag = strchr(username, '+')) != NULL) {
- *tag++ = '\0';
-
- /* skip dots after the '+' */
- while (*tag == '.')
- tag++;
- }
-
- if (aliases_get(ep->rule.r_amap, &lks->expand, username))
- return 1;
-
- bzero(&u, sizeof (u));
- ub = user_backend_lookup(USER_PWD);
- if (! ub->getbyname(&u, username))
- return 0;
-
- (void)strlcpy(ep->agent.mda.user, u.username,
- sizeof (ep->agent.mda.user));
-
- ep->type = D_MDA;
- switch (ep->rule.r_action) {
- case A_MBOX:
- ep->agent.mda.method = A_MBOX;
- (void)strlcpy(ep->agent.mda.user,
- u.username,
- sizeof (ep->agent.mda.user));
- break;
- case A_MAILDIR:
- case A_FILENAME:
- case A_MDA:
- ep->agent.mda.method = ep->rule.r_action;
- (void)strlcpy(ep->agent.mda.buffer,
- ep->rule.r_value.buffer,
- sizeof (ep->agent.mda.buffer));
-
- if (tag && *tag) {
- (void)strlcat(ep->agent.mda.buffer, "/.",
- sizeof (ep->agent.mda.buffer));
- (void)strlcat(ep->agent.mda.buffer, tag,
- sizeof (ep->agent.mda.buffer));
- }
- break;
- default:
- fatalx("lka_session_envelope_expand: unexpected rule action");
- return 0;
- }
-
- lka_session_request_forwardfile(lks, ep, u.username);
- return 1;
-
- case C_VDOM:
- if (aliases_virtual_get(ep->rule.r_condition.c_map,
- &lks->expand, &ep->dest))
- return 1;
-
- return 0;
-
- default:
- fatalx("lka_session_envelope_expand: unexpected type");
- return 0;
- }
+ lks->envelope = ss->envelope;
- return 0;
+ TAILQ_INIT(&lks->nodes);
+ bzero(&xn, sizeof xn);
+ xn.type = EXPAND_ADDRESS;
+ xn.u.mailaddr = lks->envelope.dest; /* XXX we should only have rcpt */
+ 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 envelope *ep;
+ struct lka_session *lks;
+ struct rule *rule;
+ struct expandnode *xn;
lks = tree_xget(&sessions, fwreq->id);
- lks->pending--;
-
- ep = &fwreq->envelope;
+ xn = lks->node;
+ rule = lks->rule;
- if (fd != -1) {
- /* opened .forward okay */
- strlcpy(lks->expand.user, fwreq->as_user,
- sizeof lks->expand.user);
- if (! forwards_get(fd, &lks->expand)) {
- lks->ss.code = 530;
- lks->flags |= F_ERROR;
- }
- close(fd);
- lka_session_pickup(lks, ep);
- return;
- }
+ lks->flags &= ~F_WAITING;
- if (fwreq->status) {
- /* .forward not present */
- lka_session_deliver(lks, ep);
- lka_session_pickup(lks, ep);
- return;
+ if (fd == -1 && fwreq->status) {
+ /* no .forward, just deliver to local user */
+ log_debug("lka: no .forward for user %s, just deliver",
+ fwreq->as_user),
+ lka_submit(lks, rule, xn);
}
-
- /* opening .forward failed */
- lks->ss.code = 530;
- lks->flags |= F_ERROR;
- lka_session_pickup(lks, ep);
-}
-
-static void
-lka_session_pickup(struct lka_session *lks, struct envelope *ep)
-{
- int ret;
-
- /* we want to do five iterations of lka_session_resume() but
- * we need to be interruptible in case lka_session_resume()
- * has sent an imsg and expects an answer.
- */
- while (! (lks->flags & F_ERROR) &&
- ! lks->pending && lks->iterations < 5) {
- ++lks->iterations;
- ret = lka_session_resume(lks, ep);
- if (ret == -1) {
+ else if (fd == -1) {
+ log_debug("lka: opening .forward failed for user %s",
+ fwreq->as_user),
+ lks->ss.code = 530;
+ lks->flags |= F_ERROR;
+ }
+ else {
+ /* expand for the current user and rule */
+ lks->expand.rule = rule;
+ lks->expand.parent = xn;
+ if (forwards_get(fd, &lks->expand) == 0) {
+ /* no aliases */
lks->ss.code = 530;
lks->flags |= F_ERROR;
}
-
- if (lks->pending || ret <= 0)
- break;
+ close(fd);
}
-
- if (lks->pending)
- return;
-
- lka_session_done(lks);
+ lka_resume(lks);
}
-static int
-lka_session_resume(struct lka_session *lks, struct envelope *ep)
+static void
+lka_resume(struct lka_session *lks)
{
- struct expandnode *xn;
- uint8_t done = 1;
-
- RB_FOREACH(xn, expandtree, &lks->expand.tree) {
-
- /* this node has already been expanded, skip */
- if (xn->done)
- continue;
- done = 0;
-
- switch (lka_session_resolve_node(ep, xn)) {
- case 0:
- if (! lka_session_envelope_expand(lks, ep))
- return -1;
- break;
- case 1:
- lka_session_deliver(lks, ep);
- break;
- default:
- return -1;
- }
+ struct envelope *ep;
+ struct expandnode *xn;
- xn->done = 1;
+ if (lks->flags & F_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->flags & F_ERROR)
+ goto error;
}
- /* still not done after 5 iterations ? loop detected ... reject */
- if (!done && lks->iterations == 5)
- return -1;
-
- /* we're done expanding, no need for another iteration */
- if (RB_ROOT(&lks->expand.tree) == NULL || done)
- return 0;
-
- return 1;
-}
-
-static void
-lka_session_done(struct lka_session *lks)
-{
- struct envelope *ep;
-
- /* delivery list is empty OR expansion led to an error, reject */
+ /* delivery list is empty, reject */
if (TAILQ_FIRST(&lks->deliverylist) == NULL) {
- log_info("lka_session_done: expansion led to empty delivery list");
+ log_info("lka_done: expansion led to empty delivery list");
lks->flags |= F_ERROR;
}
- if (lks->flags & F_ERROR)
- goto done;
-
- /* process the delivery list and submit envelopes to queue */
- while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) {
- imsg_compose_event(env->sc_ievs[PROC_QUEUE],
- IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, ep, sizeof *ep);
- TAILQ_REMOVE(&lks->deliverylist, ep, entry);
- free(ep);
- }
- ep = &lks->ss.envelope;
- imsg_compose_event(env->sc_ievs[PROC_QUEUE],
- IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1, ep, sizeof *ep);
-
-done:
+ error:
if (lks->flags & F_ERROR) {
lks->ss.code = 530;
imsg_compose_event(env->sc_ievs[PROC_MFA], IMSG_LKA_RCPT, 0, 0,
-1, &lks->ss, sizeof(struct submit_status));
+ while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) {
+ TAILQ_REMOVE(&lks->deliverylist, ep, entry);
+ free(ep);
+ }
}
- lka_session_destroy(lks);
-}
-
-static void
-lka_session_fail(struct lka_session *lks)
-{
- lks->ss.code = 530;
- imsg_compose_event(env->sc_ievs[PROC_MFA], IMSG_LKA_RCPT, 0, 0, -1,
- &lks->ss, sizeof(lks->ss));
- lka_session_destroy(lks);
-}
-
-static void
-lka_session_destroy(struct lka_session *lks)
-{
- struct envelope *ep;
-
- 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);
+ imsg_compose_event(env->sc_ievs[PROC_QUEUE],
+ IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1,
+ ep, sizeof *ep);
+ free(ep);
+ }
+ ep = &lks->ss.envelope;
+ imsg_compose_event(env->sc_ievs[PROC_QUEUE],
+ IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1, ep, sizeof *ep);
}
expand_free(&lks->expand);
@@ -342,126 +188,180 @@ lka_session_destroy(struct lka_session *lks)
}
static void
-lka_session_deliver(struct lka_session *lks, struct envelope *ep)
-{
- struct envelope *new_ep;
-
- new_ep = xmemdup(ep, sizeof *ep, "lka_session_deliver");
- if (new_ep->type == D_MDA) {
- switch (new_ep->agent.mda.method) {
- case A_MAILDIR:
- case A_FILENAME:
- case A_MDA:
- if (! lka_session_expand_format(
- new_ep->agent.mda.buffer,
- sizeof(new_ep->agent.mda.buffer), new_ep))
- lks->flags |= F_ERROR;
- default:
- break;
- }
- }
- else if (new_ep->type == D_MTA) {
- new_ep->agent.mta.relay = ep->rule.r_value.relayhost;
- if (ep->rule.r_as) {
- if (ep->rule.r_as->user[0]) {
- strlcpy(new_ep->sender.user,
- ep->rule.r_as->user,
- sizeof new_ep->sender.user);
- }
- if (ep->rule.r_as->domain[0]) {
- strlcpy(new_ep->sender.domain,
- ep->rule.r_as->domain,
- sizeof new_ep->sender.domain);
- }
- }
- }
- TAILQ_INSERT_TAIL(&lks->deliverylist, new_ep, entry);
-}
-
-static int
-lka_session_resolve_node(struct envelope *ep, struct expandnode *xn)
+lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
{
- struct envelope oldep;
+ struct forward_req fwreq;
+ struct envelope ep;
+ struct expandnode node;
- memcpy(&oldep, ep, sizeof (*ep));
- bzero(&ep->agent, sizeof (ep->agent));
+ if (xn->depth >= 5) {
+ log_debug("lka_expand: node too deep.");
+ lks->flags |= F_ERROR;
+ lks->ss.code = 530;
+ return;
+ }
switch (xn->type) {
case EXPAND_INVALID:
case EXPAND_INCLUDE:
- fatalx("lka_session_resolve_node: unexpected type");
+ fatalx("lka_expand: unexpected type");
break;
case EXPAND_ADDRESS:
- log_debug("lka_resolve_node: node is address: %s@%s",
+ log_debug("lka_expand: expanding address: %s@%s",
xn->u.mailaddr.user, xn->u.mailaddr.domain);
- ep->dest = xn->u.mailaddr;
- /* evaluation of ruleset assumes local source
- * since we're expanding on already accepted
- * source.
- */
- ep->flags |= DF_INTERNAL;
- if (! lka_session_rcpt_action(ep))
- return -1;
- return 0;
+ /* Pass the node through the ruleset */
+ ep = lks->envelope;
+ ep.dest = xn->u.mailaddr;
+ if (xn->parent) /* nodes with parent are forward addresses */
+ ep.flags |= DF_INTERNAL;
+ rule = ruleset_match(&ep);
+ if (rule == NULL) {
+ lks->flags |= F_ERROR;
+ lks->ss.code = 530;
+ break; /* no rule for address */
+ }
+ if (rule->r_action == A_RELAY || rule->r_action == A_RELAYVIA) {
+ lka_submit(lks, rule, xn);
+ }
+ else if (rule->r_condition.c_type == C_VDOM) {
+ /* expand */
+ lks->expand.rule = rule;
+ lks->expand.parent = xn;
+ if (aliases_virtual_get(rule->r_condition.c_map,
+ &lks->expand, &xn->u.mailaddr) == 0) {
+ log_debug("lka_expand: no aliases for virtual");
+ lks->flags |= F_ERROR;
+ lks->ss.code = 530;
+ }
+ }
+ else {
+ lks->expand.rule = rule;
+ lks->expand.parent = xn;
+ node.type = EXPAND_USERNAME;
+ mailaddr_to_username(&xn->u.mailaddr, node.u.user,
+ sizeof node.u.user);
+ expand_insert(&lks->expand, &node);
+ }
+ break;
case EXPAND_USERNAME:
- log_debug("lka_resolve_node: node is local username: %s",
- xn->u.user);
- ep->type = D_MDA;
- strlcpy(ep->agent.mda.user, xn->u.user,
- sizeof ep->agent.mda.user);
-
- /* overwrite the initial condition before we expand the
- * envelope again. if we came from a C_VDOM, not doing
- * so would lead to a VDOM loop causing recipient to be
- * rejected.
- *
- * i'll find a more elegant solution later, for now it
- * fixes an annoying bug.
- */
- ep->rule.r_condition.c_type = C_DOM;
-
- /* if expansion of a user results in same user ... deliver */
- if (strcmp(xn->u.user, xn->as_user) == 0) {
- ep->agent.mda.method = oldep.agent.mda.method;
+ log_debug("lka_expand: expanding username: %s", xn->u.user);
+
+ if (xn->sameuser) {
+ log_debug("lka_expand: same user, submitting");
+ lka_submit(lks, rule, xn);
break;
}
- /* otherwise rewrite delivery user with expansion result */
- (void)strlcpy(ep->agent.mda.user, xn->u.user,
- sizeof (ep->agent.mda.user));
- return 0;
+ /* expand aliases with the given rule */
+
+ lks->expand.rule = rule;
+ lks->expand.parent = xn;
+ if (rule->r_amap &&
+ aliases_get(rule->r_amap, &lks->expand, xn->u.user))
+ break;
+
+ /* no aliases found, query forward file */
+ lks->rule = rule;
+ lks->node = xn;
+ fwreq.id = lks->id;
+ (void)strlcpy(fwreq.as_user, xn->u.user, sizeof(fwreq.as_user));
+ imsg_compose_event(env->sc_ievs[PROC_PARENT],
+ IMSG_PARENT_FORWARD_OPEN, 0, 0, -1, &fwreq, sizeof(fwreq));
+ lks->flags |= F_WAITING;
+ break;
case EXPAND_FILENAME:
- log_debug("lka_resolve_node: node is filename: %s",
- xn->u.buffer);
- ep->type = D_MDA;
- ep->agent.mda.method = A_FILENAME;
- (void)strlcpy(ep->agent.mda.buffer, xn->u.buffer,
- sizeof (ep->agent.mda.buffer));
- (void)strlcpy(ep->agent.mda.user, xn->as_user,
- sizeof (ep->agent.mda.user));
+ log_debug("lka_expand: expanding filename: %s", xn->u.buffer);
+ lka_submit(lks, rule, xn);
break;
case EXPAND_FILTER:
- log_debug("lka_resolve_node: node is filter: %s",
- xn->u.buffer);
- ep->type = D_MDA;
- ep->agent.mda.method = A_MDA;
- (void)strlcpy(ep->agent.mda.buffer, xn->u.buffer,
- sizeof (ep->agent.mda.buffer));
- (void)strlcpy(ep->agent.mda.user, xn->as_user,
+ log_debug("lka_expand: expanding filter: %s", xn->u.buffer);
+ lka_submit(lks, rule, xn);
+ break;
+ }
+}
+
+static void
+lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn)
+{
+ struct envelope *ep;
+ struct expandnode *xn2;
+ const char *tag;
+
+ ep = xmemdup(&lks->envelope, sizeof *ep, "lka_submit");
+
+ switch (rule->r_action) {
+ case A_RELAY:
+ case A_RELAYVIA:
+ ep->type = D_MTA;
+ ep->agent.mta.relay = rule->r_value.relayhost;
+ if (xn->type != EXPAND_ADDRESS)
+ fatalx("lka_deliver: expect address");
+ ep->dest = xn->u.mailaddr;
+ break;
+ case A_MBOX:
+ case A_MAILDIR:
+ case A_FILENAME:
+ case A_MDA:
+ ep->type = D_MDA;
+
+ /* set username */
+ xn2 = xn;
+ while(xn2 && (xn2->type != EXPAND_USERNAME))
+ xn2 = xn2->parent;
+ if (xn2 == NULL)
+ fatalx("no user in node ancestry");
+ (void)strlcpy(ep->agent.mda.user, xn2->u.user,
sizeof (ep->agent.mda.user));
+
+ /* set dest */
+ xn2 = xn;
+ while(xn2 && (xn2->type != EXPAND_ADDRESS))
+ xn2 = xn2->parent;
+ if (xn2 == NULL)
+ fatalx("no address in node ancestry");
+ ep->dest = xn2->u.mailaddr;
+
+ if (xn->type == EXPAND_FILENAME) {
+ ep->agent.mda.method = A_FILENAME;
+ strlcpy(ep->agent.mda.buffer, xn->u.buffer,
+ sizeof ep->agent.mda.buffer);
+ }
+ else if (xn->type == EXPAND_FILTER) {
+ ep->agent.mda.method = A_MDA;
+ strlcpy(ep->agent.mda.buffer, xn->u.buffer,
+ sizeof ep->agent.mda.buffer);
+ }
+ else if (xn->type == EXPAND_USERNAME) {
+ ep->agent.mda.method = rule->r_action;
+ strlcpy(ep->agent.mda.buffer, rule->r_value.buffer,
+ sizeof ep->agent.mda.buffer);
+ tag = mailaddr_tag(&ep->dest);
+ if (rule->r_action == A_MAILDIR && tag && tag[0]) {
+ strlcat(ep->agent.mda.buffer, "/.",
+ sizeof (ep->agent.mda.buffer));
+ strlcat(ep->agent.mda.buffer, tag,
+ sizeof (ep->agent.mda.buffer));
+ }
+ } else
+ fatalx("lka_deliver: bad node type");
+
+ lka_expand_format(ep->agent.mda.buffer,
+ sizeof(ep->agent.mda.buffer), ep);
break;
+ default:
+ fatalx("lka_submit: bad rule action");
}
- return 1;
+ TAILQ_INSERT_TAIL(&lks->deliverylist, ep, entry);
}
static size_t
-lka_session_expand_format(char *buf, size_t len, struct envelope *ep)
+lka_expand_format(char *buf, size_t len, const struct envelope *ep)
{
char *p, *pbuf;
size_t ret, lret = 0;
@@ -517,7 +417,7 @@ lka_session_expand_format(char *buf, size_t len, struct envelope *ep)
}
}
if (*p == '%') {
- char *string, *tmp = p + 1;
+ const char *string, *tmp = p + 1;
int digit = 0;
if (isdigit((int)*tmp)) {
@@ -578,42 +478,28 @@ copy:
return ret;
}
-static int
-lka_session_rcpt_action(struct envelope *ep)
+static void
+mailaddr_to_username(const struct mailaddr *maddr, char *dst, size_t len)
{
- struct rule *r;
-
- r = ruleset_match(ep);
- if (r == NULL) {
- ep->type = D_MTA;
- return 0;
- }
+ char *tag;
- ep->rule = *r;
- switch (ep->rule.r_action) {
- case A_MBOX:
- case A_MAILDIR:
- case A_FILENAME:
- case A_MDA:
- ep->type = D_MDA;
- break;
- default:
- ep->type = D_MTA;
- }
+ xlowercase(dst, maddr->user, len);
- return 1;
+ /* gilles+hackers@ -> gilles@ */
+ if ((tag = strchr(dst, '+')) != NULL)
+ *tag++ = '\0';
}
-static void
-lka_session_request_forwardfile(struct lka_session *lks,
- struct envelope *ep, char *as_user)
+static const char *
+mailaddr_tag(const struct mailaddr *maddr)
{
- struct forward_req fwreq;
-
- fwreq.id = lks->id;
- fwreq.envelope = *ep;
- (void)strlcpy(fwreq.as_user, as_user, sizeof(fwreq.as_user));
- imsg_compose_event(env->sc_ievs[PROC_PARENT],
- IMSG_PARENT_FORWARD_OPEN, 0, 0, -1, &fwreq, sizeof(fwreq));
- ++lks->pending;
+ const char *tag;
+
+ if ((tag = strchr(maddr->user, '+'))) {
+ tag++;
+ while (*tag == '.')
+ tag++;
+ }
+
+ return (tag);
}
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 390bf7b88c5..c4a82b32f87 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.368 2012/09/26 19:52:20 eric Exp $ */
+/* $OpenBSD: smtpd.h,v 1.369 2012/09/27 18:57:25 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -350,7 +350,7 @@ struct delivery_mda {
};
struct delivery_mta {
- struct relayhost relay;
+ struct relayhost relay;
};
enum expand_type {
@@ -363,20 +363,25 @@ enum expand_type {
};
struct expandnode {
- RB_ENTRY(expandnode) entry;
- int done;
- enum expand_type type;
- char as_user[MAXLOGNAME];
+ RB_ENTRY(expandnode) entry;
+ TAILQ_ENTRY(expandnode) tq_entry;
+ enum expand_type type;
+ int sameuser;
+ struct rule *rule;
+ struct expandnode *parent;
+ unsigned int depth;
union {
- char user[MAXLOGNAME];
- char buffer[MAX_RULEBUFFER_LEN];
- struct mailaddr mailaddr;
- } u;
+ char user[MAXLOGNAME];
+ char buffer[MAX_RULEBUFFER_LEN];
+ struct mailaddr mailaddr;
+ } u;
};
struct expand {
- RB_HEAD(expandtree, expandnode) tree;
- char user[MAXLOGNAME];
+ RB_HEAD(expandtree, expandnode) tree;
+ TAILQ_HEAD(xnodes, expandnode) *queue;
+ struct rule *rule;
+ struct expandnode *parent;
};
#define SMTPD_ENVELOPE_VERSION 1
@@ -637,7 +642,6 @@ struct forward_req {
uint64_t id;
uint8_t status;
char as_user[MAXLOGNAME];
- struct envelope envelope;
};
enum dns_status {