diff options
-rw-r--r-- | usr.sbin/smtpd/bounce.c | 17 | ||||
-rw-r--r-- | usr.sbin/smtpd/client.c | 121 | ||||
-rw-r--r-- | usr.sbin/smtpd/client.h | 10 | ||||
-rw-r--r-- | usr.sbin/smtpd/enqueue.c | 16 | ||||
-rw-r--r-- | usr.sbin/smtpd/mta.c | 7 |
5 files changed, 87 insertions, 84 deletions
diff --git a/usr.sbin/smtpd/bounce.c b/usr.sbin/smtpd/bounce.c index 52feb25ad5a..a313b8503a5 100644 --- a/usr.sbin/smtpd/bounce.c +++ b/usr.sbin/smtpd/bounce.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bounce.c,v 1.13 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: bounce.c,v 1.14 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2009 Gilles Chehade <gilles@openbsd.org> @@ -58,10 +58,14 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) int msgfd = -1; char *reason; + /* get message content */ + if ((msgfd = queue_open_message_file(messagep->message_id)) == -1) + goto fail; + /* init smtp session */ if ((cc = calloc(1, sizeof(*cc))) == NULL) goto fail; - cc->pcb = client_init(fd, env->sc_hostname, 1); + cc->pcb = client_init(fd, msgfd, env->sc_hostname, 1); cc->m = *messagep; client_ssl_optional(cc->pcb); @@ -77,7 +81,7 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) /* create message header */ /* XXX - The Date: header should be added during SMTP pickup. */ - client_data_printf(cc->pcb, + client_printf(cc->pcb, "Subject: Delivery status notification\n" "From: Mailer Daemon <MAILER-DAEMON@%s>\n" "To: %s@%s\n" @@ -100,13 +104,6 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) messagep->recipient.user, messagep->recipient.domain, reason); - /* append original message */ - if ((msgfd = queue_open_message_file(messagep->message_id)) == -1) - goto fail; - client_data_fd(cc->pcb, msgfd); - close(msgfd); - msgfd = -1; - /* setup event */ session_socket_blockmode(fd, BM_NONBLOCK); event_set(&cc->ev, fd, EV_WRITE, bounce_event, cc); diff --git a/usr.sbin/smtpd/client.c b/usr.sbin/smtpd/client.c index e00bf48b7ab..ab55f29d5c2 100644 --- a/usr.sbin/smtpd/client.c +++ b/usr.sbin/smtpd/client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: client.c,v 1.18 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: client.c,v 1.19 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> @@ -45,7 +45,7 @@ void client_status(struct smtp_client *, char *, ...); int client_getln(struct smtp_client *); void client_putln(struct smtp_client *, char *, ...); -void client_data_add(struct smtp_client *, char *, size_t); +void client_body(struct msgbuf *, FILE *); #ifndef CLIENT_NO_SSL int client_ssl_connect(struct smtp_client *); @@ -65,7 +65,7 @@ void fatalx(const char *); /* XXX */ * Initialize SMTP session. */ struct smtp_client * -client_init(int fd, char *ehlo, int verbose) +client_init(int fd, int body, char *ehlo, int verbose) { struct smtp_client *sp = NULL; @@ -92,8 +92,8 @@ client_init(int fd, char *ehlo, int verbose) sp->verbose = stdout; else if ((sp->verbose = fopen("/dev/null", "a")) == NULL) fatal("client_init: fopen"); - if ((sp->data = buf_dynamic(0, SIZE_T_MAX)) == NULL) - fatal(NULL); + if ((sp->body = fdopen(body, "r")) == NULL) + fatal("client_init: fdopen"); sp->state = CLIENT_INIT; sp->handler = client_write; sp->timeout.tv_sec = 300; @@ -208,44 +208,41 @@ client_rcpt(struct smtp_client *sp, void *p, char *fmt, ...) } /* - * Append file referenced by fd to the data buffer. - */ -void -client_data_fd(struct smtp_client *sp, int fd) -{ - struct stat sb; - char *map; - - if (fstat(fd, &sb) == -1) - fatal("client_data_fd: fstat"); - if ((size_t)sb.st_size > SIZE_T_MAX) - fatalx("client_data_fd: file too large"); - if (!S_ISREG(sb.st_mode)) - fatalx("client_data_fd: non-regular file"); - map = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, - (off_t)0); - if (map == MAP_FAILED) - fatal("client_data_fd: mmap failed"); - madvise(map, sb.st_size, MADV_SEQUENTIAL); - client_data_add(sp, map, sb.st_size); - munmap(map, sb.st_size); -} - -/* * Append string to the data buffer. */ void -client_data_printf(struct smtp_client *sp, char *fmt, ...) +client_printf(struct smtp_client *sp, char *fmt, ...) { va_list ap; - char *p = NULL; + char *p, *ln, *tmp; int len; + if (sp->head == NULL) + sp->head = buf_dynamic(0, SIZE_T_MAX); + if (sp->head == NULL) + fatal(NULL); + va_start(ap, fmt); if ((len = vasprintf(&p, fmt, ap)) == -1) fatal("client_data_printf: vasprintf"); va_end(ap); - client_data_add(sp, p, len); + + /* must end with a newline */ + if (len == 0 || p[len - 1] != '\n') + fatalx("client_printf: invalid use"); + p[len - 1] = '\0'; + + /* split into lines, deal with dot escaping etc. */ + tmp = p; + while ((ln = strsep(&tmp, "\n"))) { + if (*ln == '.' && buf_add(sp->head, ".", 1)) + fatal(NULL); + if (buf_add(sp->head, ln, strlen(ln))) + fatal(NULL); + if (buf_add(sp->head, "\r\n", 2)) + fatal(NULL); + } + free(p); } @@ -503,10 +500,11 @@ client_write(struct smtp_client *sp) case CLIENT_DATA_BODY: sp->timeout.tv_sec = 180; - if (buf_add(sp->data, ".\r\n", 3) < 0) - fatal("client_write: buf_add failed"); - buf_close(&sp->w, sp->data); - sp->data = NULL; + if (sp->head) { + buf_close(&sp->w, sp->head); + sp->head = NULL; + } + client_body(&sp->w, sp->body); break; case CLIENT_QUIT: @@ -545,11 +543,12 @@ write: } } - /* - * Extend timeout after having sent final "." character. - */ - if (sp->state == CLIENT_DATA_BODY && sp->w.queued == 0) - sp->timeout.tv_sec = 600; + if (sp->state == CLIENT_DATA_BODY) { + if (!feof(sp->body)) + return (CLIENT_WANT_WRITE); + else + sp->timeout.tv_sec = 600; + } return (sp->w.queued ? CLIENT_WANT_WRITE : CLIENT_WANT_READ); } @@ -616,8 +615,8 @@ client_close(struct smtp_client *sp) free(sp->auth.plain); free(sp->auth.cert); free(sp->auth.key); - if (sp->data) - buf_free(sp->data); + if (sp->head) + buf_free(sp->head); msgbuf_clear(&sp->w); while ((rp = TAILQ_FIRST(&sp->recipients))) { TAILQ_REMOVE(&sp->recipients, rp, entry); @@ -775,9 +774,9 @@ client_putln(struct smtp_client *sp, char *fmt, ...) if ((cmd = buf_open(len + 2)) == NULL) fatal(NULL); - if (buf_add(cmd, p, len) < 0) + if (buf_add(cmd, p, len)) fatal(NULL); - if (buf_add(cmd, "\r\n", 2) < 0) + if (buf_add(cmd, "\r\n", 2)) fatal(NULL); buf_close(&sp->w, cmd); @@ -785,27 +784,35 @@ client_putln(struct smtp_client *sp, char *fmt, ...) } /* - * Append buffer to the data buffer, performing necessary transformations. + * Put chunk of message content to output buffer. */ void -client_data_add(struct smtp_client *sp, char *buf, size_t len) +client_body(struct msgbuf *out, FILE *fp) { - char *ln; + struct buf *b; + char *ln; + size_t len, total = 0; - /* must end with a newline */ - if (len == 0 || buf[len - 1] != '\n') - fatalx("client_data_add: bad buffer"); - buf[len - 1] = '\0'; + if ((b = buf_dynamic(0, SIZE_T_MAX)) == NULL) + fatal(NULL); - /* split into lines, deal with dot escaping etc. */ - while ((ln = strsep(&buf, "\n"))) { - if (*ln == '.' && buf_add(sp->data, ".", 1) < 0) + while ((ln = fgetln(fp, &len)) && total < 4096) { + if (ln[len - 1] == '\n') + len--; + if (*ln == '.' && buf_add(b, ".", 1)) fatal(NULL); - if (buf_add(sp->data, ln, strlen(ln)) < 0) + if (buf_add(b, ln, len)) fatal(NULL); - if (buf_add(sp->data, "\r\n", 2) < 0) + if (buf_add(b, "\r\n", 2)) fatal(NULL); + total += len; } + if (ferror(fp)) + fatal("client_body: fgetln"); + if (feof(fp) && buf_add(b, ".\r\n", 3)) + fatal(NULL); + + buf_close(out, b); } /* diff --git a/usr.sbin/smtpd/client.h b/usr.sbin/smtpd/client.h index d038ab0acc4..f81832e819f 100644 --- a/usr.sbin/smtpd/client.h +++ b/usr.sbin/smtpd/client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: client.h,v 1.5 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: client.h,v 1.6 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> @@ -81,7 +81,8 @@ struct smtp_client { size_t rcptokay; struct buf_read r; struct msgbuf w; - struct buf *data; + struct buf *head; + FILE *body; struct client_ext exts[CLIENT_EXT_MAX]; int (*handler)(struct smtp_client *); void *ssl_state; @@ -92,7 +93,7 @@ struct smtp_client { FILE *verbose; }; -struct smtp_client *client_init(int, char *, int); +struct smtp_client *client_init(int, int, char *, int); void client_ssl_smtps(struct smtp_client *); void client_ssl_optional(struct smtp_client *); void client_certificate(struct smtp_client *, char *, @@ -100,7 +101,6 @@ void client_certificate(struct smtp_client *, char *, void client_auth(struct smtp_client *, char *); void client_sender(struct smtp_client *, char *, ...); void client_rcpt(struct smtp_client *, void *, char *, ...); -void client_data_fd(struct smtp_client *, int); -void client_data_printf(struct smtp_client *, char *, ...); +void client_printf(struct smtp_client *, char *, ...); int client_talk(struct smtp_client *); void client_close(struct smtp_client *); diff --git a/usr.sbin/smtpd/enqueue.c b/usr.sbin/smtpd/enqueue.c index f5f6c949f95..251a2346c1f 100644 --- a/usr.sbin/smtpd/enqueue.c +++ b/usr.sbin/smtpd/enqueue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: enqueue.c,v 1.28 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: enqueue.c,v 1.29 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2005 Henning Brauer <henning@bulabula.org> @@ -27,6 +27,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <fcntl.h> #include <netdb.h> #include <pwd.h> #include <signal.h> @@ -190,7 +191,8 @@ enqueue(int argc, char *argv[]) msg.fd = open_connection(); /* init session */ - pcb = client_init(msg.fd, "localhost", verbose); + pcb = client_init(msg.fd, open("/dev/null", O_RDONLY), "localhost", + verbose); /* parse message */ if ((body = buf_dynamic(0, SIZE_T_MAX)) < 0) @@ -208,25 +210,25 @@ enqueue(int argc, char *argv[]) /* add From */ if (!msg.saw_from) - client_data_printf(pcb, "From: %s%s<%s>\n", + client_printf(pcb, "From: %s%s<%s>\n", msg.fromname ? msg.fromname : "", msg.fromname ? " " : "", msg.from); /* add Date */ if (!msg.saw_date) - client_data_printf(pcb, "Date: %s\n", time_to_text(timestamp)); + client_printf(pcb, "Date: %s\n", time_to_text(timestamp)); /* add Message-Id */ if (!msg.saw_msgid) - client_data_printf(pcb, "Message-Id: <%llu.enqueue@%s>\n", + client_printf(pcb, "Message-Id: <%llu.enqueue@%s>\n", generate_uid(), host); /* add separating newline */ if (noheader) - client_data_printf(pcb, "\n"); + client_printf(pcb, "\n"); - client_data_printf(pcb, "%.*s", buf_size(body), body->buf); + client_printf(pcb, "%.*s", buf_size(body), body->buf); buf_free(body); /* run the protocol engine */ diff --git a/usr.sbin/smtpd/mta.c b/usr.sbin/smtpd/mta.c index 99ecc7ccd3f..660fd113afd 100644 --- a/usr.sbin/smtpd/mta.c +++ b/usr.sbin/smtpd/mta.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta.c,v 1.80 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: mta.c,v 1.81 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -636,7 +636,7 @@ mta_enter_state(struct mta_session *s, int newstate, void *p) */ log_debug("mta: entering smtp phase"); - pcb = client_init(s->fd, s->env->sc_hostname, 1); + pcb = client_init(s->fd, s->datafd, s->env->sc_hostname, 1); /* lookup SSL certificate */ if (s->cert) { @@ -679,9 +679,6 @@ mta_enter_state(struct mta_session *s, int newstate, void *p) client_rcpt(pcb, m, "%s@%s", m->recipient.user, m->recipient.domain); - /* load message body */ - client_data_fd(pcb, s->datafd); - s->pcb = pcb; event_set(&s->ev, s->fd, EV_WRITE, mta_event, s); event_add(&s->ev, &pcb->timeout); |