summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacek Masiulaniec <jacekm@cvs.openbsd.org>2009-02-18 22:39:13 +0000
committerJacek Masiulaniec <jacekm@cvs.openbsd.org>2009-02-18 22:39:13 +0000
commit6f6865a18f21f0e17a7d198d39a86162292fa969 (patch)
tree982e8dd326522574479c819d8b7ca29b2abb06ff
parentda8a9fe09342881e691db6ec87d6f0aa33c59f98 (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.c78
-rw-r--r--usr.sbin/smtpd/smtpd.h4
-rw-r--r--usr.sbin/smtpd/util.c47
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;
+}