diff options
| -rw-r--r-- | imap/ChangeLog | 4 | ||||
| -rw-r--r-- | imap/configure.ac | 2 | ||||
| -rw-r--r-- | rfc1035/rfc1035qa.c | 31 | ||||
| -rw-r--r-- | tcpd/libcouriergnutls.c | 89 | 
4 files changed, 103 insertions, 23 deletions
| diff --git a/imap/ChangeLog b/imap/ChangeLog index f02a57e..8cd6989 100644 --- a/imap/ChangeLog +++ b/imap/ChangeLog @@ -1,3 +1,7 @@ +2019-12-05  Sam Varshavchik  <mrsam@courier-mta.com> + +	* Fix virtual IP and hostname handling when using GnuTLS for SSL. +  2019-09-05  Sam Varshavchik  <mrsam@courier-mta.com>  	* imap, pop3: include remote port TCP port number together with the diff --git a/imap/configure.ac b/imap/configure.ac index c21a80e..92726bc 100644 --- a/imap/configure.ac +++ b/imap/configure.ac @@ -4,7 +4,7 @@ dnl  dnl Copyright 1998 - 2019 Double Precision, Inc.  See COPYING for  dnl distribution information. -AC_INIT(courier-imap, 5.0.8, [courier-users@lists.sourceforge.net]) +AC_INIT(courier-imap, 5.0.8.20191205, [courier-users@lists.sourceforge.net])  >confdefs.h  # Kill PACKAGE_ macros diff --git a/rfc1035/rfc1035qa.c b/rfc1035/rfc1035qa.c index 46fc204..ffed34f 100644 --- a/rfc1035/rfc1035qa.c +++ b/rfc1035/rfc1035qa.c @@ -1,5 +1,5 @@  /* -** Copyright 1998 - 2011 Double Precision, Inc. +** Copyright 1998 - 2019 Double Precision, Inc.  ** See COPYING for distribution information.  */ @@ -8,6 +8,7 @@  #include	<string.h>  #include	<stdlib.h>  #include	<arpa/inet.h> +#include	<idna.h>  /* Convenient function to do forward IP lookup */ @@ -16,8 +17,9 @@  static int rfc1035_a_ipv4(struct rfc1035_res *res,  	const char *name, struct in_addr **iaptr, unsigned *iasize)  #else -int rfc1035_a(struct rfc1035_res *res, -	const char *name, RFC1035_ADDR **iaptr, unsigned *iasize) +static int rfc1035_unicode(struct rfc1035_res *res, +			   const char *name, +			   RFC1035_ADDR **iaptr, unsigned *iasize)  #endif  {  struct	rfc1035_reply *reply; @@ -111,8 +113,9 @@ unsigned i;  	return (0);  } -int rfc1035_a(struct rfc1035_res *res, -	const char *name, struct in6_addr **iaptr, unsigned *iasize) +static int rfc1035_unicode(struct rfc1035_res *res, +			   const char *name, struct in6_addr **iaptr, +			   unsigned *iasize)  {  struct	rfc1035_reply *reply;  int	n, o; @@ -236,3 +239,21 @@ unsigned k;  	return (0);  }  #endif + +int rfc1035_a(struct rfc1035_res *res, +	      const char *name, +	      RFC1035_ADDR **iaptr, unsigned *iasize) +{ +	char *p; +	int r; + +	/* Convert requested hostname to UTF-8, with fallback */ + +	if (idna_to_unicode_8z8z(name, &p, 0) != IDNA_SUCCESS) +		return rfc1035_unicode(res, name, iaptr, iasize); + +	r=rfc1035_unicode(res, p, iaptr, iasize); + +	free(p); +	return r; +} diff --git a/tcpd/libcouriergnutls.c b/tcpd/libcouriergnutls.c index 65c34cb..7a48ae3 100644 --- a/tcpd/libcouriergnutls.c +++ b/tcpd/libcouriergnutls.c @@ -1,5 +1,5 @@  /* -** Copyright 2007-2018 Double Precision, Inc. +** Copyright 2007-2019 Double Precision, Inc.  ** See COPYING for distribution information.  */  #include	"config.h" @@ -567,10 +567,21 @@ static int name_check(ssl_handle ssl,  	p=idn_domain ? idn_domain:ssl->info_cpy.peer_verify_domain; +	printf("Check %s\n", p);  	rc=gnutls_x509_crt_check_hostname(cert, p);  	if (idn_domain) +	{  		free(idn_domain); + +		/* Now try the ACE-encoded hostname for a filename. */ + +		if (rc == 0) +		{ +			p=ssl->info_cpy.peer_verify_domain; +			rc=gnutls_x509_crt_check_hostname(cert, p); +		} +	}  	return rc;  } @@ -736,10 +747,10 @@ static int dohandshake(ssl_handle ssl, int fd, fd_set *r, fd_set *w)  	return rc;  } -static char *check_cert(const char *filename, -			gnutls_certificate_type_t cert_type, -			const char *req_dn, -			int isvirtual) +static char *check_cert_unicode(const char *filename, +				gnutls_certificate_type_t cert_type, +				const char *req_dn, +				int isvirtual)  {  	if (!filename || !*filename)  		return NULL; @@ -766,6 +777,12 @@ static char *check_cert(const char *filename,  		++req_dn;  	} +	/* +	** We're called with a hostname first. Don't check the defualt +	** filename, we'll be called again with an IP address +	*/ + +	if (!isvirtual)  	{  		char *p=malloc(strlen(filename)+10); @@ -782,6 +799,33 @@ static char *check_cert(const char *filename,  	return NULL;  } +static char *check_cert(const char *filename, +			gnutls_certificate_type_t cert_type, +			const char *req_dn, +			int isvirtual) +{ +	if (isvirtual) +	{ +		char *p; +		char *retfile; + +		if (idna_to_ascii_8z(req_dn, &p, 0) != IDNA_SUCCESS) +			p=0; + +		if (p) +		{ +			retfile=check_cert_unicode(filename, cert_type, p, +						    isvirtual); +			free(p); + +			if (retfile) +				return retfile; +		} +	} + +	return check_cert_unicode(filename, cert_type, req_dn, isvirtual); +} +  static char *check_key(const char *filename,  			gnutls_certificate_type_t cert_type,  			const char *req_dn, @@ -952,39 +996,51 @@ static int get_server_cert(gnutls_session_t session,  	     ++vhost_idx)  	{  		char *p; +		char *utf8; +		char *namebuf; + +		/* Convert to UTF8 */ +		if (idna_to_unicode_8z8z(vhost_buf, &utf8, 0) +		    != IDNA_SUCCESS) +			utf8=0; -		for (p=vhost_buf; *p; p++) +		namebuf=utf8 ? utf8:vhost_buf; + +		for (p=namebuf; *p; p++)  			if (*p == '/')  				*p='.'; /* Script kiddie check */  		if (ssl->ctx->certfile)  			certfilename=check_cert(ssl->ctx->certfile,  						st->cert_type, -						vhost_buf, 1); +						namebuf, 1);  		if (ssl->ctx->keyfile)  			keyfilename=check_key(ssl->ctx->keyfile,  						st->cert_type, -						vhost_buf, 1); +						namebuf, 1); +		if (utf8) +			free(utf8);  		if (certfilename)  			break;  	}  	if (!certfilename)  	{ +		const char *ip= +			safe_getenv(ssl->ctx, +				    "TCPLOCALIP", ""); + +		if (strncmp(ip, "::ffff:", 7) == 0 && strchr(ip, '.')) +			ip += 7; +  		if (ssl->ctx->certfile)  			certfilename=check_cert(ssl->ctx->certfile, -						st->cert_type, -						safe_getenv(ssl->ctx, -							    "TCPLOCALIP", ""), -						0); +						st->cert_type, ip, 0);  		if (ssl->ctx->keyfile)  			keyfilename=check_key(ssl->ctx->keyfile, -						st->cert_type, -						safe_getenv(ssl->ctx, -							    "TCPLOCALIP", ""), -						0); +					      st->cert_type, ip, 0);  	}  	if (!certfilename) @@ -1324,7 +1380,6 @@ static int name_set(ssl_handle ssl, ssl_context ctx)  	p=idn_domain ? idn_domain:ctx->info_cpy.peer_verify_domain; -  	rc=gnutls_server_name_set(ssl->session, GNUTLS_NAME_DNS,  				  p, strlen(p)); | 
