]> Pileus Git - ~andy/fetchmail/commitdiff
Add --sslcertfile option and FETCHMAIL_NO_DEFAULT_X509_PATHS env var,
authorMatthias Andree <matthias.andree@gmx.de>
Sun, 18 Apr 2010 18:22:27 +0000 (20:22 +0200)
committerMatthias Andree <matthias.andree@gmx.de>
Sun, 18 Apr 2010 18:22:27 +0000 (20:22 +0200)
and always load the default X.509 trust stores, unless the latter is set.

12 files changed:
NEWS
driver.c
fetchmail.c
fetchmail.h
fetchmail.man
imap.c
options.c
pop3.c
rcfile_l.l
rcfile_y.y
socket.c
socket.h

diff --git a/NEWS b/NEWS
index 802309cfeb4898413964312ffb7aef2f97bc55e5..afecaf0c8c3c97a3aed7147241df62e9b6a6dd7e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -62,6 +62,14 @@ fetchmail-6.3.17 (not yet released):
   due to insufficient buffer size allocation. It would then repeatedly reallocate
   a larger buffer and fail formatting again. See fetchmail-SA-2010-02.txt.
 
+# FEATURES
+* Fetchmail now supports a --sslcertfile <file> option to specify a "CA bundle"
+  file (a file that contains trusted CA certificates). Since these bundled CA
+  files do not require c_rehash to be run, they are easier to use and immune to
+  OpenSSL library updates. Also see CHANGES below.
+* Fetchmail now supports a FETCHMAIL_NO_DEFAULT_X509_PATHS environment variable
+  to defeat loading the default SSL CA certificate locations. Also see CHANGES.
+
 # REGRESSION FIX
 * Fix string handling in rcfile scanner, which caused fetchmail to misparse a
   run control file in certain circumstances.  Fixes BerliOS bug #14257.
@@ -77,6 +85,11 @@ fetchmail-6.3.17 (not yet released):
   are now helpful pointers to --sslcertpath and c_rehash for "unable to get
   local issuer certificate" and self-signed certificates -- these usually hint
   to missing root signing CAs in the certs directory.
+* Default locations: Fetchmail will now always load the SSL default trusted CA
+  certificate locations, unless the environmental variable
+  FETCHMAIL_NO_DEFAULT_X509_PATHS is set and non-empty. Fetchmail used to load
+  the default locations only if --sslcertpath was not given.
+  This is a migration aid for systems upgrading to OpenSSL 1.0.0.
 
 # DOCUMENTATION
 * Fix table of global option to read "set softbounce" where there used to be a
