summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2011-08-31 18:56:31 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2011-08-31 18:56:31 +0000
commit765bc1b5fffe5b0e2f82f824bc4a91bba12073cc (patch)
tree3c456ecef8ff07cd9845866125edf40ae731e6a7
parent88fbf193fd2f3dc7446ff2da1e7d9f50366a84d1 (diff)
add support for per-line DATA callbacks, this allows filters to take their
decisions *while* the message is being received by the client.
-rw-r--r--usr.sbin/smtpd/filter.c44
-rw-r--r--usr.sbin/smtpd/filter.h19
-rw-r--r--usr.sbin/smtpd/mfa.c14
-rw-r--r--usr.sbin/smtpd/mfa_session.c17
-rw-r--r--usr.sbin/smtpd/parse.y5
-rw-r--r--usr.sbin/smtpd/smtp.c3
-rw-r--r--usr.sbin/smtpd/smtp_session.c41
-rw-r--r--usr.sbin/smtpd/smtpd.h5
8 files changed, 86 insertions, 62 deletions
diff --git a/usr.sbin/smtpd/filter.c b/usr.sbin/smtpd/filter.c
index 45f6f4fa084..59ca75b47e7 100644
--- a/usr.sbin/smtpd/filter.c
+++ b/usr.sbin/smtpd/filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: filter.c,v 1.1 2011/08/27 22:32:41 gilles Exp $ */
+/* $OpenBSD: filter.c,v 1.2 2011/08/31 18:56:30 gilles Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
@@ -47,11 +47,8 @@ static struct filter_internals {
int (*rcpt_cb)(u_int64_t, struct filter_rcpt *, void *);
void *rcpt_cb_arg;
- int (*data_cb)(u_int64_t, struct filter_data *, void *);
- void *data_cb_arg;
-
- int (*quit_cb)(u_int64_t, struct filter_quit *, void *);
- void *quit_cb_arg;
+ int (*dataline_cb)(u_int64_t, struct filter_dataline *, void *);
+ void *dataline_cb_arg;
} fi;
static void filter_handler(int, short, void *);
@@ -101,15 +98,9 @@ filter_register_rcpt_callback(int (*cb)(u_int64_t, struct filter_rcpt *, void *)
}
void
-filter_register_data_callback(int (*cb)(u_int64_t, struct filter_data *, void *), void *cb_arg)
-{
- filter_register_callback(FILTER_DATA, cb, cb_arg);
-}
-
-void
-filter_register_quit_callback(int (*cb)(u_int64_t, struct filter_quit *, void *), void *cb_arg)
+filter_register_dataline_callback(int (*cb)(u_int64_t, struct filter_dataline *, void *), void *cb_arg)
{
- filter_register_callback(FILTER_QUIT, cb, cb_arg);
+ filter_register_callback(FILTER_DATALINE, cb, cb_arg);
}
static void
@@ -136,14 +127,9 @@ filter_register_callback(enum filter_type type, void *cb, void *cb_arg)
fi.rcpt_cb_arg = cb_arg;
break;
- case FILTER_DATA:
- fi.data_cb = cb;
- fi.data_cb_arg = cb_arg;
- break;
-
- case FILTER_QUIT:
- fi.quit_cb = cb;
- fi.quit_cb_arg = cb_arg;
+ case FILTER_DATALINE:
+ fi.dataline_cb = cb;
+ fi.dataline_cb_arg = cb_arg;
break;
}
}
@@ -214,17 +200,11 @@ filter_handler(int fd, short event, void *p)
fm.code = fi.rcpt_cb(fm.cl_id, &fm.u.rcpt,
fi.rcpt_cb_arg);
break;
- case FILTER_DATA:
- if (fi.data_cb == NULL)
- goto ignore;
- fm.code = fi.data_cb(fm.cl_id, &fm.u.data,
- fi.data_cb_arg);
- break;
- case FILTER_QUIT:
- if (fi.quit_cb == NULL)
+ case FILTER_DATALINE:
+ if (fi.dataline_cb == NULL)
goto ignore;
- fm.code = fi.quit_cb(fm.cl_id, &fm.u.quit,
- fi.quit_cb_arg);
+ fm.code = fi.dataline_cb(fm.cl_id, &fm.u.dataline,
+ fi.dataline_cb_arg);
break;
default:
errx(1, "unsupported imsg");
diff --git a/usr.sbin/smtpd/filter.h b/usr.sbin/smtpd/filter.h
index bbd5cdc59ab..4a83d4f724d 100644
--- a/usr.sbin/smtpd/filter.h
+++ b/usr.sbin/smtpd/filter.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: filter.h,v 1.1 2011/08/27 22:32:41 gilles Exp $ */
+/* $OpenBSD: filter.h,v 1.2 2011/08/31 18:56:30 gilles Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
@@ -36,8 +36,7 @@ enum filter_type {
FILTER_EHLO,
FILTER_MAIL,
FILTER_RCPT,
- FILTER_DATA,
- FILTER_QUIT,
+ FILTER_DATALINE,
};
struct filter_helo {
@@ -54,20 +53,15 @@ struct filter_rcpt {
char domain[MAX_DOMAINPART_SIZE];
};
-struct filter_data {
- char data[4096];
-};
-
-struct filter_quit {
- char data[4096];
+struct filter_dataline {
+ char line[MAX_LINE_SIZE];
};
union filter_union {
struct filter_helo helo;
struct filter_mail mail;
struct filter_rcpt rcpt;
- struct filter_data data;
- struct filter_quit quit;
+ struct filter_dataline dataline;
};
struct filter_msg {
@@ -87,5 +81,4 @@ void filter_register_helo_callback(int (*)(u_int64_t, struct filter_helo *, void
void filter_register_ehlo_callback(int (*)(u_int64_t, struct filter_helo *, void *), void *);
void filter_register_mail_callback(int (*)(u_int64_t, struct filter_mail *, void *), void *);
void filter_register_rcpt_callback(int (*)(u_int64_t, struct filter_rcpt *, void *), void *);
-void filter_register_data_callback(int (*)(u_int64_t, struct filter_data *, void *), void *);
-void filter_register_quit_callback(int (*)(u_int64_t, struct filter_quit *, void *), void *);
+void filter_register_dataline_callback(int (*)(u_int64_t, struct filter_dataline *, void *), void *);
diff --git a/usr.sbin/smtpd/mfa.c b/usr.sbin/smtpd/mfa.c
index c6696de8bb1..96af18ef5ed 100644
--- a/usr.sbin/smtpd/mfa.c
+++ b/usr.sbin/smtpd/mfa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfa.c,v 1.60 2011/08/27 22:32:41 gilles Exp $ */
+/* $OpenBSD: mfa.c,v 1.61 2011/08/31 18:56:30 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -44,6 +44,7 @@ static void mfa_test_helo(struct envelope *);
static void mfa_test_mail(struct envelope *);
static void mfa_test_rcpt(struct envelope *);
static void mfa_test_rcpt_resume(struct submit_status *);
+static void mfa_test_dataline(struct submit_status *);
static int mfa_strip_source_route(char *, size_t);
static int mfa_fork_filter(struct filter *);
void mfa_session(struct submit_status *, enum session_state);
@@ -64,6 +65,9 @@ mfa_imsg(struct imsgev *iev, struct imsg *imsg)
case IMSG_MFA_RCPT:
mfa_test_rcpt(imsg->data);
return;
+ case IMSG_MFA_DATALINE:
+ mfa_test_dataline(imsg->data);
+ return;
}
}
@@ -303,6 +307,14 @@ mfa_test_rcpt_resume(struct submit_status *ss) {
ss, sizeof(*ss));
}
+static void
+mfa_test_dataline(struct submit_status *ss)
+{
+ ss->code = 250;
+
+ mfa_session(ss, S_DATACONTENT);
+}
+
static int
mfa_strip_source_route(char *buf, size_t len)
{
diff --git a/usr.sbin/smtpd/mfa_session.c b/usr.sbin/smtpd/mfa_session.c
index fba1c027e1d..9bd75900e22 100644
--- a/usr.sbin/smtpd/mfa_session.c
+++ b/usr.sbin/smtpd/mfa_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfa_session.c,v 1.2 2011/08/28 00:03:24 gilles Exp $ */
+/* $OpenBSD: mfa_session.c,v 1.3 2011/08/31 18:56:30 gilles Exp $ */
/*
* Copyright (c) 2011 Gilles Chehade <gilles@openbsd.org>
@@ -123,6 +123,13 @@ mfa_session_proceed(struct mfa_session *ms)
fatalx("mfa_session_proceed: RCPT: domain truncation");
break;
+ case S_DATACONTENT:
+ fm.type = FILTER_DATALINE;
+ if (strlcpy(fm.u.dataline.line, ms->ss.u.dataline,
+ sizeof(fm.u.dataline.line)) >= sizeof(fm.u.dataline.line))
+ fatalx("mfa_session_proceed: DATA: line truncation");
+ break;
+
default:
fatalx("mfa_session_proceed: no such state");
}
@@ -176,6 +183,12 @@ mfa_session_done(struct mfa_session *ms)
}
imsg_type = IMSG_MFA_RCPT;
break;
+ case S_DATACONTENT:
+ if (ms->ss.code != 530)
+ (void)strlcpy(ms->ss.u.dataline, ms->fm.u.dataline.line,
+ sizeof(ms->ss.u.dataline));
+ imsg_type = IMSG_MFA_DATALINE;
+ break;
default:
fatalx("mfa_session_done: unsupported state");
}
@@ -268,7 +281,7 @@ mfa_session_imsg(int fd, short event, void *p)
case FILTER_EHLO:
case FILTER_MAIL:
case FILTER_RCPT:
- case FILTER_DATA:
+ case FILTER_DATALINE:
ms = mfa_session_xfind(fm.id);
/* overwrite filter code */
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index 921d8027766..0207ea89b92 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.77 2011/08/27 22:32:41 gilles Exp $ */
+/* $OpenBSD: parse.y,v 1.78 2011/08/31 18:56:30 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -379,7 +379,7 @@ main : QUEUE INTERVAL interval {
YYERROR;
}
free($2);
- }/*
+ }
| FILTER STRING STRING {
struct filter *filter;
struct filter *tmp;
@@ -411,7 +411,6 @@ main : QUEUE INTERVAL interval {
free($2);
free($3);
}
- */
;
maptype : SINGLE { map->m_type = T_SINGLE; }
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c
index 9e20da78869..7614ca1344b 100644
--- a/usr.sbin/smtpd/smtp.c
+++ b/usr.sbin/smtpd/smtp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp.c,v 1.88 2011/08/29 18:49:29 chl Exp $ */
+/* $OpenBSD: smtp.c,v 1.89 2011/08/31 18:56:30 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -83,6 +83,7 @@ smtp_imsg(struct imsgev *iev, struct imsg *imsg)
case IMSG_MFA_HELO:
case IMSG_MFA_MAIL:
case IMSG_MFA_RCPT:
+ case IMSG_MFA_DATALINE:
log_debug("smtp: got imsg_mfa_helo/mail/rcpt/quit");
ss = imsg->data;
s = session_lookup(ss->id);
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index 4351d98311d..4673c0caf20 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.143 2011/08/27 22:32:41 gilles Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.144 2011/08/31 18:56:30 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -589,6 +589,7 @@ session_pickup(struct session *s, struct submit_status *ss)
return;
}
+ log_debug("state: %d", s->s_state);
switch (s->s_state) {
case S_INIT:
s->s_state = S_GREETED;
@@ -714,6 +715,13 @@ session_pickup(struct session *s, struct submit_status *ss)
fprintf(s->datafp, "%s\n", time_to_text(time(NULL)));
break;
+ case S_DATACONTENT:
+ log_debug("line: %s\n", ss->u.dataline);
+ if (ss->code != 250)
+ s->s_msg.delivery.status |= DS_PERMFAILURE;
+ session_read_data(s, ss->u.dataline);
+ break;
+
case S_DONE:
session_respond(s, "250 2.0.0 %08x Message accepted for delivery",
(u_int32_t)(s->s_msg.delivery.id >> 32));
@@ -806,9 +814,22 @@ session_read(struct bufferevent *bev, void *p)
session_command(s, line);
break;
- case S_DATACONTENT:
- session_read_data(s, line);
- break;
+ case S_DATACONTENT: {
+ struct submit_status ss;
+
+ bzero(&ss, sizeof(ss));
+ ss.id = s->s_id;
+ if (strlcpy(ss.u.dataline, line,
+ sizeof(ss.u.dataline)) >= sizeof(ss.u.dataline))
+ fatal("session_read: data truncation");
+
+ session_imsg(s, PROC_MFA, IMSG_MFA_DATALINE,
+ 0, 0, -1, &ss, sizeof(ss));
+
+ free(line);
+
+ return;
+ }
default:
fatalx("session_read: unexpected state");
@@ -850,12 +871,12 @@ session_read_data(struct session *s, char *line)
0, 0, -1, &s->s_msg, sizeof(s->s_msg));
s->s_state = S_DONE;
}
- return;
+ goto end;
}
/* Don't waste resources on message if it's going to bin anyway. */
if (s->s_msg.delivery.status & (DS_PERMFAILURE|DS_TEMPFAILURE))
- return;
+ goto end;
/* "If the first character is a period and there are other characters
* on the line, the first character is deleted." [4.5.2]
@@ -872,12 +893,12 @@ session_read_data(struct session *s, char *line)
if (SIZE_MAX - datalen < len + 1 ||
datalen + len + 1 > env->sc_maxsize) {
s->s_msg.delivery.status |= DS_PERMFAILURE;
- return;
+ goto end;
}
if (fprintf(s->datafp, "%s\n", line) != (int)len + 1) {
s->s_msg.delivery.status |= DS_TEMPFAILURE;
- return;
+ goto end;
}
if (! (s->s_flags & F_8BITMIME)) {
@@ -885,6 +906,10 @@ session_read_data(struct session *s, char *line)
if (line[i] & 0x80)
line[i] = line[i] & 0x7f;
}
+
+end:
+ bufferevent_enable(s->s_bev, EV_READ);
+ session_read(s->s_bev, s);
}
static void
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 02b86a7ed45..d05cc24b8f5 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.235 2011/08/27 22:37:35 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.236 2011/08/31 18:56:30 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -147,7 +147,7 @@ enum imsg_type {
IMSG_MFA_HELO,
IMSG_MFA_MAIL,
IMSG_MFA_RCPT,
- IMSG_MFA_DISCONNECT,
+ IMSG_MFA_DATALINE,
IMSG_QUEUE_CREATE_MESSAGE,
IMSG_QUEUE_SUBMIT_ENVELOPE,
@@ -753,6 +753,7 @@ struct submit_status {
u_int32_t msgid;
u_int64_t evpid;
char errormsg[MAX_LINE_SIZE];
+ char dataline[MAX_LINE_SIZE];
} u;
enum delivery_flags flags;
struct sockaddr_storage ss;