From: Ken Hornstein Date: Wed, 2 Nov 2016 03:13:04 +0000 (-0400) Subject: Add support for certificate verification when using TLS. X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/5cb3431b8210554b89425d60b3c0aa4f521b7414 Add support for certificate verification when using TLS. --- diff --git a/h/netsec.h b/h/netsec.h index e05e79f1..7dac5214 100644 --- a/h/netsec.h +++ b/h/netsec.h @@ -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 diff --git a/h/popsbr.h b/h/popsbr.h index 96d21a33..9991e473 100644 --- a/h/popsbr.h +++ b/h/popsbr.h @@ -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); diff --git a/man/inc.man b/man/inc.man index 47338c26..d9ceaa40 100644 --- a/man/inc.man +++ b/man/inc.man @@ -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 diff --git a/man/msgchk.man b/man/msgchk.man index 97809b2f..eb356c22 100644 --- a/man/msgchk.man +++ b/man/msgchk.man @@ -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 diff --git a/man/send.man b/man/send.man index e62b3826..4b8a1213 100644 --- a/man/send.man +++ b/man/send.man @@ -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 diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index fdc56b06..80bff194 100644 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -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); } diff --git a/mts/smtp/smtp.h b/mts/smtp/smtp.h index df02c1a4..953b3ded 100644 --- a/mts/smtp/smtp.h +++ b/mts/smtp/smtp.h @@ -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); diff --git a/sbr/netsec.c b/sbr/netsec.c index 601e2b7a..79fd6a0d 100644 --- a/sbr/netsec.c +++ b/sbr/netsec.c @@ -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; } diff --git a/uip/inc.c b/uip/inc.c index 069e3ce5..b32b3e1f 100644 --- 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 */ diff --git a/uip/msgchk.c b/uip/msgchk.c index a4613c27..eed61cd2 100644 --- a/uip/msgchk.c +++ b/uip/msgchk.c @@ -38,10 +38,13 @@ 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 (); diff --git a/uip/popsbr.c b/uip/popsbr.c index 54aa3684..fefd4954 100644 --- a/uip/popsbr.c +++ b/uip/popsbr.c @@ -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; diff --git a/uip/post.c b/uip/post.c index 9940fa71..95b23aab 100644 --- a/uip/post.c +++ b/uip/post.c @@ -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)); } diff --git a/uip/send.c b/uip/send.c index 0d90aa14..2d162a7a 100644 --- a/uip/send.c +++ b/uip/send.c @@ -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; diff --git a/uip/whatnowsbr.c b/uip/whatnowsbr.c index 5a73738e..833c2f58 100644 --- a/uip/whatnowsbr.c +++ b/uip/whatnowsbr.c @@ -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;