1
0
mirror of https://github.com/certbot/certbot.git synced 2026-01-27 19:42:53 +03:00

Merge remote-tracking branch 'pde/master'

This commit is contained in:
Jacob Hoffman-Andrews
2014-06-12 11:49:09 -04:00
7 changed files with 137 additions and 5 deletions

View File

@@ -55,7 +55,7 @@ class Config:
self.tls_policies[domain] = {} # being here enforces TLS at all
for policy, value in policies.items():
if policy == "min-tls-version":
reasonable = ["TLS", "TLSv1.1", "TLSv1.2", "TLSv1.3"]
reasonable = ["TLS", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"]
if not value in reasonable:
raise ValueError, "Not a valid TLS version string: " + `value`
self.tls_policies[domain]["min-tls-version"] = str(value)

132
MTAConfigGenerator.py Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/env python
import string
import os.path
POSTFIX_DIR = "/etc/postfix"
DEFAULT_POLICY_FILE = os.path.join(POSTFIX_DIR, "starttls_everywhere_policy")
POLICY_CF_ENTRY="texthash:" + DEFAULT_POLICY_FILE
def parse_line(line_data):
"return the and right hand sides of stripped, non-comment postfix config line"
# lines are like:
# smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
num,line = line_data
left, sep, right = line.partition("=")
if not sep:
return None
return (num, left.strip(), right.strip())
#def get_cf_values(lines, var):
class MTAConfigGenerator:
def __init__(self, policy_config):
self.policy_config = policy_config
class ExistingConfigError(ValueError): pass
class PostfixConfigGenerator(MTAConfigGenerator):
def __init__(self, policy_config, fixup=False):
self.fixup = fixup
MTAConfigGenerator.__init__(self, policy_config)
self.postfix_cf_file = self.find_postfix_cf()
self.wrangle_existing_config()
self.set_domainwise_tls_policies()
def ensure_cf_var(self, var, ideal, also_acceptable):
"""
Ensure that existing postfix config @var is in the list of @acceptable
values; if not, set it to the ideal value. """
acceptable = [ideal] + also_acceptable
l = [(num,line) for num,line in enumerate(self.cf) if line.startswith(var)]
if not any(l):
self.additions.append(var + " = " + ideal)
else:
values = map(parse_line, l)
if len(set(values)) > 1:
if self.fixup:
#print "Scheduling deletions:" + `values`
conflicting_lines = [num for num,_var,val in values]
self.deletions.extend(conflicting_lines)
self.additions.append(var + " = " + ideal)
else:
raise ExistingConfigError, "Conflicting existing config values " + `l`
val = values[0][2]
if val not in acceptable:
#print "Scheduling deletions:" + `values`
if self.fixup:
self.deletions.append(values[0][0])
self.additions.append(var + " = " + ideal)
else:
raise ExistingConfigError, "Existing config has %s=%s"%(var,val)
def wrangle_existing_config(self):
"""
Try to ensure/mutate that the config file is in a sane state.
Fixup means we'll delete existing lines if necessary to get there.
"""
self.additions = []
self.deletions = []
self.fn = self.find_postfix_cf()
self.raw_cf = open(self.fn).readlines()
self.cf = map(string.strip, self.raw_cf)
#self.cf = [line for line in cf if line and not line.startswith("#")]
# 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"])
# Maximum verbosity lets us collect failure information
self.ensure_cf_var("smtp_tls_loglevel", "1", [])
# Inject a reference to our per-domain policy map
self.ensure_cf_var("smtp_tls_policy_maps", POLICY_CF_ENTRY, [])
self.maybe_add_config_lines()
def maybe_add_config_lines(self):
if not self.additions:
return
if self.fixup:
print "Deleting lines:", self.deletions
self.additions[:0]=["#","# New config lines added by STARTTLS Everywhere","#"]
new_cf_lines = "\n".join(self.additions) + "\n"
print "Adding to %s:" % self.fn
print new_cf_lines
if self.raw_cf[-1][-1] == "\n": sep = ""
else: sep = "\n"
self.new_cf = ""
for num, line in enumerate(self.raw_cf):
if self.fixup and num in self.deletions:
self.new_cf += "# Line removed by STARTTLS Everywhere\n# " + line
else:
self.new_cf += line
self.new_cf += sep + new_cf_lines
print self.new_cf
f = open(self.fn, "w")
f.write(self.new_cf)
f.close()
def find_postfix_cf(self):
"Search far and wide for the correct postfix configuration file"
return os.path.join(POSTFIX_DIR,"main.cf")
def set_domainwise_tls_policies(self):
self.policy_lines = []
for domain, policy in self.policy_config.tls_policies.items():
entry = domain + " encrypt"
if "min-tls-version" in policy:
entry += " " + policy["min-tls-version"]
self.policy_lines.append(entry)
f = open(DEFAULT_POLICY_FILE, "w")
f.write("\n".join(self.policy_lines) + "\n")
f.close()
if __name__ == "__main__":
import ConfigParser
c = ConfigParser.Config("starttls-everywhere.json")
pcgen = PostfixConfigGenerator(c, fixup=True)

View File

@@ -53,7 +53,7 @@ The basic file format will be JSON with comments (http://blog.getify.com/json-co
// "timestamp": 1401414363, : also acceptable
"author": "Electronic Frontier Foundation https://eff.org",
"expires": "2014-06-06T14:30:16+00:00",
"security-policies": {
"tls-policies": {
// These match on the MX domain.
"*.yahoodns.net": {
"require-valid-certificate": true,

View File

@@ -3,7 +3,7 @@
"timestamp": 1401093333,
"author": "Electronic Frontier Foundation https://eff.org",
"expires": 1404677353, "comment 2:": "epoch seconds",
"tls-policies": {
"security-policies": {
"*.valid-example-recipient.com": {
"min-tls-version": "TLSv1.1"
}

View File

@@ -1,5 +1,5 @@
{
"mx-domains": {
"tls-policies": {
"*.mx.aol.com": {
"min-tls-version": "TLSv1",
"require-tls": true
@@ -49,7 +49,7 @@
"require-tls": true
}
},
"address-domains": {
"acceptable-mxs": {
"wp.pl": {
"accept-mx-domains": [
"*.wp.pl"