diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | conf.c | 1 | ||||
-rw-r--r-- | driver.c | 10 | ||||
-rw-r--r-- | fetchmail.c | 3 | ||||
-rw-r--r-- | fetchmail.h | 1 | ||||
-rw-r--r-- | fetchmail.man | 12 | ||||
-rwxr-xr-x | fetchmailconf.py | 16 | ||||
-rw-r--r-- | imap.c | 19 | ||||
-rw-r--r-- | options.c | 7 | ||||
-rw-r--r-- | pop3.c | 17 | ||||
-rw-r--r-- | rcfile_l.l | 1 | ||||
-rw-r--r-- | rcfile_y.y | 3 |
12 files changed, 72 insertions, 21 deletions
@@ -102,6 +102,9 @@ fetchmail 6.3.9 (not yet released): * In KAME/getnameinfo.c it's best to use the correct argument to inet_ntoa. (Peter O'Gorman) * In verbose mode, log if --check mode is enabled. +* Add sslcommonname option (rcfile and commandline) as a way to work around + misconfigured upstream SSL servers that use the wrong certificate name. It + specifies which CommonName fetchmail expects and logs. # DOCUMENTATION: * Add fetchmail-SA-2007-02.txt @@ -376,6 +376,7 @@ void dump_config(struct runctl *runp, struct query *querylist) stringdump("sslproto", ctl->sslproto); booldump("sslcertck", ctl->sslcertck); stringdump("sslcertpath", ctl->sslcertpath); + stringdump("sslcommonname", ctl->sslcommonname); stringdump("sslfingerprint", ctl->sslfingerprint); #endif /* SSL_ENABLE */ numdump("expunge", ctl->expunge); @@ -1088,10 +1088,12 @@ static int do_session( set_timeout(mytimeout); /* perform initial SSL handshake on open connection */ - /* Note: We pass the realhost name over for certificate - verification. We may want to make this configurable */ - if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslcert,ctl->sslkey,ctl->sslproto,ctl->sslcertck, - ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname,&ctl->remotename) == -1) + if (ctl->use_ssl && + SSLOpen(mailserver_socket, ctl->sslcert, ctl->sslkey, + ctl->sslproto, ctl->sslcertck, ctl->sslcertpath, + ctl->sslfingerprint, ctl->sslcommonname ? + ctl->sslcommonname : realhost, ctl->server.pollname, + &ctl->remotename) == -1) { report(stderr, GT_("SSL connection failed.\n")); err = PS_SOCKET; diff --git a/fetchmail.c b/fetchmail.c index ab335380..bf88b4dd 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -966,6 +966,7 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(sslproto); FLAG_MERGE(sslcertck); FLAG_MERGE(sslcertpath); + FLAG_MERGE(sslcommonname); FLAG_MERGE(sslfingerprint); #endif FLAG_MERGE(expunge); @@ -1637,6 +1638,8 @@ static void dump_params (struct runctl *runp, 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) printf(GT_(" SSL key fingerprint (checked against the server key): %s\n"), ctl->sslfingerprint); #endif diff --git a/fetchmail.h b/fetchmail.h index 107dffc1..35dfa223 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -355,6 +355,7 @@ struct query use ssl23 for SSL and opportunistic tls1 for non-SSL connections. */ char *sslcertpath; /* Trusted certificate directory for checking the server cert */ flag sslcertck; /* Strictly check the server cert. */ + char *sslcommonname; /* CommonName to expect from server */ char *sslfingerprint; /* Fingerprint to check against */ char *properties; /* passthrough properties for extensions */ diff --git a/fetchmail.man b/fetchmail.man index 2db1689c..6e4a254c 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -439,6 +439,18 @@ it - every time you add or modify a certificate in the directory, you need to use the \fBc_rehash\fR tool (which comes with OpenSSL in the tools/ subdirectory). .TP +.B \-\-sslcommonname <common name> +(Keyword: sslcommonname) +Use of this option is discouraged. Before using it, contact your +upstream and ask for a proper SSL certificate to be used. If the +upstream is clueless, this option can be used to specify the name +(CommonName) that fetchmail expects on the server certificate. A +correctly configured server will have this set to the hostname by which +it is reached, and by default fetchmail will expect as much. Use this +option when the CommonName is set to some other value, to avoid the +"Server CommonName mismatch" warning, and only if the upstream can't be +made to use proper certificates. +.TP .B \-\-sslfingerprint <fingerprint> (Keyword: sslfingerprint) Specify the fingerprint of the server key (an MD5 hash of the key) in diff --git a/fetchmailconf.py b/fetchmailconf.py index 3c7f5c38..8c6decab 100755 --- a/fetchmailconf.py +++ b/fetchmailconf.py @@ -5,7 +5,7 @@ # Matthias Andree <matthias.andree@gmx.de> # Requires Python with Tkinter, and the following OS-dependent services: # posix, posixpath, socket -version = "1.53 $Revision$" +version = "1.54 $Revision$" from Tkinter import * from Dialog import * @@ -258,6 +258,7 @@ class User: self.sslproto = None # Force SSL? self.sslcertck = 0 # Enable strict SSL cert checking self.sslcertpath = None # Path to trusted certificates + self.sslcommonname = None # SSL CommonName to expect self.sslfingerprint = None # SSL key fingerprint to check self.properties = None # Extension properties User.typemap = ( @@ -297,6 +298,7 @@ class User: ('sslcert', 'String'), ('sslcertck', 'Boolean'), ('sslcertpath', 'String'), + ('sslcommonname', 'String'), ('sslfingerprint', 'String'), ('properties', 'String')) @@ -371,6 +373,8 @@ class User: res = res + flag2str(self.sslcertck, 'sslcertck') if self.sslcertpath and self.sslcertpath != UserDefaults.sslcertpath: res = res + " sslcertpath " + `self.sslcertpath` + if self.sslcommonname and self.sslcommonname != UserDefaults.sslcommonname: + res = res + " sslcommonname " + `self.sslcommonname` if self.sslfingerprint and self.sslfingerprint != UserDefaults.sslfingerprint: res = res + " sslfingerprint " + `self.sslfingerprint` if self.expunge != UserDefaults.expunge: @@ -1000,8 +1004,10 @@ The ssl option enables SSL communication with a mailserver supporting Secure Sockets Layer. The sslkey and sslcert options declare key and certificate files for use with SSL. The sslcertck option enables strict checking of SSL server -certificates (and sslcertpath gives trusted certificate -directory). With sslfingerprint, you can specify a finger- +certificates (and sslcertpath gives the trusted certificate +directory). The sslcommonname option helps if the server is +misconfigured and returning "Server CommonName mismatch" +warnings. With sslfingerprint, you can specify a finger- print the server's key is checked against. """} @@ -1641,6 +1647,8 @@ class UserEdit(Frame, MyWidget): variable=self.sslcertck).pack(side=TOP, fill=X) LabeledEntry(sslwin, 'SSL trusted certificate directory:', self.sslcertpath, '14').pack(side=TOP, fill=X) + LabeledEntry(sslwin, 'SSL CommonName:', + self.sslcommonname, '14').pack(side=TOP, fill=X) LabeledEntry(sslwin, 'SSL key fingerprint:', self.sslfingerprint, '14').pack(side=TOP, fill=X) sslwin.pack(fill=X, anchor=N) @@ -1942,7 +1950,7 @@ def copy_instance(toclass, fromdict): optional = ('interface', 'monitor', 'esmtpname', 'esmtppassword', 'ssl', 'sslkey', 'sslcert', 'sslproto', 'sslcertck', - 'sslcertpath', 'sslfingerprint', 'showdots') + 'sslcertpath', 'sslcommonname', 'sslfingerprint', 'showdots') class_sig = setdiff(toclass.__dict__.keys(), optional) class_sig.sort() dict_keys = setdiff(fromdict.keys(), optional) @@ -381,7 +381,6 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) int ok = 0; #ifdef SSL_ENABLE int got_tls = 0; - char *realhost; #endif (void)greeting; @@ -407,9 +406,15 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) } #ifdef SSL_ENABLE - realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname; - if (maybe_tls(ctl)) { + char *commonname; + + commonname = ctl->server.pollname; + if (ctl->server.via) + commonname = ctl->server.via; + if (ctl->sslcommonname) + commonname = ctl->sslcommonname; + if (strstr(capabilities, "STARTTLS")) { /* Use "tls1" rather than ctl->sslproto because tls1 is the only @@ -418,7 +423,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, realhost, + ctl->sslcertpath, ctl->sslfingerprint, commonname, ctl->server.pollname, &ctl->remotename) != -1) { /* @@ -438,7 +443,7 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) capa_probe(sock, ctl); if (outlevel >= O_VERBOSE) { - report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), realhost); + report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), commonname); } } } @@ -447,11 +452,11 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) if (must_tls(ctl)) { /* Config required TLS but we couldn't guarantee it, so we must * stop. */ - report(stderr, GT_("%s: upgrade to TLS failed.\n"), realhost); + report(stderr, GT_("%s: upgrade to TLS failed.\n"), commonname); return PS_SOCKET; } else { if (outlevel >= O_VERBOSE) { - report(stdout, GT_("%s: opportunistic upgrade to TLS failed, trying to continue\n"), realhost); + report(stdout, GT_("%s: opportunistic upgrade to TLS failed, trying to continue\n"), commonname); } /* We don't know whether the connection is in a working state, so * test by issuing a NOOP. */ @@ -46,6 +46,7 @@ enum { LA_SSLPROTO, LA_SSLCERTCK, LA_SSLCERTPATH, + LA_SSLCOMMONNAME, LA_SSLFINGERPRINT, LA_FETCHSIZELIMIT, LA_FASTUIDL, @@ -125,6 +126,7 @@ static const struct option longoptions[] = { {"sslproto", required_argument, (int *) 0, LA_SSLPROTO }, {"sslcertck", no_argument, (int *) 0, LA_SSLCERTCK }, {"sslcertpath", required_argument, (int *) 0, LA_SSLCERTPATH }, + {"sslcommonname", required_argument, (int *) 0, LA_SSLCOMMONNAME }, {"sslfingerprint", required_argument, (int *) 0, LA_SSLFINGERPRINT }, #endif @@ -539,6 +541,10 @@ int parsecmdline (int argc /** argument count */, ctl->sslcertpath = prependdir(optarg, currentwd); break; + case LA_SSLCOMMONNAME: + ctl->sslcommonname = xstrdup(optarg); + break; + case LA_SSLFINGERPRINT: ctl->sslfingerprint = xstrdup(optarg); break; @@ -611,6 +617,7 @@ int parsecmdline (int argc /** argument count */, 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_(" --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")); #endif @@ -307,7 +307,6 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) char *challenge; #endif /* OPIE_ENABLE */ #ifdef SSL_ENABLE - char *realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname; flag connection_may_have_tls_errors = FALSE; flag got_tls = FALSE; #endif /* SSL_ENABLE */ @@ -476,6 +475,14 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) #ifdef SSL_ENABLE if (maybe_tls(ctl)) { + char *commonname; + + commonname = ctl->server.pollname; + if (ctl->server.via) + commonname = ctl->server.via; + if (ctl->sslcommonname) + commonname = ctl->sslcommonname; + if (has_stls) { /* Use "tls1" rather than ctl->sslproto because tls1 is the only @@ -484,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, realhost, + ctl->sslcertpath, ctl->sslfingerprint, commonname, ctl->server.pollname, &ctl->remotename) != -1) { /* @@ -508,7 +515,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) } if (outlevel >= O_VERBOSE) { - report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), realhost); + report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), commonname); } } } @@ -517,7 +524,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) if (must_tls(ctl)) { /* Config required TLS but we couldn't guarantee it, so we must * stop. */ - report(stderr, GT_("%s: upgrade to TLS failed.\n"), realhost); + report(stderr, GT_("%s: upgrade to TLS failed.\n"), commonname); return PS_SOCKET; } else { /* We don't know whether the connection is usable, and there's @@ -528,7 +535,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) connection_may_have_tls_errors = TRUE; if (outlevel >= O_VERBOSE) { - report(stdout, GT_("%s: opportunistic upgrade to TLS failed, trying to continue.\n"), realhost); + report(stdout, GT_("%s: opportunistic upgrade to TLS failed, trying to continue.\n"), commonname); } } } @@ -187,6 +187,7 @@ sslcert { return SSLCERT; } sslproto { return SSLPROTO; } sslcertck { return SSLCERTCK; } sslcertpath { return SSLCERTPATH; } +sslcommonname { return SSLCOMMONNAME; } sslfingerprint { return SSLFINGERPRINT; } checkalias { return CHECKALIAS; } @@ -76,7 +76,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 SSLFINGERPRINT +%token SSL SSLKEY SSLCERT SSLPROTO SSLCERTCK SSLCERTPATH SSLCOMMONNAME SSLFINGERPRINT %token PRINCIPAL ESMTPNAME ESMTPPASSWORD %token TRACEPOLLS @@ -338,6 +338,7 @@ user_option : TO localnames HERE | SSLPROTO STRING {current.sslproto = xstrdup($2);} | SSLCERTCK {current.sslcertck = FLAG_TRUE;} | SSLCERTPATH STRING {current.sslcertpath = prependdir($2, rcfiledir);} + | SSLCOMMONNAME STRING {current.sslcommonname = xstrdup($2);} | SSLFINGERPRINT STRING {current.sslfingerprint = xstrdup($2);} | NO KEEP {current.keep = FLAG_FALSE;} |