diff options
author | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2009-12-12 10:33:12 +0000 |
---|---|---|
committer | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2009-12-12 10:33:12 +0000 |
commit | 173db6f90670e33ca553f47f7b652265aee3a240 (patch) | |
tree | b058a07cd10d9bc3337f633b76ea06e0db0be950 /usr.sbin | |
parent | 26ca1705c8c1bcff436db5b16871b448eef40ed9 (diff) |
Simplify client_* api, mainly by making fatal conditions result in immediate
fatals instead of passing the error up (kills ~300 lines).
Implement sending of the QUIT command which replaces crude close(2).
tested by gilles@, todd@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/smtpd/bounce.c | 81 | ||||
-rw-r--r-- | usr.sbin/smtpd/client.c | 602 | ||||
-rw-r--r-- | usr.sbin/smtpd/client.h | 46 | ||||
-rw-r--r-- | usr.sbin/smtpd/enqueue.c | 80 | ||||
-rw-r--r-- | usr.sbin/smtpd/mta.c | 168 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 4 |
6 files changed, 352 insertions, 629 deletions
diff --git a/usr.sbin/smtpd/bounce.c b/usr.sbin/smtpd/bounce.c index 2293db048d6..52feb25ad5a 100644 --- a/usr.sbin/smtpd/bounce.c +++ b/usr.sbin/smtpd/bounce.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bounce.c,v 1.12 2009/11/11 10:04:05 chl Exp $ */ +/* $OpenBSD: bounce.c,v 1.13 2009/12/12 10:33:11 jacekm Exp $ */ /* * Copyright (c) 2009 Gilles Chehade <gilles@openbsd.org> @@ -39,7 +39,7 @@ struct client_ctx { struct event ev; struct message m; - struct smtp_client *sp; + struct smtp_client *pcb; }; void bounce_event(int, short, void *); @@ -61,17 +61,14 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) /* init smtp session */ if ((cc = calloc(1, sizeof(*cc))) == NULL) goto fail; - if ((cc->sp = client_init(fd, env->sc_hostname)) == NULL) - goto fail; + cc->pcb = client_init(fd, env->sc_hostname, 1); cc->m = *messagep; - if (client_ssl_optional(cc->sp) < 0) - goto fail; + client_ssl_optional(cc->pcb); /* assign recipient */ - if (client_rcpt(cc->sp, "%s@%s", messagep->sender.user, - messagep->sender.domain) < 0) - goto fail; + client_rcpt(cc->pcb, NULL, "%s@%s", messagep->sender.user, + messagep->sender.domain); /* Construct an appropriate reason line. */ reason = messagep->session_errorline; @@ -80,7 +77,7 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) /* create message header */ /* XXX - The Date: header should be added during SMTP pickup. */ - if (client_data_printf(cc->sp, + client_data_printf(cc->pcb, "Subject: Delivery status notification\n" "From: Mailer Daemon <MAILER-DAEMON@%s>\n" "To: %s@%s\n" @@ -101,27 +98,25 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) messagep->sender.user, messagep->sender.domain, time_to_text(time(NULL)), messagep->recipient.user, messagep->recipient.domain, - reason) < 0) - goto fail; + reason); /* append original message */ if ((msgfd = queue_open_message_file(messagep->message_id)) == -1) goto fail; - if (client_data_fd(cc->sp, msgfd) < 0) - 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); - event_add(&cc->ev, client_timeout(cc->sp)); + event_add(&cc->ev, &cc->pcb->timeout); return 1; fail: close(msgfd); - if (cc && cc->sp) - client_close(cc->sp); + if (cc && cc->pcb) + client_close(cc->pcb); free(cc); return 0; } @@ -130,45 +125,29 @@ void bounce_event(int fd, short event, void *p) { struct client_ctx *cc = p; - char *ep = NULL; - int error = 0; - int (*iofunc)(struct smtp_client *); + char *ep; if (event & EV_TIMEOUT) { - message_set_errormsg(&cc->m, "150 timeout"); - cc->m.status = S_MESSAGE_TEMPFAILURE; - queue_message_update(&cc->m); - client_close(cc->sp); - free(cc); - return; + ep = "150 timeout"; + goto out; } - if (event & EV_READ) - iofunc = client_read; - else - iofunc = client_write; - - switch (iofunc(cc->sp)) { + switch (client_talk(cc->pcb)) { case CLIENT_WANT_READ: - event_set(&cc->ev, fd, EV_READ, bounce_event, cc); - event_add(&cc->ev, client_timeout(cc->sp)); - return; + goto read; case CLIENT_WANT_WRITE: - event_set(&cc->ev, fd, EV_WRITE, bounce_event, cc); - event_add(&cc->ev, client_timeout(cc->sp)); - return; - case CLIENT_ERROR: - error = 1; + goto write; case CLIENT_RCPT_FAIL: + ep = cc->pcb->reply; + break; case CLIENT_DONE: + ep = cc->pcb->status; break; + default: + fatalx("bounce_event: unexpected code"); } - if (error) - ep = client_strerror(cc->sp); - else - ep = client_reply(cc->sp); - +out: if (*ep == '2') queue_remove_envelope(&cc->m); else { @@ -180,6 +159,16 @@ bounce_event(int fd, short event, void *p) queue_message_update(&cc->m); } - client_close(cc->sp); + client_close(cc->pcb); free(cc); + return; + +read: + event_set(&cc->ev, fd, EV_READ, bounce_event, cc); + event_add(&cc->ev, &cc->pcb->timeout); + return; + +write: + event_set(&cc->ev, fd, EV_WRITE, bounce_event, cc); + event_add(&cc->ev, &cc->pcb->timeout); } diff --git a/usr.sbin/smtpd/client.c b/usr.sbin/smtpd/client.c index 1c64a3dd519..e00bf48b7ab 100644 --- a/usr.sbin/smtpd/client.c +++ b/usr.sbin/smtpd/client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: client.c,v 1.17 2009/11/17 09:22:19 jacekm Exp $ */ +/* $OpenBSD: client.c,v 1.18 2009/12/12 10:33:11 jacekm Exp $ */ /* * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> @@ -38,11 +38,14 @@ #include "imsg.h" #include "client.h" +int client_read(struct smtp_client *); +int client_write(struct smtp_client *); int client_next_state(struct smtp_client *); +void client_status(struct smtp_client *, char *, ...); int client_getln(struct smtp_client *); -int client_putln(struct smtp_client *, char *, ...); -int client_data_add(struct smtp_client *, char *, size_t); +void client_putln(struct smtp_client *, char *, ...); +void client_data_add(struct smtp_client *, char *, size_t); #ifndef CLIENT_NO_SSL int client_ssl_connect(struct smtp_client *); @@ -54,19 +57,20 @@ int ssl_buf_write(SSL *, struct msgbuf *); char *buf_getln(struct buf_read *); int buf_read(int, struct buf_read *); +void log_debug(const char *, ...); /* XXX */ +void fatal(const char *); /* XXX */ +void fatalx(const char *); /* XXX */ + /* - * client_init() - * * Initialize SMTP session. */ struct smtp_client * -client_init(int fd, char *ehlo) +client_init(int fd, char *ehlo, int verbose) { struct smtp_client *sp = NULL; - int rv = -1; if ((sp = calloc(1, sizeof(*sp))) == NULL) - goto done; + fatal(NULL); if (ehlo == NULL || *ehlo == '\0') { char buf[NI_MAXHOST]; struct sockaddr_storage sa; @@ -74,342 +78,201 @@ client_init(int fd, char *ehlo) len = sizeof(sa); if (getsockname(fd, (struct sockaddr *)&sa, &len)) - goto done; + fatal("client_init: getsockname"); if (getnameinfo((struct sockaddr *)&sa, len, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST)) - goto done; + fatalx("client_init: getnameinfo"); if (asprintf(&sp->ehlo, "[%s]", buf) == -1) - goto done; + fatal("client_init: asprintf"); } else if ((sp->ehlo = strdup(ehlo)) == NULL) - goto done; + fatal(NULL); if ((sp->sender = strdup("")) == NULL) - goto done; + fatal(NULL); + if (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) - goto done; + fatal(NULL); sp->state = CLIENT_INIT; + sp->handler = client_write; + sp->timeout.tv_sec = 300; msgbuf_init(&sp->w); sp->w.fd = fd; TAILQ_INIT(&sp->recipients); -#ifndef CLIENT_NO_SSL +#ifdef CLIENT_NO_SSL + sp->exts[CLIENT_EXT_STARTTLS].want = 0; + sp->exts[CLIENT_EXT_STARTTLS].must = 0; +#else sp->exts[CLIENT_EXT_STARTTLS].want = 1; sp->exts[CLIENT_EXT_STARTTLS].must = 1; +#endif sp->exts[CLIENT_EXT_STARTTLS].state = CLIENT_STARTTLS; sp->exts[CLIENT_EXT_STARTTLS].name = "STARTTLS"; -#endif sp->exts[CLIENT_EXT_AUTH].want = 0; sp->exts[CLIENT_EXT_AUTH].must = 0; sp->exts[CLIENT_EXT_AUTH].state = CLIENT_AUTH; sp->exts[CLIENT_EXT_AUTH].name = "AUTH"; - rv = 0; -done: - if (rv && sp != NULL) { - free(sp->ehlo); - free(sp->sender); - if (sp->data) - buf_free(sp->data); - free(sp); - sp = NULL; - } return (sp); } /* - * client_verbose() - * - * Enable logging of SMTP commands. - */ -void -client_verbose(struct smtp_client *sp, FILE *fp) -{ - sp->verbose = fp; -} - -/* - * client_ssl_smtps() - * * Request that connection be secured using SSL from the start. */ -int +void client_ssl_smtps(struct smtp_client *sp) { - /* check if too late */ - if (sp->state != CLIENT_INIT) - return (-1); - -#ifndef CLIENT_NO_SSL sp->state = CLIENT_SSL_INIT; sp->exts[CLIENT_EXT_STARTTLS].want = 0; sp->exts[CLIENT_EXT_STARTTLS].must = 0; - - return (0); -#else - return (-1); -#endif } /* - * client_ssl_optional() - * * Allow session to progress in plaintext if STARTTLS fails. */ -int +void client_ssl_optional(struct smtp_client *sp) { - if (sp->state != CLIENT_INIT) - return (-1); - -#ifndef CLIENT_NO_SSL sp->exts[CLIENT_EXT_STARTTLS].must = 0; - - return (0); -#else - return (-1); -#endif } /* - * client_certificate() - * * Use the provided certificate during SSL handshake. */ -int +void client_certificate(struct smtp_client *sp, char *cert, size_t certsz, char *key, size_t keysz) { - int rv = -1; - - if (sp->state != CLIENT_INIT && sp->state != CLIENT_SSL_INIT) - goto done; - if ((sp->auth.cert = malloc(certsz)) == NULL) - goto done; + fatal(NULL); if ((sp->auth.key = malloc(keysz)) == NULL) - goto done; + fatal(NULL); memcpy(sp->auth.cert, cert, certsz); memcpy(sp->auth.key, key, keysz); sp->auth.certsz = certsz; sp->auth.keysz = keysz; - - rv = 0; -done: - if (rv) { - free(sp->auth.cert); - free(sp->auth.key); - sp->auth.cert = NULL; - sp->auth.certsz = 0; - sp->auth.key = NULL; - sp->auth.keysz = 0; - } - return (rv); } /* - * client_auth() - * * Use the AUTH extension. */ -int +void client_auth(struct smtp_client *sp, char *secret) { - int rv = -1; - - if (sp->state != CLIENT_INIT && sp->state != CLIENT_SSL_INIT) - goto done; - if ((sp->auth.plain = strdup(secret)) == NULL) - goto done; + fatal(NULL); sp->exts[CLIENT_EXT_AUTH].want = 1; sp->exts[CLIENT_EXT_AUTH].must = 1; - - rv = 0; -done: - if (rv) { - free(sp->auth.plain); - sp->auth.plain = NULL; - } - return (rv); } /* - * client_sender() - * * Set envelope sender. If not called, the sender is assumed to be "<>". */ -int +void client_sender(struct smtp_client *sp, char *fmt, ...) { va_list ap; - char *mbox = NULL; - int rv = -1; - - va_start(ap, fmt); - - /* check if too late */ - switch (sp->state) { - case CLIENT_INIT: - case CLIENT_SSL_INIT: - case CLIENT_EHLO: - case CLIENT_HELO: - break; - default: - goto done; - } - if (vasprintf(&mbox, fmt, ap) == -1) - goto done; free(sp->sender); - sp->sender = mbox; - rv = 0; -done: + va_start(ap, fmt); + if (vasprintf(&sp->sender, fmt, ap) == -1) + fatal("client_sender: vasprintf"); va_end(ap); - if (rv) - free(mbox); - return (rv); } /* - * client_rcpt() - * * Add mail recipient. */ -int -client_rcpt(struct smtp_client *sp, char *fmt, ...) +void +client_rcpt(struct smtp_client *sp, void *p, char *fmt, ...) { va_list ap; struct rcpt *rp = NULL; - int rv = -1; - - va_start(ap, fmt); - - /* check if too late */ - switch (sp->state) { - case CLIENT_INIT: - case CLIENT_SSL_INIT: - case CLIENT_EHLO: - case CLIENT_HELO: - case CLIENT_MAILFROM: - break; - default: - goto done; - } if ((rp = calloc(1, sizeof(*rp))) == NULL) - goto done; - if (vasprintf(&rp->mbox, fmt, ap) == -1) - goto done; - TAILQ_INSERT_TAIL(&sp->recipients, rp, entry); + fatal(NULL); + rp->p = p; - rv = 0; -done: + va_start(ap, fmt); + if (vasprintf(&rp->mbox, fmt, ap) == -1) + fatal("client_rcpt: vasprintf"); va_end(ap); - if (rv) { - if (rp) - free(rp->mbox); - free(rp); - } - return (rv); + + TAILQ_INSERT_TAIL(&sp->recipients, rp, entry); + sp->rcpt = TAILQ_FIRST(&sp->recipients); } /* - * client_data_fd() - * * Append file referenced by fd to the data buffer. */ -int +void client_data_fd(struct smtp_client *sp, int fd) { struct stat sb; - char *map = NULL; - int rv = -1; + char *map; if (fstat(fd, &sb) == -1) - goto done; + fatal("client_data_fd: fstat"); if ((size_t)sb.st_size > SIZE_T_MAX) - goto done; + fatalx("client_data_fd: file too large"); if (!S_ISREG(sb.st_mode)) - goto done; + 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) - goto done; + fatal("client_data_fd: mmap failed"); madvise(map, sb.st_size, MADV_SEQUENTIAL); - - if (client_data_add(sp, map, sb.st_size) < 0) - goto done; - - rv = 0; -done: - if (map) - munmap(map, sb.st_size); - return (rv); + client_data_add(sp, map, sb.st_size); + munmap(map, sb.st_size); } /* - * client_data_printf() - * * Append string to the data buffer. */ -int +void client_data_printf(struct smtp_client *sp, char *fmt, ...) { va_list ap; char *p = NULL; - int len, rv = -1; + int len; va_start(ap, fmt); if ((len = vasprintf(&p, fmt, ap)) == -1) - goto done; - - if (client_data_add(sp, p, len) < 0) - goto done; - - rv = 0; -done: + fatal("client_data_printf: vasprintf"); va_end(ap); + client_data_add(sp, p, len); free(p); - return (rv); } /* - * client_udata_set() - * - * Associate user pointer with the most recently recorded recipient. + * Routine called by the user to progress the session. */ -void -client_udata_set(struct smtp_client *sp, void *p) +int +client_talk(struct smtp_client *sp) { - struct rcpt *lastrcpt; + int ret; - lastrcpt = TAILQ_LAST(&sp->recipients, rlist); - lastrcpt->udata = p; -} + ret = sp->handler(sp); -/* - * client_udata_get() - * - * Return user pointer associated with most recently sent recipient. - */ -void * -client_udata_get(struct smtp_client *sp) -{ - return (sp->rcptsent->udata); + if (ret == CLIENT_WANT_READ) + sp->handler = client_read; + else if (ret == CLIENT_WANT_WRITE) + sp->handler = client_write; + + return (ret); } /* - * client_read() - * * Handler to be called when socket becomes readable. */ int client_read(struct smtp_client *sp) { - int rv = CLIENT_ERROR; - #ifndef CLIENT_NO_SSL if (sp->state == CLIENT_SSL_CONNECT) return client_ssl_connect(sp); @@ -429,9 +292,8 @@ client_read(struct smtp_client *sp) return (CLIENT_WANT_WRITE); default: - strlcpy(sp->ebuf, "130 ssl_buf_read error", - sizeof(sp->ebuf)); - return (CLIENT_ERROR); + client_status(sp, "130 ssl_buf_read error"); + return (CLIENT_DONE); } #else if (0) { @@ -440,18 +302,18 @@ client_read(struct smtp_client *sp) errno = 0; if (buf_read(sp->w.fd, &sp->r) == -1) { if (errno) - snprintf(sp->ebuf, sizeof(sp->ebuf), - "130 buf_read: %s", strerror(errno)); + client_status(sp, "130 buf_read: %s", + strerror(errno)); else - snprintf(sp->ebuf, sizeof(sp->ebuf), - "130 buf_read: connection closed"); - return (CLIENT_ERROR); + client_status(sp, "130 buf_read: " + "connection closed"); + return (CLIENT_DONE); } } /* get server reply */ if (client_getln(sp) < 0) - return (CLIENT_ERROR); + goto quit2; if (*sp->reply == '\0') return (CLIENT_WANT_READ); @@ -466,14 +328,14 @@ client_read(struct smtp_client *sp) sp->state != CLIENT_RCPTTO && sp->state != CLIENT_DATA && sp->state != CLIENT_DATA_BODY) { - memcpy(sp->reply, "190", 3); - goto done; + client_status(sp, "190 untimely 5yz reply: %s", sp->reply); + goto quit2; } switch (sp->state) { case CLIENT_INIT: if (*sp->reply != '2') - goto done; + goto quit; else sp->state = CLIENT_EHLO; break; @@ -482,19 +344,19 @@ client_read(struct smtp_client *sp) if (*sp->reply != '2') { if (sp->exts[CLIENT_EXT_STARTTLS].must || sp->exts[CLIENT_EXT_AUTH].must) - goto done; + goto quit; else sp->state = CLIENT_HELO; break; } if ((sp->state = client_next_state(sp)) == 0) - return (CLIENT_ERROR); + goto quit2; break; case CLIENT_HELO: if (*sp->reply != '2') - goto done; + goto quit; else sp->state = CLIENT_MAILFROM; break; @@ -503,7 +365,7 @@ client_read(struct smtp_client *sp) if (*sp->reply != '2') { sp->exts[CLIENT_EXT_STARTTLS].fail = 1; if ((sp->state = client_next_state(sp)) == 0) - return (CLIENT_ERROR); + goto quit2; } else sp->state = CLIENT_SSL_INIT; break; @@ -515,56 +377,59 @@ client_read(struct smtp_client *sp) sp->exts[CLIENT_EXT_AUTH].done = 1; if ((sp->state = client_next_state(sp)) == 0) - return (CLIENT_ERROR); + goto quit2; break; case CLIENT_MAILFROM: if (*sp->reply != '2') - goto done; + goto quit; else sp->state = CLIENT_RCPTTO; break; case CLIENT_RCPTTO: - if (*sp->reply != '2') { - rv = CLIENT_RCPT_FAIL; - goto done; - } else if (TAILQ_NEXT(sp->rcptsent, entry) == NULL) - sp->state = CLIENT_DATA; + if (*sp->reply == '2') { + sp->rcptokay++; + sp->rcpt = TAILQ_NEXT(sp->rcpt, entry); + } else { + sp->rcptfail = sp->rcpt; + sp->rcpt = TAILQ_NEXT(sp->rcpt, entry); + return (CLIENT_RCPT_FAIL); + } break; case CLIENT_DATA: if (*sp->reply != '3') - goto done; + goto quit; else sp->state = CLIENT_DATA_BODY; break; case CLIENT_DATA_BODY: - if (*sp->reply == '2') - rv = CLIENT_DONE; - goto done; + goto quit; + + case CLIENT_QUIT: + return (CLIENT_WANT_READ); default: - abort(); + fatalx("client_read: unexpected state"); } - rv = CLIENT_WANT_WRITE; -done: - if (rv == CLIENT_ERROR) - strlcpy(sp->ebuf, sp->reply, sizeof(sp->ebuf)); - return (rv); + return (CLIENT_WANT_WRITE); + +quit: + client_status(sp, "%s", sp->reply); +quit2: + sp->state = CLIENT_QUIT; + return (CLIENT_WANT_WRITE); } /* - * client_write() - * * Handler to be called when socket becomes writable. */ int client_write(struct smtp_client *sp) { - int rv = CLIENT_ERROR; #ifndef CLIENT_NO_SSL if (sp->state == CLIENT_SSL_CONNECT) @@ -578,15 +443,13 @@ client_write(struct smtp_client *sp) switch (sp->state) { #ifndef CLIENT_NO_SSL case CLIENT_SSL_INIT: - if (sp->verbose) - fprintf(sp->verbose, "client: ssl handshake started\n"); + log_debug("client: ssl handshake started"); sp->ssl_state = ssl_client_init(sp->w.fd, sp->auth.cert, sp->auth.certsz, sp->auth.key, sp->auth.keysz); if (sp->ssl_state == NULL) { - strlcpy(sp->ebuf, "130 SSL init failed", - sizeof(sp->ebuf)); - return (CLIENT_ERROR); + client_status(sp, "130 SSL init failed"); + return (CLIENT_DONE); } else { sp->state = CLIENT_SSL_CONNECT; return (CLIENT_WANT_WRITE); @@ -606,56 +469,53 @@ client_write(struct smtp_client *sp) sp->exts[CLIENT_EXT_AUTH].have = 0; sp->exts[CLIENT_EXT_AUTH].fail = 0; - if (client_putln(sp, "%sLO %s", - sp->state == CLIENT_EHLO ? "EH" : "HE", sp->ehlo) < 0) - goto done; + client_putln(sp, "%s %s", sp->state == CLIENT_EHLO ? "EHLO" : + "HELO", sp->ehlo); break; case CLIENT_AUTH: - if (client_putln(sp, "AUTH PLAIN %s", sp->auth.plain) < 0) - goto done; + client_putln(sp, "AUTH PLAIN %s", sp->auth.plain); break; case CLIENT_STARTTLS: - if (client_putln(sp, "STARTTLS") < 0) - goto done; + client_putln(sp, "STARTTLS"); break; case CLIENT_MAILFROM: - if (client_putln(sp, "MAIL FROM:<%s>", sp->sender) < 0) - goto done; + client_putln(sp, "MAIL FROM:<%s>", sp->sender); break; case CLIENT_RCPTTO: - if (sp->rcptsent == NULL) - sp->rcptsent = TAILQ_FIRST(&sp->recipients); - else - sp->rcptsent = TAILQ_NEXT(sp->rcptsent, entry); - - if (sp->rcptsent == NULL) - goto done; - - if (client_putln(sp, "RCPT TO:<%s>", sp->rcptsent->mbox) < 0) - goto done; + if (sp->rcpt == NULL) { + if (sp->rcptokay > 0) + sp->state = CLIENT_DATA; + else + sp->state = CLIENT_QUIT; + return (CLIENT_WANT_WRITE); + } + client_putln(sp, "RCPT TO:<%s>", sp->rcpt->mbox); break; case CLIENT_DATA: - if (client_putln(sp, "DATA") < 0) - goto done; + sp->timeout.tv_sec = 120; + client_putln(sp, "DATA"); break; case CLIENT_DATA_BODY: - if (buf_add(sp->data, ".\r\n", 3) < 0) { - strlcpy(sp->ebuf, "190 buf_add error", - sizeof(sp->ebuf)); - goto done; - } + 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; break; + case CLIENT_QUIT: + sp->timeout.tv_sec = 300; + client_putln(sp, "QUIT"); + break; + default: - abort(); + fatalx("client_write: unexpected state"); } write: @@ -666,38 +526,36 @@ write: break; case SSL_ERROR_WANT_READ: - rv = CLIENT_WANT_READ; - goto done; + return (CLIENT_WANT_READ); case SSL_ERROR_WANT_WRITE: - rv = CLIENT_WANT_WRITE; - goto done; + return (CLIENT_WANT_WRITE); default: - strlcpy(sp->ebuf, "130 ssl_buf_write error", - sizeof(sp->ebuf)); - goto done; + client_status(sp, "130 ssl_buf_write error"); + return (CLIENT_DONE); } #else if (0) { #endif } else { if (buf_write(&sp->w) < 0) { - strlcpy(sp->ebuf, "130 buf_write error", - sizeof(sp->ebuf)); - goto done; + client_status(sp, "130 buf_write error"); + return (CLIENT_DONE); } } - rv = sp->w.queued ? CLIENT_WANT_WRITE : CLIENT_WANT_READ; -done: - return (rv); + /* + * Extend timeout after having sent final "." character. + */ + if (sp->state == CLIENT_DATA_BODY && sp->w.queued == 0) + sp->timeout.tv_sec = 600; + + return (sp->w.queued ? CLIENT_WANT_WRITE : CLIENT_WANT_READ); } #ifndef CLIENT_NO_SSL /* - * client_ssl_connect() - * * Progress SSL handshake. */ int @@ -708,37 +566,31 @@ client_ssl_connect(struct smtp_client *sp) ret = SSL_connect(sp->ssl_state); switch (SSL_get_error(sp->ssl_state, ret)) { - case SSL_ERROR_NONE: - break; - case SSL_ERROR_WANT_READ: return (CLIENT_WANT_READ); case SSL_ERROR_WANT_WRITE: return (CLIENT_WANT_WRITE); + case SSL_ERROR_NONE: + break; + default: - if (sp->verbose) - fprintf(sp->verbose, "client: ssl handshake failed\n"); + log_debug("client: ssl handshake failed"); if (sp->exts[CLIENT_EXT_STARTTLS].want) { sp->exts[CLIENT_EXT_STARTTLS].fail = 1; - SSL_free(sp->ssl_state); sp->ssl_state = NULL; - - if ((sp->state = client_next_state(sp)) == 0) - return (CLIENT_ERROR); - else + if ((sp->state = client_next_state(sp)) != 0) return (CLIENT_WANT_WRITE); - } else { - strlcpy(sp->ebuf, "130 SSL_connect error", sizeof(sp->ebuf)); - return (CLIENT_ERROR); - } + } else + client_status(sp, "130 SSL_connect error"); + + return (CLIENT_DONE); } - if (sp->verbose) - fprintf(sp->verbose, "client: ssl handshake completed\n"); + log_debug("client: ssl handshake completed"); if (sp->exts[CLIENT_EXT_STARTTLS].want) sp->state = CLIENT_EHLO; @@ -752,33 +604,6 @@ client_ssl_connect(struct smtp_client *sp) #endif /* - * client_strerror() - * - * Access error string explaining most recent client_{read,write} failure. - */ -char * -client_strerror(struct smtp_client *sp) -{ - if (sp->ebuf[0] == '\0') - return (NULL); - else - return (sp->ebuf); -} - -/* - * client_reply() - * - * Access string containing most recent server reply. - */ -char * -client_reply(struct smtp_client *sp) -{ - return (sp->reply); -} - -/* - * client_close() - * * Deinitialization routine. */ void @@ -808,8 +633,6 @@ client_close(struct smtp_client *sp) } /* - * client_next_state() - * * Decide if any extensions need to be requested before proceeding to * the MAIL FROM command. */ @@ -826,8 +649,7 @@ client_next_state(struct smtp_client *sp) if (e->have && !e->fail) return (e->state); else if (e->must) { - snprintf(sp->ebuf, sizeof(sp->ebuf), - "%s %s", e->name, + client_status(sp, "600 %s %s", e->name, e->fail ? "failed" : "not available"); return (0); } @@ -838,37 +660,25 @@ client_next_state(struct smtp_client *sp) } /* - * client_timeout() - * - * Return a timeout that applies to the current session state. + * Update status field which the caller uses to check if any errors were + * encountered. */ -struct timeval * -client_timeout(struct smtp_client *sp) +void +client_status(struct smtp_client *sp, char *fmt, ...) { - switch (sp->state) { - case CLIENT_DATA: - sp->timeout.tv_sec = 120; - break; - - case CLIENT_DATA_BODY: - if (sp->w.queued) - sp->timeout.tv_sec = 180; - else - sp->timeout.tv_sec = 600; - break; + va_list ap; - default: - sp->timeout.tv_sec = 300; - } - - sp->timeout.tv_usec = 0; + /* Don't record errors that occurred at QUIT. */ + if (sp->state == CLIENT_QUIT) + return; - return (&sp->timeout); + va_start(ap, fmt); + if (vsnprintf(sp->status, sizeof(sp->status), fmt, ap) == -1) + fatal("client_status: vnprintf"); + va_end(ap); } /* - * client_getln() - * * Read and validate next line from the input buffer. */ int @@ -890,8 +700,7 @@ client_getln(struct smtp_client *sp) goto done; } - if (sp->verbose) - fprintf(sp->verbose, "<<< %s\n", ln); + fprintf(sp->verbose, "<<< %s\n", ln); /* 3-char replies are invalid on their own, append space */ if (strlen(ln) == 3) { @@ -941,96 +750,65 @@ client_getln(struct smtp_client *sp) rv = 0; done: if (rv) - strlcpy(sp->ebuf, cause, sizeof(sp->ebuf)); + client_status(sp, cause); free(ln); return (rv); } /* - * client_putln() - * * Add a line to the output buffer. */ -int +void client_putln(struct smtp_client *sp, char *fmt, ...) { struct buf *cmd = NULL; char *p = NULL; - int len, rv = -1; + int len; va_list ap; va_start(ap, fmt); if ((len = vasprintf(&p, fmt, ap)) == -1) - goto done; + fatal("client_putln: vasprintf"); + va_end(ap); - if (sp->verbose) - fprintf(sp->verbose, ">>> %s\n", p); + fprintf(sp->verbose, ">>> %s\n", p); if ((cmd = buf_open(len + 2)) == NULL) - goto done; + fatal(NULL); if (buf_add(cmd, p, len) < 0) - goto done; + fatal(NULL); if (buf_add(cmd, "\r\n", 2) < 0) - goto done; + fatal(NULL); buf_close(&sp->w, cmd); - cmd = NULL; - - rv = 0; -done: - if (rv) - snprintf(sp->ebuf, sizeof(sp->ebuf), "190 %s", strerror(errno)); - va_end(ap); free(p); - if (cmd) - buf_free(cmd); - return (rv); } /* - * client_data_add() - * * Append buffer to the data buffer, performing necessary transformations. */ -int +void client_data_add(struct smtp_client *sp, char *buf, size_t len) { char *ln; - /* check if too late */ - switch (sp->state) { - case CLIENT_INIT: - case CLIENT_SSL_INIT: - case CLIENT_EHLO: - case CLIENT_HELO: - case CLIENT_MAILFROM: - case CLIENT_RCPTTO: - break; - default: - return (-1); - } - /* must end with a newline */ if (len == 0 || buf[len - 1] != '\n') - return (-1); + fatalx("client_data_add: bad buffer"); buf[len - 1] = '\0'; /* split into lines, deal with dot escaping etc. */ while ((ln = strsep(&buf, "\n"))) { if (*ln == '.' && buf_add(sp->data, ".", 1) < 0) - return (-1); + fatal(NULL); if (buf_add(sp->data, ln, strlen(ln)) < 0) - return (-1); + fatal(NULL); if (buf_add(sp->data, "\r\n", 2) < 0) - return (-1); + fatal(NULL); } - - return (0); } /* - * buf_getln() - * * Read a full line from the read buffer. */ char * @@ -1063,8 +841,6 @@ buf_getln(struct buf_read *r) } /* - * buf_read() - * * I/O routine for reading UNIX socket. */ int diff --git a/usr.sbin/smtpd/client.h b/usr.sbin/smtpd/client.h index 14fefbe2e5f..d038ab0acc4 100644 --- a/usr.sbin/smtpd/client.h +++ b/usr.sbin/smtpd/client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: client.h,v 1.4 2009/09/22 12:24:06 jacekm Exp $ */ +/* $OpenBSD: client.h,v 1.5 2009/12/12 10:33:11 jacekm Exp $ */ /* * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> @@ -24,10 +24,9 @@ struct smtp_client; /* return codes for io routines */ #define CLIENT_DONE 0 /* finished ok */ -#define CLIENT_ERROR -1 /* generic error */ -#define CLIENT_WANT_READ -2 /* need more data */ -#define CLIENT_WANT_WRITE -3 /* have to send sth */ -#define CLIENT_RCPT_FAIL -4 /* recipient refused */ +#define CLIENT_WANT_READ -1 /* need more data */ +#define CLIENT_WANT_WRITE -2 /* have to send sth */ +#define CLIENT_RCPT_FAIL -3 /* recipient refused */ /* client states */ #define CLIENT_SSL_INIT 0x1 @@ -41,6 +40,7 @@ struct smtp_client; #define CLIENT_RCPTTO 0x9 #define CLIENT_DATA 0xa #define CLIENT_DATA_BODY 0xb +#define CLIENT_QUIT 0xc /* smtp extensions */ #define CLIENT_EXT_STARTTLS 0 @@ -50,7 +50,7 @@ struct smtp_client; struct rcpt { TAILQ_ENTRY(rcpt) entry; char *mbox; - void *udata; + void *p; }; struct client_auth { @@ -76,35 +76,31 @@ struct smtp_client { char *ehlo; char *sender; TAILQ_HEAD(rlist,rcpt) recipients; - struct rcpt *rcptsent; + struct rcpt *rcpt; + struct rcpt *rcptfail; + size_t rcptokay; struct buf_read r; struct msgbuf w; struct buf *data; struct client_ext exts[CLIENT_EXT_MAX]; + int (*handler)(struct smtp_client *); void *ssl_state; struct client_auth auth; struct timeval timeout; char reply[1024]; - char ebuf[1024]; + char status[1024]; FILE *verbose; }; -struct smtp_client *client_init(int, char *); -struct timeval *client_timeout(struct smtp_client *); -void client_verbose(struct smtp_client *, FILE *); -int client_ssl_smtps(struct smtp_client *); -int client_ssl_optional(struct smtp_client *); -int client_certificate(struct smtp_client *, char *, +struct smtp_client *client_init(int, char *, int); +void client_ssl_smtps(struct smtp_client *); +void client_ssl_optional(struct smtp_client *); +void client_certificate(struct smtp_client *, char *, size_t, char *, size_t); -int client_auth(struct smtp_client *, char *); -int client_sender(struct smtp_client *, char *, ...); -int client_rcpt(struct smtp_client *, char *, ...); -void client_udata_set(struct smtp_client *, void *); -void *client_udata_get(struct smtp_client *); -int client_data_fd(struct smtp_client *, int); -int client_data_printf(struct smtp_client *, char *, ...); -int client_read(struct smtp_client *); -int client_write(struct smtp_client *); +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 *, ...); +int client_talk(struct smtp_client *); void client_close(struct smtp_client *); -char *client_reply(struct smtp_client *); -char *client_strerror(struct smtp_client *); diff --git a/usr.sbin/smtpd/enqueue.c b/usr.sbin/smtpd/enqueue.c index 8adef042444..f5f6c949f95 100644 --- a/usr.sbin/smtpd/enqueue.c +++ b/usr.sbin/smtpd/enqueue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: enqueue.c,v 1.27 2009/12/12 10:14:07 jacekm Exp $ */ +/* $OpenBSD: enqueue.c,v 1.28 2009/12/12 10:33:11 jacekm Exp $ */ /* * Copyright (c) 2005 Henning Brauer <henning@bulabula.org> @@ -78,7 +78,6 @@ struct { }; #define SMTP_LINELEN 1000 -#define SMTP_TIMEOUT 120 #define TIMEOUTMSG "Timeout\n" #define WSP(c) (c == ' ' || c == '\t') @@ -122,10 +121,10 @@ sighdlr(int sig) int enqueue(int argc, char *argv[]) { - int i, ch, tflag = 0, noheader, ret; + int i, ch, tflag = 0, noheader; char *fake_from = NULL; struct passwd *pw; - struct smtp_client *sp; + struct smtp_client *pcb; struct buf *body; bzero(&msg, sizeof(msg)); @@ -186,15 +185,12 @@ enqueue(int argc, char *argv[]) } signal(SIGALRM, sighdlr); - alarm(SMTP_TIMEOUT); + alarm(300); msg.fd = open_connection(); /* init session */ - if ((sp = client_init(msg.fd, "localhost")) == NULL) - err(1, "client_init failed"); - if (verbose) - client_verbose(sp, stdout); + pcb = client_init(msg.fd, "localhost", verbose); /* parse message */ if ((body = buf_dynamic(0, SIZE_T_MAX)) < 0) @@ -202,67 +198,59 @@ enqueue(int argc, char *argv[]) noheader = parse_message(stdin, fake_from == NULL, tflag, body); /* set envelope from */ - if (client_sender(sp, "%s", msg.from) < 0) - err(1, "client_sender failed"); + client_sender(pcb, "%s", msg.from); /* add recipients */ if (msg.rcpt_cnt == 0) errx(1, "no recipients"); for (i = 0; i < msg.rcpt_cnt; i++) - if (client_rcpt(sp, "%s", msg.rcpts[i]) < 0) - err(1, "client_rcpt failed"); + client_rcpt(pcb, "%s", msg.rcpts[i]); /* add From */ - if (!msg.saw_from) { - if (msg.fromname != NULL) { - if (client_data_printf(sp, - "From: %s <%s>\n", msg.fromname, msg.from) < 0) - err(1, "client_data_printf failed"); - } else - if (client_data_printf(sp, - "From: %s\n", msg.from) < 0) - err(1, "client_data_printf failed"); - } + if (!msg.saw_from) + client_data_printf(pcb, "From: %s%s<%s>\n", + msg.fromname ? msg.fromname : "", + msg.fromname ? " " : "", + msg.from); /* add Date */ if (!msg.saw_date) - if (client_data_printf(sp, - "Date: %s\n", time_to_text(timestamp)) < 0) - err(1, "client_data_printf failed"); + client_data_printf(pcb, "Date: %s\n", time_to_text(timestamp)); /* add Message-Id */ if (!msg.saw_msgid) - if (client_data_printf(sp, - "Message-Id: <%llu.enqueue@%s>\n", - generate_uid(), host) < 0) - err(1, "client_data_printf failed"); + client_data_printf(pcb, "Message-Id: <%llu.enqueue@%s>\n", + generate_uid(), host); /* add separating newline */ if (noheader) - if (client_data_printf(sp, "\n") < 0) - err(1, "client_data_printf failed"); + client_data_printf(pcb, "\n"); - if (client_data_printf(sp, "%.*s", buf_size(body), body->buf) < 0) - err(1, "client_data_printf failed"); + client_data_printf(pcb, "%.*s", buf_size(body), body->buf); buf_free(body); /* run the protocol engine */ for (;;) { - while ((ret = client_read(sp)) == CLIENT_WANT_READ) - ; - if (ret == CLIENT_ERROR) - errx(1, "read error: %s", client_strerror(sp)); - if (ret == CLIENT_RCPT_FAIL) - errx(1, "recipient refused: %s", client_reply(sp)); - if (ret == CLIENT_DONE) + alarm(pcb->timeout.tv_sec); + + switch (client_talk(pcb)) { + case CLIENT_WANT_READ: + case CLIENT_WANT_WRITE: + continue; + case CLIENT_RCPT_FAIL: + errx(1, "%s", pcb->reply); + case CLIENT_DONE: break; - while ((ret = client_write(sp)) == CLIENT_WANT_WRITE) - ; - if (ret == CLIENT_ERROR) - errx(1, "write error: %s", client_strerror(sp)); + default: + errx(1, "client_talk: unexpected code"); + } + + if (pcb->status[0] != '2') + errx(1, "%s", pcb->status); + break; } - client_close(sp); + client_close(pcb); close(msg.fd); exit (0); diff --git a/usr.sbin/smtpd/mta.c b/usr.sbin/smtpd/mta.c index 216d1ab1c7c..99ecc7ccd3f 100644 --- a/usr.sbin/smtpd/mta.c +++ b/usr.sbin/smtpd/mta.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta.c,v 1.79 2009/12/10 15:02:30 jacekm Exp $ */ +/* $OpenBSD: mta.c,v 1.80 2009/12/12 10:33:11 jacekm Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -56,10 +56,10 @@ void mta_event(int, short, void *); void mta_status(struct mta_session *, const char *, ...); void mta_message_status(struct message *, char *); +void mta_message_log(struct mta_session *, struct message *); void mta_message_done(struct mta_session *, struct message *); void mta_connect_done(int, short, void *); void mta_request_datafd(struct mta_session *); -size_t mta_todo(struct mta_session *); void mta_sig_handler(int sig, short event, void *p) @@ -537,6 +537,7 @@ mta_enter_state(struct mta_session *s, int newstate, void *p) struct mta_relay *relay; struct sockaddr *sa; struct message *m; + struct smtp_client *pcb; int max_reuse; s->state = newstate; @@ -606,7 +607,8 @@ mta_enter_state(struct mta_session *s, int newstate, void *p) if (connect(s->fd, sa, sa->sa_len) == -1) { if (errno != EINPROGRESS) { - mta_status(s, "110 connect error: %s", strerror(errno)); + mta_status(s, "110 connect error: %s", + strerror(errno)); close(s->fd); continue; } @@ -634,10 +636,7 @@ mta_enter_state(struct mta_session *s, int newstate, void *p) */ log_debug("mta: entering smtp phase"); - s->smtp_state = client_init(s->fd, s->env->sc_hostname); - if (s->smtp_state == NULL) - fatal("mta: client_init failed"); - client_verbose(s->smtp_state, stderr); + pcb = client_init(s->fd, s->env->sc_hostname, 1); /* lookup SSL certificate */ if (s->cert) { @@ -646,57 +645,46 @@ mta_enter_state(struct mta_session *s, int newstate, void *p) strlcpy(key.ssl_name, s->cert, sizeof(key.ssl_name)); res = SPLAY_FIND(ssltree, s->env->sc_ssl, &key); if (res == NULL) { - client_close(s->smtp_state); - s->smtp_state = NULL; + client_close(pcb); mta_status(s, "190 certificate not found"); mta_enter_state(s, MTA_DONE, NULL); break; } - if (client_certificate(s->smtp_state, + client_certificate(pcb, res->ssl_cert, res->ssl_cert_len, - res->ssl_key, res->ssl_key_len) < 0) - fatal("mta: client_certificate failed"); + res->ssl_key, res->ssl_key_len); } /* choose SMTPS vs. STARTTLS */ relay = TAILQ_FIRST(&s->relays); - if ((s->flags & MTA_FORCE_ANYSSL) && relay->used == 1) { - if (client_ssl_smtps(s->smtp_state) < 0) - fatal("mta: client_ssl_smtps failed"); - } else if (s->flags & MTA_FORCE_SMTPS) { - if (client_ssl_smtps(s->smtp_state) < 0) - fatal("mta: client_ssl_smtps failed"); - } else if (s->flags & MTA_ALLOW_PLAIN) { - if (client_ssl_optional(s->smtp_state) < 0) - fatal("mta: client_ssl_optional failed"); - } + if ((s->flags & MTA_FORCE_ANYSSL) && relay->used == 1) + client_ssl_smtps(pcb); + else if (s->flags & MTA_FORCE_SMTPS) + client_ssl_smtps(pcb); + else if (s->flags & MTA_ALLOW_PLAIN) + client_ssl_optional(pcb); /* enable AUTH */ if (s->secret) - if (client_auth(s->smtp_state, s->secret) < 0) - fatal("mta: client_auth failed"); + client_auth(pcb, s->secret); /* set envelope sender */ m = TAILQ_FIRST(&s->recipients); if (m->sender.user[0] && m->sender.domain[0]) - if (client_sender(s->smtp_state, "%s@%s", - m->sender.user, m->sender.domain) < 0) - fatal("mta: client_sender failed"); + client_sender(pcb, "%s@%s", m->sender.user, + m->sender.domain); /* set envelope recipients */ - TAILQ_FOREACH(m, &s->recipients, entry) { - if (client_rcpt(s->smtp_state, "%s@%s", m->recipient.user, - m->recipient.domain) < 0) - fatal("mta: client_rcpt failed"); - client_udata_set(s->smtp_state, m); - } + TAILQ_FOREACH(m, &s->recipients, entry) + client_rcpt(pcb, m, "%s@%s", m->recipient.user, + m->recipient.domain); /* load message body */ - if (client_data_fd(s->smtp_state, s->datafd) < 0) - fatal("mta: client_data_fd failed"); + client_data_fd(pcb, s->datafd); + s->pcb = pcb; event_set(&s->ev, s->fd, EV_WRITE, mta_event, s); - event_add(&s->ev, client_timeout(s->smtp_state)); + event_add(&s->ev, &pcb->timeout); break; case MTA_DONE: @@ -781,7 +769,7 @@ mta_pickup(struct mta_session *s, void *p) /* Remote accepted/rejected connection. */ error = session_socket_error(s->fd); if (error) { - mta_status(s, "110 connect error"); + mta_status(s, "110 connect error: %s", strerror(error)); close(s->fd); mta_enter_state(s, MTA_CONNECT, NULL); } else @@ -801,57 +789,48 @@ void mta_event(int fd, short event, void *p) { struct mta_session *s = p; - int error = 0; - int (*iofunc)(struct smtp_client *); + struct smtp_client *pcb = s->pcb; if (event & EV_TIMEOUT) { - log_debug("mta: leaving smtp phase due to timeout"); mta_status(s, "150 timeout"); - - client_close(s->smtp_state); - s->smtp_state = NULL; - - mta_enter_state(s, MTA_CONNECT, NULL); - return; + goto out; } - if (event & EV_READ) - iofunc = client_read; - else - iofunc = client_write; - - switch (iofunc(s->smtp_state)) { - case CLIENT_RCPT_FAIL: - mta_message_status(client_udata_get(s->smtp_state), - client_reply(s->smtp_state)); - case CLIENT_WANT_WRITE: - event_set(&s->ev, fd, EV_WRITE, mta_event, s); - event_add(&s->ev, client_timeout(s->smtp_state)); - return; + switch (client_talk(pcb)) { case CLIENT_WANT_READ: - event_set(&s->ev, fd, EV_READ, mta_event, s); - event_add(&s->ev, client_timeout(s->smtp_state)); - return; - case CLIENT_ERROR: - error = 1; + goto read; + case CLIENT_WANT_WRITE: + goto write; + case CLIENT_RCPT_FAIL: + mta_message_status(pcb->rcptfail->p, pcb->reply); + mta_message_log(s, pcb->rcptfail->p); + mta_message_done(s, pcb->rcptfail->p); + goto write; case CLIENT_DONE: + mta_status(s, "%s", pcb->status); break; + default: + fatalx("mta_event: unexpected code"); } - log_debug("mta: leaving smtp phase"); - - if (error) - mta_status(s, "%s", client_strerror(s->smtp_state)); - else - mta_status(s, "%s", client_reply(s->smtp_state)); - - client_close(s->smtp_state); - s->smtp_state = NULL; +out: + client_close(pcb); + pcb = NULL; - if (mta_todo(s) == 0) + if (TAILQ_EMPTY(&s->recipients)) mta_enter_state(s, MTA_DONE, NULL); else mta_enter_state(s, MTA_CONNECT, NULL); + return; + +read: + event_set(&s->ev, fd, EV_READ, mta_event, s); + event_add(&s->ev, &pcb->timeout); + return; + +write: + event_set(&s->ev, fd, EV_WRITE, mta_event, s); + event_add(&s->ev, &pcb->timeout); } void @@ -859,7 +838,6 @@ mta_status(struct mta_session *s, const char *fmt, ...) { char *status; struct message *m, *next; - struct mta_relay *relay; va_list ap; va_start(ap, fmt); @@ -873,19 +851,9 @@ mta_status(struct mta_session *s, const char *fmt, ...) /* save new status */ mta_message_status(m, status); - relay = TAILQ_FIRST(&s->relays); - /* remove queue entry */ if (*status == '2' || *status == '5' || *status == '6') { - log_info("%s: to=<%s@%s>, delay=%d, relay=%s [%s]," - " stat=%s (%s)", - m->message_id, m->recipient.user, - m->recipient.domain, time(NULL) - m->creation, - relay ? relay->fqdn : "(none)", - relay ? ss_to_text(&relay->sa) : "", - *status == '2' ? "Sent" : - *status == '5' ? "RemoteError" : "LocalError", - m->session_errorline + 4); + mta_message_log(s, m); mta_message_done(s, m); } } @@ -911,6 +879,23 @@ mta_message_status(struct message *m, char *status) } void +mta_message_log(struct mta_session *s, struct message *m) +{ + struct mta_relay *relay = TAILQ_FIRST(&s->relays); + char *status = m->session_errorline; + + log_info("%s: to=<%s@%s>, delay=%d, relay=%s [%s], stat=%s (%s)", + m->message_id, m->recipient.user, + m->recipient.domain, time(NULL) - m->creation, + relay ? relay->fqdn : "(none)", + relay ? ss_to_text(&relay->sa) : "", + *status == '2' ? "Sent" : + *status == '5' ? "RemoteError" : + *status == '4' ? "RemoteError" : "LocalError", + status + 4); +} + +void mta_message_done(struct mta_session *s, struct message *m) { switch (m->session_errorline[0]) { @@ -950,15 +935,4 @@ mta_request_datafd(struct mta_session *s) 0, 0, -1, &b, sizeof(b)); } -size_t -mta_todo(struct mta_session *s) -{ - struct message *m; - size_t n = 0; - - TAILQ_FOREACH(m, &s->recipients, entry) - n++; - return (n); -} - SPLAY_GENERATE(mtatree, mta_session, entry, mta_session_cmp); diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index 137427e181e..43830fb1492 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.159 2009/11/13 11:27:52 jacekm Exp $ */ +/* $OpenBSD: smtpd.h,v 1.160 2009/12/12 10:33:11 jacekm Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -793,7 +793,7 @@ struct mta_session { int datafd; struct event ev; char *cert; - void *smtp_state; + void *pcb; }; /* aliases.c */ |