Compare commits

..

20 Commits

Author SHA1 Message Date
Scott Kitterman abba014c5c Add release date for 1.1.4 2019-11-22 20:35:38 -05:00
Scott Kitterman 807b1391b2 - Delete own_socketfile to resolve race condition where the permissions
change fails on a Unix socket because it hasn't been created yet (libmilter
   will do this correctly on its own based on umask, the milter doesn't need
   to do it) (LP: #1849712)
2019-10-29 07:15:51 -04:00
Scott Kitterman dcb781c365 Make error logging more explicit to aid debugging 2019-10-18 23:31:34 -04:00
Scott Kitterman 577a971f1a Fix typo in README 2019-10-07 00:41:43 -04:00
Scott Kitterman 59296be0cf Bump version to 1.1.3 2019-10-06 00:14:54 -04:00
Scott Kitterman 4e1fa3c8ff Update README now that sysv init is tested 2019-10-06 00:14:27 -04:00
Scott Kitterman 99899062bb Fix sysv init so it works (LP: #1839487) 2019-10-05 21:48:44 -04:00
Scott Kitterman 6a1705926f Update version/release date for 1.1.2 2019-09-23 13:36:56 -04:00
Scott Kitterman e6f8db9f94 More reslience fixes 2019-09-23 11:36:10 -04:00
Scott Kitterman e63867d517 Merge branch 'stable1.1' of git+ssh://git.launchpad.net/dkimpy-milter into stable1.1 2019-09-23 11:27:33 -04:00
Scott Kitterman 209ad11661 Catch more ascii encoding errors to improve resilience against bad data
(LP: #1844189)
2019-09-23 11:26:10 -04:00
Scott Kitterman 795a914845 Catch more ascii encoding errors to improve resilience against bad data
(LP: #1844189)
2019-09-23 11:04:02 -04:00
Scott Kitterman be92e5c5b1 Catch more ascii encoding errors to improve resilience against bad data
(LP: #1844189)
2019-09-23 10:48:04 -04:00
Scott Kitterman 6910ff1f9a Fix variable initialization so mailformed mails missing body From do not
cause a traceback (LP: #1844161)
2019-09-16 20:08:34 -04:00
Scott Kitterman 7953e54ffb CHANGES and setup.py updates for 1.1.1 release prep 2019-09-06 00:52:18 -04:00
Scott Kitterman bc98f9180f Fix startup logging so it provides information at a useful time 2019-09-06 00:41:42 -04:00
Scott Kitterman a144791f2a Minor README corrections 2019-09-06 00:37:46 -04:00
Scott Kitterman 55e1a6b54e Fixup missing i= processing 2019-09-06 00:27:52 -04:00
Scott Kitterman 7c3ff1905a - Fix verify processing so missing (optional) i= tag doesn't cause the milter
to fail
2019-09-06 00:22:00 -04:00
Scott Kitterman 7ec97a6001 - Fix message extraction so that signing in the same pass through the milter
as verifying works correctly
2019-09-05 23:55:34 -04:00
6 changed files with 75 additions and 50 deletions
+23
View File
@@ -1,3 +1,26 @@
1.1.4 2019-11-22
- Make error logging more explicit to aid debugging
- Delete own_socketfile to resolve race condition where the permissions
change fails on a Unix socket because it hasn't been created yet (libmilter
will do this correctly on its own based on umask, the milter doesn't need
to do it) (LP: #1849712)
1.1.3 2019-10-06
- Fix sysv init so it works (LP: #1839487)
1.1.2 2019-09-23
- Fix variable initialization so mailformed mails missing body From do not
cause a traceback (LP: #1844161)
- Catch more ascii encoding errors to improve resilience against bad data
(LP: #1844189)
1.1.1 2019-09-06
- Fix startup logging so it provides information at a useful time
- Fix verify processing so missing (optional) i= tag doesn't cause the milter
to fail (LP: #1842250)
- Fix message extraction so that signing in the same pass through the milter
as verifying works correctly
1.1.0 2019-04-12
- Add SubDomains option to enable signing for sub-domains (LP: #1811535)
- Port to python3 (LP: #1815502)
+5 -6
View File
@@ -22,7 +22,7 @@ python3 setup.py install --single-version-externally-managed --record=/dev/null
For users of Debian Stable (Debian 9, Codename Squeeze), all dependencies are
available in either the main or backports repositories:
[sudo] apt install python3-milter python3-nacl python3-ipaddress python3-dnspython
[sudo] apt install python3-milter python3-nacl python3-dnspython
[sudo] apt install -t stretch-backports python3-authres python3-dkim
The preferred method of installation is from PyPi using pip (if distribution
@@ -33,11 +33,11 @@ packages are not available):
Using pip will cause required packages to be installed via easy_install if they
have not been previously installed. Because pymilter and PyNaCl are compiled
Python extensions, the system will need appropriate development packages and
an C compiler. Alternately, install these dependencies from dsitribution/OS
an C compiler. Alternately, install these dependencies from distribution/OS
packages and then pip install dkimpy_milter.
The milter will work with either py3dns (DNS) or dnspython (dns), preferring
dnspython is both are available. The dkimpy DKIM module also works with
dnspython if both are available. The dkimpy DKIM module also works with
either.
@@ -84,9 +84,8 @@ MTA INTEGRATION
Both a systemd unit file and a sysv init file are provided. Both make
assumptions about defaults being used, e.g. if a non-standard pidfile name is
used, they will need to be updated. The sysv init file is Debian specific and
untested, since the developers are not using sysv init. Feedback/patches
welcome.
used, they will need to be updated. The sysv init file uses start-stop-deamon
from Debian. It is not portable to systems without that available.
The dkimpy-milter drops priviledges after setup to the user/group specified in
UserID. During initial setup, this system user needs to be manually created.
+32 -10
View File
@@ -37,7 +37,6 @@ from dkimpy_milter.util import drop_privileges
from dkimpy_milter.util import setExceptHook
from dkimpy_milter.util import write_pid
from dkimpy_milter.util import read_keyfile
from dkimpy_milter.util import own_socketfile
from dkimpy_milter.util import fold
__version__ = "1.0.1"
@@ -55,6 +54,7 @@ class dkimMilter(Milter.Base):
self.privatersa = privateRSA
self.privateed25519 = privateEd25519
self.fp = None
self.fdomain = ''
@Milter.noreply
def connect(self, hostname, unused, hostaddr):
@@ -136,14 +136,18 @@ class dkimMilter(Milter.Base):
try:
self.fdomain = self.author.split('@')[1].lower()
except IndexError as er:
self.fdomain = '' # self.author was not a proper email address
pass # self.author was not a proper email address
if (milterconfig.get('Syslog') and
milterconfig.get('debugLevel') >= 1):
syslog.syslog("{0}: {1}".format(name, val))
elif lname == 'authentication-results':
self.arheaders.append(val)
if self.fp:
try:
self.fp.write(b"%s: %s\n" % (codecs.encode(name, 'ascii'), codecs.encode(val, 'ascii')))
except:
# Don't choke on header fields with non-ascii garbage in them.
pass
return Milter.CONTINUE
@Milter.noreply
@@ -177,8 +181,9 @@ class dkimMilter(Milter.Base):
except:
# Don't error out on unparseable AR header fiels
pass
# Check or sign DKIM
# Check and/or sign DKIM
self.fp.seek(0)
txt = self.fp.read()
if milterconfig.get('Domain'):
domain = milterconfig.get('Domain')
else:
@@ -187,12 +192,10 @@ class dkimMilter(Milter.Base):
self.fdomain = _get_parent_domain(self.fdomain, domain)
if ((self.fdomain in domain) and not milterconfig.get('Mode') == 'v'
and not self.external_connection):
txt = self.fp.read()
self.sign_dkim(txt)
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)
if self.arresults:
h = authres.AuthenticationResultsHeader(authserv_id=
@@ -261,6 +264,7 @@ class dkimMilter(Milter.Base):
def check_dkim(self, txt):
res = False
self.header_a = None
for y in range(self.has_dkim): # Verify _ALL_ the signatures
d = dkim.DKIM(txt)
try:
@@ -288,10 +292,22 @@ class dkimMilter(Milter.Base):
except Exception as x:
self.dkim_comment = str(x)
if milterconfig.get('Syslog'):
syslog.syslog("check_dkim: {0}".format(x))
syslog.syslog("check_dkim: Internal program fault while verifying: {0}".format(x))
try:
# i= is optional and dkimpy is fine if it's not provided
self.header_i = codecs.decode(d.signature_fields.get(b'i'), 'ascii')
except TypeError as x:
self.header_i = None
try:
self.header_d = codecs.decode(d.signature_fields.get(b'd'), 'ascii')
self.header_a = codecs.decode(d.signature_fields.get(b'a'), 'ascii')
except Exception as x:
self.dkim_comment = str(x)
if milterconfig.get('Syslog'):
syslog.syslog("check_dkim: Internal proram fuault extracting header a or d: {0}".format(x))
self.header_d = None
if not self.header_a:
self.header_a = 'rsa-sha256'
if res:
if (milterconfig.get('Syslog') and
(milterconfig.get('SyslogSuccess') or
@@ -311,12 +327,18 @@ class dkimMilter(Milter.Base):
syslog.syslog('DKIM: Fail (saved as {0})'
.format(fname))
else:
syslog.syslog('DKIM: Fail ({0})'.format(d.domain.lower()))
if milterconfig.get('Syslog'):
if d.domain:
syslog.syslog('DKIM: Fail ({0})'
.format(d.domain.lower()))
else:
syslog.syslog('DKIM: Fail, unextractable domain')
if res:
result = 'pass'
else:
result = 'fail'
res = False
if self.header_d:
self.arresults.append(
authres.DKIMAuthenticationResult(result=result,
header_i=self.header_i,
@@ -325,6 +347,7 @@ class dkimMilter(Milter.Base):
result_comment=
self.dkim_comment)
)
self.header_a = None
return
# get parent domain to be signed for if fdomain is a subdomain
@@ -377,13 +400,12 @@ def main():
socketname = 'fd:3'
if socketname is None:
socketname = 'local:/var/run/dkimpy-milter/dkimpy-milter.sock'
own_socketfile(milterconfig, socketname)
drop_privileges(milterconfig)
sys.stdout.flush()
Milter.runmilter(miltername, socketname, 240)
if milterconfig.get('Syslog'):
syslog.syslog('dkimpy-milter started:{0} user:{1}'
syslog.syslog('dkimpy-milter starting:{0} user:{1}'
.format(pid, milterconfig.get('UserID')))
Milter.runmilter(miltername, socketname, 240)
if __name__ == "__main__":
main()
-21
View File
@@ -149,27 +149,6 @@ def write_pid(milterconfig):
return pid
def own_socketfile(milterconfig, sockname=None):
"""If socket is Unix socket, chown to UserID before dropping privileges"""
import os
user, group = user_group(milterconfig.get('UserID'))
offset = None
if sockname is None:
sockname = milterconfig.get('Socket')
if sockname is None:
return
if sockname[:1] == '/':
offset = 0
elif sockname[:6] == "local:":
offset = 6
elif sockname[:5] == "unix:":
offset = 5
if offset is not None:
if os.path.exists(sockname[offset:]):
os.chown(sockname[offset:], user, group)
def read_keyfile(milterconfig, keytype):
"""Read private key from file."""
import syslog
+1 -1
View File
@@ -30,7 +30,7 @@ except ImportError: # If PyDNS is not installed, prefer dnspython
setup(
name='dkimpy-milter',
version='1.1.0',
version='1.1.4',
author='Scott Kitterman',
author_email='scott@kitterman.com',
url='https://launchpad.net/dkimpy-milter',
+8 -6
View File
@@ -20,7 +20,7 @@
### END INIT INFO
prefix="/usr/local"
exec_prefix=${prefix}
sysconfdir="/etc/dkimpy-milter"
sysconfdir="/usr/local/etc"
bindir="${exec_prefix}/bin/"
RUNDIR="/run/dkimpy-milter"
DAEMON=${bindir}/dkimpy-milter
@@ -67,14 +67,14 @@ case "$1" in
fi
fi
fi
start-stop-daemon --start --quiet --pidfile $RUNDIR/$NAME.pid --startas \
$DAEMON $sysconfdir/$NAME.conf --name $NAME --test > /dev/null \
start-stop-daemon --start --background --quiet --pidfile \
$RUNDIR/$NAME.pid --exec $DAEMON $sysconfdir/$NAME.conf
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
if [ -f $RUNDIR/$NAME.pid ]; then
chown root:root $RUNDIR/$NAME.pid
start-stop-daemon --stop --pidfile $RUNDIR/$NAME.pid
rm $RUNDIR/$NAME.pid
#echo $SOCKET
@@ -87,6 +87,7 @@ case "$1" in
force-reload)
echo -n "Force reloading $DESC: "
if [ -f $RUNDIR/$NAME.pid ]; then
chown root:root $RUNDIR/$NAME.pid
start-stop-daemon --stop --pidfile $RUNDIR/$NAME.pid
rm $RUNDIR/$NAME.pid
#echo $SOCKET
@@ -95,7 +96,7 @@ case "$1" in
fi
fi
sleep 1
start-stop-daemon --start --chuid $USER --background --quiet --pidfile \
start-stop-daemon --start --background --quiet --pidfile \
$RUNDIR/$NAME.pid --exec $DAEMON $sysconfdir/$NAME.conf
echo "$NAME."
;;
@@ -103,6 +104,7 @@ case "$1" in
echo "Restarting $DESC: "
echo -n "Stopping $DESC: "
if [ -f $RUNDIR/$NAME.pid ]; then
chown root:root $RUNDIR/$NAME.pid
start-stop-daemon --stop --pidfile $RUNDIR/$NAME.pid
rm $RUNDIR/$NAME.pid
#echo $SOCKET
@@ -113,7 +115,7 @@ case "$1" in
echo "$NAME."
sleep 1
echo -n "Starting $DESC: "
start-stop-daemon --start --chuid $USER --background --quiet --pidfile \
start-stop-daemon --start --background --quiet --pidfile \
$RUNDIR/$NAME.pid --exec $DAEMON $sysconfdir/$NAME.conf
echo "$NAME."
;;