There is currently no way to force TLS on a relay rule in general, and
force certificate checking.  Typical use case: a secondary MX needing
to relay safely to lower preference MXs.

This diff below allows the "tls" option to be used alone, including on
non-smarthost relay rules, to specify that the relay must be using
TLS.  The "no-verify" keyword becomes optional.

Currently, the different cases are as follows:

- action <name> relay
      Standard relaying, using smtp with opportunistic STARTTLS.
      When using TLS, certificates are not checked.

- action <name> relay host <smarthost>
      Relay through smarthost, using TLS or not, depending on the protocol.
      When using TLS, certificates are checked.

- action <name> relay host <smarthost> tls no-verify
      Same as above, but certificates are not checked.

With the proposed change, we get:

- action <name> relay
      Standard relaying, using smtp with opportunistic STARTTLS.
      When using TLS, certificates are not checked.

- action <name> relay tls
      Standard relaying, using smtp with mandatory STARTTLS.
      Certificates are checked.

- action <name> relay tls no-verify
      Same as above, but certificates are not checked.

- action <name> relay host <smarthost>
      Relay through smarthost, using TLS or not, depending on the protocol.
      For "smtp+tls://" and "smtps://" certificates are checked.
      For "smtp://" (opportunistic TLS) certificates are not checked.

- action <name> relay host <smarthost> tls
      Relay through smarthost with mandatory TLS.
      Certificates are checked.
      The "smtp://" protocol is updated to "smtp+tls://" internally.
      The "smtp+notls://" protocol is rejected, and no relaying happens.

- action <name> relay host <smarthost> tls no-verify
      Same as above, but certificates are not checked.


The differences with the currently allowed syntax are:

1) the "tls no-verify" option on smarthost relay actually forces TLS,
2) a relay with a "smtp://" smarthost and no "tls no-verify" does not
   require a valid certificate anymore.

It is more constistent altogether, and in practice it should not be
a problem because most smarthost configurations uses strict TLS.

Now, for the secondary MX example, the rule would look like:

   action "do-backup" relay backup tls

Comments?

Eric.

Index: mta.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/mta.c,v
retrieving revision 1.225
diff -u -p -r1.225 mta.c
--- mta.c       19 Sep 2018 05:31:12 -0000      1.225
+++ mta.c       21 Sep 2018 08:09:14 -0000
@@ -657,6 +657,23 @@ mta_handle_envelope(struct envelope *evp
                return;
        }
 
+       if (dispatcher->u.remote.tls_required) {
+               /* Reject relay if smtp+notls:// is requested */
+               if (relayh.tls == RELAY_TLS_NO) {
+                       log_warnx("warn: TLS required for action \"%s\"",
+                           evp->dispatcher);
+                       m_create(p_queue, IMSG_MTA_DELIVERY_TEMPFAIL, 0, 0, -1);
+                       m_add_evpid(p_queue, evp->id);
+                       m_add_string(p_queue, "TLS required for relaying");
+                       m_add_int(p_queue, ESC_OTHER_STATUS);
+                       m_close(p_queue);
+                       return;
+               }
+               /* Update smtp:// to smtp+tls:// */
+               if (relayh.tls == RELAY_TLS_OPPORTUNISTIC)
+                       relayh.tls = RELAY_TLS_STARTTLS;
+       }
+
        relay = mta_relay(evp, &relayh);
        /* ignore if we don't know the limits yet */
        if (relay->limits &&
@@ -1739,7 +1756,7 @@ mta_relay(struct envelope *e, struct rel
        if (!key.authlabel[0])
                key.authlabel = NULL;
 
-       if (dispatcher->u.remote.smarthost &&
+       if ((key.tls == RELAY_TLS_STARTTLS || key.tls == RELAY_TLS_SMTPS) &&
            dispatcher->u.remote.tls_noverify == 0)
                key.flags |= RELAY_TLS_VERIFY;
 
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
retrieving revision 1.221
diff -u -p -r1.221 parse.y
--- parse.y     7 Sep 2018 07:35:31 -0000       1.221
+++ parse.y     21 Sep 2018 08:09:14 -0000
@@ -739,17 +739,21 @@ HELO STRING {
 
        dispatcher->u.remote.smarthost = strdup(t->t_name);
 }
-| TLS NO_VERIFY {
-       if (dispatcher->u.remote.smarthost == NULL) {
-               yyerror("tls no-verify may not be specified without host on a 
dispatcher");
+| TLS {
+       if (dispatcher->u.remote.tls_required == 1) {
+               yyerror("tls already specified for this dispatcher");
                YYERROR;
        }
 
-       if (dispatcher->u.remote.tls_noverify == 1) {
-               yyerror("tls no-verify already specified for this dispatcher");
+       dispatcher->u.remote.tls_required = 1;
+}
+| TLS NO_VERIFY {
+       if (dispatcher->u.remote.tls_required == 1) {
+               yyerror("tls already specified for this dispatcher");
                YYERROR;
        }
 
+       dispatcher->u.remote.tls_required = 1;
        dispatcher->u.remote.tls_noverify = 1;
 }
 | AUTH tables {
Index: smtpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.conf.5,v
retrieving revision 1.204
diff -u -p -r1.204 smtpd.conf.5
--- smtpd.conf.5        10 Sep 2018 12:42:17 -0000      1.204
+++ smtpd.conf.5        21 Sep 2018 08:09:15 -0000
@@ -265,8 +265,13 @@ and
 .Dq smtps
 protocols for authentication.
 Server certificates for those protocols are verified by default.
-.It Cm tls no-verify
-Do not require a valid certificate for the specified host.
+.It Cm tls Op no-verify
+Require TLS to be used when relaying, using mandatory STARTTLS by default.
+When used with a smarthost, the protocol must not be
+.Dq smtp+notls:// .
+If 
+.Op no-verify
+is specified, do not require a valid certificate.
 .It Cm auth Pf < Ar table Ns >
 Use the mapping
 .Ar table
Index: smtpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
retrieving revision 1.561
diff -u -p -r1.561 smtpd.h
--- smtpd.h     19 Sep 2018 05:31:12 -0000      1.561
+++ smtpd.h     21 Sep 2018 08:09:15 -0000
@@ -1063,6 +1063,7 @@ struct dispatcher_remote {
 
        char    *smarthost;
        char    *auth;
+       int      tls_required;
        int      tls_noverify;
 
        int      backup;

Reply via email to