summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorEric Faurot <eric@cvs.openbsd.org>2014-02-04 13:44:42 +0000
committerEric Faurot <eric@cvs.openbsd.org>2014-02-04 13:44:42 +0000
commit5466a3045acfc02b1542c40152b69df386bcf9e0 (patch)
treebd0ebdfd026b293d6b0de4ba08d970ce0ffbce92 /usr.sbin
parent18a6e075a482dcb67a689f725c9795e20a72a992 (diff)
pki code cleanup
- rename "struct ssl" and "cert" to "struct pki" and "cert" to "pki_name" - inherit pki conf on fork instead of passing it through imsg at startup - implement SNI on smtp listeners
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/smtpd/config.c22
-rw-r--r--usr.sbin/smtpd/control.c5
-rw-r--r--usr.sbin/smtpd/envelope.c8
-rw-r--r--usr.sbin/smtpd/lka.c196
-rw-r--r--usr.sbin/smtpd/mta.c24
-rw-r--r--usr.sbin/smtpd/mta_session.c14
-rw-r--r--usr.sbin/smtpd/parse.y50
-rw-r--r--usr.sbin/smtpd/smtp.c114
-rw-r--r--usr.sbin/smtpd/smtp_session.c108
-rw-r--r--usr.sbin/smtpd/smtpd.c169
-rw-r--r--usr.sbin/smtpd/smtpd.h32
-rw-r--r--usr.sbin/smtpd/ssl.c56
-rw-r--r--usr.sbin/smtpd/ssl.h46
-rw-r--r--usr.sbin/smtpd/ssl_privsep.c2
-rw-r--r--usr.sbin/smtpd/ssl_smtpd.c11
15 files changed, 303 insertions, 554 deletions
diff --git a/usr.sbin/smtpd/config.c b/usr.sbin/smtpd/config.c
index 19a675e049a..daed0bd7c40 100644
--- a/usr.sbin/smtpd/config.c
+++ b/usr.sbin/smtpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.23 2014/02/04 09:05:06 eric Exp $ */
+/* $OpenBSD: config.c,v 1.24 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -43,7 +43,7 @@ purge_config(uint8_t what)
struct listener *l;
struct table *t;
struct rule *r;
- struct ssl *s;
+ struct pki *p;
if (what & PURGE_LISTENERS) {
while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
@@ -67,16 +67,16 @@ purge_config(uint8_t what)
free(env->sc_rules);
env->sc_rules = NULL;
}
- if (what & PURGE_SSL) {
- while (dict_poproot(env->sc_ssl_dict, (void **)&s)) {
- memset(s->ssl_cert, 0, s->ssl_cert_len);
- memset(s->ssl_key, 0, s->ssl_key_len);
- free(s->ssl_cert);
- free(s->ssl_key);
- free(s);
+ if (what & PURGE_PKI) {
+ while (dict_poproot(env->sc_pki_dict, (void **)&p)) {
+ memset(p->pki_cert, 0, p->pki_cert_len);
+ memset(p->pki_key, 0, p->pki_key_len);
+ free(p->pki_cert);
+ free(p->pki_key);
+ free(p);
}
- free(env->sc_ssl_dict);
- env->sc_ssl_dict = NULL;
+ free(env->sc_pki_dict);
+ env->sc_pki_dict = NULL;
}
}
diff --git a/usr.sbin/smtpd/control.c b/usr.sbin/smtpd/control.c
index 8e95836584e..49fc41f2bfd 100644
--- a/usr.sbin/smtpd/control.c
+++ b/usr.sbin/smtpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.94 2013/12/26 17:25:32 eric Exp $ */
+/* $OpenBSD: control.c,v 1.95 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
@@ -445,8 +445,7 @@ control_dispatch_ext(struct mproc *p, struct imsg *imsg)
switch (imsg->hdr.type) {
case IMSG_SMTP_ENQUEUE_FD:
- if (env->sc_flags & (SMTPD_SMTP_PAUSED |
- SMTPD_CONFIGURING | SMTPD_EXITING)) {
+ if (env->sc_flags & (SMTPD_SMTP_PAUSED | SMTPD_EXITING)) {
m_compose(p, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
return;
}
diff --git a/usr.sbin/smtpd/envelope.c b/usr.sbin/smtpd/envelope.c
index eaa2717051b..4d3e0d071e7 100644
--- a/usr.sbin/smtpd/envelope.c
+++ b/usr.sbin/smtpd/envelope.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: envelope.c,v 1.26 2013/12/26 17:25:32 eric Exp $ */
+/* $OpenBSD: envelope.c,v 1.27 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
@@ -458,8 +458,8 @@ ascii_load_field(const char *field, struct envelope *ep, char *buf)
sizeof ep->agent.mta.relay.authtable);
if (strcasecmp("mta-relay-cert", field) == 0)
- return ascii_load_string(ep->agent.mta.relay.cert, buf,
- sizeof ep->agent.mta.relay.cert);
+ return ascii_load_string(ep->agent.mta.relay.pki_name, buf,
+ sizeof ep->agent.mta.relay.pki_name);
if (strcasecmp("mta-relay-flags", field) == 0)
return ascii_load_mta_relay_flags(&ep->agent.mta.relay.flags, buf);
@@ -742,7 +742,7 @@ ascii_dump_field(const char *field, const struct envelope *ep,
buf, len);
if (strcasecmp(field, "mta-relay-cert") == 0)
- return ascii_dump_string(ep->agent.mta.relay.cert,
+ return ascii_dump_string(ep->agent.mta.relay.pki_name,
buf, len);
if (strcasecmp(field, "mta-relay-flags") == 0)
diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c
index c03838a1b59..30205777408 100644
--- a/usr.sbin/smtpd/lka.c
+++ b/usr.sbin/smtpd/lka.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka.c,v 1.163 2014/02/04 09:50:31 eric Exp $ */
+/* $OpenBSD: lka.c,v 1.164 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -59,16 +59,10 @@ static int lka_X509_verify(struct ca_vrfy_req_msg *, const char *, const char *)
static void
lka_imsg(struct mproc *p, struct imsg *imsg)
{
- struct rule *rule;
struct table *table;
- void *tmp;
int ret;
- const char *key, *val;
- struct ssl *ssl;
+ struct pki *pki;
struct iovec iov[3];
- static struct dict *ssl_dict;
- static struct dict *tables_dict;
- static struct table *table_last;
static struct ca_vrfy_req_msg *req_ca_vrfy_smtp = NULL;
static struct ca_vrfy_req_msg *req_ca_vrfy_mta = NULL;
struct ca_vrfy_req_msg *req_ca_vrfy_chain;
@@ -130,29 +124,27 @@ lka_imsg(struct mproc *p, struct imsg *imsg)
xlowercase(buf, req_ca_cert->name, sizeof(buf));
log_debug("debug: lka: looking up pki \"%s\"", buf);
- ssl = dict_get(env->sc_ssl_dict, buf);
- if (ssl == NULL) {
+ pki = dict_get(env->sc_pki_dict, buf);
+ if (pki == NULL) {
resp_ca_cert.status = CA_FAIL;
m_compose(p, IMSG_LKA_SSL_INIT, 0, 0, -1, &resp_ca_cert,
sizeof(resp_ca_cert));
return;
}
resp_ca_cert.status = CA_OK;
- resp_ca_cert.cert_len = ssl->ssl_cert_len;
- resp_ca_cert.key_len = ssl->ssl_key_len;
+ resp_ca_cert.cert_len = pki->pki_cert_len;
+ resp_ca_cert.key_len = pki->pki_key_len;
iov[0].iov_base = &resp_ca_cert;
iov[0].iov_len = sizeof(resp_ca_cert);
- iov[1].iov_base = ssl->ssl_cert;
- iov[1].iov_len = ssl->ssl_cert_len;
- iov[2].iov_base = ssl->ssl_key;
- iov[2].iov_len = ssl->ssl_key_len;
+ iov[1].iov_base = pki->pki_cert;
+ iov[1].iov_len = pki->pki_cert_len;
+ iov[2].iov_base = pki->pki_key;
+ iov[2].iov_len = pki->pki_key_len;
m_composev(p, IMSG_LKA_SSL_INIT, 0, 0, -1, iov, nitems(iov));
return;
case IMSG_LKA_SSL_VERIFY_CERT:
req_ca_vrfy_smtp = xmemdup(imsg->data, sizeof *req_ca_vrfy_smtp, "lka:ca_vrfy");
- if (req_ca_vrfy_smtp == NULL)
- fatal(NULL);
req_ca_vrfy_smtp->cert = xmemdup((char *)imsg->data +
sizeof *req_ca_vrfy_smtp, req_ca_vrfy_smtp->cert_len, "lka:ca_vrfy");
req_ca_vrfy_smtp->chain_cert = xcalloc(req_ca_vrfy_smtp->n_chain,
@@ -176,10 +168,10 @@ lka_imsg(struct mproc *p, struct imsg *imsg)
fatalx("lka:ca_vrfy: verify without a certificate");
resp_ca_vrfy.reqid = req_ca_vrfy_smtp->reqid;
- ssl = dict_xget(env->sc_ssl_dict, req_ca_vrfy_smtp->pkiname);
+ pki = dict_xget(env->sc_pki_dict, req_ca_vrfy_smtp->pkiname);
cafile = CA_FILE;
- if (ssl->ssl_ca_file)
- cafile = ssl->ssl_ca_file;
+ if (pki->pki_ca_file)
+ cafile = pki->pki_ca_file;
if (! lka_X509_verify(req_ca_vrfy_smtp, cafile, NULL))
resp_ca_vrfy.status = CA_FAIL;
else
@@ -254,29 +246,27 @@ lka_imsg(struct mproc *p, struct imsg *imsg)
xlowercase(buf, req_ca_cert->name, sizeof(buf));
log_debug("debug: lka: looking up pki \"%s\"", buf);
- ssl = dict_get(env->sc_ssl_dict, buf);
- if (ssl == NULL) {
+ pki = dict_get(env->sc_pki_dict, buf);
+ if (pki == NULL) {
resp_ca_cert.status = CA_FAIL;
m_compose(p, IMSG_LKA_SSL_INIT, 0, 0, -1, &resp_ca_cert,
sizeof(resp_ca_cert));
return;
}
resp_ca_cert.status = CA_OK;
- resp_ca_cert.cert_len = ssl->ssl_cert_len;
- resp_ca_cert.key_len = ssl->ssl_key_len;
+ resp_ca_cert.cert_len = pki->pki_cert_len;
+ resp_ca_cert.key_len = pki->pki_key_len;
iov[0].iov_base = &resp_ca_cert;
iov[0].iov_len = sizeof(resp_ca_cert);
- iov[1].iov_base = ssl->ssl_cert;
- iov[1].iov_len = ssl->ssl_cert_len;
- iov[2].iov_base = ssl->ssl_key;
- iov[2].iov_len = ssl->ssl_key_len;
+ iov[1].iov_base = pki->pki_cert;
+ iov[1].iov_len = pki->pki_cert_len;
+ iov[2].iov_base = pki->pki_key;
+ iov[2].iov_len = pki->pki_key_len;
m_composev(p, IMSG_LKA_SSL_INIT, 0, 0, -1, iov, nitems(iov));
return;
case IMSG_LKA_SSL_VERIFY_CERT:
req_ca_vrfy_mta = xmemdup(imsg->data, sizeof *req_ca_vrfy_mta, "lka:ca_vrfy");
- if (req_ca_vrfy_mta == NULL)
- fatal(NULL);
req_ca_vrfy_mta->cert = xmemdup((char *)imsg->data +
sizeof *req_ca_vrfy_mta, req_ca_vrfy_mta->cert_len, "lka:ca_vrfy");
req_ca_vrfy_mta->chain_cert = xcalloc(req_ca_vrfy_mta->n_chain,
@@ -301,11 +291,11 @@ lka_imsg(struct mproc *p, struct imsg *imsg)
fatalx("lka:ca_vrfy: verify without a certificate");
resp_ca_vrfy.reqid = req_ca_vrfy_mta->reqid;
- ssl = dict_get(env->sc_ssl_dict, req_ca_vrfy_mta->pkiname);
+ pki = dict_get(env->sc_pki_dict, req_ca_vrfy_mta->pkiname);
cafile = CA_FILE;
- if (ssl && ssl->ssl_ca_file)
- cafile = ssl->ssl_ca_file;
+ if (pki && pki->pki_ca_file)
+ cafile = pki->pki_ca_file;
if (! lka_X509_verify(req_ca_vrfy_mta, cafile, NULL))
resp_ca_vrfy.status = CA_FAIL;
else
@@ -392,149 +382,13 @@ lka_imsg(struct mproc *p, struct imsg *imsg)
if (p->proc == PROC_PARENT) {
switch (imsg->hdr.type) {
case IMSG_CONF_START:
- env->sc_rules_reload = xcalloc(1,
- sizeof *env->sc_rules, "lka:sc_rules_reload");
- tables_dict = xcalloc(1,
- sizeof *tables_dict, "lka:tables_dict");
-
- ssl_dict = calloc(1, sizeof *ssl_dict);
- if (ssl_dict == NULL)
- fatal(NULL);
- dict_init(ssl_dict);
- dict_init(tables_dict);
- TAILQ_INIT(env->sc_rules_reload);
-
- return;
-
- case IMSG_CONF_SSL:
- ssl = calloc(1, sizeof *ssl);
- if (ssl == NULL)
- fatal(NULL);
- *ssl = *(struct ssl *)imsg->data;
- ssl->ssl_cert = xstrdup((char *)imsg->data +
- sizeof *ssl, "smtp:ssl_cert");
- ssl->ssl_key = xstrdup((char *)imsg->data +
- sizeof *ssl + ssl->ssl_cert_len, "smtp:ssl_key");
- if (ssl->ssl_dhparams_len) {
- ssl->ssl_dhparams = xstrdup((char *)imsg->data
- + sizeof *ssl + ssl->ssl_cert_len +
- ssl->ssl_key_len, "smtp:ssl_dhparams");
- }
- if (ssl->ssl_ca_len) {
- ssl->ssl_ca = xstrdup((char *)imsg->data
- + sizeof *ssl + ssl->ssl_cert_len +
- ssl->ssl_key_len + ssl->ssl_dhparams_len,
- "smtp:ssl_ca");
- }
- dict_set(ssl_dict, ssl->ssl_name, ssl);
- return;
-
- case IMSG_CONF_RULE:
- rule = xmemdup(imsg->data, sizeof *rule, "lka:rule");
- TAILQ_INSERT_TAIL(env->sc_rules_reload, rule, r_entry);
- return;
-
- case IMSG_CONF_TABLE:
- table_last = table = xmemdup(imsg->data, sizeof *table,
- "lka:table");
- dict_init(&table->t_dict);
- dict_set(tables_dict, table->t_name, table);
- return;
-
- case IMSG_CONF_RULE_SOURCE:
- rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
- tmp = env->sc_tables_dict;
- env->sc_tables_dict = tables_dict;
- rule->r_sources = table_find(imsg->data, NULL);
- if (rule->r_sources == NULL)
- fatalx("lka: tables inconsistency");
- env->sc_tables_dict = tmp;
- return;
-
- case IMSG_CONF_RULE_SENDER:
- rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
- tmp = env->sc_tables_dict;
- env->sc_tables_dict = tables_dict;
- rule->r_senders = table_find(imsg->data, NULL);
- if (rule->r_senders == NULL)
- fatalx("lka: tables inconsistency");
- env->sc_tables_dict = tmp;
- return;
-
- case IMSG_CONF_RULE_RECIPIENT:
- rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
- tmp = env->sc_tables_dict;
- env->sc_tables_dict = tables_dict;
- rule->r_recipients = table_find(imsg->data, NULL);
- if (rule->r_recipients == NULL)
- fatalx("lka: tables inconsistency");
- env->sc_tables_dict = tmp;
- return;
-
- case IMSG_CONF_RULE_DESTINATION:
- rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
- tmp = env->sc_tables_dict;
- env->sc_tables_dict = tables_dict;
- rule->r_destination = table_find(imsg->data, NULL);
- if (rule->r_destination == NULL)
- fatalx("lka: tables inconsistency");
- env->sc_tables_dict = tmp;
- return;
-
- case IMSG_CONF_RULE_MAPPING:
- rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
- tmp = env->sc_tables_dict;
- env->sc_tables_dict = tables_dict;
- rule->r_mapping = table_find(imsg->data, NULL);
- if (rule->r_mapping == NULL)
- fatalx("lka: tables inconsistency");
- env->sc_tables_dict = tmp;
- return;
-
- case IMSG_CONF_RULE_USERS:
- rule = TAILQ_LAST(env->sc_rules_reload, rulelist);
- tmp = env->sc_tables_dict;
- env->sc_tables_dict = tables_dict;
- rule->r_userbase = table_find(imsg->data, NULL);
- if (rule->r_userbase == NULL)
- fatalx("lka: tables inconsistency");
- env->sc_tables_dict = tmp;
- return;
-
- case IMSG_CONF_TABLE_CONTENT:
- table = table_last;
- if (table == NULL)
- fatalx("lka: tables inconsistency");
-
- key = imsg->data;
- if (table->t_type == T_HASH)
- val = key + strlen(key) + 1;
- else
- val = NULL;
-
- dict_set(&table->t_dict, key,
- val ? xstrdup(val, "lka:dict_set") : NULL);
return;
case IMSG_CONF_END:
-
- if (env->sc_rules)
- purge_config(PURGE_RULES);
- if (env->sc_tables_dict) {
- table_close_all();
- purge_config(PURGE_TABLES);
- }
- env->sc_rules = env->sc_rules_reload;
- env->sc_ssl_dict = ssl_dict;
- env->sc_tables_dict = tables_dict;
if (verbose & TRACE_TABLES)
table_dump_all();
table_open_all();
- ssl_dict = NULL;
- table_last = NULL;
- tables_dict = NULL;
-
/* Start fulfilling requests */
mproc_enable(p_mda);
mproc_enable(p_mta);
@@ -629,7 +483,7 @@ lka(void)
return (pid);
}
- purge_config(PURGE_EVERYTHING);
+ purge_config(PURGE_LISTENERS);
if ((pw = getpwnam(SMTPD_USER)) == NULL)
fatalx("unknown user " SMTPD_USER);
diff --git a/usr.sbin/smtpd/mta.c b/usr.sbin/smtpd/mta.c
index f7f364e0309..487425cf9b8 100644
--- a/usr.sbin/smtpd/mta.c
+++ b/usr.sbin/smtpd/mta.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mta.c,v 1.178 2013/12/26 17:25:32 eric Exp $ */
+/* $OpenBSD: mta.c,v 1.179 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -1604,9 +1604,9 @@ mta_relay(struct envelope *e)
key.flags |= e->agent.mta.relay.flags;
key.port = e->agent.mta.relay.port;
- key.cert = e->agent.mta.relay.cert;
- if (!key.cert[0])
- key.cert = NULL;
+ key.pki_name = e->agent.mta.relay.pki_name;
+ if (!key.pki_name[0])
+ key.pki_name = NULL;
key.authtable = e->agent.mta.relay.authtable;
if (!key.authtable[0])
key.authtable = NULL;
@@ -1633,7 +1633,7 @@ mta_relay(struct envelope *e)
xstrdup(key.backupname, "mta: backupname") : NULL;
r->backuppref = -1;
r->port = key.port;
- r->cert = key.cert ? xstrdup(key.cert, "mta: cert") : NULL;
+ r->pki_name = key.pki_name ? xstrdup(key.pki_name, "mta: pki_name") : NULL;
if (key.authtable)
r->authtable = xstrdup(key.authtable, "mta: authtable");
if (key.authlabel)
@@ -1688,7 +1688,7 @@ mta_relay_unref(struct mta_relay *relay)
free(relay->authlabel);
free(relay->authtable);
free(relay->backupname);
- free(relay->cert);
+ free(relay->pki_name);
free(relay->helotable);
free(relay->heloname);
free(relay->secret);
@@ -1732,10 +1732,10 @@ mta_relay_to_text(struct mta_relay *relay)
strlcat(buf, relay->authlabel, sizeof buf);
}
- if (relay->cert) {
+ if (relay->pki_name) {
strlcat(buf, sep, sizeof buf);
- strlcat(buf, "cert=", sizeof buf);
- strlcat(buf, relay->cert, sizeof buf);
+ strlcat(buf, "pki_name=", sizeof buf);
+ strlcat(buf, relay->pki_name, sizeof buf);
}
if (relay->flags & RELAY_MX) {
@@ -1911,11 +1911,11 @@ mta_relay_cmp(const struct mta_relay *a, const struct mta_relay *b)
if (a->heloname && ((r = strcmp(a->heloname, b->heloname))))
return (r);
- if (a->cert == NULL && b->cert)
+ if (a->pki_name == NULL && b->pki_name)
return (-1);
- if (a->cert && b->cert == NULL)
+ if (a->pki_name && b->pki_name == NULL)
return (1);
- if (a->cert && ((r = strcmp(a->cert, b->cert))))
+ if (a->pki_name && ((r = strcmp(a->pki_name, b->pki_name))))
return (r);
if (a->backupname && ((r = strcmp(a->backupname, b->backupname))))
diff --git a/usr.sbin/smtpd/mta_session.c b/usr.sbin/smtpd/mta_session.c
index a5362bde65d..16b3b83dff5 100644
--- a/usr.sbin/smtpd/mta_session.c
+++ b/usr.sbin/smtpd/mta_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mta_session.c,v 1.51 2014/02/04 09:50:31 eric Exp $ */
+/* $OpenBSD: mta_session.c,v 1.52 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -195,7 +195,7 @@ mta_session(struct mta_relay *relay, struct mta_route *route)
if (relay->flags & RELAY_SSL && relay->flags & RELAY_AUTH)
s->flags |= MTA_USE_AUTH;
- if (relay->cert)
+ if (relay->pki_name)
s->flags |= MTA_USE_CERT;
if (relay->flags & RELAY_LMTP)
s->flags |= MTA_LMTP;
@@ -318,7 +318,7 @@ mta_session_imsg(struct mproc *p, struct imsg *imsg)
return;
if (resp_ca_cert->status == CA_FAIL) {
- if (s->relay->cert) {
+ if (s->relay->pki_name) {
log_info("smtp-out: Disconnecting session %016"PRIx64
": CA failure", s->id);
mta_free(s);
@@ -1498,8 +1498,8 @@ mta_start_tls(struct mta_session *s)
struct ca_cert_req_msg req_ca_cert;
const char *certname;
- if (s->relay->cert)
- certname = s->relay->cert;
+ if (s->relay->pki_name)
+ certname = s->relay->pki_name;
else
certname = s->helo;
@@ -1540,8 +1540,8 @@ mta_verify_certificate(struct mta_session *s)
/* Send the client certificate */
memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
- if (s->relay->cert)
- pkiname = s->relay->cert;
+ if (s->relay->pki_name)
+ pkiname = s->relay->pki_name;
else
pkiname = s->helo;
if (strlcpy(req_ca_vrfy.pkiname, pkiname, sizeof req_ca_vrfy.pkiname)
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index 38d8062fe07..8d3188492cb 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.136 2014/01/22 00:21:17 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.137 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -96,7 +96,7 @@ struct table *table = NULL;
struct rule *rule = NULL;
struct listener l;
struct mta_limits *limits;
-static struct ssl *pki_ssl;
+static struct pki *pki;
static struct listen_opts {
char *ifx;
@@ -332,16 +332,16 @@ limits_scheduler: opt_limit_scheduler limits_scheduler
;
opt_pki : CERTIFICATE STRING {
- pki_ssl->ssl_cert_file = $2;
+ pki->pki_cert_file = $2;
}
| KEY STRING {
- pki_ssl->ssl_key_file = $2;
+ pki->pki_key_file = $2;
}
| CA STRING {
- pki_ssl->ssl_ca_file = $2;
+ pki->pki_ca_file = $2;
}
| DHPARAMS STRING {
- pki_ssl->ssl_dhparams_file = $2;
+ pki->pki_dhparams_file = $2;
}
;
@@ -463,14 +463,14 @@ opt_relay_common: AS STRING {
sizeof rule->r_value.relayhost.helotable);
}
| PKI STRING {
- if (! lowercase(rule->r_value.relayhost.cert, $2,
- sizeof(rule->r_value.relayhost.cert))) {
+ if (! lowercase(rule->r_value.relayhost.pki_name, $2,
+ sizeof(rule->r_value.relayhost.pki_name))) {
yyerror("pki name too long: %s", $2);
free($2);
YYERROR;
}
- if (dict_get(conf->sc_ssl_dict,
- rule->r_value.relayhost.cert) == NULL) {
+ if (dict_get(conf->sc_pki_dict,
+ rule->r_value.relayhost.pki_name) == NULL) {
log_warnx("pki name not found: %s", $2);
free($2);
YYERROR;
@@ -633,11 +633,11 @@ main : BOUNCEWARN {
char buf[MAXHOSTNAMELEN];
xlowercase(buf, $2, sizeof(buf));
free($2);
- pki_ssl = dict_get(conf->sc_ssl_dict, buf);
- if (pki_ssl == NULL) {
- pki_ssl = xcalloc(1, sizeof *pki_ssl, "parse:pki");
- strlcpy(pki_ssl->ssl_name, buf, sizeof(pki_ssl->ssl_name));
- dict_set(conf->sc_ssl_dict, pki_ssl->ssl_name, pki_ssl);
+ pki = dict_get(conf->sc_pki_dict, buf);
+ if (pki == NULL) {
+ pki = xcalloc(1, sizeof *pki, "parse:pki");
+ strlcpy(pki->pki_name, buf, sizeof(pki->pki_name));
+ dict_set(conf->sc_pki_dict, pki->pki_name, pki);
}
} pki
;
@@ -1452,7 +1452,7 @@ check_file_secrecy(int fd, const char *fname)
return (-1);
}
if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
- log_warnx("%s: group writable or world read/writable", fname);
+ log_warnx("warn: %s: group/world readable/writeable", fname);
return (-1);
}
return (0);
@@ -1526,6 +1526,7 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts)
conf->sc_tables_dict = calloc(1, sizeof(*conf->sc_tables_dict));
conf->sc_rules = calloc(1, sizeof(*conf->sc_rules));
conf->sc_listeners = calloc(1, sizeof(*conf->sc_listeners));
+ conf->sc_pki_dict = calloc(1, sizeof(*conf->sc_pki_dict));
conf->sc_ssl_dict = calloc(1, sizeof(*conf->sc_ssl_dict));
conf->sc_limits_dict = calloc(1, sizeof(*conf->sc_limits_dict));
@@ -1535,12 +1536,13 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts)
if (conf->sc_tables_dict == NULL ||
conf->sc_rules == NULL ||
conf->sc_listeners == NULL ||
- conf->sc_ssl_dict == NULL ||
+ conf->sc_pki_dict == NULL ||
conf->sc_limits_dict == NULL) {
log_warn("warn: cannot allocate memory");
free(conf->sc_tables_dict);
free(conf->sc_rules);
free(conf->sc_listeners);
+ free(conf->sc_pki_dict);
free(conf->sc_ssl_dict);
free(conf->sc_limits_dict);
return (-1);
@@ -1553,6 +1555,7 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts)
dict_init(&conf->sc_filters);
+ dict_init(conf->sc_pki_dict);
dict_init(conf->sc_ssl_dict);
dict_init(conf->sc_tables_dict);
@@ -1732,9 +1735,6 @@ create_listener(struct listenerlist *ll, struct listen_opts *lo)
if (lo->pki && !lo->ssl)
errx(1, "invalid listen option: pki requires tls/smtps");
- if (lo->ssl && !lo->pki)
- errx(1, "invalid listen option: tls/smtps requires pki");
-
flags = lo->flags;
if (lo->port) {
@@ -1775,18 +1775,16 @@ config_listener(struct listener *h, struct listen_opts *lo)
if (lo->hostname == NULL)
lo->hostname = conf->sc_hostname;
- h->ssl = NULL;
- h->ssl_cert_name[0] = '\0';
+ h->pki_name[0] = '\0';
if (lo->authtable != NULL)
(void)strlcpy(h->authtable, lo->authtable->t_name, sizeof(h->authtable));
if (lo->pki != NULL) {
- if (! lowercase(h->ssl_cert_name, lo->pki,
- sizeof(h->ssl_cert_name))) {
+ if (! lowercase(h->pki_name, lo->pki, sizeof(h->pki_name))) {
log_warnx("pki name too long: %s", lo->pki);
fatalx(NULL);
}
- if (dict_get(conf->sc_ssl_dict, h->ssl_cert_name) == NULL) {
+ if (dict_get(conf->sc_pki_dict, h->pki_name) == NULL) {
log_warnx("pki name not found: %s", lo->pki);
fatalx(NULL);
}
@@ -1855,7 +1853,7 @@ host_dns(struct listenerlist *al, struct listen_opts *lo)
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
+ hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(lo->ifx, NULL, &hints, &res0);
if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
return (0);
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c
index 106e81c795b..91b079d9a8f 100644
--- a/usr.sbin/smtpd/smtp.c
+++ b/usr.sbin/smtpd/smtp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp.c,v 1.132 2014/02/04 09:05:06 eric Exp $ */
+/* $OpenBSD: smtp.c,v 1.133 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -50,6 +50,7 @@ static void smtp_resume(void);
static void smtp_accept(int, short, void *);
static int smtp_enqueue(uid_t *);
static int smtp_can_accept(void);
+static void smtp_setup_listeners(void);
#define SMTP_FD_RESERVE 5
static size_t sessions;
@@ -57,8 +58,6 @@ static size_t sessions;
static void
smtp_imsg(struct mproc *p, struct imsg *imsg)
{
- struct listener *l;
- struct ssl *ssl;
struct msg m;
int v;
@@ -105,68 +104,10 @@ smtp_imsg(struct mproc *p, struct imsg *imsg)
switch (imsg->hdr.type) {
case IMSG_CONF_START:
- if (env->sc_flags & SMTPD_CONFIGURING)
- return;
- env->sc_flags |= SMTPD_CONFIGURING;
- env->sc_listeners = calloc(1,
- sizeof *env->sc_listeners);
- if (env->sc_listeners == NULL)
- fatal(NULL);
- env->sc_ssl_dict = calloc(1, sizeof *env->sc_ssl_dict);
- if (env->sc_ssl_dict == NULL)
- fatal(NULL);
- dict_init(env->sc_ssl_dict);
- TAILQ_INIT(env->sc_listeners);
- return;
-
- case IMSG_CONF_SSL:
- if (!(env->sc_flags & SMTPD_CONFIGURING))
- return;
- ssl = calloc(1, sizeof *ssl);
- if (ssl == NULL)
- fatal(NULL);
- *ssl = *(struct ssl *)imsg->data;
- ssl->ssl_cert = xstrdup((char *)imsg->data +
- sizeof *ssl, "smtp:ssl_cert");
- ssl->ssl_key = xstrdup((char *)imsg->data +
- sizeof *ssl + ssl->ssl_cert_len, "smtp:ssl_key");
- if (ssl->ssl_dhparams_len) {
- ssl->ssl_dhparams = xstrdup((char *)imsg->data
- + sizeof *ssl + ssl->ssl_cert_len +
- ssl->ssl_key_len, "smtp:ssl_dhparams");
- }
- if (ssl->ssl_ca_len) {
- ssl->ssl_ca = xstrdup((char *)imsg->data
- + sizeof *ssl + ssl->ssl_cert_len +
- ssl->ssl_key_len + ssl->ssl_dhparams_len,
- "smtp:ssl_ca");
- }
- dict_set(env->sc_ssl_dict, ssl->ssl_name, ssl);
- return;
-
- case IMSG_CONF_LISTENER:
- if (!(env->sc_flags & SMTPD_CONFIGURING))
- return;
- l = calloc(1, sizeof *l);
- if (l == NULL)
- fatal(NULL);
- *l = *(struct listener *)imsg->data;
- l->fd = imsg->fd;
- if (l->fd < 0)
- fatalx("smtp: listener pass failed");
- if (l->flags & F_SSL) {
- l->ssl = dict_get(env->sc_ssl_dict, l->ssl_cert_name);
- if (l->ssl == NULL)
- fatalx("smtp: ssltree out of sync");
- }
- TAILQ_INSERT_TAIL(env->sc_listeners, l, entry);
return;
case IMSG_CONF_END:
- if (!(env->sc_flags & SMTPD_CONFIGURING))
- return;
smtp_setup_events();
- env->sc_flags &= ~SMTPD_CONFIGURING;
return;
case IMSG_CTL_VERBOSE:
@@ -247,7 +188,10 @@ smtp(void)
return (pid);
}
- purge_config(PURGE_EVERYTHING);
+ smtp_setup_listeners();
+
+ /* SSL will be purged later */
+ purge_config(PURGE_TABLES|PURGE_RULES);
if ((pw = getpwnam(SMTPD_USER)) == NULL)
fatalx("unknown user " SMTPD_USER);
@@ -289,15 +233,41 @@ smtp(void)
}
static void
+smtp_setup_listeners(void)
+{
+ struct listener *l;
+ int opt;
+
+ TAILQ_FOREACH(l, env->sc_listeners, entry) {
+ if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1) {
+ if (errno == EAFNOSUPPORT) {
+ log_warn("smtpd: socket");
+ continue;
+ }
+ fatal("smtpd: socket");
+ }
+ opt = 1;
+ if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt,
+ sizeof(opt)) < 0)
+ fatal("smtpd: setsockopt");
+ if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1)
+ fatal("smtpd: bind");
+ }
+}
+
+static void
smtp_setup_events(void)
{
struct listener *l;
- struct ssl *ssl, key;
+ struct pki *pki;
+ SSL_CTX *ssl_ctx;
+ void *iter;
+ const char *k;
TAILQ_FOREACH(l, env->sc_listeners, entry) {
log_debug("debug: smtp: listen on %s port %d flags 0x%01x"
" pki \"%s\"", ss_to_text(&l->ss), ntohs(l->port),
- l->flags, l->ssl_cert_name);
+ l->flags, l->pki_name);
session_socket_blockmode(l->fd, BM_NONBLOCK);
if (listen(l->fd, SMTPD_BACKLOG) == -1)
@@ -306,20 +276,16 @@ smtp_setup_events(void)
if (!(env->sc_flags & SMTPD_SMTP_PAUSED))
event_add(&l->ev, NULL);
+ }
- if (!(l->flags & F_SSL))
- continue;
-
- if (strlcpy(key.ssl_name, l->ssl_cert_name, sizeof(key.ssl_name))
- >= sizeof(key.ssl_name))
- fatal("smtp_setup_events: certificate name truncated");
- if ((ssl = dict_get(env->sc_ssl_dict, l->ssl_cert_name)) == NULL)
- fatal("smtp_setup_events: certificate tree corrupted");
- if (! ssl_setup((SSL_CTX **)&l->ssl_ctx, ssl))
+ iter = NULL;
+ while (dict_iter(env->sc_pki_dict, &iter, &k, (void **)&pki)) {
+ if (! ssl_setup((SSL_CTX **)&ssl_ctx, pki))
fatal("smtp_setup_events: ssl_setup failure");
+ dict_xset(env->sc_ssl_dict, k, ssl_ctx);
}
- purge_config(PURGE_SSL);
+ purge_config(PURGE_PKI);
log_debug("debug: smtp: will accept at most %d clients",
(getdtablesize() - getdtablecount())/2 - SMTP_FD_RESERVE);
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index 3a8d4ff8838..5b6ac71f3fc 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.193 2014/02/04 09:50:31 eric Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.194 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -112,9 +112,11 @@ struct smtp_session {
struct iobuf iobuf;
struct io io;
struct listener *listener;
+ void *ssl_ctx;
struct sockaddr_storage ss;
char hostname[SMTPD_MAXHOSTNAMELEN];
char smtpname[SMTPD_MAXHOSTNAMELEN];
+ char sni[SMTPD_MAXHOSTNAMELEN];
int flags;
int phase;
@@ -154,6 +156,7 @@ struct smtp_session {
static int smtp_mailaddr(struct mailaddr *, char *, int, char **, const char *);
static void smtp_session_init(void);
+static int smtp_lookup_servername(struct smtp_session *);
static void smtp_connected(struct smtp_session *);
static void smtp_send_banner(struct smtp_session *);
static void smtp_mfa_response(struct smtp_session *, int, uint32_t,
@@ -174,6 +177,7 @@ static const char *smtp_strstate(int);
static int smtp_verify_certificate(struct smtp_session *);
static void smtp_auth_failure_pause(struct smtp_session *);
static void smtp_auth_failure_resume(int, short, void *);
+static int smtp_sni_callback(SSL *, int *, void *);
static struct { int code; const char *cmd; } commands[] = {
{ CMD_HELO, "HELO" },
@@ -260,7 +264,8 @@ smtp_session(struct listener *listener, int sock,
if (!strcmp(hostname, "localhost"))
s->flags |= SF_BOUNCE;
strlcpy(s->hostname, hostname, sizeof(s->hostname));
- smtp_connected(s);
+ if (smtp_lookup_servername(s))
+ smtp_connected(s);
} else {
dns_query_ptr(s->id, (struct sockaddr *)&s->ss);
tree_xset(&wait_lka_ptr, s->id, s);
@@ -284,6 +289,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
uint32_t code, msgid;
int status, success, dnserror;
X509 *x;
+ void *ssl_ctx;
switch (imsg->hdr.type) {
case IMSG_DNS_PTR:
@@ -297,7 +303,8 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
m_end(&m);
s = tree_xpop(&wait_lka_ptr, reqid);
strlcpy(s->hostname, line, sizeof s->hostname);
- smtp_connected(s);
+ if (smtp_lookup_servername(s))
+ smtp_connected(s);
return;
case IMSG_LKA_EXPAND_RCPT:
@@ -335,8 +342,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
strlcpy(s->smtpname, helo, sizeof(s->smtpname));
}
m_end(&m);
- smtp_reply(s, SMTPD_BANNER, s->smtpname, SMTPD_NAME);
- io_reload(&s->io);
+ smtp_connected(s);
return;
case IMSG_MFA_SMTP_RESPONSE:
@@ -579,9 +585,15 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
sizeof *resp_ca_cert + resp_ca_cert->cert_len,
"smtp:ca_key");
- ssl = ssl_smtp_init(s->listener->ssl_ctx,
+ if (s->listener->pki_name[0])
+ ssl_ctx = dict_get(env->sc_ssl_dict, s->listener->pki_name);
+ else
+ ssl_ctx = dict_get(env->sc_ssl_dict, s->smtpname);
+
+ ssl = ssl_smtp_init(ssl_ctx,
resp_ca_cert->cert, resp_ca_cert->cert_len,
- resp_ca_cert->key, resp_ca_cert->key_len);
+ resp_ca_cert->key, resp_ca_cert->key_len,
+ smtp_sni_callback, s);
io_set_read(&s->io);
io_start_tls(&s->io, ssl);
@@ -641,7 +653,7 @@ smtp_mfa_response(struct smtp_session *s, int status, uint32_t code,
if (s->listener->flags & F_SMTPS) {
req_ca_cert.reqid = s->id;
- strlcpy(req_ca_cert.name, s->listener->ssl_cert_name,
+ strlcpy(req_ca_cert.name, s->smtpname,
sizeof req_ca_cert.name);
m_compose(p_lka, IMSG_LKA_SSL_INIT, 0, 0, -1,
&req_ca_cert, sizeof(req_ca_cert));
@@ -881,11 +893,10 @@ smtp_io(struct io *io, int evt)
break;
}
-
/* Wait for the client to start tls */
if (s->state == STATE_TLS) {
req_ca_cert.reqid = s->id;
- strlcpy(req_ca_cert.name, s->listener->ssl_cert_name,
+ strlcpy(req_ca_cert.name, s->smtpname,
sizeof req_ca_cert.name);
m_compose(p_lka, IMSG_LKA_SSL_INIT, 0, 0, -1,
&req_ca_cert, sizeof(req_ca_cert));
@@ -1335,6 +1346,32 @@ smtp_parse_mail_args(struct smtp_session *s, char *args)
return (0);
}
+static int
+smtp_lookup_servername(struct smtp_session *s)
+{
+ struct sockaddr *sa;
+ socklen_t sa_len;
+ struct sockaddr_storage ss;
+
+ if (s->listener->hostnametable[0]) {
+ sa_len = sizeof(ss);
+ sa = (struct sockaddr *)&ss;
+ if (getsockname(s->io.sock, sa, &sa_len) == -1) {
+ log_warn("warn: getsockname()");
+ }
+ else {
+ m_create(p_lka, IMSG_LKA_HELO, 0, 0, -1);
+ m_add_id(p_lka, s->id);
+ m_add_string(p_lka, s->listener->hostnametable);
+ m_add_sockaddr(p_lka, sa);
+ m_close(p_lka);
+ tree_xset(&wait_lka_helo, s->id, s);
+ return 0;
+ }
+ }
+ return 1;
+}
+
static void
smtp_connected(struct smtp_session *s)
{
@@ -1365,27 +1402,6 @@ smtp_connected(struct smtp_session *s)
static void
smtp_send_banner(struct smtp_session *s)
{
- struct sockaddr_storage ss;
- struct sockaddr *sa;
- socklen_t sa_len;
-
- if (s->listener->hostnametable[0]) {
- sa_len = sizeof(ss);
- sa = (struct sockaddr *)&ss;
- if (getsockname(s->io.sock, sa, &sa_len) == -1) {
- log_warn("warn: getsockname()");
- }
- else {
- m_create(p_lka, IMSG_LKA_HELO, 0, 0, -1);
- m_add_id(p_lka, s->id);
- m_add_string(p_lka, s->listener->hostnametable);
- m_add_sockaddr(p_lka, sa);
- m_close(p_lka);
- tree_xset(&wait_lka_helo, s->id, s);
- return;
- }
- }
-
smtp_reply(s, SMTPD_BANNER, s->smtpname, SMTPD_NAME);
io_reload(&s->io);
}
@@ -1636,6 +1652,7 @@ smtp_verify_certificate(struct smtp_session *s)
X509 *x;
STACK_OF(X509) *xchain;
int i;
+ const char *pkiname;
x = SSL_get_peer_certificate(s->io.ssl);
if (x == NULL)
@@ -1654,7 +1671,12 @@ smtp_verify_certificate(struct smtp_session *s)
/* Send the client certificate */
memset(&req_ca_vrfy, 0, sizeof req_ca_vrfy);
- if (strlcpy(req_ca_vrfy.pkiname, s->listener->ssl_cert_name, sizeof req_ca_vrfy.pkiname)
+ if (s->listener->pki_name[0])
+ pkiname = s->listener->pki_name;
+ else
+ pkiname = s->smtpname;
+
+ if (strlcpy(req_ca_vrfy.pkiname, pkiname, sizeof req_ca_vrfy.pkiname)
>= sizeof req_ca_vrfy.pkiname)
return 0;
@@ -1720,6 +1742,28 @@ smtp_auth_failure_pause(struct smtp_session *s)
evtimer_add(&s->pause, &tv);
}
+static int
+smtp_sni_callback(SSL *ssl, int *ad, void *arg)
+{
+ const char *sn;
+ struct smtp_session *s = arg;
+ void *ssl_ctx;
+
+ sn = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (sn == NULL)
+ return SSL_TLSEXT_ERR_NOACK;
+ if (strlcpy(s->sni, sn, sizeof s->sni) >= sizeof s->sni) {
+ log_warnx("warn: client SNI exceeds max hostname length");
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ ssl_ctx = dict_get(env->sc_ssl_dict, sn);
+ if (ssl_ctx == NULL) {
+ log_warnx("warn: SNI name not found in PKI");
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ SSL_set_SSL_CTX(ssl, ssl_ctx);
+ return SSL_TLSEXT_ERR_OK;
+}
#define CASE(x) case x : return #x
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c
index 3fdd9c807a3..820e9badd3b 100644
--- a/usr.sbin/smtpd/smtpd.c
+++ b/usr.sbin/smtpd/smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.c,v 1.209 2014/02/04 09:05:06 eric Exp $ */
+/* $OpenBSD: smtpd.c,v 1.210 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -75,7 +75,7 @@ static int offline_enqueue(char *);
static void purge_task(int, short, void *);
static void log_imsg(int, int, struct imsg *);
static int parent_auth_user(const char *, const char *);
-static void load_ssl_tree(void);
+static void load_pki_tree(void);
enum child_type {
CHILD_DAEMON,
@@ -327,48 +327,14 @@ parent_send_config(int fd, short event, void *p)
parent_send_config_lka();
parent_send_config_mfa();
parent_send_config_smtp();
- purge_config(PURGE_SSL);
+ purge_config(PURGE_PKI);
}
static void
parent_send_config_smtp(void)
{
- struct listener *l;
- struct ssl *s;
- void *iter = NULL;
- struct iovec iov[5];
- int opt;
-
log_debug("debug: parent_send_config: configuring smtp");
m_compose(p_smtp, IMSG_CONF_START, 0, 0, -1, NULL, 0);
-
- while (dict_iter(env->sc_ssl_dict, &iter, NULL, (void **)&s)) {
- iov[0].iov_base = s;
- iov[0].iov_len = sizeof(*s);
- iov[1].iov_base = s->ssl_cert;
- iov[1].iov_len = s->ssl_cert_len;
- iov[2].iov_base = s->ssl_key;
- iov[2].iov_len = s->ssl_key_len;
- iov[3].iov_base = s->ssl_dhparams;
- iov[3].iov_len = s->ssl_dhparams_len;
- iov[4].iov_base = s->ssl_ca;
- iov[4].iov_len = s->ssl_ca_len;
- m_composev(p_smtp, IMSG_CONF_SSL, 0, 0, -1, iov, nitems(iov));
- }
-
- TAILQ_FOREACH(l, env->sc_listeners, entry) {
- if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1)
- fatal("smtpd: socket");
- opt = 1;
- if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt,
- sizeof(opt)) < 0)
- fatal("smtpd: setsockopt");
- if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1)
- fatal("smtpd: bind");
- m_compose(p_smtp, IMSG_CONF_LISTENER, 0, 0, l->fd,
- l, sizeof(*l));
- }
-
m_compose(p_smtp, IMSG_CONF_END, 0, 0, -1, NULL, 0);
}
@@ -390,93 +356,8 @@ parent_send_config_mfa()
void
parent_send_config_lka()
{
- struct rule *r;
- struct table *t;
- void *iter_tree;
- void *iter_dict;
- const char *k;
- char *v;
- char *buffer;
- size_t buflen;
- struct ssl *s;
- struct iovec iov[5];
-
log_debug("debug: parent_send_config_ruleset: reloading");
m_compose(p_lka, IMSG_CONF_START, 0, 0, -1, NULL, 0);
-
- iter_dict = NULL;
- while (dict_iter(env->sc_ssl_dict, &iter_dict, NULL, (void **)&s)) {
- iov[0].iov_base = s;
- iov[0].iov_len = sizeof(*s);
- iov[1].iov_base = s->ssl_cert;
- iov[1].iov_len = s->ssl_cert_len;
- iov[2].iov_base = s->ssl_key;
- iov[2].iov_len = s->ssl_key_len;
- iov[3].iov_base = s->ssl_dhparams;
- iov[3].iov_len = s->ssl_dhparams_len;
- iov[4].iov_base = s->ssl_ca;
- iov[4].iov_len = s->ssl_ca_len;
- m_composev(p_lka, IMSG_CONF_SSL, 0, 0, -1, iov, nitems(iov));
- }
-
- iter_tree = NULL;
- while (dict_iter(env->sc_tables_dict, &iter_tree, NULL,
- (void **)&t)) {
- m_compose(p_lka, IMSG_CONF_TABLE, 0, 0, -1, t, sizeof(*t));
-
- iter_dict = NULL;
- while (dict_iter(&t->t_dict, &iter_dict, &k,
- (void **)&v)) {
- buflen = strlen(k) + 1;
- if (v)
- buflen += strlen(v) + 1;
- buffer = xcalloc(1, buflen,
- "parent_send_config_ruleset");
- memcpy(buffer, k, strlen(k) + 1);
- if (v)
- memcpy(buffer + strlen(k) + 1, v,
- strlen(v) + 1);
- m_compose(p_lka, IMSG_CONF_TABLE_CONTENT, 0, 0, -1,
- buffer, buflen);
- free(buffer);
- }
- }
-
- TAILQ_FOREACH(r, env->sc_rules, r_entry) {
- m_compose(p_lka, IMSG_CONF_RULE, 0, 0, -1, r, sizeof(*r));
- m_compose(p_lka, IMSG_CONF_RULE_SOURCE, 0, 0, -1,
- &r->r_sources->t_name,
- sizeof(r->r_sources->t_name));
- if (r->r_senders) {
- m_compose(p_lka, IMSG_CONF_RULE_SENDER,
- 0, 0, -1,
- &r->r_senders->t_name,
- sizeof(r->r_senders->t_name));
- }
- if (r->r_recipients) {
- m_compose(p_lka, IMSG_CONF_RULE_RECIPIENT,
- 0, 0, -1,
- &r->r_recipients->t_name,
- sizeof(r->r_recipients->t_name));
- }
- if (r->r_destination) {
- m_compose(p_lka, IMSG_CONF_RULE_DESTINATION,
- 0, 0, -1,
- &r->r_destination->t_name,
- sizeof(r->r_destination->t_name));
- }
- if (r->r_mapping) {
- m_compose(p_lka, IMSG_CONF_RULE_MAPPING, 0, 0, -1,
- &r->r_mapping->t_name,
- sizeof(r->r_mapping->t_name));
- }
- if (r->r_userbase) {
- m_compose(p_lka, IMSG_CONF_RULE_USERS, 0, 0, -1,
- &r->r_userbase->t_name,
- sizeof(r->r_userbase->t_name));
- }
- }
-
m_compose(p_lka, IMSG_CONF_END, 0, 0, -1, NULL, 0);
}
@@ -715,7 +596,7 @@ main(int argc, char *argv[])
errx(1, "config file exceeds SMTPD_MAXPATHLEN");
if (env->sc_opts & SMTPD_OPT_NOACTION) {
- load_ssl_tree();
+ load_pki_tree();
fprintf(stderr, "configuration OK\n");
exit(0);
}
@@ -742,7 +623,7 @@ main(int argc, char *argv[])
log_init(foreground);
log_verbose(verbose);
- load_ssl_tree();
+ load_pki_tree();
log_info("info: %s %s starting", SMTPD_NAME, SMTPD_VERSION);
@@ -818,32 +699,32 @@ main(int argc, char *argv[])
}
static void
-load_ssl_tree(void)
+load_pki_tree(void)
{
- struct ssl *ssl;
- void *iter_dict;
+ struct pki *pki;
const char *k;
+ void *iter_dict;
log_debug("debug: init ssl-tree");
iter_dict = NULL;
- while (dict_iter(env->sc_ssl_dict, &iter_dict, &k, (void **)&ssl)) {
+ while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
log_debug("info: loading pki information for %s", k);
- if (ssl->ssl_cert_file == NULL)
- fatalx("load_ssl_tree: missing certificate file");
- if (ssl->ssl_key_file == NULL)
- fatalx("load_ssl_tree: missing key file");
-
- if (! ssl_load_certificate(ssl, ssl->ssl_cert_file))
- fatalx("load_ssl_tree: failed to load certificate file");
- if (! ssl_load_keyfile(ssl, ssl->ssl_key_file, k))
- fatalx("load_ssl_tree: failed to load key file");
-
- if (ssl->ssl_ca_file)
- if (! ssl_load_cafile(ssl, ssl->ssl_ca_file))
- fatalx("load_ssl_tree: failed to load CA file");
- if (ssl->ssl_dhparams_file)
- if (! ssl_load_dhparams(ssl, ssl->ssl_dhparams_file))
- fatalx("load_ssl_tree: failed to load dhparams file");
+ if (pki->pki_cert_file == NULL)
+ fatalx("load_pki_tree: missing certificate file");
+ if (pki->pki_key_file == NULL)
+ fatalx("load_pki_tree: missing key file");
+
+ if (! ssl_load_certificate(pki, pki->pki_cert_file))
+ fatalx("load_pki_tree: failed to load certificate file");
+ if (! ssl_load_keyfile(pki, pki->pki_key_file, k))
+ fatalx("load_pki_tree: failed to load key file");
+
+ if (pki->pki_ca_file)
+ if (! ssl_load_cafile(pki, pki->pki_ca_file))
+ fatalx("load_pki_tree: failed to load CA file");
+ if (pki->pki_dhparams_file)
+ if (! ssl_load_dhparams(pki, pki->pki_dhparams_file))
+ fatalx("load_pki_tree: failed to load dhparams file");
}
}
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 1bd804c0575..835cd3f92f2 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.444 2014/02/04 10:38:06 eric Exp $ */
+/* $OpenBSD: smtpd.h,v 1.445 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -107,7 +107,7 @@ struct relayhost {
uint16_t flags;
char hostname[SMTPD_MAXHOSTNAMELEN];
uint16_t port;
- char cert[SMTPD_MAXPATHLEN];
+ char pki_name[SMTPD_MAXPATHLEN];
char authtable[SMTPD_MAXPATHLEN];
char authlabel[SMTPD_MAXPATHLEN];
char sourcetable[SMTPD_MAXPATHLEN];
@@ -474,7 +474,7 @@ struct listener {
in_port_t port;
struct timeval timeout;
struct event ev;
- char ssl_cert_name[SMTPD_MAXPATHLEN];
+ char pki_name[SMTPD_MAXPATHLEN];
struct ssl *ssl;
void *ssl_ctx;
char tag[MAX_TAG_SIZE];
@@ -492,15 +492,14 @@ struct smtpd {
#define SMTPD_OPT_NOACTION 0x00000002
uint32_t sc_opts;
-#define SMTPD_CONFIGURING 0x00000001
-#define SMTPD_EXITING 0x00000002
-#define SMTPD_MDA_PAUSED 0x00000004
-#define SMTPD_MTA_PAUSED 0x00000008
-#define SMTPD_SMTP_PAUSED 0x00000010
-#define SMTPD_MDA_BUSY 0x00000020
-#define SMTPD_MTA_BUSY 0x00000040
-#define SMTPD_BOUNCE_BUSY 0x00000080
-#define SMTPD_SMTP_DISABLED 0x00000100
+#define SMTPD_EXITING 0x00000001
+#define SMTPD_MDA_PAUSED 0x00000002
+#define SMTPD_MTA_PAUSED 0x00000004
+#define SMTPD_SMTP_PAUSED 0x00000008
+#define SMTPD_MDA_BUSY 0x00000010
+#define SMTPD_MTA_BUSY 0x00000020
+#define SMTPD_BOUNCE_BUSY 0x00000040
+#define SMTPD_SMTP_DISABLED 0x00000080
uint32_t sc_flags;
#define QUEUE_COMPRESSION 0x00000001
@@ -534,8 +533,9 @@ struct smtpd {
TAILQ_HEAD(listenerlist, listener) *sc_listeners;
- TAILQ_HEAD(rulelist, rule) *sc_rules, *sc_rules_reload;
+ TAILQ_HEAD(rulelist, rule) *sc_rules;
+ struct dict *sc_pki_dict;
struct dict *sc_ssl_dict;
struct dict *sc_tables_dict; /* keyed lookup */
@@ -722,7 +722,7 @@ struct mta_relay {
int backuppref;
char *sourcetable;
uint16_t port;
- char *cert;
+ char *pki_name;
char *authtable;
char *authlabel;
char *helotable;
@@ -1039,7 +1039,7 @@ int uncompress_file(FILE *, FILE *);
#define PURGE_LISTENERS 0x01
#define PURGE_TABLES 0x02
#define PURGE_RULES 0x04
-#define PURGE_SSL 0x08
+#define PURGE_PKI 0x08
#define PURGE_EVERYTHING 0xff
void purge_config(uint8_t);
void init_pipes(void);
@@ -1269,7 +1269,7 @@ const char *imsg_to_str(int);
/* ssl_smtpd.c */
void *ssl_mta_init(char *, off_t, char *, off_t);
-void *ssl_smtp_init(void *, char *, off_t, char *, off_t);
+void *ssl_smtp_init(void *, char *, off_t, char *, off_t, void *, void *);
/* stat_backend.c */
diff --git a/usr.sbin/smtpd/ssl.c b/usr.sbin/smtpd/ssl.c
index 65e65cd9950..bdccfe1785e 100644
--- a/usr.sbin/smtpd/ssl.c
+++ b/usr.sbin/smtpd/ssl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl.c,v 1.58 2013/12/26 17:25:32 eric Exp $ */
+/* $OpenBSD: ssl.c,v 1.59 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -62,7 +62,7 @@ ssl_init(void)
}
int
-ssl_setup(SSL_CTX **ctxp, struct ssl *ssl)
+ssl_setup(SSL_CTX **ctxp, struct pki *pki)
{
DH *dh;
SSL_CTX *ctx;
@@ -70,28 +70,28 @@ ssl_setup(SSL_CTX **ctxp, struct ssl *ssl)
ctx = ssl_ctx_create();
if (!ssl_ctx_use_certificate_chain(ctx,
- ssl->ssl_cert, ssl->ssl_cert_len))
+ pki->pki_cert, pki->pki_cert_len))
goto err;
if (!ssl_ctx_use_private_key(ctx,
- ssl->ssl_key, ssl->ssl_key_len))
+ pki->pki_key, pki->pki_key_len))
goto err;
if (!SSL_CTX_check_private_key(ctx))
goto err;
if (!SSL_CTX_set_session_id_context(ctx,
- (const unsigned char *)ssl->ssl_name,
- strlen(ssl->ssl_name) + 1))
+ (const unsigned char *)pki->pki_name,
+ strlen(pki->pki_name) + 1))
goto err;
- if (ssl->ssl_dhparams_len == 0)
+ if (pki->pki_dhparams_len == 0)
dh = get_dh1024();
else
- dh = get_dh_from_memory(ssl->ssl_dhparams,
- ssl->ssl_dhparams_len);
+ dh = get_dh_from_memory(pki->pki_dhparams,
+ pki->pki_dhparams_len);
ssl_set_ephemeral_key_exchange(ctx, dh);
DH_free(dh);
- ssl_set_ecdh_curve(ctx);
+ ssl_set_ecdh_curve(ctx, SSL_ECDH_CURVE);
*ctxp = ctx;
return 1;
@@ -184,7 +184,7 @@ end:
char *
ssl_load_key(const char *name, off_t *len, char *pass, mode_t perm, const char *pkiname)
{
- FILE *fp;
+ FILE *fp = NULL;
EVP_PKEY *key = NULL;
BIO *bio = NULL;
long size;
@@ -220,6 +220,7 @@ ssl_load_key(const char *name, off_t *len, char *pass, mode_t perm, const char *
(void)snprintf(prompt, sizeof prompt, "passphrase for %s: ", pkiname);
key = PEM_read_PrivateKey(fp, NULL, ssl_getpass_cb, prompt);
fclose(fp);
+ fp = NULL;
if (key == NULL)
goto fail;
/*
@@ -244,11 +245,12 @@ fail:
free(buf);
if (bio != NULL)
BIO_free_all(bio);
+ fclose(fp);
return (NULL);
}
SSL_CTX *
-ssl_ctx_create(void)
+ssl_ctx_create()
{
SSL_CTX *ctx;
@@ -274,39 +276,39 @@ ssl_ctx_create(void)
}
int
-ssl_load_certificate(struct ssl *s, const char *pathname)
+ssl_load_certificate(struct pki *p, const char *pathname)
{
- s->ssl_cert = ssl_load_file(pathname, &s->ssl_cert_len, 0755);
- if (s->ssl_cert == NULL)
+ p->pki_cert = ssl_load_file(pathname, &p->pki_cert_len, 0755);
+ if (p->pki_cert == NULL)
return 0;
return 1;
}
int
-ssl_load_keyfile(struct ssl *s, const char *pathname, const char *pkiname)
+ssl_load_keyfile(struct pki *p, const char *pathname, const char *pkiname)
{
char pass[1024];
- s->ssl_key = ssl_load_key(pathname, &s->ssl_key_len, pass, 0700, pkiname);
- if (s->ssl_key == NULL)
+ p->pki_key = ssl_load_key(pathname, &p->pki_key_len, pass, 0700, pkiname);
+ if (p->pki_key == NULL)
return 0;
return 1;
}
int
-ssl_load_cafile(struct ssl *s, const char *pathname)
+ssl_load_cafile(struct pki *p, const char *pathname)
{
- s->ssl_ca = ssl_load_file(pathname, &s->ssl_ca_len, 0755);
- if (s->ssl_ca == NULL)
+ p->pki_ca = ssl_load_file(pathname, &p->pki_ca_len, 0755);
+ if (p->pki_ca == NULL)
return 0;
return 1;
}
int
-ssl_load_dhparams(struct ssl *s, const char *pathname)
+ssl_load_dhparams(struct pki *p, const char *pathname)
{
- s->ssl_dhparams = ssl_load_file(pathname, &s->ssl_dhparams_len, 0755);
- if (s->ssl_dhparams == NULL) {
+ p->pki_dhparams = ssl_load_file(pathname, &p->pki_dhparams_len, 0755);
+ if (p->pki_dhparams == NULL) {
if (errno == EACCES)
return 0;
log_info("info: No DH parameters found in %s: "
@@ -422,12 +424,14 @@ ssl_set_ephemeral_key_exchange(SSL_CTX *ctx, DH *dh)
}
void
-ssl_set_ecdh_curve(SSL_CTX *ctx)
+ssl_set_ecdh_curve(SSL_CTX *ctx, const char *curve)
{
int nid;
EC_KEY *ecdh;
- if ((nid = OBJ_sn2nid(SSL_ECDH_CURVE)) == 0) {
+ if (curve == NULL)
+ curve = SSL_ECDH_CURVE;
+ if ((nid = OBJ_sn2nid(curve)) == 0) {
ssl_error("ssl_set_ecdh_curve");
fatal("ssl_set_ecdh_curve: unknown curve name "
SSL_ECDH_CURVE);
diff --git a/usr.sbin/smtpd/ssl.h b/usr.sbin/smtpd/ssl.h
index cbf5574da4b..d5eebe080c4 100644
--- a/usr.sbin/smtpd/ssl.h
+++ b/usr.sbin/smtpd/ssl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl.h,v 1.4 2013/11/28 12:50:40 eric Exp $ */
+/* $OpenBSD: ssl.h,v 1.5 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2013 Gilles Chehade <gilles@poolp.org>
*
@@ -19,37 +19,35 @@
#define SSL_ECDH_CURVE "prime256v1"
#define SSL_SESSION_TIMEOUT 300
-struct ssl {
- char ssl_name[PATH_MAX];
+struct pki {
+ char pki_name[PATH_MAX];
- char *ssl_ca_file;
- char *ssl_ca;
- off_t ssl_ca_len;
+ char *pki_ca_file;
+ char *pki_ca;
+ off_t pki_ca_len;
- char *ssl_cert_file;
- char *ssl_cert;
- off_t ssl_cert_len;
+ char *pki_cert_file;
+ char *pki_cert;
+ off_t pki_cert_len;
- char *ssl_key_file;
- char *ssl_key;
- off_t ssl_key_len;
+ char *pki_key_file;
+ char *pki_key;
+ off_t pki_key_len;
- char *ssl_dhparams_file;
- char *ssl_dhparams;
- off_t ssl_dhparams_len;
+ char *pki_dhparams_file;
+ char *pki_dhparams;
+ off_t pki_dhparams_len;
};
/* ssl.c */
void ssl_init(void);
-int ssl_setup(SSL_CTX **, struct ssl *);
+int ssl_setup(SSL_CTX **, struct pki *);
SSL_CTX *ssl_ctx_create(void);
-void *ssl_mta_init(char *, off_t, char *, off_t);
-void *ssl_smtp_init(void *, char *, off_t, char *, off_t);
-int ssl_cmp(struct ssl *, struct ssl *);
+int ssl_cmp(struct pki *, struct pki *);
DH *get_dh1024(void);
DH *get_dh_from_memory(char *, size_t);
void ssl_set_ephemeral_key_exchange(SSL_CTX *, DH *);
-void ssl_set_ecdh_curve(SSL_CTX *);
+void ssl_set_ecdh_curve(SSL_CTX *, const char *);
extern int ssl_ctx_load_verify_memory(SSL_CTX *, char *, off_t);
char *ssl_load_file(const char *, off_t *, mode_t);
char *ssl_load_key(const char *, off_t *, char *, mode_t, const char *);
@@ -57,10 +55,10 @@ char *ssl_load_key(const char *, off_t *, char *, mode_t, const char *);
const char *ssl_to_text(const SSL *);
void ssl_error(const char *);
-int ssl_load_certificate(struct ssl *, const char *);
-int ssl_load_keyfile(struct ssl *, const char *, const char *);
-int ssl_load_cafile(struct ssl *, const char *);
-int ssl_load_dhparams(struct ssl *, const char *);
+int ssl_load_certificate(struct pki *, const char *);
+int ssl_load_keyfile(struct pki *, const char *, const char *);
+int ssl_load_cafile(struct pki *, const char *);
+int ssl_load_dhparams(struct pki *, const char *);
/* ssl_privsep.c */
diff --git a/usr.sbin/smtpd/ssl_privsep.c b/usr.sbin/smtpd/ssl_privsep.c
index ffd62166ec2..e53fb4f418e 100644
--- a/usr.sbin/smtpd/ssl_privsep.c
+++ b/usr.sbin/smtpd/ssl_privsep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_privsep.c,v 1.5 2013/01/26 09:37:24 gilles Exp $ */
+/* $OpenBSD: ssl_privsep.c,v 1.6 2014/02/04 13:44:41 eric Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
diff --git a/usr.sbin/smtpd/ssl_smtpd.c b/usr.sbin/smtpd/ssl_smtpd.c
index 5de8c53c35d..8d796d51836 100644
--- a/usr.sbin/smtpd/ssl_smtpd.c
+++ b/usr.sbin/smtpd/ssl_smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_smtpd.c,v 1.3 2013/10/28 17:02:08 eric Exp $ */
+/* $OpenBSD: ssl_smtpd.c,v 1.4 2014/02/04 13:44:41 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -90,12 +90,12 @@ dummy_verify(int ok, X509_STORE_CTX *store)
}
void *
-ssl_smtp_init(void *ssl_ctx, char *cert, off_t cert_len, char *key, off_t key_len)
+ssl_smtp_init(void *ssl_ctx, char *cert, off_t cert_len, char *key, off_t key_len, void *sni, void *arg)
{
SSL *ssl = NULL;
+ int (*cb)(SSL *,int *,void *) = sni;
log_debug("debug: session_start_ssl: switching to SSL");
-
if (!ssl_ctx_use_certificate_chain(ssl_ctx, cert, cert_len))
goto err;
else if (!ssl_ctx_use_private_key(ssl_ctx, key, key_len))
@@ -105,6 +105,11 @@ ssl_smtp_init(void *ssl_ctx, char *cert, off_t cert_len, char *key, off_t key_le
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, dummy_verify);
+ if (cb) {
+ SSL_CTX_set_tlsext_servername_callback(ssl_ctx, cb);
+ SSL_CTX_set_tlsext_servername_arg(ssl_ctx, arg);
+ }
+
if ((ssl = SSL_new(ssl_ctx)) == NULL)
goto err;
if (!SSL_set_ssl_method(ssl, SSLv23_server_method()))