summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd
diff options
context:
space:
mode:
authorJacek Masiulaniec <jacekm@cvs.openbsd.org>2008-12-18 23:38:13 +0000
committerJacek Masiulaniec <jacekm@cvs.openbsd.org>2008-12-18 23:38:13 +0000
commitcf571d3248d7e58bd50da6ba9ab2dad934f46497 (patch)
tree94ad93be163956e76185a556fb81e7131f698209 /usr.sbin/smtpd
parent8e5a9b81108dd9b24965d7429111649379ce8442 (diff)
Check fwrite return code at DATA stage.
Add basic line length checking, as required by rfc. It is no longer required to disable EV_READ upon evbuffer_readline failure. ok gilles@
Diffstat (limited to 'usr.sbin/smtpd')
-rw-r--r--usr.sbin/smtpd/smtp_session.c105
-rw-r--r--usr.sbin/smtpd/smtpd.h5
2 files changed, 70 insertions, 40 deletions
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index d6f5f560223..fd695015849 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.28 2008/12/18 15:11:21 jacekm Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.29 2008/12/18 23:38:12 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -669,57 +669,30 @@ session_read(struct bufferevent *bev, void *p)
char *line;
char *ep;
char *args;
+ size_t nr;
read:
s->s_tm = time(NULL);
+ nr = EVBUFFER_LENGTH(bev->input);
line = evbuffer_readline(bev->input);
- if (line == NULL) {
- if (s->s_state != S_DATACONTENT)
- bufferevent_disable(s->s_bev, EV_READ);
+ if (line == NULL)
return;
- }
+ nr -= EVBUFFER_LENGTH(bev->input);
if (s->s_state == S_DATACONTENT) {
- /*log_debug("content: %s", line);*/
- if (strcmp(line, ".") == 0) {
- s->s_state = S_DONE;
- fclose(s->s_msg.datafp);
- s->s_msg.datafp = NULL;
-
- bufferevent_disable(s->s_bev, EV_READ);
-
- if (s->s_msg.status & S_MESSAGE_PERMFAILURE) {
- session_respond(s, "554 Transaction failed");
- free(line);
- return;
- }
- session_msg_submit(s);
+ if (session_read_data(s, line, nr)) {
free(line);
return;
- } else {
- size_t i;
- size_t len;
-
- len = strlen(line);
- fwrite(line, 1, len, s->s_msg.datafp);
- fwrite("\n", 1, 1, s->s_msg.datafp);
- fflush(s->s_msg.datafp);
-
- if (! (s->s_flags & F_8BITMIME)) {
- for (i = 0; i < len; ++i) {
- if (line[i] & 0x80) {
- s->s_msg.status |= S_MESSAGE_PERMFAILURE;
- strlcpy(s->s_msg.session_errorline,
- "8BIT data transfered over 7BIT limited channel",
- sizeof s->s_msg.session_errorline);
- }
- }
- }
- free(line);
}
+ free(line);
goto read;
}
+ if (nr > SMTP_CMDLINE_MAX) {
+ session_respond(s, "500 Line too long");
+ return;
+ }
+
if ((ep = strchr(line, ':')) == NULL)
ep = strchr(line, ' ');
if (ep != NULL) {
@@ -735,6 +708,59 @@ read:
return;
}
+int
+session_read_data(struct session *s, char *line, size_t nread)
+{
+ size_t len = strlen(line);
+ size_t i;
+
+ if (strcmp(line, ".") == 0) {
+ if (fclose(s->s_msg.datafp))
+ s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
+ s->s_msg.datafp = NULL;
+
+ if (s->s_msg.status & S_MESSAGE_PERMFAILURE) {
+ session_respond(s, "554 Transaction failed");
+ s->s_state = S_HELO;
+ } else if (s->s_msg.status & S_MESSAGE_TEMPFAILURE) {
+ session_respond(s, "421 Temporary failure");
+ s->s_state = S_HELO;
+ } else {
+ session_msg_submit(s);
+ s->s_state = S_DONE;
+ }
+
+ return 1;
+ }
+
+ /* Don't waste resources on message if it's going to bin anyway. */
+ if (s->s_msg.status & (S_MESSAGE_PERMFAILURE|S_MESSAGE_TEMPFAILURE))
+ return 0;
+
+ if (nread > SMTP_TEXTLINE_MAX) {
+ s->s_msg.status |= S_MESSAGE_PERMFAILURE;
+ return 0;
+ }
+
+ if (fwrite(line, len, 1, s->s_msg.datafp) != 1 ||
+ fwrite("\n", 1, 1, s->s_msg.datafp) != 1) {
+ s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
+ return 0;
+ }
+
+ if (! (s->s_flags & F_8BITMIME)) {
+ for (i = 0; i < len; ++i)
+ if (line[i] & 0x80)
+ break;
+ if (i != len) {
+ s->s_msg.status |= S_MESSAGE_PERMFAILURE;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
void
session_write(struct bufferevent *bev, void *p)
{
@@ -800,6 +826,7 @@ session_msg_submit(struct session *s)
imsg_compose(s->s_env->sc_ibufs[PROC_QUEUE],
IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, &s->s_msg,
sizeof(s->s_msg));
+ bufferevent_disable(s->s_bev, EV_READ);
s->s_state = S_DONE;
}
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 106b894dde5..804ac1dfd02 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.28 2008/12/17 18:47:37 jacekm Exp $ */
+/* $OpenBSD: smtpd.h,v 1.29 2008/12/18 23:38:12 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -65,6 +65,9 @@
/* number of MX records to lookup */
#define MXARRAYSIZE 5
+/* rfc5321 limits */
+#define SMTP_TEXTLINE_MAX 1000
+#define SMTP_CMDLINE_MAX 512
#define F_STARTTLS 0x01
#define F_SSMTP 0x02