]> diplodocus.org Git - nmh/commitdiff
Add support for certificate verification when using TLS.
authorKen Hornstein <kenh@pobox.com>
Wed, 2 Nov 2016 03:13:04 +0000 (23:13 -0400)
committerKen Hornstein <kenh@pobox.com>
Wed, 2 Nov 2016 03:14:10 +0000 (23:14 -0400)
14 files changed:
h/netsec.h
h/popsbr.h
man/inc.man
man/msgchk.man
man/send.man
mts/smtp/smtp.c
mts/smtp/smtp.h
sbr/netsec.c
uip/inc.c
uip/msgchk.c
uip/popsbr.c
uip/post.c
uip/send.c
uip/whatnowsbr.c

index e05e79f..7dac521 100644 (file)
@@ -51,6 +51,19 @@ void netsec_set_fd(netsec_context *ns_context, int readfd, int writefd);
 
 void netsec_set_userid(netsec_context *ns_context, const char *userid);
 
+/*
+ * Set the hostname of the server we're connecting to.  This is used
+ * by the Cyrus-SASL library and by the TLS code.  This must be called
+ * before netsec_negotiate_tls() or netsec_set_sasl_params().
+ *
+ * Arguments:
+ *
+ * ns_context  - Network security context
+ * hostname    - FQDN of remote host.  Cannot be NULL.
+ */
+
+void netsec_set_hostname(netsec_context *ns_context, const char *hostname);
+
 /*
  * Returns "snoop" status on current connection.
  *
@@ -300,7 +313,6 @@ typedef int (*netsec_sasl_callback)(enum sasl_message_type mtype,
  * Arguments:
  *
  * ns_context  - Network security context
- * hostname    - Fully qualified hostname of remote host.
  * service     - Service name (set to NULL to disable SASL).
  * mechanism   - The mechanism desired by the user.  If NULL, the SASL
  *               library will attempt to negotiate the best mechanism.
@@ -310,8 +322,8 @@ typedef int (*netsec_sasl_callback)(enum sasl_message_type mtype,
  * Returns NOTOK if SASL is not supported.
  */
 
-int netsec_set_sasl_params(netsec_context *ns_context, const char *hostname,
-                          const char *service, const char *mechanism,
+int netsec_set_sasl_params(netsec_context *ns_context, const char *service,
+                          const char *mechanism,
                           netsec_sasl_callback callback, char **errstr);
 
 /*
@@ -364,17 +376,23 @@ int netsec_set_oauth_service(netsec_context *ns_context, const char *service);
  * Controls whether or not TLS will be negotiated for this connection.
  *
  * Note: callers still have to call netsec_tls_negotiate() to start
- * TLS negotiation at the appropriate point in the protocol.
+ * TLS negotiation at the appropriate point in the protocol.  The
+ * remote hostname (controlled by netsec_set_hostname()) should have
+ * already been set before this function is called unless certificate
+ * verification is disabled.
  *
  * Arguments
  *
  * tls         - If nonzero, enable TLS. Otherwise disable TLS
  *               negotiation.
+ * noverify    - If nonzero, disable server certificate and hostname
+ *               validation.
  *
  * Returns NOTOK if TLS is not supported or was unable to initialize.
  */
 
-int netsec_set_tls(netsec_context *context, int tls, char **errstr);
+int netsec_set_tls(netsec_context *context, int tls, int noverify,
+                  char **errstr);
 
 /*
  * Start TLS negotiation on this protocol.  This connection should have
index 96d21a3..9991e47 100644 (file)
@@ -3,6 +3,9 @@
  * popsbr.h -- header for POP client subroutines
  */
 
+/* TLS flags */
+#define P_INITTLS 0x01
+#define P_NOVERIFY 0x02
 int pop_init (char *, char *, char *, char *, int, int, char *, int,
              const char *);
 int pop_fd (char *, int, char *, int);
index 47338c2..d9ceaa4 100644 (file)
@@ -43,6 +43,7 @@ inc \- incorporate new mail
 .IR service ]
 .RB [ \-initialtls ]
 .RB [ \-notls ]
