diff options
author | Eric Faurot <eric@cvs.openbsd.org> | 2014-02-04 13:44:42 +0000 |
---|---|---|
committer | Eric Faurot <eric@cvs.openbsd.org> | 2014-02-04 13:44:42 +0000 |
commit | 5466a3045acfc02b1542c40152b69df386bcf9e0 (patch) | |
tree | bd0ebdfd026b293d6b0de4ba08d970ce0ffbce92 /usr.sbin | |
parent | 18a6e075a482dcb67a689f725c9795e20a72a992 (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.c | 22 | ||||
-rw-r--r-- | usr.sbin/smtpd/control.c | 5 | ||||
-rw-r--r-- | usr.sbin/smtpd/envelope.c | 8 | ||||
-rw-r--r-- | usr.sbin/smtpd/lka.c | 196 | ||||
-rw-r--r-- | usr.sbin/smtpd/mta.c | 24 | ||||
-rw-r--r-- | usr.sbin/smtpd/mta_session.c | 14 | ||||
-rw-r--r-- | usr.sbin/smtpd/parse.y | 50 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp.c | 114 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp_session.c | 108 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.c | 169 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 32 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl.c | 56 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl.h | 46 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl_privsep.c | 2 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl_smtpd.c | 11 |
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())) |