Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 539d50325b | |||
| 04dd916ab2 | |||
| 34b2edbb50 | |||
| d117330113 | |||
| 2528632ba6 | |||
| 3ea22f1529 | |||
| 097e053309 | |||
| 419d2b54ea | |||
| 3ff685205c | |||
| 7986de6629 | |||
| 5322c81027 | |||
| 94538ffa6b | |||
| 721da801fe |
@@ -1,3 +1,20 @@
|
||||
1.0.3 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.0.2 2019-10-07
|
||||
- Fix startup logging so it provides information at a useful time
|
||||
- Fix message extraction so that signing in the same pass through the milter
|
||||
as verifying works correctly
|
||||
- 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)
|
||||
- Fix sysv init so it works (LP: #1839487)
|
||||
|
||||
1.0.1 2019-02-11
|
||||
* Reorder milter start and dropping privileges so permissions on Unix socket
|
||||
are correct (LP: 1797720)
|
||||
|
||||
@@ -37,7 +37,7 @@ an C compiler. Alternately, install these dependencies from dsitribution/OS
|
||||
packages and then pip install dkimpy_milter.
|
||||
|
||||
The milter will work with either pydns (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.
|
||||
|
||||
+31
-10
@@ -36,7 +36,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"
|
||||
@@ -54,6 +53,7 @@ class dkimMilter(Milter.Base):
|
||||
self.privatersa = privateRSA
|
||||
self.privateed25519 = privateEd25519
|
||||
self.fp = None
|
||||
self.fdomain = ''
|
||||
|
||||
@Milter.noreply
|
||||
def connect(self, hostname, unused, hostaddr):
|
||||
@@ -133,14 +133,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("%s: %s\n" % (name, val))
|
||||
except:
|
||||
# Don't choke on header fields with garbage in them.
|
||||
pass
|
||||
return Milter.CONTINUE
|
||||
|
||||
@Milter.noreply
|
||||
@@ -174,20 +178,19 @@ 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:
|
||||
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=
|
||||
@@ -255,6 +258,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:
|
||||
@@ -280,10 +284,21 @@ 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:
|
||||
self.header_i = d.signature_fields.get(b'i')
|
||||
except TypeError as x:
|
||||
self.header_i = None
|
||||
try:
|
||||
self.header_d = d.signature_fields.get(b'd')
|
||||
self.header_a = d.signature_fields.get(b'a')
|
||||
except Exception as x:
|
||||
self.dkim_comment = str(x)
|
||||
if milterconfig.get('Syslog'):
|
||||
syslog.syslog("check_dkim: Internal proram fault 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
|
||||
@@ -303,12 +318,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,
|
||||
@@ -317,6 +338,7 @@ class dkimMilter(Milter.Base):
|
||||
result_comment=
|
||||
self.dkim_comment)
|
||||
)
|
||||
self.header_a = None
|
||||
return
|
||||
|
||||
|
||||
@@ -348,13 +370,12 @@ def main():
|
||||
Milter.set_flags(Milter.CHGHDRS + Milter.ADDHDRS)
|
||||
miltername = 'dkimpy-filter'
|
||||
socketname = milterconfig.get('Socket')
|
||||
own_socketfile(milterconfig)
|
||||
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()
|
||||
|
||||
@@ -146,16 +146,6 @@ def write_pid(milterconfig):
|
||||
return pid
|
||||
|
||||
|
||||
def own_socketfile(milterconfig):
|
||||
"""If socket is Unix socket, chown to UserID before dropping privileges"""
|
||||
import os
|
||||
user, group = user_group(milterconfig.get('UserID'))
|
||||
if milterconfig.get('Socket')[:1] == '/':
|
||||
os.chown(milterconfig.get('Socket')[1:], user, group)
|
||||
if milterconfig.get('Socket')[:6] == "local:":
|
||||
os.chown(milterconfig.get('Socket')[6:], user, group)
|
||||
|
||||
|
||||
def read_keyfile(milterconfig, keytype):
|
||||
"""Read private key from file."""
|
||||
import syslog
|
||||
|
||||
@@ -30,7 +30,7 @@ except ImportError: # If PyDNS is not installed, prefer dnspython
|
||||
|
||||
setup(
|
||||
name='dkimpy-milter',
|
||||
version='1.0.1',
|
||||
version='1.0.3',
|
||||
author='Scott Kitterman',
|
||||
author_email='scott@kitterman.com',
|
||||
url='https://launchpad.net/dkimpy-milter',
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
### END INIT INFO
|
||||
prefix="/usr/local"
|
||||
exec_prefix=${prefix}
|
||||
sysconfdir="/etc/dkimpy-milter"
|
||||
sysconfdir="/usr/local/etc"
|
||||
bindir="${exec_prefix}/bin/"
|
||||
RUNDIR="/var/run/dkimpy-milter"
|
||||
RUNDIR="/run/dkimpy-milter"
|
||||
DAEMON=${bindir}/dkimpy-milter
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
|
||||
NAME=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."
|
||||
;;
|
||||
|
||||
Reference in New Issue
Block a user