+.RB [ \-certverify " | " \-nocertverify ]
 .RB [ \-snoop ]
 .ad
 .SH DESCRIPTION
@@ -310,6 +311,15 @@ transaction with the
 switch.  The
 .B \-notls
 switch will disable all attempts to negotiate TLS.
+.PP
+When using TLS the default is to verify the remote certificate and SubjectName
+against the local trusted certificate store.  This can be controlled by
+the
+.B \-certverify
+and
+.B \-nocertverify
+switches.  See your OpenSSL documentation for more information on certificate
+verification.
 .SH FILES
 .PD 0
 .TP 20
index 97809b2..eb356c2 100644 (file)
@@ -19,11 +19,12 @@ all/mail/nomail ]
 .IR hostname ]
 .RB [ \-user
 .IR username ]
-.RB [ \-sasl ]
+.RB [ \-sasl " | " \-nosasl ]
 .RB [ \-saslmech
 .IR mechanism ]
 .RB [ \-initialtls ]
 .RB [ \-notls ]
+.RB [ \-certverify " | " \-nocertverify ]
 .RB [ \-authservice
 .IR service ]
 .RB [ \-snoop ]
@@ -164,6 +165,15 @@ transaction with the
 switch.  The
 .B \-notls
 switch will disable all attempts to negotiate TLS.
+.PP
+When using TLS the default is to verify the remote certificate and SubjectName
+against the local trusted certificate store.  This can be controlled by
+the
+.B \-certverify
+and
+.B \-nocertverify
+switches.  See your OpenSSL documentation for more information on certificate
+verification.
 .SH FILES
 .fc ^ ~
 .nf
index e62b382..4b8a121 100644 (file)
@@ -52,6 +52,8 @@ send \- send a message
 .RB [ \-tls ]
 .RB [ \-initialtls ]
 .RB [ \-notls ]
