diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2009-01-29 13:00:13 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2009-01-29 13:00:13 +0000 |
commit | f2d99bc67c64b127af29db19d8973f978dd85ee2 (patch) | |
tree | a89ddc86d4bf6a304b562557bcf11dc661061e79 | |
parent | ba96c5d19beb899512c74a252bc27ba22155b7bc (diff) |
bring initial support for SSL in the mta part of smtpd, allowing for:
accept for domain "openbsd.org" relay via ssmtp "mx1.example.org"
to ensure that deliveries for whatever@openbsd.org goes through an SSL session
to mx1.example.org
-rw-r--r-- | usr.sbin/smtpd/mta.c | 43 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 3 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl.c | 86 |
3 files changed, 106 insertions, 26 deletions
diff --git a/usr.sbin/smtpd/mta.c b/usr.sbin/smtpd/mta.c index d0393905176..5a13c33b37e 100644 --- a/usr.sbin/smtpd/mta.c +++ b/usr.sbin/smtpd/mta.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta.c,v 1.21 2009/01/28 23:46:03 gilles Exp $ */ +/* $OpenBSD: mta.c,v 1.22 2009/01/29 13:00:12 gilles Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -26,6 +26,8 @@ #include <netinet/in.h> #include <arpa/inet.h> +#include <ssl/ssl.h> + #include <errno.h> #include <event.h> #include <pwd.h> @@ -55,6 +57,8 @@ void mta_expand_mxarray(struct session *); void session_respond(struct session *, char *, ...) __attribute__ ((format (printf, 2, 3))); +void ssl_client_init(struct session *); + void mta_sig_handler(int sig, short event, void *p) { @@ -356,6 +360,7 @@ mta(struct smtpd *env) return (pid); } + ssl_init(); purge_config(env, PURGE_EVERYTHING); pw = env->sc_pw; @@ -444,7 +449,7 @@ mta_connect(struct session* sessionp) sessionp->s_tv.tv_sec = SMTPD_CONNECT_TIMEOUT; sessionp->s_tv.tv_usec = 0; - sessionp->peerfd = s; + sessionp->s_fd = s; event_set(&sessionp->s_ev, s, EV_TIMEOUT|EV_WRITE, mta_write, sessionp); event_add(&sessionp->s_ev, &sessionp->s_tv); @@ -481,22 +486,23 @@ mta_write(int s, short event, void *arg) return; mta_batch_update_queue(batchp); + session_destroy(sessionp); return; } - sessionp->s_l = calloc(1, sizeof(struct listener)); - if (sessionp->s_l == NULL) - fatal("calloc"); - sessionp->s_l->fd = s; sessionp->s_bev = bufferevent_new(s, mta_read_handler, mta_write_handler, mta_error_handler, sessionp); if (sessionp->s_bev == NULL) { mta_batch_update_queue(batchp); - close(s); + session_destroy(sessionp); return; } + if (sessionp->mxarray[sessionp->mx_off].flags & F_SSMTP) { + ssl_client_init(sessionp); + return; + } bufferevent_enable(sessionp->s_bev, EV_READ|EV_WRITE); } @@ -696,6 +702,11 @@ mta_reply_handler(struct bufferevent *bev, void *arg) session_respond(sessionp, "\tby %s with ESMTP id %s", "", batchp->message_id); + if (sessionp->s_flags & F_SECURE) { + session_respond(sessionp, "X-OpenSMTPD-Cipher: %s", + SSL_get_cipher(sessionp->s_ssl)); + } + TAILQ_FOREACH(messagep, &batchp->messages, entry) { session_respond(sessionp, "X-OpenSMTPD-Loop: %s@%s", messagep->session_rcpt.user, @@ -791,7 +802,7 @@ mta_write_handler(struct bufferevent *bev, void *arg) if (sessionp->s_state == S_QUIT) { bufferevent_disable(bev, EV_READ|EV_WRITE); log_debug("closing connection because of QUIT"); - close(sessionp->peerfd); + close(sessionp->s_fd); return; } @@ -839,7 +850,7 @@ mta_error_handler(struct bufferevent *bev, short error, void *arg) if (error & (EVBUFFER_TIMEOUT|EVBUFFER_EOF)) { bufferevent_disable(bev, EV_READ|EV_WRITE); log_debug("closing connection because of an error"); - close(sessionp->peerfd); + close(sessionp->s_fd); return; } } @@ -849,8 +860,6 @@ mta_batch_update_queue(struct batch *batchp) { struct smtpd *env = batchp->env; struct message *messagep; - struct session *sessionp; - struct session key; while ((messagep = TAILQ_FIRST(&batchp->messages)) != NULL) { @@ -870,24 +879,12 @@ mta_batch_update_queue(struct batch *batchp) free(messagep); } - sessionp = batchp->sessionp; - SPLAY_REMOVE(batchtree, &env->batch_queue, batchp); if (batchp->messagefp) fclose(batchp->messagefp); - if (sessionp->s_bev) - bufferevent_free(sessionp->s_bev); - - if (sessionp->peerfd != -1) - close(sessionp->peerfd); - free(batchp); - - SPLAY_REMOVE(sessiontree, &env->sc_sessions, &key); - free(sessionp->mxarray); - free(sessionp); } void diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index f66bcc04441..ae124674101 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.57 2009/01/29 12:43:25 jacekm Exp $ */ +/* $OpenBSD: smtpd.h,v 1.58 2009/01/29 13:00:12 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -593,7 +593,6 @@ struct session { struct session_auth_req s_auth; - int peerfd; struct mxhost *mxarray; u_int8_t mx_cnt; u_int8_t mx_off; diff --git a/usr.sbin/smtpd/ssl.c b/usr.sbin/smtpd/ssl.c index 8b508c14c19..49f7d1238c7 100644 --- a/usr.sbin/smtpd/ssl.c +++ b/usr.sbin/smtpd/ssl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl.c,v 1.5 2009/01/01 16:15:47 jacekm Exp $ */ +/* $OpenBSD: ssl.c,v 1.6 2009/01/29 13:00:12 gilles Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -49,11 +49,64 @@ void ssl_session_accept(int, short, void *); void ssl_read(int, short, void *); void ssl_write(int, short, void *); int ssl_bufferevent_add(struct event *, int); +void ssl_connect(int, short, void *); +void ssl_client_init(struct session *); extern void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *); void +ssl_connect(int fd, short event, void *p) +{ + struct session *s = p; + int ret; + int retry_flag; + int ssl_err; + + if (event == EV_TIMEOUT) { + log_debug("ssl_session_accept: session timed out"); + session_destroy(s); + return; + } + + ret = SSL_connect(s->s_ssl); + if (ret <= 0) { + ssl_err = SSL_get_error(s->s_ssl, ret); + + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + retry_flag = EV_READ; + goto retry; + case SSL_ERROR_WANT_WRITE: + retry_flag = EV_WRITE; + goto retry; + case SSL_ERROR_ZERO_RETURN: + case SSL_ERROR_SYSCALL: + if (ret == 0) { + log_debug("session destroy in MTA #1"); + session_destroy(s); + return; + } + /* FALLTHROUGH */ + default: + ssl_error("ssl_session_connect"); + session_destroy(s); + return; + } + } + + event_set(&s->s_bev->ev_read, s->s_fd, EV_READ, ssl_read, s->s_bev); + event_set(&s->s_bev->ev_write, s->s_fd, EV_WRITE, ssl_write, s->s_bev); + + log_info("ssl_connect: connected to remote ssl server"); + bufferevent_enable(s->s_bev, EV_READ); + s->s_flags |= F_SECURE; + return; +retry: + event_add(&s->s_ev, &s->s_tv); +} + +void ssl_read(int fd, short event, void *p) { struct bufferevent *bufev = p; @@ -491,6 +544,37 @@ ssl_session_init(struct session *s) } void +ssl_client_init(struct session *s) +{ + SSL_CTX *ctx; + + log_debug("ssl_client_init: preparing SSL"); + ctx = ssl_ctx_create(); + + s->s_ssl = SSL_new(ctx); + if (s->s_ssl == NULL) + goto err; + + if (!SSL_set_ssl_method(s->s_ssl, SSLv23_client_method())) + goto err; + if (!SSL_set_fd(s->s_ssl, s->s_fd)) + goto err; + SSL_set_connect_state(s->s_ssl); + + s->s_tv.tv_sec = SMTPD_SESSION_TIMEOUT; + s->s_tv.tv_usec = 0; + + event_set(&s->s_ev, s->s_fd, EV_WRITE|EV_TIMEOUT, ssl_connect, s); + event_add(&s->s_ev, &s->s_tv); + return; + + err: + if (s->s_ssl != NULL) + SSL_free(s->s_ssl); + ssl_error("ssl_client_init"); +} + +void ssl_session_destroy(struct session *s) { SSL_free(s->s_ssl); |