summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2009-01-29 13:00:13 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2009-01-29 13:00:13 +0000
commitf2d99bc67c64b127af29db19d8973f978dd85ee2 (patch)
treea89ddc86d4bf6a304b562557bcf11dc661061e79
parentba96c5d19beb899512c74a252bc27ba22155b7bc (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.c43
-rw-r--r--usr.sbin/smtpd/smtpd.h3
-rw-r--r--usr.sbin/smtpd/ssl.c86
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);