index 32cfffb1182d9bd2e224fdec5366d900fc58b709..68a388d12feea2ab465563dbfe89d5a38ae79c52 100644 (file)
--- a/driver.c
+++ b/driver.c
@@ -1109,7 +1109,8 @@ static int do_session(
        /* perform initial SSL handshake on open connection */
        if (ctl->use_ssl &&
                SSLOpen(mailserver_socket, ctl->sslcert, ctl->sslkey,
-                   ctl->sslproto, ctl->sslcertck, ctl->sslcertpath,
+                   ctl->sslproto, ctl->sslcertck,
+                   ctl->sslcertfile, ctl->sslcertpath,
                    ctl->sslfingerprint, ctl->sslcommonname ?
                    ctl->sslcommonname : realhost, ctl->server.pollname,
                    &ctl->remotename) == -1)
index af2a5dda3e3ac16ddac78ee9264f33fca50a69ae..6d63c714ef0fd7a730eb04b759812eb910106182 100644 (file)
@@ -981,6 +981,7 @@ static void optmerge(struct query *h2, struct query *h1, int force)
     FLAG_MERGE(sslcert);
     FLAG_MERGE(sslproto);
     FLAG_MERGE(sslcertck);
+    FLAG_MERGE(sslcertfile);
     FLAG_MERGE(sslcertpath);
     FLAG_MERGE(sslcommonname);
     FLAG_MERGE(sslfingerprint);
@@ -1667,9 +1668,11 @@ static void dump_params (struct runctl *runp,
            printf(GT_("  SSL protocol: %s.\n"), ctl->sslproto);
        if (ctl->sslcertck) {
            printf(GT_("  SSL server certificate checking enabled.\n"));
-           if (ctl->sslcertpath != NULL)
-               printf(GT_("  SSL trusted certificate directory: %s\n"), ctl->sslcertpath);
        }
+       if (ctl->sslcertfile != NULL)
+               printf(GT_("  SSL trusted certificate file: %s\n"), ctl->sslcertfile);
+       if (ctl->sslcertpath != NULL)
+               printf(GT_("  SSL trusted certificate directory: %s\n"), ctl->sslcertpath);
        if (ctl->sslcommonname != NULL)
                printf(GT_("  SSL server CommonName: %s\n"), ctl->sslcommonname);
        if (ctl->sslfingerprint != NULL)
index 40ab2eb8944d1de30fca1a5e903db52224e9a64a..b9e382714dcd9b160a142396ea0388ee37a50b77 100644 (file)
@@ -358,6 +358,7 @@ struct query
     char *sslcert;             /* optional SSL certificate file */
     char *sslproto;            /** force transport protocol (ssl2|ssl3|ssl23|tls1) - if NULL,
                                  use ssl23 for SSL and opportunistic tls1 for non-SSL connections. */
+    char *sslcertfile;         /* Trusted certificate file for checking the server cert */
     char *sslcertpath;         /* Trusted certificate directory for checking the server cert */
     flag sslcertck;            /* Strictly check the server cert. */
     char *sslcommonname;       /* CommonName to expect from server */
index 1c6344cc873358978855c51903da344a22d6c3d3..f6c8915f2cf7965726fd02e61884c29126f84506 100644 (file)
@@ -10,7 +10,7 @@
 .\" Load www macros to process .URL requests, this requires groff:
 .mso www.tmac
 .\"
-.TH fetchmail 1 "fetchmail 6.3.16" "fetchmail" "fetchmail reference manual"
+.TH fetchmail 1 "fetchmail 6.3.17-pre1" "fetchmail" "fetchmail reference manual"
 
 .SH NAME
 fetchmail \- fetch mail from a POP, IMAP, ETRN, or ODMR-capable server
@@ -495,10 +495,10 @@ to try appropriate protocols depending on context.
 (Keyword: sslcertck)
 .br
 Causes fetchmail to strictly check the server certificate against a set of
-local trusted certificates (see the \fBsslcertpath\fP option). If the server
-certificate cannot be obtained or is not signed by one of the trusted ones
-(directly or indirectly), the SSL connection will fail, regardless of
-the \fBsslfingerprint\fP option.
+local trusted certificates (see the \fBsslcertfile\fP and \fBsslcertpath\fP
+options). If the server certificate cannot be obtained or is not signed by one
+of the trusted ones (directly or indirectly), the SSL connection will fail,
+regardless of the \fBsslfingerprint\fP option.
 .IP
 Note that CRL (certificate revocation lists) are only supported in
 OpenSSL 0.9.7 and newer! Your system clock should also be reasonably
@@ -507,6 +507,18 @@ accurate when using this option.
 Note that this optional behavior may become default behavior in future
 fetchmail versions.
 .TP
+.B \-\-sslcertfile <file>
+(Keyword: sslcertfile, since v6.3.17)
+.br
+Sets the file fetchmail uses to look up local certificates.  The default is
+empty.  This can be given in addition to \fB\-\-sslcertpath\fP below, and
+certificates specified in \fB\-\-sslcertfile\fP will be processed before those
+in \fB\-\-sslcertpath\fP.  The option can be used in addition to \fB\-\-sslcertpath\fP.
+.IP
+Note that fetchmail will always first load the default SSL trusted CA certificates file
+unless that is defeated by setting the environment variable
+.BR FETCHMAIL_NO_DEFAULT_X509_PATHS .
+.TP
 .B \-\-sslcertpath <directory>
 (Keyword: sslcertpath)
 .br
@@ -516,6 +528,13 @@ expects it - every time you add or modify a certificate in the directory, you
 need to use the \fBc_rehash\fP tool (which comes with OpenSSL in the tools/
 subdirectory). Also, after OpenSSL upgrades, you may need to run
 \fBc_rehash\fP; particularly when upgrading from 0.9.X to 1.0.0.
+.IP
+This can be given in addition to \fB\-\-sslcertfile\fP above, which see for
+precedence rules.
+.IP
+Note that fetchmail will also add the default SSL trusted CA certificates directory
+first unless defeated by setting the environment variable
+.BR FETCHMAIL_NO_DEFAULT_X509_PATHS .
 .TP
 .B \-\-sslcommonname <common name>
 (Keyword: sslcommonname; since v6.3.9)
@@ -1806,10 +1825,16 @@ ssl             \&      \&      T{
 Connect to server over the specified base protocol using SSL encryption
 T}
 sslcert        \&      \&      T{
-Specify file for client side public SSL certificate
+Specify file for \fBclient side\fP public SSL certificate
+T}
+sslcertfile    \&      \&      T{
+Specify file with trusted CA certificates
+T}
+sslcertpath    \&      \&      T{
+Specify c_rehash-ed directory with trusted CA certificates.
 T}
 sslkey         \&      \&      T{
-Specify file for client side private SSL key
+Specify file for \fBclient side\fP private SSL key
 T}
 sslproto       \&      \&      T{
 Force ssl protocol for connection
@@ -2728,7 +2753,7 @@ lock file to help prevent concurrent runs (root mode, systems without /var/run).
 
 .SH ENVIRONMENT
 .B FETCHMAILUSER:
-If the FETCHMAILUSER variable is set, it is used as the name of the
+If this environment variable is set, it is used as the name of the
 calling user (default local name) for purposes such as mailing error
 notifications.  Otherwise, if either the LOGNAME or USER variable is
 correctly set (e.g. the corresponding UID matches the session user ID)
@@ -2738,13 +2763,23 @@ session ID (this elaborate logic is designed to handle the case of
 multiple names per userid gracefully).
 
 .B FETCHMAILHOME:
-If the environment variable FETCHMAILHOME is set to a valid and
+If this environment variable is set to a valid and
 existing directory name, fetchmail will read $FETCHMAILHOME/fetchmailrc
 (the dot is missing in this case), $FETCHMAILHOME/.fetchids and
 $FETCHMAILHOME/.fetchmail.pid rather than from the user's home
 directory.  The .netrc file is always looked for in the the invoking
 user's home directory regardless of FETCHMAILHOME's setting.
 
+.B FETCHMAIL_NO_DEFAULT_X509_PATHS
+(since v6.3.17):
+If this environment variable is set and not empty, fetchmail will NOT load the
+default X.509 trusted certificate locations for SSL/TLS CA certificates.
+Default (if variable unset or empty): load certificate locations. This is
+rarely necessary outside testing. It might be useful in conjunction with
+\fB\-\-sslcertfile\fP and \fB\-\-sslcertpath\fP in case there are broken
+certificates in the system directories and the user has no administrator
+privileges to remedy the problem.
+
 .B HOME_ETC:
 If the HOME_ETC variable is set, fetchmail will read
 $HOME_ETC/.fetchmailrc instead of ~/.fetchmailrc.
diff --git a/imap.c b/imap.c
index 35b3bd07941000f961d5934a24bcdd09823a2b64..7c33d8a48142d2a07e0ca5cfb19a7f5422141f2c 100644 (file)
--- a/imap.c
+++ b/imap.c
@@ -484,7 +484,7 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting)
             * (see below). */
            if (gen_transact(sock, "STARTTLS") == PS_SUCCESS
                    && SSLOpen(sock, ctl->sslcert, ctl->sslkey, "tls1", ctl->sslcertck,
-                       ctl->sslcertpath, ctl->sslfingerprint, commonname,
+                       ctl->sslcertfile, ctl->sslcertpath, ctl->sslfingerprint, commonname,
                        ctl->server.pollname, &ctl->remotename) != -1)
            {
                /*
index 715902967c6e9b113e8d6ce5ca43272875d3356d..d0c7c2ab7ec598feafc7bceb105e365c754b7cd4 100644 (file)
--- a/options.c
+++ b/options.c
@@ -45,6 +45,7 @@ enum {
     LA_SSLCERT,
     LA_SSLPROTO,
     LA_SSLCERTCK,
+    LA_SSLCERTFILE,
     LA_SSLCERTPATH,
     LA_SSLCOMMONNAME,
     LA_SSLFINGERPRINT,
@@ -131,6 +132,7 @@ static const struct option longoptions[] = {
   {"sslcert",  required_argument, (int *) 0, LA_SSLCERT },
   {"sslproto",  required_argument, (int *) 0, LA_SSLPROTO },
   {"sslcertck", no_argument,      (int *) 0, LA_SSLCERTCK },
+  {"sslcertfile",   required_argument, (int *) 0, LA_SSLCERTFILE },
   {"sslcertpath",   required_argument, (int *) 0, LA_SSLCERTPATH },
   {"sslcommonname",    required_argument, (int *) 0, LA_SSLCOMMONNAME },
   {"sslfingerprint",   required_argument, (int *) 0, LA_SSLFINGERPRINT },
@@ -560,6 +562,10 @@ int parsecmdline (int argc /** argument count */,
            ctl->sslcertck = FLAG_TRUE;
            break;
 
+       case LA_SSLCERTFILE:
+           ctl->sslcertfile = prependdir(optarg, currentwd);
+           break;
+
        case LA_SSLCERTPATH:
            ctl->sslcertpath = prependdir(optarg, currentwd);
            break;
@@ -641,7 +647,8 @@ int parsecmdline (int argc /** argument count */,
        P(GT_("      --sslkey      ssl private key file\n"));
        P(GT_("      --sslcert     ssl client certificate\n"));
        P(GT_("      --sslcertck   do strict server certificate check (recommended)\n"));
-       P(GT_("      --sslcertpath path to ssl certificates\n"));
+       P(GT_("      --sslcertfile path to trusted-CA ssl certificate file\n"));
+       P(GT_("      --sslcertpath path to trusted-CA ssl certificate directory\n"));
        P(GT_("      --sslcommonname  expect this CommonName from server (discouraged)\n"));
        P(GT_("      --sslfingerprint fingerprint that must match that of the server's cert.\n"));
        P(GT_("      --sslproto    force ssl protocol (SSL2/SSL3/TLS1)\n"));
diff --git a/pop3.c b/pop3.c
index abd690e8096c7e1968bd8b7fc490aaf588825ea5..0cf58da776cbf469ba423919fbe1ce35b72d3185 100644 (file)
--- a/pop3.c
+++ b/pop3.c
@@ -491,7 +491,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting)
                * (see below). */
               if (gen_transact(sock, "STLS") == PS_SUCCESS
                       && SSLOpen(sock, ctl->sslcert, ctl->sslkey, "tls1", ctl->sslcertck,
-                          ctl->sslcertpath, ctl->sslfingerprint, commonname,
+                          ctl->sslcertfile, ctl->sslcertpath, ctl->sslfingerprint, commonname,
                           ctl->server.pollname, &ctl->remotename) != -1)
               {
                   /*
index 6d64d041b3e42ad3d4182d9a5c836b417c5a546d..4bb0864bbee027fe2ee21928fdecd9cb9ebbcc6f 100644 (file)
@@ -177,6 +177,7 @@ sslkey              { return SSLKEY; }
 sslcert                { return SSLCERT; }
 sslproto       { return SSLPROTO; }
 sslcertck      { return SSLCERTCK; }
+sslcertfile    { return SSLCERTFILE; }
 sslcertpath    { return SSLCERTPATH; }
 sslcommonname  { return SSLCOMMONNAME; }
 sslfingerprint { return SSLFINGERPRINT; }
index 607e6bd31da38cbf41743d21ac10c86304e79c0b..fe3a59d1b0de39d859aab7951d4e90866d772b59 100644 (file)
@@ -77,7 +77,7 @@ extern char * yytext;
 %token NO KEEP FLUSH LIMITFLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS 
 %token DROPSTATUS DROPDELIVERED
 %token DNS SERVICE PORT UIDL INTERVAL MIMEDECODE IDLE CHECKALIAS 
-%token SSL SSLKEY SSLCERT SSLPROTO SSLCERTCK SSLCERTPATH SSLCOMMONNAME SSLFINGERPRINT
+%token SSL SSLKEY SSLCERT SSLPROTO SSLCERTCK SSLCERTFILE SSLCERTPATH SSLCOMMONNAME SSLFINGERPRINT
 %token PRINCIPAL ESMTPNAME ESMTPPASSWORD
 %token TRACEPOLLS
 
@@ -344,6 +344,7 @@ user_option : TO localnames HERE
                | SSLCERT STRING        {current.sslcert = prependdir ($2, rcfiledir); free($2);}
                | SSLPROTO STRING       {current.sslproto = $2;}
                | SSLCERTCK             {current.sslcertck = FLAG_TRUE;}
+               | SSLCERTFILE STRING    {current.sslcertfile = prependdir($2, rcfiledir); free($2);}
                | SSLCERTPATH STRING    {current.sslcertpath = prependdir($2, rcfiledir); free($2);}
                | SSLCOMMONNAME STRING  {current.sslcommonname = $2;}
                | SSLFINGERPRINT STRING {current.sslfingerprint = $2;}
index 2ef709619cf9d2ba752e06916a2b6e6557581d3d..fd42ca4cd62f0cb0ba2336589e49f2c78f63f287 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -857,7 +857,8 @@ static const char *SSLCertGetCN(const char *mycert,
  * uses SSL *ssl global variable, which is currently defined
  * in this file
  */
-int SSLOpen(int sock, char *mycert, char *mykey, const char *myproto, int certck, char *certpath,
+int SSLOpen(int sock, char *mycert, char *mykey, const char *myproto, int certck,
+    char *cacertfile, char *certpath,
     char *fingerprint, char *servercname, char *label, char **remotename)
 {
         struct stat randstat;
@@ -921,10 +922,16 @@ int SSLOpen(int sock, char *mycert, char *mykey, const char *myproto, int certck
                 *  we provide the callback for output and possible fingerprint checks. */
                SSL_CTX_set_verify(_ctx[sock], SSL_VERIFY_PEER, SSL_nock_verify_callback);
        }
-       if (certpath)
-               SSL_CTX_load_verify_locations(_ctx[sock], NULL, certpath);
-       else
-               SSL_CTX_set_default_verify_paths(_ctx[sock]);
+
+       {
+               char *t = getenv("FETCHMAIL_NO_DEFAULT_X509_PATHS");
+
+               if (t == NULL || t[0] == '\0')
+                       SSL_CTX_set_default_verify_paths(_ctx[sock]);
+       }
+
+       if (certpath || cacertfile)
+               SSL_CTX_load_verify_locations(_ctx[sock], cacertfile, certpath);
        
        _ssl_context[sock] = SSL_new(_ctx[sock]);
        
index b340c4ce13f90b363e64a6c680a1a5c662e21750..9365f2f8b0c46c5a39bc052a85d61cf41670c0de 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -75,7 +75,7 @@ FIXME: document this
 int UnixOpen(const char *path);
 
 #ifdef SSL_ENABLE
-int SSLOpen(int sock, char *mycert, char *mykey, const char *myproto, int certck, char *certpath,
+int SSLOpen(int sock, char *mycert, char *mykey, const char *myproto, int certck, char *cacertfile, char *cacertpath,
     char *fingerprint, char *servercname, char *label, char **remotename);
 #endif /* SSL_ENABLE */