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;} | 
