diff options
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/smtpd/forward.c | 5 | ||||
-rw-r--r-- | usr.sbin/smtpd/lka.c | 442 | ||||
-rw-r--r-- | usr.sbin/smtpd/mfa.c | 131 | ||||
-rw-r--r-- | usr.sbin/smtpd/queue.c | 97 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp.c | 23 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp_session.c | 13 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 10 |
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; }; |