mirror of
				https://github.com/mail-in-a-box/mailinabox.git
				synced 2025-10-30 18:50:53 +00:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/master'
This commit is contained in:
		
						commit
						57dea6f285
					
				
							
								
								
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @ -9,6 +9,17 @@ Mail: | ||||
| * An MTA-STS policy for incoming mail is now published (in DNS and over HTTPS) when the primary hostname and email address domain both have a signed TLS certificate installed. | ||||
| * MTA-STS reporting is enabled with reports sent to administrator@ the primary hostname. | ||||
| 
 | ||||
| DNS: | ||||
| 
 | ||||
| * autoconfig and autodiscover subdomains and CalDAV/CardDAV SRV records are no longer generated for domains that don't have user accounts since they are unnecessary. | ||||
| 
 | ||||
| v0.46 (June 11, 2020) | ||||
| --------------------- | ||||
| 
 | ||||
| Security fixes: | ||||
| 
 | ||||
| * Roundcube is updated to version 1.4.6 (https://roundcube.net/news/2020/06/02/security-updates-1.4.5-and-1.3.12). | ||||
| 
 | ||||
| v0.45 (May 16, 2020) | ||||
| -------------------- | ||||
| 
 | ||||
|  | ||||
| @ -63,7 +63,7 @@ by him: | ||||
| 	$ curl -s https://keybase.io/joshdata/key.asc | gpg --import | ||||
| 	gpg: key C10BDD81: public key "Joshua Tauberer <jt@occams.info>" imported | ||||
| 
 | ||||
| 	$ git verify-tag v0.45 | ||||
| 	$ git verify-tag v0.46 | ||||
| 	gpg: Signature made ..... using RSA key ID C10BDD81 | ||||
| 	gpg: Good signature from "Joshua Tauberer <jt@occams.info>" | ||||
| 	gpg: WARNING: This key is not certified with a trusted signature! | ||||
| @ -76,7 +76,7 @@ and on his [personal homepage](https://razor.occams.info/). (Of course, if this | ||||
| 
 | ||||
| Checkout the tag corresponding to the most recent release: | ||||
| 
 | ||||
| 	$ git checkout v0.45 | ||||
| 	$ git checkout v0.46 | ||||
| 
 | ||||
| Begin the installation. | ||||
| 
 | ||||
|  | ||||
| @ -16,10 +16,10 @@ if [ `date "+%u"` -eq 1 ]; then | ||||
| fi | ||||
| 
 | ||||
| # Take a backup. | ||||
| management/backup.py | management/email_administrator.py "Backup Status" | ||||
| management/backup.py 2>&1 | management/email_administrator.py "Backup Status" | ||||
| 
 | ||||
| # Provision any new certificates for new domains or domains with expiring certificates. | ||||
| management/ssl_certificates.py -q | management/email_administrator.py "TLS Certificate Provisioning Result" | ||||
| management/ssl_certificates.py -q  2>&1 | management/email_administrator.py "TLS Certificate Provisioning Result" | ||||
| 
 | ||||
| # Run status checks and email the administrator if anything changed. | ||||
| management/status_checks.py --show-changes | management/email_administrator.py "Status Checks Change Notice" | ||||
| management/status_checks.py --show-changes  2>&1 | management/email_administrator.py "Status Checks Change Notice" | ||||
|  | ||||
| @ -281,28 +281,30 @@ def build_zone(domain, all_domains, additional_records, www_redirect_domains, en | ||||
| 		if not has_rec(dmarc_qname, "TXT", prefix="v=DMARC1; "): | ||||
| 			records.append((dmarc_qname, "TXT", 'v=DMARC1; p=reject', "Recommended. Prevents use of this domain name for outbound mail by specifying that the SPF rule should be honoured for mail from @%s." % (qname + "." + domain))) | ||||
| 
 | ||||
| 	# Add CardDAV/CalDAV SRV records on the non-primary hostname that points to the primary hostname. | ||||
| 	# Add CardDAV/CalDAV SRV records on the non-primary hostname that points to the primary hostname | ||||
| 	# for autoconfiguration of mail clients (so only domains hosting user accounts need it). | ||||
| 	# The SRV record format is priority (0, whatever), weight (0, whatever), port, service provider hostname (w/ trailing dot). | ||||
| 	if domain != env["PRIMARY_HOSTNAME"]: | ||||
| 	if domain != env["PRIMARY_HOSTNAME"] and domain in get_mail_domains(env, users_only=True): | ||||
| 		for dav in ("card", "cal"): | ||||
| 			qname = "_" + dav + "davs._tcp" | ||||
| 			if not has_rec(qname, "SRV"): | ||||
| 				records.append((qname, "SRV", "0 0 443 " + env["PRIMARY_HOSTNAME"] + ".", "Recommended. Specifies the hostname of the server that handles CardDAV/CalDAV services for email addresses on this domain.")) | ||||
| 
 | ||||
| 	# Adds autoconfiguration A records for all domains. | ||||
| 	# Adds autoconfiguration A records for all domains that there are user accounts at. | ||||
| 	# This allows the following clients to automatically configure email addresses in the respective applications. | ||||
| 	# autodiscover.* - Z-Push ActiveSync Autodiscover | ||||
| 	# autoconfig.* - Thunderbird Autoconfig | ||||
| 	autodiscover_records = [ | ||||
| 		("autodiscover", "A", env["PUBLIC_IP"], "Provides email configuration autodiscovery support for Z-Push ActiveSync Autodiscover."), | ||||
| 		("autodiscover", "AAAA", env["PUBLIC_IPV6"], "Provides email configuration autodiscovery support for Z-Push ActiveSync Autodiscover."), | ||||
| 		("autoconfig", "A", env["PUBLIC_IP"], "Provides email configuration autodiscovery support for Thunderbird Autoconfig."), | ||||
| 		("autoconfig", "AAAA", env["PUBLIC_IPV6"], "Provides email configuration autodiscovery support for Thunderbird Autoconfig.") | ||||
| 	] | ||||
| 	for qname, rtype, value, explanation in autodiscover_records: | ||||
| 		if value is None or value.strip() == "": continue # skip IPV6 if not set | ||||
| 		if not has_rec(qname, rtype): | ||||
| 			records.append((qname, rtype, value, explanation)) | ||||
| 	if domain in get_mail_domains(env, users_only=True): | ||||
| 		autodiscover_records = [ | ||||
| 			("autodiscover", "A", env["PUBLIC_IP"], "Provides email configuration autodiscovery support for Z-Push ActiveSync Autodiscover."), | ||||
| 			("autodiscover", "AAAA", env["PUBLIC_IPV6"], "Provides email configuration autodiscovery support for Z-Push ActiveSync Autodiscover."), | ||||
| 			("autoconfig", "A", env["PUBLIC_IP"], "Provides email configuration autodiscovery support for Thunderbird Autoconfig."), | ||||
| 			("autoconfig", "AAAA", env["PUBLIC_IPV6"], "Provides email configuration autodiscovery support for Thunderbird Autoconfig.") | ||||
| 		] | ||||
| 		for qname, rtype, value, explanation in autodiscover_records: | ||||
| 			if value is None or value.strip() == "": continue # skip IPV6 if not set | ||||
| 			if not has_rec(qname, rtype): | ||||
| 				records.append((qname, rtype, value, explanation)) | ||||
| 
 | ||||
| 	# If this is a domain name that there are email addresses configured for, i.e. "something@" | ||||
| 	# this domain name, then the domain name is a MTA-STS (https://tools.ietf.org/html/rfc8461) | ||||
|  | ||||
| @ -258,13 +258,15 @@ def get_domain(emailaddr, as_unicode=True): | ||||
| 			pass | ||||
| 	return ret | ||||
| 
 | ||||
| def get_mail_domains(env, filter_aliases=lambda alias : True): | ||||
| def get_mail_domains(env, filter_aliases=lambda alias : True, users_only=False): | ||||
| 	# Returns the domain names (IDNA-encoded) of all of the email addresses | ||||
| 	# configured on the system. | ||||
| 	return set( | ||||
| 		   [get_domain(login, as_unicode=False) for login in get_mail_users(env)] | ||||
| 		 + [get_domain(address, as_unicode=False) for address, *_ in get_mail_aliases(env) if filter_aliases(address) ] | ||||
| 		 ) | ||||
| 	# configured on the system. If users_only is True, only return domains | ||||
| 	# with email addresses that correspond to user accounts. | ||||
| 	domains = [] | ||||
| 	domains.extend([get_domain(login, as_unicode=False) for login in get_mail_users(env)]) | ||||
| 	if not users_only: | ||||
| 		domains.extend([get_domain(address, as_unicode=False) for address, *_ in get_mail_aliases(env) if filter_aliases(address) ]) | ||||
| 	return set(domains) | ||||
| 
 | ||||
| def add_mail_user(email, pw, privs, env): | ||||
| 	# validate email | ||||
|  | ||||
| @ -24,13 +24,13 @@ def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True) | ||||
| 		# the topmost of each domain we serve. | ||||
| 		domains |= set('www.' + zone for zone, zonefile in get_dns_zones(env)) | ||||
| 
 | ||||
| 	# Add Autoconfiguration domains, allowing us to serve correct SSL certs. | ||||
| 	# Add Autoconfiguration domains for domains that there are user accounts at: | ||||
| 	# 'autoconfig.' for Mozilla Thunderbird auto setup. | ||||
| 	# 'autodiscover.' for Activesync autodiscovery. | ||||
| 	domains |= set('autoconfig.' + maildomain for maildomain in get_mail_domains(env)) | ||||
| 	domains |= set('autodiscover.' + maildomain for maildomain in get_mail_domains(env)) | ||||
| 	domains |= set('autoconfig.' + maildomain for maildomain in get_mail_domains(env, users_only=True)) | ||||
| 	domains |= set('autodiscover.' + maildomain for maildomain in get_mail_domains(env, users_only=True)) | ||||
| 
 | ||||
| 	# 'mta-sts.' for MTA-STS support. | ||||
| 	# 'mta-sts.' for MTA-STS support for all domains that have email addresses. | ||||
| 	domains |= set('mta-sts.' + maildomain for maildomain in get_mail_domains(env)) | ||||
| 
 | ||||
| 	if exclude_dns_elsewhere: | ||||
| @ -158,9 +158,23 @@ def make_domain_config(domain, templates, ssl_certificates, env): | ||||
| 
 | ||||
| 			# any proxy or redirect here? | ||||
| 			for path, url in yaml.get("proxies", {}).items(): | ||||
| 				# Parse some flags in the fragment of the URL. | ||||
| 				pass_http_host_header = False | ||||
| 				m = re.search("#(.*)$", url) | ||||
| 				if m: | ||||
| 					for flag in m.group(1).split(","): | ||||
| 						if flag == "pass-http-host": | ||||
| 							pass_http_host_header = True | ||||
| 					url = re.sub("#(.*)$", "", url) | ||||
| 
 | ||||
| 				nginx_conf_extra += "\tlocation %s {" % path | ||||
| 				nginx_conf_extra += "\n\t\tproxy_pass %s;" % url | ||||
| 				if pass_http_host_header: | ||||
| 					nginx_conf_extra += "\n\t\tproxy_set_header Host $http_host;" | ||||
| 				nginx_conf_extra += "\n\t\tproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;" | ||||
| 				nginx_conf_extra += "\n\t\tproxy_set_header X-Forwarded-Host $http_host;" | ||||
| 				nginx_conf_extra += "\n\t\tproxy_set_header X-Forwarded-Proto $scheme;" | ||||
| 				nginx_conf_extra += "\n\t\tproxy_set_header X-Real-IP $remote_addr;" | ||||
| 				nginx_conf_extra += "\n\t}\n" | ||||
| 			for path, alias in yaml.get("aliases", {}).items(): | ||||
| 				nginx_conf_extra += "\tlocation %s {" % path | ||||
|  | ||||
| @ -20,7 +20,7 @@ if [ -z "$TAG" ]; then | ||||
| 	# want to display in status checks. | ||||
| 	if [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/18\.04\.[0-9]/18.04/' `" == "Ubuntu 18.04 LTS" ]; then | ||||
| 		# This machine is running Ubuntu 18.04. | ||||
| 		TAG=v0.45 | ||||
| 		TAG=v0.46 | ||||
| 
 | ||||
| 	elif [ "`lsb_release -d | sed 's/.*:\s*//' | sed 's/14\.04\.[0-9]/14.04/' `" == "Ubuntu 14.04 LTS" ]; then | ||||
| 		# This machine is running Ubuntu 14.04. | ||||
|  | ||||
| @ -136,7 +136,14 @@ function get_default_privateip { | ||||
| function ufw_allow { | ||||
| 	if [ -z "${DISABLE_FIREWALL:-}" ]; then | ||||
| 		# ufw has completely unhelpful output | ||||
| 		ufw allow $1 > /dev/null; | ||||
| 		ufw allow "$1" > /dev/null; | ||||
| 	fi | ||||
| } | ||||
| 
 | ||||
| function ufw_limit { | ||||
| 	if [ -z "${DISABLE_FIREWALL:-}" ]; then | ||||
| 		# ufw has completely unhelpful output | ||||
| 		ufw limit "$1" > /dev/null; | ||||
| 	fi | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -256,7 +256,7 @@ if [ -z "${DISABLE_FIREWALL:-}" ]; then | ||||
| 	apt_install ufw | ||||
| 
 | ||||
| 	# Allow incoming connections to SSH. | ||||
| 	ufw_allow ssh; | ||||
| 	ufw_limit ssh; | ||||
| 
 | ||||
| 	# ssh might be running on an alternate port. Use sshd -T to dump sshd's #NODOC | ||||
| 	# settings, find the port it is supposedly running on, and open that port #NODOC | ||||
| @ -266,7 +266,7 @@ if [ -z "${DISABLE_FIREWALL:-}" ]; then | ||||
| 	if [ "$SSH_PORT" != "22" ]; then | ||||
| 
 | ||||
| 	echo Opening alternate SSH port $SSH_PORT. #NODOC | ||||
| 	ufw_allow $SSH_PORT #NODOC | ||||
| 	ufw_limit $SSH_PORT #NODOC | ||||
| 
 | ||||
| 	fi | ||||
| 	fi | ||||
|  | ||||
| @ -28,8 +28,8 @@ apt_install \ | ||||
| # Install Roundcube from source if it is not already present or if it is out of date. | ||||
| # Combine the Roundcube version number with the commit hash of plugins to track | ||||
| # whether we have the latest version of everything. | ||||
| VERSION=1.4.4 | ||||
| HASH=4e425263f5bec27d39c07bde524f421bda205c07 | ||||
| VERSION=1.4.6 | ||||
| HASH=44961ef62bb9c9875141ca34704bbc7d6f36373d | ||||
| PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435 | ||||
| HTML5_NOTIFIER_VERSION=4b370e3cd60dabd2f428a26f45b677ad1b7118d5 | ||||
| CARDDAV_VERSION=3.0.3 | ||||
| @ -160,7 +160,7 @@ mkdir -p /var/log/roundcubemail /var/tmp/roundcubemail $STORAGE_ROOT/mail/roundc | ||||
| chown -R www-data.www-data /var/log/roundcubemail /var/tmp/roundcubemail $STORAGE_ROOT/mail/roundcube | ||||
| 
 | ||||
| # Ensure the log file monitored by fail2ban exists, or else fail2ban can't start. | ||||
| sudo -u www-data touch /var/log/roundcubemail/errors | ||||
| sudo -u www-data touch /var/log/roundcubemail/errors.log | ||||
| 
 | ||||
| # Password changing plugin settings | ||||
| # The config comes empty by default, so we need the settings | ||||
|  | ||||
| @ -58,7 +58,7 @@ def generate_documentation(): | ||||
| 	    	} | ||||
| 
 | ||||
| 	    	.prose { | ||||
| 	    		padding-top: 1em;    	 | ||||
| 	    		padding-top: 1em; | ||||
| 	    		padding-bottom: 1em; | ||||
| 	    	} | ||||
| 	    	.terminal { | ||||
| @ -261,6 +261,10 @@ class UfwAllow(Grammar): | ||||
| 	grammar = (ZERO_OR_MORE(SPACE), L("ufw_allow "), REST_OF_LINE, EOL) | ||||
| 	def value(self): | ||||
| 		return shell_line("ufw allow " + self[2].string) | ||||
| class UfwLimit(Grammar): | ||||
| 	grammar = (ZERO_OR_MORE(SPACE), L("ufw_limit "), REST_OF_LINE, EOL) | ||||
| 	def value(self): | ||||
| 		return shell_line("ufw limit " + self[2].string) | ||||
| class RestartService(Grammar): | ||||
| 	grammar = (ZERO_OR_MORE(SPACE), L("restart_service "), REST_OF_LINE, EOL) | ||||
| 	def value(self): | ||||
| @ -275,7 +279,7 @@ class OtherLine(Grammar): | ||||
| 		return "<pre class='shell'><div>" + recode_bash(self.string.strip()) + "</div></pre>\n" | ||||
| 
 | ||||
| class BashElement(Grammar): | ||||
| 	grammar = Comment | CatEOF | EchoPipe | EchoLine | HideOutput | EditConf | SedReplace | AptGet | UfwAllow | RestartService | OtherLine | ||||
| 	grammar = Comment | CatEOF | EchoPipe | EchoLine | HideOutput | EditConf | SedReplace | AptGet | UfwAllow | UfwLimit | RestartService | OtherLine | ||||
| 	def value(self): | ||||
| 		return self[0].value() | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user