diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2011-08-31 18:56:31 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2011-08-31 18:56:31 +0000 |
commit | 765bc1b5fffe5b0e2f82f824bc4a91bba12073cc (patch) | |
tree | 3c456ecef8ff07cd9845866125edf40ae731e6a7 | |
parent | 88fbf193fd2f3dc7446ff2da1e7d9f50366a84d1 (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.c | 44 | ||||
-rw-r--r-- | usr.sbin/smtpd/filter.h | 19 | ||||
-rw-r--r-- | usr.sbin/smtpd/mfa.c | 14 | ||||
-rw-r--r-- | usr.sbin/smtpd/mfa_session.c | 17 | ||||
-rw-r--r-- | usr.sbin/smtpd/parse.y | 5 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp.c | 3 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp_session.c | 41 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 5 |
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; |