diff --git a/ConfigParser.py b/ConfigParser.py index eff4d3557..2d7c88ada 100755 --- a/ConfigParser.py +++ b/ConfigParser.py @@ -35,6 +35,8 @@ class Config: def __init__(self, cfg_file_name = "config.json"): f = open(cfg_file_name) self.cfg = json.loads(f.read()) + self.tls_policies = {} + self.mx_map = {} for atr, val in self.cfg.items(): # Verify each attribute of the structure if atr.startswith("comment"): @@ -47,17 +49,32 @@ class Config: elif atr == "expires": self.expires = parse_timestamp(val) elif atr == "tls-policies": - self.tls_policies = {} for domain, policies in self.check_tls_policy_domains(val): if type(policies) != dict: raise TypeError, domain + "'s policies should be a dict: " + `policies` self.tls_policies[domain] = {} # being here enforces TLS at all - for policy, value in policies.items(): - if policy == "min-tls-version": + for policy, v in policies.items(): + value = str(v).lower() + if policy == "require-tls": + if value in ("true", "1", "yes"): + self.tls_policies[domain]["required"] = True + elif value in ("false", "0", "no"): + self.tls_policies[domain]["required"] = False + else: + raise ValueError, "Unknown require-tls value " + `value` + elif policy == "min-tls-version": reasonable = ["TLS", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"] + reasonable = map(string.lower, reasonable) if not value in reasonable: raise ValueError, "Not a valid TLS version string: " + `value` self.tls_policies[domain]["min-tls-version"] = str(value) + elif policy == "enforce-mode": + if value == "enforce": + self.tls_policies[domain]["enforce"] = True + elif value == "log-only": + self.tls_policies[domain]["enforce"] = False + else: + raise ValueError, "Not a known enoforcement policy " + `value` elif atr == "acceptable-mxs": self.acceptable_mxs = val self.mx_domain_to_address_domains = collections.defaultdict(set) @@ -70,6 +87,10 @@ class Config: pass else: sys.stderr.write("Unknown attribute: " + `atr` + "\n") + # XXX is it ever permissible to have a domain with an acceptable-mx + # that does not point to a TLS security policy? If not, check/warn/fail + # here + print self.tls_policies def get_address_domains(self, mx_hostname): labels = mx_hostname.split(".") diff --git a/MTAConfigGenerator.py b/MTAConfigGenerator.py index 15bc017ab..4d2f3432a 100755 --- a/MTAConfigGenerator.py +++ b/MTAConfigGenerator.py @@ -2,12 +2,13 @@ import sys import string -import os.path +import os, os.path def parse_line(line_data): """ Return the left and right hand sides of stripped, non-comment postfix - config line. + Return the (line number, left hand side, right hand side) of a stripped + postfix config line. Lines are like: smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache @@ -33,7 +34,7 @@ class PostfixConfigGenerator(MTAConfigGenerator): self.postfix_cf_file = self.find_postfix_cf() self.wrangle_existing_config() self.set_domainwise_tls_policies() - print "Configuration complete. Now run `sudo service postfix reload'." + os.system("sudo service postfix reload") def ensure_cf_var(self, var, ideal, also_acceptable): """ @@ -79,7 +80,7 @@ class PostfixConfigGenerator(MTAConfigGenerator): # Check we're currently accepting inbound STARTTLS sensibly self.ensure_cf_var("smtpd_use_tls", "yes", []) # Ideally we use it opportunistically in the outbound direction - self.ensure_cf_var("smtp_tls_security_level", "may", ["encrypt"]) + self.ensure_cf_var("smtp_tls_security_level", "may", ["encrypt","dane"]) # Maximum verbosity lets us collect failure information self.ensure_cf_var("smtp_tls_loglevel", "1", []) # Inject a reference to our per-domain policy map @@ -109,7 +110,7 @@ class PostfixConfigGenerator(MTAConfigGenerator): self.new_cf += line self.new_cf += sep + new_cf_lines - print self.new_cf + #print self.new_cf f = open(self.fn, "w") f.write(self.new_cf) f.close() diff --git a/README.md b/README.md index 6e3d4212b..e50630ab8 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,6 @@ The basic file format will be JSON with comments (http://blog.getify.com/json-co "eff.org": { "accept-mx-domains": ["*.eff.org"] } - "*.yahoodns.net": { - "require-valid-certificate": true, - } } } diff --git a/Vagrantfile b/Vagrantfile index 3ce93c917..b7153a7b8 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -16,6 +16,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| valid.vm.hostname = "valid-example-recipient.com" end config.vm.synced_folder "vagrant-shared", "/vagrant" + config.vm.synced_folder "vagrant-shared/starttls-everywhere", "/vagrant/starttls-everywhere" config.vm.provision :shell, path: "vagrant-bootstrap.sh" config.vm.provider "virtualbox" do |vb| diff --git a/vagrant-bootstrap.sh b/vagrant-bootstrap.sh index 13593a0cc..82622edea 100755 --- a/vagrant-bootstrap.sh +++ b/vagrant-bootstrap.sh @@ -23,9 +23,9 @@ if [ "`hostname`" = "sender" ]; then (while sleep 10; do echo -e 'Subject: hi\n\nhi' | sendmail vagrant@valid-example-recipient.com done) & - ln -sf "/vagrant/postfix-config-sender-tls_policy.cf" /etc/postfix/tls_policy + #ln -sf "/vagrant/postfix-config-sender-tls_policy.cf" /etc/postfix/tls_policy fi -ln -sf "/vagrant/postfix-config-`hostname`.cf" /etc/postfix/main.cf -ln -sf "/vagrant/certificates" /etc/certificates +#ln -sf "/vagrant/postfix-config-`hostname`.cf" /etc/postfix/main.cf +#ln -sf "/vagrant/certificates" /etc/certificates postfix reload