summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2009-11-05 23:30:02 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2009-11-05 23:30:02 +0000
commitbc1a437cc2bfd454a2a92a61e839d7ef366335b1 (patch)
tree8719aa1755ae95f2e179f4e85279380cff0dee81 /usr.sbin
parent0929a0632ee1a8c9fba681cdfc711fcdeb4e5acf (diff)
evbuffer_readline() assumes end of line to be \r, \n, \r\n, \n\r or \r\r.
smtp protocol expects lines to end with \r\n. if a client sends a very long line which is unfortunately read up to \r, evbuffer_readline() will return the line, then will detect another line when the buffer is filled again and starts with \n, returning again with an empty line. this is a bug which trigger very rarely and usually shows up as an empty line in the middle of headers, causing all subsequent headers to appear as part of the body to most mail user agents. upstream fixes this with evbuffer_readln() in version 2.0 of libevent, a mail will be sent to see if they can backport it, meanwhile we fix it by introducing evbuffer_readln_crlf(). discussed with and ok jacekm@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/smtpd/smtp_session.c40
1 files changed, 37 insertions, 3 deletions
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index 928041e2650..ae32db2413d 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.122 2009/10/19 20:48:13 gilles Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.123 2009/11/05 23:30:01 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -74,6 +74,7 @@ void session_respond_delayed(int, short, void *);
int session_set_path(struct path *, char *);
void session_imsg(struct session *, enum smtp_proc_type,
enum imsg_type, u_int32_t, pid_t, int, void *, u_int16_t);
+char *evbuffer_readln_crlf(struct evbuffer *);
struct session_cmd {
char *name;
@@ -996,7 +997,7 @@ session_readline(struct session *s)
size_t nr;
nr = EVBUFFER_LENGTH(s->s_bev->input);
- line = evbuffer_readline(s->s_bev->input);
+ line = evbuffer_readln_crlf(s->s_bev->input);
if (line == NULL) {
if (EVBUFFER_LENGTH(s->s_bev->input) > SMTP_LINE_MAX) {
session_respond(s, "500 Line too long");
@@ -1018,7 +1019,7 @@ session_readline(struct session *s)
}
if ((s->s_state != S_DATACONTENT || strcmp(line, ".") == 0) &&
- (line2 = evbuffer_readline(s->s_bev->input)) != NULL) {
+ (line2 = evbuffer_readln_crlf(s->s_bev->input)) != NULL) {
session_respond(s, "500 Pipelining unsupported");
s->s_env->stats->smtp.toofast++;
s->s_flags |= F_QUIT;
@@ -1165,4 +1166,37 @@ session_imsg(struct session *s, enum smtp_proc_type proc, enum imsg_type type,
datalen);
}
+char *
+evbuffer_readln_crlf(struct evbuffer *buffer)
+{
+ u_char *data = EVBUFFER_DATA(buffer);
+ size_t len = EVBUFFER_LENGTH(buffer);
+ char *line;
+ unsigned int i, j;
+
+ for (i = 0; i < len; ++i) {
+ if (data[i] == '\n')
+ break;
+ }
+
+ if (i == len)
+ return NULL;
+
+ j = i;
+ if (i != 0 && data[i - 1] == '\r')
+ --j;
+
+ line = calloc(j + 1, 1);
+ if (line == NULL)
+ fatal("calloc");
+
+ if (j != 0)
+ memcpy(line, data, j);
+
+ evbuffer_drain(buffer, i + 1);
+
+ return (line);
+}
+
+
SPLAY_GENERATE(sessiontree, session, s_nodes, session_cmp);