summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2009-01-04 00:59:00 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2009-01-04 00:59:00 +0000
commit65d5eea4d2d2eea990e0af85286c7ffc76999b7a (patch)
tree5b818dd066767fb7b845263e7343a0f80bca9a9b
parent40a5535f8935f28641c54bc1be8601c57346cad6 (diff)
aliases/forwards expansion was not done correctly and a race could
cause delivery to happen before expansion is over, causing some of the recipients to never receive the mail. change how the mfa, lka, queue and smtp processes communicate to ensure smtp never receives an acknowledgment before ALL expanded envelopes are on disk. While at it, lka was doing work which belongs in mfa, fix that also. this is based on an idea from a talk with jacekm@, change not over but already better than what we had.
-rw-r--r--usr.sbin/smtpd/forward.c5
-rw-r--r--usr.sbin/smtpd/lka.c442
-rw-r--r--usr.sbin/smtpd/mfa.c131
-rw-r--r--usr.sbin/smtpd/queue.c97
-rw-r--r--usr.sbin/smtpd/smtp.c23
-rw-r--r--usr.sbin/smtpd/smtp_session.c13
-rw-r--r--usr.sbin/smtpd/smtpd.h10
7 files changed, 349 insertions, 372 deletions
diff --git a/usr.sbin/smtpd/forward.c b/usr.sbin/smtpd/forward.c
index 8289d9678cf..7613f729940 100644
--- a/usr.sbin/smtpd/forward.c
+++ b/usr.sbin/smtpd/forward.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: forward.c,v 1.7 2009/01/01 16:15:47 jacekm Exp $ */
+/* $OpenBSD: forward.c,v 1.8 2009/01/04 00:58:59 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -30,6 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "smtpd.h"
@@ -40,10 +41,10 @@ forwards_get(struct aliaseslist *aliases, char *username)
struct alias alias;
struct alias *aliasp;
char pathname[MAXPATHLEN];
- struct passwd *pw;
char *buf, *lbuf;
size_t len;
struct stat sb;
+ struct passwd *pw;
pw = getpwnam(username);
if (pw == NULL)
diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c
index 2e38c7aa619..5e50b653426 100644
--- a/usr.sbin/smtpd/lka.c
+++ b/usr.sbin/smtpd/lka.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka.c,v 1.12 2009/01/01 16:15:47 jacekm Exp $ */
+/* $OpenBSD: lka.c,v 1.13 2009/01/04 00:58:59 gilles Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -47,7 +47,6 @@ void lka_dispatch_runner(int, short, void *);
void lka_setup_events(struct smtpd *);
void lka_disable_events(struct smtpd *);
int lka_verify_mail(struct smtpd *, struct path *);
-int lka_verify_rcpt(struct smtpd *, struct path *, struct sockaddr_storage *);
int lka_resolve_mail(struct smtpd *, struct rule *, struct path *);
int lka_resolve_rcpt(struct smtpd *, struct rule *, struct path *);
int lka_forward_file(struct passwd *);
@@ -55,13 +54,15 @@ size_t getmxbyname(char *, char ***);
int lka_expand(char *, size_t, struct path *);
int aliases_exist(struct smtpd *, char *);
int aliases_get(struct smtpd *, struct aliaseslist *, char *);
-int lka_resolve_alias(struct smtpd *, struct imsgbuf *, struct message *, struct alias *);
+int lka_resolve_alias(struct smtpd *, struct path *, struct alias *);
int lka_parse_include(char *);
int forwards_get(struct aliaseslist *, char *);
int lka_check_source(struct smtpd *, struct map *, struct sockaddr_storage *);
int lka_match_mask(struct sockaddr_storage *, struct netaddr *);
int aliases_virtual_get(struct smtpd *, struct aliaseslist *, struct path *);
int aliases_virtual_exist(struct smtpd *, struct path *);
+int lka_resolve_path(struct smtpd *, struct path *);
+int lka_expand_aliases(struct smtpd *, struct aliaseslist *, struct path *);
void
lka_sig_handler(int sig, short event, void *p)
@@ -176,21 +177,67 @@ lka_dispatch_mfa(int sig, short event, void *p)
break;
}
case IMSG_LKA_RCPT: {
- struct submit_status *ss;
+ struct submit_status *ss;
+ struct alias *alias;
+ struct aliaseslist aliases;
+ struct message message;
+ int expret;
ss = imsg.data;
ss->code = 530;
- if (lka_verify_rcpt(env, &ss->u.path, &ss->ss))
- ss->code = 250;
- else if (ss->flags & F_MESSAGE_AUTHENTICATED) {
- log_debug("accepting for authenticated user");
- ss->code = 250;
+ if (! lka_resolve_path(env, &ss->u.path)) {
+ imsg_compose(ibuf, IMSG_LKA_RCPT, 0, 0, -1,
+ ss, sizeof(*ss));
}
+ else {
+ ss->code = 250;
- imsg_compose(ibuf, IMSG_LKA_RCPT, 0, 0, -1,
- ss, sizeof(*ss));
-
+ TAILQ_INIT(&aliases);
+
+ expret = lka_expand_aliases(env, &aliases, &ss->u.path);
+ if (expret < 0) {
+ log_debug("loop detected, rejecting recipient");
+ ss->code = 530;
+ imsg_compose(ibuf, IMSG_LKA_RCPT, 0, 0, -1,
+ ss, sizeof(*ss));
+ }
+ else if (expret == 0) {
+ log_debug("expansion resulted in empty list");
+ if (! (ss->u.path.flags & F_ACCOUNT)) {
+ ss->code = 530;
+ imsg_compose(ibuf, IMSG_LKA_RCPT, 0, 0, -1,
+ ss, sizeof(*ss));
+ }
+ else {
+ message = ss->msg;
+ message.recipient = ss->u.path;
+ imsg_compose(env->sc_ibufs[PROC_QUEUE],
+ IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, &message,
+ sizeof (struct message));
+ imsg_compose(env->sc_ibufs[PROC_QUEUE],
+ IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1, &message,
+ sizeof (struct message));
+ }
+ }
+ else {
+ log_debug("a list of aliases is available");
+ message = ss->msg;
+ while ((alias = TAILQ_FIRST(&aliases)) != NULL) {
+ bzero(&message.recipient, sizeof (struct path));
+ lka_resolve_alias(env, &message.recipient, alias);
+ imsg_compose(env->sc_ibufs[PROC_QUEUE],
+ IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, &message,
+ sizeof (struct message));
+
+ TAILQ_REMOVE(&aliases, alias, entry);
+ free(alias);
+ }
+ imsg_compose(env->sc_ibufs[PROC_QUEUE],
+ IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1, &message,
+ sizeof (struct message));
+ }
+ }
break;
}
default:
@@ -311,153 +358,6 @@ lka_dispatch_queue(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
-
- case IMSG_LKA_ALIAS: {
- struct message *messagep;
- struct alias *alias;
- struct alias *remalias;
- struct path *path;
- struct aliaseslist aliases;
- u_int8_t done = 0;
- size_t nbiterations = 5;
- int ret;
-
- messagep = imsg.data;
- path = &messagep->recipient;
-
- if (path->flags & F_EXPANDED)
- break;
-
- TAILQ_INIT(&aliases);
-
- if (path->flags & F_ALIAS) {
- ret = aliases_get(env, &aliases, path->user);
- }
-
- if (path->flags & F_VIRTUAL) {
- ret = aliases_virtual_get(env, &aliases, path);
- }
-
- if (! ret) {
- /*
- * Aliases could not be retrieved, this happens
- * if the aliases database is regenerated while
- * the message is being processed. It is not an
- * error necessarily so just ignore this and it
- * will be handled by the queue process.
- */
- imsg_compose(ibuf, IMSG_QUEUE_REMOVE_SUBMISSION, 0, 0, -1, messagep,
- sizeof(struct message));
- break;
- }
-
- /* First pass, figure out if some of the usernames that
- * are in the list are actually aliases and expand them
- * if they are. The resolution will be tried five times
- * at most with an early exit if list did not change in
- * a pass.
- */
- while (!done && nbiterations--) {
- done = 1;
- remalias = NULL;
- TAILQ_FOREACH(alias, &aliases, entry) {
- if (remalias) {
- TAILQ_REMOVE(&aliases, remalias, entry);
- free(remalias);
- remalias = NULL;
- }
-
- if (alias->type == ALIAS_ADDRESS) {
- if (aliases_virtual_get(env, &aliases, &alias->u.path)) {
- done = 0;
- remalias = alias;
- }
- }
-
- else if (alias->type == ALIAS_USERNAME) {
- if (aliases_get(env, &aliases, alias->u.username)) {
- done = 0;
- remalias = alias;
- }
- }
- }
- if (remalias) {
- TAILQ_REMOVE(&aliases, remalias, entry);
- free(remalias);
- remalias = NULL;
- }
- }
-
- /* Second pass, the list no longer contains aliases and
- * the message can be sent back to queue process with a
- * modified path.
- */
- TAILQ_FOREACH(alias, &aliases, entry) {
- struct message message = *messagep;
- lka_resolve_alias(env, ibuf, &message, alias);
- imsg_compose(ibuf, IMSG_LKA_ALIAS, 0, 0, -1,
- &message, sizeof(struct message));
- }
-
- imsg_compose(ibuf, IMSG_QUEUE_REMOVE_SUBMISSION, 0, 0, -1,
- messagep, sizeof(struct message));
-
- while ((alias = TAILQ_FIRST(&aliases))) {
- TAILQ_REMOVE(&aliases, alias, entry);
- free(alias);
- }
- break;
- }
-
- case IMSG_LKA_FORWARD: {
- struct message *messagep;
- struct aliaseslist aliases;
- struct alias *alias;
-
- messagep = imsg.data;
-
- /* this is the tenth time the message has been forwarded
- * internally, break out of the loop.
- */
- if (messagep->recipient.forwardcnt == 10) {
- imsg_compose(ibuf, IMSG_QUEUE_REMOVE_SUBMISSION, 0, 0, -1, messagep,
- sizeof(struct message));
- break;
- }
- messagep->recipient.forwardcnt++;
-
- TAILQ_INIT(&aliases);
- if (! forwards_get(&aliases, messagep->recipient.pw_name)) {
- messagep->recipient.flags |= F_NOFORWARD;
- imsg_compose(ibuf, IMSG_LKA_FORWARD, 0, 0, -1,
- messagep, sizeof(struct message));
- imsg_compose(ibuf, IMSG_QUEUE_REMOVE_SUBMISSION,
- 0, 0, -1, messagep, sizeof(struct message));
- break;
- }
-
- TAILQ_FOREACH(alias, &aliases, entry) {
- struct message message = *messagep;
- lka_resolve_alias(env, ibuf, &message, alias);
- if (strcmp(messagep->recipient.pw_name, alias->u.username) == 0) {
-
- message.recipient.flags |= F_FORWARDED;
- }
- imsg_compose(ibuf, IMSG_LKA_FORWARD, 0, 0, -1,
- &message, sizeof(struct message));
- }
-
- imsg_compose(ibuf, IMSG_QUEUE_REMOVE_SUBMISSION, 0, 0,
- -1, messagep, sizeof(struct message));
-
- while ((alias = TAILQ_FIRST(&aliases))) {
- TAILQ_REMOVE(&aliases, alias, entry);
- free(alias);
- }
-
- break;
- }
-
default:
log_debug("lka_dispatch_queue: unexpected imsg %d",
imsg.hdr.type);
@@ -711,58 +611,6 @@ lka_verify_mail(struct smtpd *env, struct path *path)
}
int
-lka_verify_rcpt(struct smtpd *env, struct path *path, struct sockaddr_storage *ss)
-{
- struct rule *r;
- struct cond *cond;
- struct map *map;
- struct mapel *me;
-
- TAILQ_FOREACH(r, env->sc_rules, r_entry) {
-
- TAILQ_FOREACH(cond, &r->r_conditions, c_entry) {
-
- if (cond->c_type == C_ALL) {
- path->rule = *r;
-
- if (! lka_check_source(env, r->r_sources, ss))
- return 0;
-
- if (r->r_action == A_MBOX ||
- r->r_action == A_MAILDIR) {
- return lka_resolve_rcpt(env, r, path);
- }
- return 1;
- }
-
- if (cond->c_type == C_DOM) {
-
- cond->c_match = map_find(env, cond->c_map);
- if (cond->c_match == NULL)
- fatal("lka failed to lookup map.");
-
- map = cond->c_match;
- TAILQ_FOREACH(me, &map->m_contents, me_entry) {
- if (strcasecmp(me->me_key.med_string,
- path->domain) == 0) {
- path->rule = *r;
- if (! lka_check_source(env, r->r_sources, ss))
- return 0;
-
- if (IS_MAILBOX(r->r_action) ||
- IS_EXT(r->r_action)) {
- return lka_resolve_rcpt(env, r, path);
- }
- return 1;
- }
- }
- }
- }
- }
- return 0;
-}
-
-int
lka_resolve_mail(struct smtpd *env, struct rule *rule, struct path *path)
{
char username[MAXLOGNAME];
@@ -943,41 +791,32 @@ lka_expand(char *buf, size_t len, struct path *path)
}
int
-lka_resolve_alias(struct smtpd *env, struct imsgbuf *ibuf, struct message *messagep, struct alias *alias)
+lka_resolve_alias(struct smtpd *env, struct path *path, struct alias *alias)
{
- struct path *rpath = &messagep->recipient;
-
- rpath->flags &= ~F_ALIAS;
- rpath->flags |= F_EXPANDED;
-
switch (alias->type) {
case ALIAS_USERNAME:
- if (strlcpy(rpath->pw_name, alias->u.username,
- sizeof(rpath->pw_name)) >= sizeof(rpath->pw_name))
+ log_debug("USERNAME: %s", alias->u.username);
+ if (strlcpy(path->pw_name, alias->u.username,
+ sizeof(path->pw_name)) >= sizeof(path->pw_name))
return 0;
- lka_verify_rcpt(env, rpath, NULL);
break;
case ALIAS_FILENAME:
- rpath->rule.r_action = A_FILENAME;
- strlcpy(rpath->u.filename, alias->u.filename, MAXPATHLEN);
+ log_debug("FILENAME: %s", alias->u.filename);
+ path->rule.r_action = A_FILENAME;
+ strlcpy(path->u.filename, alias->u.filename, MAXPATHLEN);
break;
case ALIAS_FILTER:
- rpath->rule.r_action = A_EXT;
- strlcpy(rpath->rule.r_value.command, alias->u.filter + 2, MAXPATHLEN);
- rpath->rule.r_value.command[strlen(rpath->rule.r_value.command) - 1] = '\0';
+ log_debug("FILTER: %s", alias->u.filter);
+ path->rule.r_action = A_EXT;
+ strlcpy(path->rule.r_value.command, alias->u.filter + 2, MAXPATHLEN);
+ path->rule.r_value.command[strlen(path->rule.r_value.command) - 1] = '\0';
break;
case ALIAS_ADDRESS:
- *rpath = alias->u.path;
- lka_verify_rcpt(env, rpath, NULL);
- if (IS_MAILBOX(rpath->rule.r_action) ||
- IS_EXT(rpath->rule.r_action))
- messagep->type = T_MDA_MESSAGE;
- else
- messagep->type = T_MTA_MESSAGE;
-
+ log_debug("ADDRESS: %s@%s", alias->u.path.user, alias->u.path.domain);
+ *path = alias->u.path;
break;
default:
/* ALIAS_INCLUDE cannot happen here, make gcc shut up */
@@ -987,68 +826,103 @@ lka_resolve_alias(struct smtpd *env, struct imsgbuf *ibuf, struct message *messa
}
int
-lka_check_source(struct smtpd *env, struct map *map, struct sockaddr_storage *ss)
+lka_expand_aliases(struct smtpd *env, struct aliaseslist *aliases, struct path *path)
{
- struct mapel *me;
+ u_int8_t done = 0;
+ size_t iterations = 5;
+ struct alias *rmalias = NULL;
+ int ret;
+ struct alias *alias;
+
+ log_debug("RESOLVE ALIASES/.FORWARD FILES");
+ log_debug("path->user: %s", path->user);
+ log_debug("path->domain: %s", path->domain);
+
+ if (path->flags & F_ACCOUNT)
+ ret = forwards_get(aliases, path->pw_name);
+ else if (path->flags & F_ALIAS)
+ ret = aliases_get(env, aliases, path->user);
+ else if (path->flags & F_VIRTUAL)
+ ret = aliases_virtual_get(env, aliases, path);
+
+ if (! ret)
+ return 0;
+
+
+ while (!done && iterations--) {
+ done = 1;
+ rmalias = NULL;
+ TAILQ_FOREACH(alias, aliases, entry) {
+ if (rmalias) {
+ TAILQ_REMOVE(aliases, rmalias, entry);
+ free(rmalias);
+ rmalias = NULL;
+ }
- if (ss == NULL) {
- /* This happens when caller is part of an internal
- * lookup (ie: alias resolved to a remote address)
- */
- return 1;
+ if (alias->type == ALIAS_ADDRESS) {
+ if (aliases_virtual_get(env, aliases, &alias->u.path)) {
+ done = 0;
+ rmalias = alias;
+ }
+ }
+
+ else if (alias->type == ALIAS_USERNAME) {
+ if (aliases_get(env, aliases, alias->u.username) ||
+ forwards_get(aliases, alias->u.username)) {
+ done = 0;
+ rmalias = alias;
+ }
+ }
+ }
+ if (rmalias) {
+ TAILQ_REMOVE(aliases, rmalias, entry);
+ free(rmalias);
+ rmalias = NULL;
+ }
}
- TAILQ_FOREACH(me, &map->m_contents, me_entry) {
-
- if (ss->ss_family != me->me_key.med_addr.ss.ss_family)
- continue;
-
- if (ss->ss_len == me->me_key.med_addr.ss.ss_len)
- continue;
+ /* Loop detected, empty list */
+ if (!done) {
+ while ((alias = TAILQ_FIRST(aliases)) != NULL) {
+ TAILQ_REMOVE(aliases, alias, entry);
+ free(alias);
+ }
+ return -1;
+ }
- if (lka_match_mask(ss, &me->me_key.med_addr))
- return 1;
+ if (TAILQ_FIRST(aliases) == NULL)
+ return 0;
- }
- return 0;
+ return 1;
}
int
-lka_match_mask(struct sockaddr_storage *ss, struct netaddr *ssmask)
+lka_resolve_path(struct smtpd *env, struct path *path)
{
- if (ss->ss_family == AF_INET) {
- struct sockaddr_in *ssin = (struct sockaddr_in *)ss;
- struct sockaddr_in *ssinmask = (struct sockaddr_in *)&ssmask->ss;
-
- if ((ssin->sin_addr.s_addr & ssinmask->sin_addr.s_addr) ==
- ssinmask->sin_addr.s_addr)
- return (1);
- return (0);
- }
+ char username[MAXLOGNAME];
+ struct passwd *pw;
+ char *p;
- if (ss->ss_family == AF_INET6) {
- struct in6_addr *in;
- struct in6_addr *inmask;
- struct in6_addr mask;
- int i;
-
- bzero(&mask, sizeof(mask));
- for (i = 0; i < (128 - ssmask->masked) / 8; i++)
- mask.s6_addr[i] = 0xff;
- i = ssmask->masked % 8;
- if (i)
- mask.s6_addr[ssmask->masked / 8] = 0xff00 >> i;
-
- in = &((struct sockaddr_in6 *)ss)->sin6_addr;
- inmask = &((struct sockaddr_in6 *)&ssmask->ss)->sin6_addr;
-
- for (i = 0; i < 16; i++) {
- if ((in->s6_addr[i] & mask.s6_addr[i]) !=
- inmask->s6_addr[i])
- return (0);
- }
- return (1);
+ (void)strlcpy(username, path->user, MAXLOGNAME);
+
+ for (p = &username[0]; *p != '\0' && *p != '+'; ++p)
+ *p = tolower((int)*p);
+ *p = '\0';
+
+ if (aliases_virtual_exist(env, path))
+ path->flags |= F_VIRTUAL;
+ else if (aliases_exist(env, username))
+ path->flags |= F_ALIAS;
+ else {
+ path->flags |= F_ACCOUNT;
+ pw = getpwnam(username);
+ if (pw == NULL)
+ return 0;
+ (void)strlcpy(path->pw_name, pw->pw_name, MAXLOGNAME);
+ if (lka_expand(path->rule.r_value.path, MAXPATHLEN, path) >=
+ MAXPATHLEN)
+ return 0;
}
- return (0);
+ return 1;
}
diff --git a/usr.sbin/smtpd/mfa.c b/usr.sbin/smtpd/mfa.c
index 2be0f399fa9..18d6fcc7d21 100644
--- a/usr.sbin/smtpd/mfa.c
+++ b/usr.sbin/smtpd/mfa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfa.c,v 1.5 2009/01/01 16:15:47 jacekm Exp $ */
+/* $OpenBSD: mfa.c,v 1.6 2009/01/04 00:58:59 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -23,10 +23,14 @@
#include <sys/param.h>
#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#include <event.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <strings.h>
#include <unistd.h>
#include "smtpd.h"
@@ -40,6 +44,10 @@ void mfa_setup_events(struct smtpd *);
void mfa_disable_events(struct smtpd *);
void mfa_timeout(int, short, void *);
+int mfa_check_rcpt(struct smtpd *, struct path *, struct sockaddr_storage *);
+int mfa_check_source(struct smtpd *, struct map *, struct sockaddr_storage *);
+int mfa_match_mask(struct sockaddr_storage *, struct netaddr *);
+
void
mfa_sig_handler(int sig, short event, void *p)
{
@@ -156,14 +164,24 @@ mfa_dispatch_smtp(int sig, short event, void *p)
mr = imsg.data;
log_debug("mfa_dispatch_smtp: testing forward path");
ss.id = mr->id;
- ss.code = 250;
+ ss.code = 530;
ss.u.path = mr->path;
ss.ss = mr->ss;
+ ss.msg = mr->msg;
ss.flags = mr->flags;
- imsg_compose(env->sc_ibufs[PROC_LKA], IMSG_LKA_RCPT, 0,
- 0, -1, &ss, sizeof(ss));
+ if (! mfa_check_rcpt(env, &ss.u.path, &ss.ss) &&
+ ! (ss.flags & F_MESSAGE_AUTHENTICATED)) {
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_MFA_RCPT, 0,
+ 0, -1, &ss, sizeof(ss));
+ }
+ else {
+ ss.code = 250;
+ imsg_compose(env->sc_ibufs[PROC_LKA], IMSG_LKA_RCPT, 0,
+ 0, -1, &ss, sizeof(ss));
+ }
+
break;
}
default:
@@ -352,4 +370,109 @@ msg_cmp(struct message *m1, struct message *m2)
return (0);
}
+int
+mfa_check_rcpt(struct smtpd *env, struct path *path, struct sockaddr_storage *ss)
+{
+ struct rule *r;
+ struct cond *cond;
+ struct map *map;
+ struct mapel *me;
+
+ TAILQ_FOREACH(r, env->sc_rules, r_entry) {
+ if (! mfa_check_source(env, r->r_sources, ss))
+ continue;
+
+ log_debug("client authorized");
+ TAILQ_FOREACH(cond, &r->r_conditions, c_entry) {
+ if (cond->c_type == C_ALL) {
+ path->rule = *r;
+ return 1;
+ }
+
+ if (cond->c_type == C_DOM) {
+ cond->c_match = map_find(env, cond->c_map);
+ if (cond->c_match == NULL)
+ fatal("mfa failed to lookup map.");
+
+ map = cond->c_match;
+ TAILQ_FOREACH(me, &map->m_contents, me_entry) {
+ if (strcasecmp(me->me_key.med_string,
+ path->domain) == 0) {
+ path->rule = *r;
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int
+mfa_check_source(struct smtpd *env, struct map *map, struct sockaddr_storage *ss)
+{
+ struct mapel *me;
+
+ if (ss == NULL) {
+ /* This happens when caller is part of an internal
+ * lookup (ie: alias resolved to a remote address)
+ */
+ return 1;
+ }
+
+ TAILQ_FOREACH(me, &map->m_contents, me_entry) {
+
+ if (ss->ss_family != me->me_key.med_addr.ss.ss_family)
+ continue;
+
+ if (ss->ss_len == me->me_key.med_addr.ss.ss_len)
+ continue;
+
+ if (mfa_match_mask(ss, &me->me_key.med_addr))
+ return 1;
+
+ }
+ return 0;
+}
+
+int
+mfa_match_mask(struct sockaddr_storage *ss, struct netaddr *ssmask)
+{
+ if (ss->ss_family == AF_INET) {
+ struct sockaddr_in *ssin = (struct sockaddr_in *)ss;
+ struct sockaddr_in *ssinmask = (struct sockaddr_in *)&ssmask->ss;
+
+ if ((ssin->sin_addr.s_addr & ssinmask->sin_addr.s_addr) ==
+ ssinmask->sin_addr.s_addr)
+ return (1);
+ return (0);
+ }
+
+ if (ss->ss_family == AF_INET6) {
+ struct in6_addr *in;
+ struct in6_addr *inmask;
+ struct in6_addr mask;
+ int i;
+
+ bzero(&mask, sizeof(mask));
+ for (i = 0; i < (128 - ssmask->masked) / 8; i++)
+ mask.s6_addr[i] = 0xff;
+ i = ssmask->masked % 8;
+ if (i)
+ mask.s6_addr[ssmask->masked / 8] = 0xff00 >> i;
+
+ in = &((struct sockaddr_in6 *)ss)->sin6_addr;
+ inmask = &((struct sockaddr_in6 *)&ssmask->ss)->sin6_addr;
+
+ for (i = 0; i < 16; i++) {
+ if ((in->s6_addr[i] & mask.s6_addr[i]) !=
+ inmask->s6_addr[i])
+ return (0);
+ }
+ return (1);
+ }
+
+ return (0);
+}
+
SPLAY_GENERATE(msgtree, message, nodes, msg_cmp);
diff --git a/usr.sbin/smtpd/queue.c b/usr.sbin/smtpd/queue.c
index 1ee80863d01..b8ef27480d6 100644
--- a/usr.sbin/smtpd/queue.c
+++ b/usr.sbin/smtpd/queue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: queue.c,v 1.42 2009/01/02 22:08:02 jacekm Exp $ */
+/* $OpenBSD: queue.c,v 1.43 2009/01/04 00:58:59 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -178,55 +178,6 @@ queue_dispatch_smtp(int sig, short event, void *p)
queue_delete_incoming_message(messagep->message_id);
break;
}
- case IMSG_QUEUE_SUBMIT_ENVELOPE: {
- struct message *messagep;
- struct submit_status ss;
-
- messagep = imsg.data;
- messagep->id = queue_generate_id();
- ss.id = messagep->session_id;
- ss.code = 250;
- ss.u.path = messagep->recipient;
-
- if (IS_MAILBOX(messagep->recipient.rule.r_action) ||
- IS_EXT(messagep->recipient.rule.r_action))
- messagep->type = T_MDA_MESSAGE;
- else
- messagep->type = T_MTA_MESSAGE;
-
- /* Write to disk */
- if (! queue_record_incoming_envelope(messagep)) {
- ss.code = 421;
- imsg_compose(ibuf, IMSG_QUEUE_SUBMIT_ENVELOPE,
- 0, 0, -1, &ss, sizeof(ss));
- break;
- }
-
- imsg_compose(ibuf, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1,
- &ss, sizeof(ss));
-
- if (messagep->type & T_MTA_MESSAGE) {
- break;
- }
-
- if ((messagep->recipient.flags & (F_ALIAS|F_VIRTUAL)) == 0) {
- /* not an alias, perform ~/.forward resolution */
- imsg_compose(env->sc_ibufs[PROC_LKA],
- IMSG_LKA_FORWARD, 0, 0, -1, messagep,
- sizeof(struct message));
- break;
- }
-
- /* Recipient is an alias, proceed to resolving it.
- * ~/.forward will be handled by the IMSG_LKA_ALIAS
- * dispatch case.
- */
- imsg_compose(env->sc_ibufs[PROC_LKA],
- IMSG_LKA_ALIAS, 0, 0, -1, messagep,
- sizeof (struct message));
-
- break;
- }
case IMSG_QUEUE_COMMIT_MESSAGE: {
struct message *messagep;
struct submit_status ss;
@@ -420,36 +371,41 @@ queue_dispatch_lka(int sig, short event, void *p)
switch (imsg.hdr.type) {
- case IMSG_LKA_ALIAS: {
- struct message *messagep;
+ case IMSG_QUEUE_SUBMIT_ENVELOPE: {
+ struct message *messagep;
+ struct submit_status ss;
messagep = imsg.data;
messagep->id = queue_generate_id();
- messagep->batch_id = 0;
- queue_record_incoming_envelope(messagep);
+ ss.id = messagep->session_id;
- if (messagep->type & T_MDA_MESSAGE) {
- imsg_compose(ibuf, IMSG_LKA_FORWARD, 0, 0, -1,
- messagep, sizeof(struct message));
- }
- break;
- }
+ if (IS_MAILBOX(messagep->recipient.rule.r_action) ||
+ IS_EXT(messagep->recipient.rule.r_action))
+ messagep->type = T_MDA_MESSAGE;
+ else
+ messagep->type = T_MTA_MESSAGE;
- case IMSG_LKA_FORWARD: {
- struct message *messagep;
+ /* Write to disk */
+ if (! queue_record_incoming_envelope(messagep)) {
+ ss.code = 421;
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_QUEUE_TEMPFAIL,
+ 0, 0, -1, &ss, sizeof(ss));
+ break;
+ }
- messagep = (struct message *)imsg.data;
- messagep->id = queue_generate_id();
- messagep->batch_id = 0;
- queue_record_incoming_envelope(messagep);
break;
}
- case IMSG_QUEUE_REMOVE_SUBMISSION: {
- struct message *messagep;
+ case IMSG_QUEUE_COMMIT_ENVELOPES: {
+ struct message *messagep;
+ struct submit_status ss;
- messagep = (struct message *)imsg.data;
- queue_remove_incoming_envelope(messagep);
+ messagep = imsg.data;
+ ss.id = messagep->session_id;
+ ss.code = 250;
+
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_QUEUE_COMMIT_ENVELOPES,
+ 0, 0, -1, &ss, sizeof(ss));
break;
}
@@ -893,6 +849,7 @@ queue_update_envelope(struct message *messagep)
fatal("queue_update_envelope: open");
if (flock(fileno(fp), LOCK_EX) == -1)
fatal("queue_update_envelope: flock");
+
if (fwrite(messagep, sizeof(struct message), 1, fp) != 1) {
if (errno == ENOSPC)
return 0;
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c
index 80e24c3cce6..a9bff9a0a78 100644
--- a/usr.sbin/smtpd/smtp.c
+++ b/usr.sbin/smtpd/smtp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp.c,v 1.14 2009/01/01 16:15:47 jacekm Exp $ */
+/* $OpenBSD: smtp.c,v 1.15 2009/01/04 00:58:59 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -410,7 +410,26 @@ smtp_dispatch_queue(int sig, short event, void *p)
break;
}
- case IMSG_QUEUE_SUBMIT_ENVELOPE:
+ case IMSG_QUEUE_TEMPFAIL: {
+ struct submit_status *ss;
+ struct session *s;
+ struct session key;
+
+ log_debug("smtp_dispatch_queue: queue acknownedged a temporary failure");
+ ss = imsg.data;
+ key.s_id = ss->id;
+ key.s_msg.id = ss->id;
+
+ s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key);
+ if (s == NULL) {
+ /* Session was removed while we were waiting for the message */
+ break;
+ }
+ s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
+ break;
+ }
+
+ case IMSG_QUEUE_COMMIT_ENVELOPES:
case IMSG_QUEUE_COMMIT_MESSAGE: {
struct submit_status *ss;
struct session *s;
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index e904961b471..da5a61dc90b 100644
--- a/usr.sbin/smtpd/smtp_session.c
+++ b/usr.sbin/smtpd/smtp_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp_session.c,v 1.38 2009/01/01 16:15:47 jacekm Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.39 2009/01/04 00:58:59 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -460,6 +460,7 @@ session_rfc5321_rcpt_handler(struct session *s, char *args)
mr.id = s->s_msg.id;
s->s_state = S_RCPTREQUEST;
mr.ss = s->s_ss;
+ mr.msg = s->s_msg;
if (s->s_flags & F_AUTHENTICATED) {
@@ -631,7 +632,8 @@ session_pickup(struct session *s, struct submit_status *ss)
bufferevent_enable(s->s_bev, EV_READ);
- if (ss != NULL && ss->code == 421)
+ if ((ss != NULL && ss->code == 421) ||
+ (s->s_msg.status & S_MESSAGE_TEMPFAILURE))
goto tempfail;
switch (s->s_state) {
@@ -689,14 +691,9 @@ session_pickup(struct session *s, struct submit_status *ss)
s->s_state = S_RCPT;
s->s_msg.rcptcount++;
s->s_msg.recipient = ss->u.path;
- imsg_compose(s->s_env->sc_ibufs[PROC_QUEUE],
- IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, &s->s_msg,
- sizeof(s->s_msg));
- bufferevent_disable(s->s_bev, EV_READ);
- break;
+ session_respond(s, "%d Recipient ok", ss->code);
case S_RCPT:
- session_respond(s, "%d Recipient ok", ss->code);
break;
case S_DATAREQUEST:
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index fadadadadce..c77de671eb2 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.37 2008/12/27 17:36:37 jacekm Exp $ */
+/* $OpenBSD: smtpd.h,v 1.38 2009/01/04 00:58:59 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -174,8 +174,10 @@ enum imsg_type {
IMSG_QUEUE_CREATE_MESSAGE,
IMSG_QUEUE_SUBMIT_ENVELOPE,
+ IMSG_QUEUE_COMMIT_ENVELOPES,
IMSG_QUEUE_REMOVE_MESSAGE,
IMSG_QUEUE_COMMIT_MESSAGE,
+ IMSG_QUEUE_TEMPFAIL,
IMSG_QUEUE_REMOVE_SUBMISSION,
IMSG_QUEUE_MESSAGE_UPDATE,
@@ -191,6 +193,7 @@ enum imsg_type {
IMSG_PARENT_MAILBOX_RENAME,
IMSG_PARENT_AUTHENTICATE
+
};
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
@@ -332,7 +335,8 @@ enum path_flags {
F_VIRTUAL = 0x2,
F_EXPANDED = 0x4,
F_NOFORWARD = 0x8,
- F_FORWARDED = 0x10
+ F_FORWARDED = 0x10,
+ F_ACCOUNT = 0x20,
};
struct path {
@@ -614,6 +618,7 @@ struct submit_status {
} u;
enum message_flags flags;
struct sockaddr_storage ss;
+ struct message msg;
};
struct message_recipient {
@@ -621,6 +626,7 @@ struct message_recipient {
struct sockaddr_storage ss;
enum message_flags flags;
struct path path;
+ struct message msg;
};