+.RB [ \-certverify ]
+.RB [ \-nocertverify ]
 .RB [ \-width
 .IR columns ]
 .RB [ file
@@ -479,6 +481,15 @@ will be implied if TLS support was compiled in.  Though port 465 for
 SMTPS (SMTP over SSL) was deregistered by IANA in 1998, it is still
 used for that service.
 .PP
+When using TLS the default is to verify the remote certificate and SubjectName
+against the local trusted certificate store.  This can be controlled by
+the
+.B \-certverify
+and
+.B \-nocertverify
+switches.  See your OpenSSL documentation for more information on certificate
+verification.
+.PP
 The files specified by the profile entry \*(lqAliasfile:\*(rq and any
 additional alias files given by the
 .B \-alias
@@ -630,6 +641,7 @@ man page for login credentials.
 .RB ` \-noverbose '
 .RB ` \-nowatch '
 .RB ` "\-width\ 72" '
+.RB ` \-certverify '
 .fi
 .SH CONTEXT
 None
index fdc56b0..80bff19 100644 (file)
@@ -141,12 +141,14 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
     if (user)
        netsec_set_userid(nsc, user);
 
+    netsec_set_hostname(nsc, server);
+
     if (sm_debug)
        netsec_set_snoop(nsc, 1);
 
     if (sasl) {
-       if (netsec_set_sasl_params(nsc, server, "smtp", saslmech,
-                                  sm_sasl_callback, &errstr) != OK)
+       if (netsec_set_sasl_params(nsc, "smtp", saslmech, sm_sasl_callback,
+                                  &errstr) != OK)
            return sm_nerror(errstr);
     }
 
@@ -162,18 +164,18 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
 
     netsec_set_fd(nsc, sd1, sd1);
 
-    if (tls) {
-       if (netsec_set_tls(nsc, 1, &errstr) != OK)
+    if (tls & S_TLSENABLEMASK) {
+       if (netsec_set_tls(nsc, 1, tls & S_NOVERIFY, &errstr) != OK)
            return sm_nerror(errstr);
     }
 
     /*
-     * If tls == 2, that means that the user requested "initial" TLS,
-     * which happens right after the connection has opened.  Do that
-     * negotiation now
+     * If tls == S_INITTLS, that means that the user requested
+     * "initial" TLS, which happens right after the connection has
+     * opened.  Do that negotiation now
      */
 
-    if (tls == 2) {
+    if (tls & S_INITTLS) {
        if (netsec_negotiate_tls(nsc, &errstr) != OK) {
            sm_end(NOTOK);
            return sm_nerror(errstr);
@@ -214,7 +216,7 @@ smtp_init (char *client, char *server, char *port, int watch, int verbose,
      * restart the EHLO dialog after TLS negotiation is complete.
      */
 
-    if (tls == 1) {
+    if (tls & S_STARTTLS) {
        if (! EHLOset("STARTTLS")) {
            sm_end(NOTOK);
            return sm_ierror("SMTP server does not support TLS");
@@ -308,12 +310,14 @@ sendmail_init (char *client, int watch, int verbose, int debug, int sasl,
     if (user)
        netsec_set_userid(nsc, user);
 
+    netsec_set_hostname(nsc, client);
+
     if (sm_debug)
        netsec_set_snoop(nsc, 1);
 
     if (sasl) {
-       if (netsec_set_sasl_params(nsc, client, "smtp", saslmech,
-                                  sm_sasl_callback, &errstr) != OK)
+       if (netsec_set_sasl_params(nsc, "smtp", saslmech, sm_sasl_callback,
+                                  &errstr) != OK)
            return sm_nerror(errstr);
     }
 
index df02c1a..953b3de 100644 (file)
@@ -16,6 +16,11 @@ struct smtp {
  * prototypes
  */
 /* int client (); */
+/* TLS flags */
+#define S_STARTTLS 0x01
+#define S_INITTLS 0x02
+#define S_TLSENABLEMASK 0x03
+#define S_NOVERIFY 0x04
 int sm_init (char *, char *, char *, int, int, int, int, const char *,
              const char *, const char *, int);
 int sm_winit (char *, int, int);
index 601e2b7..79fd6a0 100644 (file)
@@ -62,6 +62,7 @@ struct _netsec_context {
     void *ns_snoop_context;    /* Context data for snoop function */
     int ns_timeout;            /* Network read timeout, in seconds */
     char *ns_userid;           /* Userid for authentication */
+    char *ns_hostname;         /* Hostname we've connected to */
     unsigned char *ns_inbuffer;        /* Our read input buffer */
     unsigned char *ns_inptr;   /* Our read buffer input pointer */
     unsigned int ns_inbuflen;  /* Length of data in input buffer */
@@ -77,7 +78,6 @@ struct _netsec_context {
     char *oauth_service;       /* OAuth2 service name */
 #endif /* OAUTH_SUPPORT */
 #ifdef CYRUS_SASL
-    char *sasl_hostname;       /* Hostname we've connected to */
     sasl_conn_t *sasl_conn;    /* SASL connection context */
     sasl_ssf_t sasl_ssf;       /* SASL Security Strength Factor */
     sasl_callback_t *sasl_cbs; /* Callbacks used by SASL */
@@ -147,6 +147,7 @@ netsec_init(void)
     nsc->ns_snoop_cb = NULL;
     nsc->ns_snoop_context = NULL;
     nsc->ns_userid = NULL;
+    nsc->ns_hostname = NULL;
     nsc->ns_timeout = 60;      /* Our default */
     nsc->ns_inbufsize = NETSEC_BUFSIZE;
     nsc->ns_inbuffer = mh_xmalloc(nsc->ns_inbufsize);
@@ -164,7 +165,6 @@ netsec_init(void)
 #endif /* OAUTH_SUPPORT */
 #ifdef CYRUS_SASL
     nsc->sasl_conn = NULL;
-    nsc->sasl_hostname = NULL;
     nsc->sasl_cbs = NULL;
     nsc->sasl_creds = NULL;
     nsc->sasl_secret = NULL;
@@ -189,6 +189,7 @@ void
 netsec_shutdown(netsec_context *nsc, int closeflag)
 {
     mh_xfree(nsc->ns_userid);
+    mh_xfree(nsc->ns_hostname);
     mh_xfree(nsc->ns_inbuffer);
     mh_xfree(nsc->ns_outbuffer);
     mh_xfree(nsc->sasl_mech);
@@ -199,7 +200,6 @@ netsec_shutdown(netsec_context *nsc, int closeflag)
 #ifdef CYRUS_SASL
     if (nsc->sasl_conn)
        sasl_dispose(&nsc->sasl_conn);
-    mh_xfree(nsc->sasl_hostname);
     mh_xfree(nsc->sasl_cbs);
     if (nsc->sasl_creds)
        nmh_credentials_free(nsc->sasl_creds);
@@ -251,6 +251,16 @@ netsec_set_userid(netsec_context *nsc, const char *userid)
     nsc->ns_userid = getcpy(userid);
 }
 
+/*
+ * Set the hostname of the remote host we're connecting to.
+ */
+
+void
+netsec_set_hostname(netsec_context *nsc, const char *hostname)
+{
+    nsc->ns_hostname = mh_xstrdup(hostname);
+}
+
 /*
  * Get the snoop flag for this connection
  */
@@ -937,14 +947,19 @@ netsec_flush(netsec_context *nsc, char **errstr)
  */
 
 int
-netsec_set_sasl_params(netsec_context *nsc, const char *hostname,
-                      const char *service, const char *mechanism,
-                      netsec_sasl_callback callback, char **errstr)
+netsec_set_sasl_params(netsec_context *nsc, const char *service,
+                      const char *mechanism, netsec_sasl_callback callback,
+                      char **errstr)
 {
 #ifdef CYRUS_SASL
     sasl_callback_t *sasl_cbs;
     int retval;
 
+    if (!nsc->ns_hostname) {
+       netsec_err(errstr, "Internal error: ns_hostname is NULL");
+       return NOTOK;
+    }
+
     if (! sasl_initialized) {
        retval = sasl_client_init(NULL);
        if (retval != SASL_OK) {
@@ -980,8 +995,8 @@ netsec_set_sasl_params(netsec_context *nsc, const char *hostname,
 
     nsc->sasl_cbs = sasl_cbs;
 
-    retval = sasl_client_new(service, hostname, NULL, NULL, nsc->sasl_cbs, 0,
-                            &nsc->sasl_conn);
+    retval = sasl_client_new(service, nsc->ns_hostname, NULL, NULL,
+                            nsc->sasl_cbs, 0, &nsc->sasl_conn);
 
     if (retval) {
        netsec_err(errstr, "SASL new client allocation failed: %s",
@@ -989,13 +1004,11 @@ netsec_set_sasl_params(netsec_context *nsc, const char *hostname,
        return NOTOK;
     }
 
-    nsc->sasl_hostname = mh_xstrdup(hostname);
-
     /*
      * Set up our credentials
      */
 
-    nsc->sasl_creds = nmh_get_credentials(nsc->sasl_hostname, nsc->ns_userid);
+    nsc->sasl_creds = nmh_get_credentials(nsc->ns_hostname, nsc->ns_userid);
 
 #else /* CYRUS_SASL */
     NMH_UNUSED(hostname);
@@ -1420,7 +1433,7 @@ netsec_set_oauth_service(netsec_context *nsc, const char *service)
  */
 
 int
-netsec_set_tls(netsec_context *nsc, int tls, char **errstr)
+netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr)
 {
 #ifdef TLS_SUPPORT
     if (tls) {
@@ -1448,6 +1461,13 @@ netsec_set_tls(netsec_context *nsc, int tls, char **errstr)
            SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
                                SSL_OP_NO_TLSv1);
 
+           if (!SSL_CTX_set_default_verify_paths(sslctx)) {
+               netsec_err(errstr, "Unable to set default certificate "
+                          "verification paths: %s",
+                          ERR_error_string(ERR_get_error(), NULL));
+               return NOTOK;
+           }
+
            tls_initialized++;
        }
 
@@ -1512,6 +1532,38 @@ netsec_set_tls(netsec_context *nsc, int tls, char **errstr)
        SSL_set_bio(ssl, rbio, wbio);
        SSL_set_connect_state(ssl);
 
+       /*
+        * If noverify is NOT set, then do certificate validation.
+        * Turning on SSL_VERIFY_PEER will verify the certificate chain
+        * against locally stored root certificates (the locations are
+        * set using SSL_CTX_set_default_verify_paths()), and we put
+        * the hostname in the X509 verification parameters so the OpenSSL
+        * code will verify that the hostname appears in the server
+        * certificate.
+        */
+
+       if (! noverify) {
+           X509_VERIFY_PARAM *param;
+
+           SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
+           if (! nsc->ns_hostname) {
+               netsec_err(errstr, "Internal error: hostname not set and "
+                          "certification verification enabled");
+               SSL_free(ssl);
+               return NOTOK;
+           }
+
+           param = SSL_get0_param(ssl);
+
+           if (! X509_VERIFY_PARAM_set1_host(param, nsc->ns_hostname, 0)) {
+               netsec_err(errstr, "Unable to add hostname %s to cert "
+                          "verification parameters: %s", nsc->ns_hostname,
+                          ERR_error_string(ERR_get_error(), NULL));
+               SSL_free(ssl);
+               return NOTOK;
+           }
+       }
+
        ssl_bio = BIO_new(BIO_f_ssl());
 
        if (! ssl_bio) {
@@ -1555,8 +1607,42 @@ netsec_negotiate_tls(netsec_context *nsc, char **errstr)
     }
 
     if (BIO_do_handshake(nsc->ssl_io) < 1) {
-       netsec_err(errstr, "TLS negotiation failed: %s",
-                  ERR_error_string(ERR_get_error(), NULL));
+       unsigned long errcode = ERR_get_error();
+
+       /*
+        * Print a more detailed message if it was certificate verification
+        * failure.
+        */
+
+       if (ERR_GET_LIB(errcode) == ERR_LIB_SSL &&
+               ERR_GET_REASON(errcode) == SSL_R_CERTIFICATE_VERIFY_FAILED) {
+           SSL *ssl;
+
+           if (BIO_get_ssl(nsc->ssl_io, &ssl) < 1) {
+               netsec_err(errstr, "Certificate verification failed, but "
+                          "cannot retrieve SSL handle: %s",
+                          ERR_error_string(ERR_get_error(), NULL));
+           } else {
+               netsec_err(errstr, "Server certificate verification failed: %s",
+                          X509_verify_cert_error_string(
+                                               SSL_get_verify_result(ssl)));
+           }
+       } else {
+           netsec_err(errstr, "TLS negotiation failed: %s",
+                      ERR_error_string(ERR_get_error(), NULL));
+       }
+
+       /*
+        * Because negotiation failed, shut down TLS so we don't get any
+        * garbage on the connection.  Because of weirdness with SSL_shutdown,
+        * we end up calling it twice: once explicitly, once as part of
+        * BIO_free_all().
+        */
+
+       BIO_ssl_shutdown(nsc->ssl_io);
+       BIO_free_all(nsc->ssl_io);
+       nsc->ssl_io = NULL;
+
        return NOTOK;
     }
 
index 069e3ce..b32b3e1 100644 (file)
--- a/uip/inc.c
+++ b/uip/inc.c
@@ -75,6 +75,8 @@
     X("saslmech", 0, SASLMECHSW) \
     X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NOTLSSW) \
+    X("certverify", TLSminc(-10), CERTVERSW) \
+    X("nocertverify", TLSminc(-12), NOCERTVERSW) \
     X("authservice", 0, AUTHSERVICESW) \
     X("proxy command", 0, PROXYSW) \
 
@@ -187,7 +189,7 @@ main (int argc, char **argv)
     int chgflag = 1, trnflag = 1;
     int noisy = 1, width = -1;
     int hghnum = 0, msgnum = 0;
-    int sasl = 0, tls = 0;
+    int sasl = 0, tls = 0, noverify = 1;
     int incerr = 0; /* <0 if inc hits an error which means it should not truncate mailspool */
     char *cp, *maildir = NULL, *folder = NULL;
     char *format = NULL, *form = NULL;
@@ -363,6 +365,14 @@ main (int argc, char **argv)
                tls = 0;
                continue;
 
+           case CERTVERSW:
+               noverify = 0;
+               continue;
+
+           case NOCERTVERSW:
+               noverify++;
+               continue;
+
            case AUTHSERVICESW:
 #ifdef OAUTH_SUPPORT
                 if (!(auth_svc = *argp++) || *auth_svc == '-')
@@ -412,6 +422,8 @@ main (int argc, char **argv)
      * a POP server?
      */
     if (inc_type == INC_POP) {
+       int tlsflag = 0;
+
        if (auth_svc == NULL) {
            if (saslmech  &&  ! strcasecmp(saslmech, "xoauth2")) {
                adios (NULL, "must specify -authservice with -saslmech xoauth2");
@@ -422,11 +434,17 @@ main (int argc, char **argv)
            }
        }
 
+       if (tls)
+           tlsflag |= P_INITTLS;
+
+       if (noverify)
+           tlsflag |= P_NOVERIFY;
+
        /*
         * initialize POP connection
         */
        if (pop_init (host, port, user, proxy, snoop, sasl, saslmech,
-                     tls, auth_svc) == NOTOK)
+                     tlsflag, auth_svc) == NOTOK)
            adios (NULL, "%s", response);
 
        /* Check if there are any messages */
index a4613c2..eed61cd 100644 (file)
     X("help", 0, HELPSW) \
     X("snoop", 0, SNOOPSW) \
     X("sasl", SASLminc(4), SASLSW) \
+    X("nosasl", SASLminc(6), NOSASLSW) \
     X("saslmech", SASLminc(5), SASLMECHSW) \
     X("authservice", SASLminc(0), AUTHSERVICESW) \
     X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NOTLSSW) \
+    X("certverify", TLSminc(-10), CERTVERSW) \
+    X("nocertverify", TLSminc(-12), NOCERTVERSW) \
     X("proxy command", 0, PROXYSW) \
 
 #define X(sw, minchars, id) id,
@@ -87,7 +90,7 @@ int
 main (int argc, char **argv)
 {
     int datesw = 1, notifysw = NT_ALL;
-    int status = 0, sasl = 0, tls = 0;
+    int status = 0, sasl = 0, tls = 0, noverify = 0;
     int snoop = 0, vecp = 0;
     char *cp, *host = NULL, *port = NULL, *user = NULL, *proxy = NULL;
     char buf[BUFSIZ], *saslmech = NULL, *auth_svc = NULL;
@@ -164,6 +167,10 @@ main (int argc, char **argv)
                    sasl++;
                    continue;
                
+               case NOSASLSW:
+                   sasl = 0;
+                   continue;
+
                case SASLMECHSW:
                    if (!(saslmech = *argp++) || *saslmech == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
@@ -177,6 +184,14 @@ main (int argc, char **argv)
                    tls = 0;
                    continue;
 
+               case CERTVERSW:
+                   noverify = 0;
+                   continue;
+
+               case NOCERTVERSW:
+                   noverify++;
+                   continue;
+
                case AUTHSERVICESW:
 #ifdef OAUTH_SUPPORT
                    if (!(auth_svc = *argp++) || *auth_svc == '-')
@@ -216,13 +231,21 @@ main (int argc, char **argv)
        vec[vecp] = NULL;
 
     if (host) {
+       int tlsflag = 0;
+
+       if (tls)
+           tlsflag |= P_INITTLS;
+
+       if (noverify)
+           tlsflag |= P_NOVERIFY;
+
        if (vecp == 0) {
            status = remotemail (host, port, user, proxy, notifysw, 1,
-                                snoop, sasl, saslmech, tls, auth_svc);
+                                snoop, sasl, saslmech, tlsflag, auth_svc);
        } else {
            for (vecp = 0; vec[vecp]; vecp++)
                status += remotemail (host, port, vec[vecp], proxy, notifysw, 0,
-                                     snoop, sasl, saslmech, tls, auth_svc);
+                                     snoop, sasl, saslmech, tlsflag, auth_svc);
        }
     } else {
        if (user == NULL) user = getusername ();
index 54aa368..fefd495 100644 (file)
@@ -144,6 +144,8 @@ pop_init (char *host, char *port, char *user, char *proxy, int snoop,
     if (user)
        netsec_set_userid(nsc, user);
 
+    netsec_set_hostname(nsc, host);
+
     if (oauth_svc != NULL) {
        if (netsec_set_oauth_service(nsc, oauth_svc) != OK) {
            snprintf(response, sizeof(response), "OAuth2 not supported");
@@ -211,8 +213,8 @@ pop_init (char *host, char *port, char *user, char *proxy, int snoop,
     netsec_set_fd(nsc, fd1, fd2);
     netsec_set_snoop(nsc, snoop);
 
-    if (tls) {
-       if (netsec_set_tls(nsc, 1, &errstr) != OK) {
+    if (tls & P_INITTLS) {
+       if (netsec_set_tls(nsc, 1, tls & P_NOVERIFY, &errstr) != OK) {
            snprintf(response, sizeof(response), "%s", errstr);
            free(errstr);
            return NOTOK;
@@ -226,8 +228,8 @@ pop_init (char *host, char *port, char *user, char *proxy, int snoop,
     }
 
     if (sasl) {
-       if (netsec_set_sasl_params(nsc, host, "pop", mech,
-                                  pop_sasl_callback, &errstr) != OK) {
+       if (netsec_set_sasl_params(nsc, "pop", mech, pop_sasl_callback,
+                                  &errstr) != OK) {
            snprintf(response, sizeof(response), "%s", errstr);
            free(errstr);
            return NOTOK;
index 9940fa7..95b23aa 100644 (file)
@@ -89,6 +89,8 @@
     X("tls", TLSminc(-3), TLSSW) \
     X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NTLSSW) \
+    X("certverify", TLSminc(-10), CERTVERSW) \
+    X("nocertverify", TLSminc(-12), NOCERTVERSW) \
     X("fileproc", -4, FILEPROCSW) \
     X("mhlproc", -3, MHLPROCSW) \
     X("sendmail program", 0, MTSSM) \
@@ -239,7 +241,7 @@ static int sasl=0;          /* Use SASL auth for SMTP                */
 static char *saslmech=NULL;    /* Force use of particular SASL mech     */
 static char *user=NULL;                /* Authenticate as this user             */
 static char *port="submission";        /* Name of server port for SMTP submission */
-static int tls=-1;             /* Use TLS for encryption                */
+static int tlsflag=0;          /* Flags to control TLS settings         */
 static int fromcount=0;                /* Count of addresses on From: header    */
 static int seensender=0;       /* Have we seen a Sender: header?        */
 
@@ -313,7 +315,8 @@ static int find_prefix (void);
 int
 main (int argc, char **argv)
 {
-    int state, compnum, dashstuff = 0, swnum, oauth_flag = 0;
+    int state, compnum, dashstuff = 0, swnum, oauth_flag = 0, tls = -1;
+    int noverify = 0;
     int eai = 0; /* use Email Address Internationalization (EAI) (SMTPUTF8) */
     char *cp, *msg = NULL, **argp, **arguments, *envelope;
     char buf[BUFSIZ], name[NAMESZ], *auth_svc = NULL;
@@ -530,6 +533,14 @@ main (int argc, char **argv)
                    tls = 0;
                    continue;
 
+               case CERTVERSW:
+                   noverify = 0;
+                   continue;
+
+               case NOCERTVERSW:
+                   noverify++;
+                   continue;
+
                case FILEPROCSW:
                    if (!(cp = *argp++) || *cp == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
@@ -692,6 +703,16 @@ main (int argc, char **argv)
 #endif /* ! TLS_SUPPORT */
     }
 
+    if (tls == 1)
+       tlsflag = S_STARTTLS;
+    else if (tls == 2)
+       tlsflag = S_INITTLS;
+    else
+       tlsflag = 0;
+
+    if (noverify)
+       tlsflag |= S_NOVERIFY;
+
     /*
      * If we were given any oauth flags, store the appropriate profile
      * entries and make sure an authservice was given (we have to do this
@@ -1680,7 +1701,7 @@ post (char *file, int bccque, int talk, int eai, char *envelope,
 
        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
                                        verbose, snoop, sasl, saslmech, user,
-                                       oauth_flag ? auth_svc : NULL, tls))
+                                       oauth_flag ? auth_svc : NULL, tlsflag))
                || rp_isbad (retval = sm_winit (envelope, eai, eightbit))) {
            close (fd);
            die (NULL, "problem initializing server; %s", rp_string (retval));
@@ -1724,7 +1745,7 @@ verify_all_addresses (int talk, int eai, char *envelope, int oauth_flag,
 
        if (rp_isbad (retval = sm_init (clientsw, serversw, port, watch,
                                        verbose, snoop, sasl, saslmech, user,
-                                       oauth_flag ? auth_svc : NULL, tls))
+                                       oauth_flag ? auth_svc : NULL, tlsflag))
                || rp_isbad (retval = sm_winit (envelope, eai, eightbit))) {
            die (NULL, "problem initializing server; %s", rp_string (retval));
        }
index 0d90aa1..2d162a7 100644 (file)
@@ -73,6 +73,8 @@
     X("tls", TLSminc(-3), TLSSW) \
     X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NTLSSW) \
+    X("certverify", TLSminc(-10), CERTVERSW) \
+    X("nocertverify", TLSminc(-12), NOCERTVERSW) \
     X("sendmail program", 0, MTSSM) \
     X("mts smtp|sendmail/smtp|sendmail/pipe", 2, MTSSW) \
     X("messageid localname|random", 2, MESSAGEIDSW) \
@@ -256,6 +258,8 @@ main (int argc, char **argv)
                case TLSSW:
                case INITTLSSW:
                case NTLSSW:
+               case CERTVERSW:
+               case NOCERTVERSW:
                    vec[vecp++] = --cp;
                    continue;
 
index 5a73738..833c2f5 100644 (file)
@@ -954,6 +954,8 @@ buildfile (char **argp, char *file)
     X("tls", TLSminc(-3), TLSSW) \
     X("initialtls", TLSminc(-10), INITTLSSW) \
     X("notls", TLSminc(-5), NTLSSW) \
+    X("certverify", TLSminc(-10), CERTVERSW) \
+    X("nocertverify", TLSminc(-12), NOCERTVERSW) \
     X("sendmail program", 0, MTSSM) \
     X("mts smtp|sendmail/smtp|sendmail/pipe", 2, MTSSW) \
     X("messageid localname|random", 2, MESSAGEIDSW) \
@@ -1134,6 +1136,8 @@ sendit (char *sp, char **arg, char *file, int pushed)
                case TLSSW:
                case INITTLSSW:
                case NTLSSW:
+               case CERTVERSW:
+               case NOCERTVERSW:
                    vec[vecp++] = --cp;
                    continue;