diff options
author | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2009-02-18 22:39:13 +0000 |
---|---|---|
committer | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2009-02-18 22:39:13 +0000 |
commit | 6f6865a18f21f0e17a7d198d39a86162292fa969 (patch) | |
tree | 982e8dd326522574479c819d8b7ca29b2abb06ff | |
parent | da8a9fe09342881e691db6ec87d6f0aa33c59f98 (diff) |
- add basic syntax checking to mfa
- decline source routing at MAIL FROM, strip at RCPT TO
ok gilles@
-rw-r--r-- | usr.sbin/smtpd/mfa.c | 78 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 4 | ||||
-rw-r--r-- | usr.sbin/smtpd/util.c | 47 |
3 files changed, 112 insertions, 17 deletions
diff --git a/usr.sbin/smtpd/mfa.c b/usr.sbin/smtpd/mfa.c index 21f2498ed58..1ae047dc44b 100644 --- a/usr.sbin/smtpd/mfa.c +++ b/usr.sbin/smtpd/mfa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mfa.c,v 1.13 2009/02/18 16:42:30 jacekm Exp $ */ +/* $OpenBSD: mfa.c,v 1.14 2009/02/18 22:39:12 jacekm Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -26,6 +26,7 @@ #include <netinet/in.h> #include <arpa/inet.h> +#include <ctype.h> #include <event.h> #include <pwd.h> #include <stdio.h> @@ -45,11 +46,14 @@ void mfa_setup_events(struct smtpd *); void mfa_disable_events(struct smtpd *); void mfa_timeout(int, short, void *); +void mfa_test_mail(struct smtpd *, struct message *, int); void mfa_test_rcpt(struct smtpd *, struct message_recipient *, int); int mfa_ruletest_rcpt(struct smtpd *, struct path *, struct sockaddr_storage *); int mfa_check_source(struct map *, struct sockaddr_storage *); int mfa_match_mask(struct sockaddr_storage *, struct netaddr *); +int strip_source_route(char *, size_t); + void mfa_sig_handler(int sig, short event, void *p) { @@ -145,20 +149,9 @@ mfa_dispatch_smtp(int sig, short event, void *p) break; switch (imsg.hdr.type) { - case IMSG_MFA_MAIL: { - struct message *m; - struct submit_status ss; - - m = imsg.data; - log_debug("mfa_dispatch_smtp: testing return path"); - ss.id = m->id; - ss.code = 250; - ss.u.path = m->sender; - - imsg_compose(env->sc_ibufs[PROC_LKA], IMSG_LKA_MAIL, 0, - 0, -1, &ss, sizeof(ss)); + case IMSG_MFA_MAIL: + mfa_test_mail(env, imsg.data, PROC_SMTP); break; - } case IMSG_MFA_RCPT: mfa_test_rcpt(env, imsg.data, PROC_SMTP); break; @@ -406,6 +399,41 @@ msg_cmp(struct message *m1, struct message *m2) } void +mfa_test_mail(struct smtpd *env, struct message *m, int sender) +{ + struct submit_status ss; + + ss.id = m->id; + ss.code = 530; + ss.u.path = m->sender; + + if (strip_source_route(ss.u.path.user, sizeof(ss.u.path.user))) + goto refuse; + + if (! valid_localpart(ss.u.path.user) || + ! valid_domainpart(ss.u.path.domain)) { + /* + * "MAIL FROM:<>" is the exception we allow. + */ + if (!(ss.u.path.user[0] == '\0' && ss.u.path.domain[0] == '\0')) + goto refuse; + } + + /* Current policy is to allow all well-formed addresses. */ + goto accept; + +refuse: + imsg_compose(env->sc_ibufs[sender], IMSG_MFA_MAIL, 0, 0, -1, &ss, + sizeof(ss)); + return; + +accept: + ss.code = 250; + imsg_compose(env->sc_ibufs[PROC_LKA], IMSG_LKA_MAIL, 0, + 0, -1, &ss, sizeof(ss)); +} + +void mfa_test_rcpt(struct smtpd *env, struct message_recipient *mr, int sender) { struct submit_status ss; @@ -418,12 +446,19 @@ mfa_test_rcpt(struct smtpd *env, struct message_recipient *mr, int sender) ss.flags = mr->flags; + strip_source_route(ss.u.path.user, sizeof(ss.u.path.user)); + + if (! valid_localpart(ss.u.path.user) || + ! valid_domainpart(ss.u.path.domain)) + goto refuse; + if (sender == PROC_SMTP && (ss.flags & F_MESSAGE_AUTHENTICATED)) goto accept; if (mfa_ruletest_rcpt(env, &ss.u.path, &ss.ss)) goto accept; +refuse: imsg_compose(env->sc_ibufs[sender], IMSG_MFA_RCPT, 0, 0, -1, &ss, sizeof(ss)); return; @@ -539,4 +574,19 @@ mfa_match_mask(struct sockaddr_storage *ss, struct netaddr *ssmask) return (0); } +int +strip_source_route(char *buf, size_t len) +{ + char *p; + + p = strchr(buf, ':'); + if (p != NULL) { + p++; + memmove(buf, p, strlen(p) + 1); + return 1; + } + + return 0; +} + SPLAY_GENERATE(msgtree, message, nodes, msg_cmp); diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index 209cc55436f..cdbb828d1b9 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.72 2009/02/17 23:43:57 jacekm Exp $ */ +/* $OpenBSD: smtpd.h,v 1.73 2009/02/18 22:39:12 jacekm Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -897,3 +897,5 @@ struct passwd *safe_getpwnam(const char *); struct passwd *safe_getpwuid(uid_t); int hostname_match(char *, char *); int recipient_to_path(struct path *, char *); +int valid_localpart(char *); +int valid_domainpart(char *); diff --git a/usr.sbin/smtpd/util.c b/usr.sbin/smtpd/util.c index 743ff47dc71..687b3267fca 100644 --- a/usr.sbin/smtpd/util.c +++ b/usr.sbin/smtpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.10 2009/01/28 12:56:46 jacekm Exp $ */ +/* $OpenBSD: util.c,v 1.11 2009/02/18 22:39:12 jacekm Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -120,7 +120,7 @@ recipient_to_path(struct path *path, char *recipient) char *hostname; username = recipient; - hostname = strchr(username, '@'); + hostname = strrchr(username, '@'); if (username[0] == '\0') { *path->user = '\0'; @@ -146,3 +146,46 @@ recipient_to_path(struct path *path, char *recipient) return 1; } + +int +valid_localpart(char *s) +{ +#define IS_ATEXT(c) (isalnum(c) || strchr("!#$%&'*+-/=?^_`{|}~", (c))) +nextatom: + if (! IS_ATEXT(*s) || *s == '\0') + return 0; + while (*(++s) != '\0') { + if (*s == '.') + break; + if (IS_ATEXT(*s)) + continue; + return 0; + } + if (*s == '.') { + s++; + goto nextatom; + } + return 1; +} + +int +valid_domainpart(char *s) +{ +nextsub: + if (!isalnum(*s)) + return 0; + while (*(++s) != '\0') { + if (*s == '.') + break; + if (isalnum(*s) || *s == '-') + continue; + return 0; + } + if (s[-1] == '-') + return 0; + if (*s == '.') { + s++; + goto nextsub; + } + return 1; +} |