Hi,

This diff allows to specify tls ciphers and protocols on listen rules,
as it's been done already for relay actions. While there, sanitize
error checking on protocols config in the mta.

Eric.

Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/config.c,v
retrieving revision 1.54
diff -u -p -r1.54 config.c
--- config.c    5 Mar 2021 12:37:32 -0000       1.54
+++ config.c    6 Apr 2021 10:24:18 -0000
@@ -252,6 +252,8 @@ purge_config(uint8_t what)
        if (what & PURGE_LISTENERS) {
                while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
                        TAILQ_REMOVE(env->sc_listeners, l, entry);
+                       free(l->tls_ciphers);
+                       free(l->tls_protocols);
                        free(l->pki);
                        free(l);
                }
Index: mta.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/mta.c,v
retrieving revision 1.237
diff -u -p -r1.237 mta.c
--- mta.c       2 Apr 2021 06:30:55 -0000       1.237
+++ mta.c       6 Apr 2021 10:39:52 -0000
@@ -508,10 +508,14 @@ mta_setup_dispatcher(struct dispatcher *
        if (ciphers && tls_config_set_ciphers(config, ciphers) == -1)
                err(1, "%s", tls_config_error(config));
 
-       if (remote->tls_protocols &&
-           (tls_config_parse_protocols(&protos, remote->tls_protocols) == -1
-           || tls_config_set_protocols(config, protos) == -1))
-               err(1, "%s", tls_config_error(config));
+       if (remote->tls_protocols) {
+               if (tls_config_parse_protocols(&protos,
+                   remote->tls_protocols) == -1)
+                       err(1, "failed to parse protocols \"%s\"",
+                           remote->tls_protocols);
+               if (tls_config_set_protocols(config, protos) == -1)
+                       err(1, "%s", tls_config_error(config));
+       }
 
        if (remote->pki) {
                pki = dict_get(env->sc_pki_dict, remote->pki);
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
retrieving revision 1.286
diff -u -p -r1.286 parse.y
--- parse.y     31 Mar 2021 17:47:16 -0000      1.286
+++ parse.y     6 Apr 2021 10:19:33 -0000
@@ -137,6 +137,8 @@ static struct listen_opts {
        char           *filtername;
        char           *pki[PKI_MAX];
        int             pkicount;
+       char           *tls_ciphers;
+       char           *tls_protocols;
        char           *ca;
        uint16_t        auth;
        struct table   *authtable;
@@ -2333,6 +2335,20 @@ opt_if_listen : INET4 {
                        listen_opts.options |= LO_SSL;
                        listen_opts.ssl = 
F_STARTTLS|F_STARTTLS_REQUIRE|F_TLS_VERIFY;
                }
+               | CIPHERS STRING {
+                       if (listen_opts.tls_ciphers) {
+                               yyerror("ciphers already specified");
+                               YYERROR;
+                       }
+                       listen_opts.tls_ciphers = $2;
+               }
+               | PROTOCOLS STRING {
+                       if (listen_opts.tls_protocols) {
+                               yyerror("protocols already specified");
+                               YYERROR;
+                       }
+                       listen_opts.tls_protocols = $2;
+               }
                | PKI STRING                    {
                        if (listen_opts.pkicount == PKI_MAX) {
                                yyerror("too many pki specified");
@@ -2516,7 +2532,11 @@ listen           : LISTEN {
                        memset(&listen_opts, 0, sizeof listen_opts);
                        listen_opts.family = AF_UNSPEC;
                        listen_opts.flags |= F_EXT_DSN;
-               } ON listener_type
+               } ON listener_type {
+                       free(listen_opts.tls_protocols);
+                       free(listen_opts.tls_ciphers);
+                       memset(&listen_opts, 0, sizeof listen_opts);
+               }
                ;
 
 table          : TABLE STRING STRING   {
@@ -3310,6 +3330,16 @@ config_listener(struct listener *h,  str
                        log_warnx("pki name not found: %s", lo->pki[i]);
                        fatalx(NULL);
                }
+       }
+
+       if (lo->tls_ciphers != NULL &&
+           (h->tls_ciphers = strdup(lo->tls_ciphers)) == NULL) {
+               fatal("strdup");
+       }
+
+       if (lo->tls_protocols != NULL &&
+           (h->tls_protocols = strdup(lo->tls_protocols)) == NULL) {
+               fatal("strdup");
        }
 
        if (lo->ca != NULL) {
Index: smtp.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtp.c,v
retrieving revision 1.168
diff -u -p -r1.168 smtp.c
--- smtp.c      10 Mar 2021 17:25:59 -0000      1.168
+++ smtp.c      6 Apr 2021 10:39:34 -0000
@@ -169,6 +169,8 @@ smtp_setup_listener_tls(struct listener 
 {
        static const char *dheparams[] = { "none", "auto", "legacy" };
        struct tls_config *config;
+       const char *ciphers;
+       uint32_t protos;
        struct pki *pki;
        struct ca *ca;
        int i;
@@ -176,9 +178,19 @@ smtp_setup_listener_tls(struct listener 
        if ((config = tls_config_new()) == NULL)
                fatal("smtpd: tls_config_new");
 
-       if (env->sc_tls_ciphers &&
-           tls_config_set_ciphers(config, env->sc_tls_ciphers) == -1)
+       ciphers = env->sc_tls_ciphers;
+       if (l->tls_ciphers)
+               ciphers = l->tls_ciphers;
+       if (ciphers && tls_config_set_ciphers(config, ciphers) == -1)
+               err(1, "%s", tls_config_error(config));
+
+       if (l->tls_protocols) {
+               if (tls_config_parse_protocols(&protos, l->tls_protocols) == -1)
+                       err(1, "failed to parse protocols \"%s\"",
+                           l->tls_protocols);
+               if (tls_config_set_protocols(config, protos) == -1)
                        err(1, "%s", tls_config_error(config));
+       }
 
        pki = l->pki[0];
        if (pki == NULL)
Index: smtpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.conf.5,v
retrieving revision 1.259
diff -u -p -r1.259 smtpd.conf.5
--- smtpd.conf.5        31 Mar 2021 17:47:16 -0000      1.259
+++ smtpd.conf.5        6 Apr 2021 10:31:20 -0000
@@ -527,6 +527,18 @@ With the
 .Cm verify
 option, clients must also provide a valid certificate
 to establish an SMTP session.
+.It Cm protocols Ar protostr
+Define the protocol versions to be used for TLS sessions.
+Refer to the
+.Xr tls_config_parse_protocols 3
+manpage for the format of
+.Ar protostr .
+.It Cm ciphers Ar cipherstr
+Define the list of ciphers that may be used for TLS sessions.
+Refer to the
+.Xr tls_config_set_ciphers 3
+manpage for the format of
+.Ar cipherstr .
 .El
 .It Ic listen on Cm socket Op Ar options
 Listen for incoming SMTP connections on the Unix domain socket
Index: smtpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
retrieving revision 1.664
diff -u -p -r1.664 smtpd.h
--- smtpd.h     31 Mar 2021 19:09:19 -0000      1.664
+++ smtpd.h     6 Apr 2021 10:02:28 -0000
@@ -543,6 +543,8 @@ struct listener {
 
        int                      local;         /* there must be a better way */
 
+       char                    *tls_protocols;
+       char                    *tls_ciphers;
        struct tls              *tls;
        struct pki              **pki;
        int                      pkicount;

Reply via email to