- Implemented support for Canonicalization option

- Implemented support for SyslogFacility option
 - Initial dataset support: csl
 - Only sign if mail from from a domain in Domain and only if Mode is not
   verfication only
 - Fixed Canonicalize option
This commit is contained in:
Scott Kitterman
2018-02-19 13:31:28 -05:00
parent a71d3b5d99
commit 98e5c17858
6 changed files with 57 additions and 24 deletions
+7 -5
View File
@@ -119,6 +119,7 @@ class dkimMilter(Milter.Base):
self.has_dkim += 1
if lname == 'from':
fname,self.author = parseaddr(val)
self.fdomain = self.author.split('@')[1]
if milterconfig.get('Syslog'):
syslog.syslog("{0}: {1}".format(name,val))
elif lname == 'authentication-results':
@@ -154,11 +155,11 @@ class dkimMilter(Milter.Base):
syslog.syslog('REMOVE: {0}'.format(val))
# Check or sign DKIM
self.fp.seek(0)
if self.internal_connection or milterconfig.get('Mode') == 's' or milterconfig.get('Mode') == 'sv':
if (self.fdomain in milterconfig.get('Domain')) and (not milterconfig.get('Mode') == 'v'):
txt = self.fp.read()
self.sign_dkim(txt)
result = None
if self.has_dkim and (milterconfig.get('Mode') == 'v' or milterconfig.get('Mode') == 'sv'):
if (self.has_dkim) and (not self.internal_connection) and (milterconfig.get('Mode') == 'v' or milterconfig.get('Mode') == 'sv'):
txt = self.fp.read()
self.check_dkim(txt)
else:
@@ -174,6 +175,7 @@ class dkimMilter(Milter.Base):
def sign_dkim(self,txt):
canon = milterconfig.get('Canonicalization')
canonicalize = []
if len(canon.split('/')) == 2:
canonicalize.append(canon.split('/')[0])
canonicalize.append(canon.split('/')[1])
@@ -183,13 +185,13 @@ class dkimMilter(Milter.Base):
syslog.syslog('canonicalize: {0}'.format(canonicalize))
try:
d = dkim.DKIM(txt)
h = d.sign(milterconfig.get('Selector'),milterconfig.get('Domain'), privateRSA,
h = d.sign(milterconfig.get('Selector'), self.fdomain, privateRSA,
canonicalize=(canonicalize[0], canonicalize[1]))
name,val = h.split(': ',1)
self.addheader(name,val.strip().replace('\r\n','\n'),0)
if privateEd25519:
d = dkim.DKIM(txt)
h = d.sign(milterconfig.get('SelectorEd25519'),milterconfig.get('Domain'), privateEd25519,
h = d.sign(milterconfig.get('SelectorEd25519'), self.fdomain, privateEd25519,
canonicalize=(canonicalize[0], canonicalize[1]), signature_algorithm='ed25519-sha256')
name,val = h.split(': ',1)
self.addheader(name,val.strip().replace('\r\n','\n'),0)
@@ -259,7 +261,7 @@ def main():
configFile = sys.argv[1]
milterconfig = config._processConfigFile(filename = configFile)
if milterconfig.get('Syslog'):
facility = "syslog.LOG_{0}".format(milterconfig.get('SyslogFacility').upper())
facility = eval("syslog.LOG_{0}".format(milterconfig.get('SyslogFacility').upper()))
syslog.openlog(os.path.basename(sys.argv[0]), syslog.LOG_PID, facility)
setExceptHook()
pid = write_pid(milterconfig)
+25 -6
View File
@@ -84,6 +84,20 @@ def _find_boolean(item):
return item
def _dataset_to_list(dataset):
"""Convert a dataset (as defined in dkimpymilter.8) and return a python
list of values."""
if not isinstance(dataset, basestring):
# If it was a csl, it's already a list, we only need to remove the name
# from the first value
if dataset[0][:4] == 'csl:':
dataset[0] = dataset[0][4:]
for item in dataset:
dataset[dataset.index(item)] = item.strip().strip(',')
return dataset
else:
raise dkim.ParameterError('Unimplmented dataset type')
###############################################################
commentRx = re.compile(r'^(.*)#.*$')
def _readConfigFile(path, configData = None, configGlobal = {}):
@@ -105,7 +119,7 @@ def _readConfigFile(path, configData = None, configGlobal = {}):
'Socket' : 'str',
'PidFile' : 'str',
'UserID' : 'str',
'Domain' : 'str',
'Domain' : 'dataset',
'KeyFile' : 'str',
'KeyFileEd25519' : 'str',
'Selector' : 'str',
@@ -138,11 +152,14 @@ def _readConfigFile(path, configData = None, configGlobal = {}):
if debugLevel >= 1:
syslog.syslog('Configuration item "%s" not defined in file "%s"'
% ( line, path ))
else:
syslog.syslog('ERROR parsing line "%s" from file "%s"'
% ( line, path ))
continue
name, value = data
if len(data) == 1:
name = data
value = ''
if len(data) == 2:
name, value = data
if len(data) >= 3:
name = data[0]
value = data[1:]
# check validity of name
conversion = nameConversion.get(name)
@@ -158,6 +175,8 @@ def _readConfigFile(path, configData = None, configGlobal = {}):
configData[name] = str(value)
elif conversion == 'int':
configData[name] = int(value)
elif conversion == 'dataset':
configData[name] = _dataset_to_list(value)
else:
syslog.syslog(str('name: ' + name + ' value: ' + value + ' conversion: ' + conversion))
configData[name] = conversion(value)