From 782cda36396b5a4b48e87e1ac2fd883b13c8e8aa Mon Sep 17 00:00:00 2001 From: mcmaster Date: Wed, 20 Jan 2010 15:53:25 -0500 Subject: [PATCH] GPG Mailgate 0.1 --- GnuPG/__init__.py | 43 +++++++++++++++++++++++++ INSTALL | 26 +++++++++++++++ gpg-mailgate.conf.sample | 23 ++++++++++++++ gpg-mailgate.py | 69 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 GnuPG/__init__.py create mode 100644 INSTALL create mode 100644 gpg-mailgate.conf.sample create mode 100755 gpg-mailgate.py diff --git a/GnuPG/__init__.py b/GnuPG/__init__.py new file mode 100644 index 0000000..674c7b3 --- /dev/null +++ b/GnuPG/__init__.py @@ -0,0 +1,43 @@ +import os +import subprocess + +def public_keys( keyhome ): + cmd = '/usr/bin/gpg --homedir %s --list-keys --with-colons' % keyhome + p = subprocess.Popen( cmd.split(' '), stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) + p.wait() + keys = list() + for line in p.stdout.readlines(): + if line[0:3] == 'uid' or line[0:3] == 'pub': + key = line.split('<')[1].split('>')[0] + if keys.count(key) == 0: + keys.append(key) + return keys + +class GPGEncryptor: + def __init__(self, keyhome, recipients = None): + self._keyhome = keyhome + self._message = '' + self._recipients = list() + if recipients != None: + self._recipients.extend(recipients) + + def update(self, message): + self._message += message + + def encrypt(self): + p = subprocess.Popen( self._command(), stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE ) + (stdin, stdout, stderr) = (p.stdin, p.stdout, p.stderr) + + # Write the data + stdin.write(self._message) + stdin.close() + + # Read the encrypted data + p.wait() + encdata = stdout.read() + + return encdata + + def _command(self): + cmd = "/usr/bin/gpg --homedir %s --batch --yes --pgp7 --no-secmem-warning -a -e -r %s" % (self._keyhome, ' -r '.join(self._recipients)) + return cmd.split() diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..e7bd421 --- /dev/null +++ b/INSTALL @@ -0,0 +1,26 @@ +1) Ensure that GPG is installed and configured. + a) Make sure public keys for all of your potential recipients are + available in the GPG home directory you use in step 2 +2) Configure /etc/gpg-mailgate.conf based on the provided sample config +3) Place gpg-mailgate.py in /usr/local/bin/ +4) Place the GnuPG directory in /usr/local/lib/python2.5/site-packages +5) Add the following to the end of /etc/postfix/master.cf + +gpg-mailgate unix - n n - - pipe + flags= user=nobody argv=/usr/local/bin/gpg-mailgate.py + +127.0.0.1:10028 inet n - n - 10 smtpd + -o content_filter= + -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks + -o smtpd_helo_restrictions= + -o smtpd_client_restrictions= + -o smtpd_sender_restrictions= + -o smtpd_recipient_restrictions=permit_mynetworks,reject + -o mynetworks=127.0.0.0/8 + -o smtpd_authorized_xforward_hosts=127.0.0.0/8 + +6) Add the following to /etc/postfix/main.cf + +content_filter = gpg-mailgate + +7) Restart postfix. diff --git a/gpg-mailgate.conf.sample b/gpg-mailgate.conf.sample new file mode 100644 index 0000000..4bf338f --- /dev/null +++ b/gpg-mailgate.conf.sample @@ -0,0 +1,23 @@ +[default] +add_header = yes +domains = example.com,corp.org + +[gpg] +keyhome = /var/gpg/.gnupg + +[logging] +file = /tmp/gpg-mailgate.log + +[relay] +host = 127.0.0.1 +port = 10028 + +[keymap] +# You can find these by running the following command: +# gpg --list-keys --keyid-format long user@example.com +# Which will return output similar to: +# pub 1024D/AAAAAAAAAAAAAAAA 2007-10-22 +# uid Joe User +# sub 2048g/BBBBBBBBBBBBBBBB 2007-10-22 +# You want the AAAAAAAAAAAAAAAA not BBBBBBBBBBBBBBBB. +#user@example.com diff --git a/gpg-mailgate.py b/gpg-mailgate.py new file mode 100755 index 0000000..717ab97 --- /dev/null +++ b/gpg-mailgate.py @@ -0,0 +1,69 @@ +#!/usr/bin/python + +from ConfigParser import RawConfigParser +import email +import GnuPG +import smtplib +import sys + +# Read configuration from /etc/gpg-mailgate.conf +_cfg = RawConfigParser() +_cfg.read('/etc/gpg-mailgate.conf') +cfg = dict() +for sect in _cfg.sections(): + cfg[sect] = dict() + for (name, value) in _cfg.items(sect): + cfg[sect][name] = value + +# Read e-mail from stdin +raw = sys.stdin.read() +raw_message = email.message_from_string( raw ) +from_addr = raw_message['From'] +to_addrs = map(lambda x: x.strip(), raw_message['To'].split(',')) +if raw_message.has_key('Cc'): + to_addrs.extend( map(lambda x: x.strip(), raw_message['Cc'].split(','))) +if raw_message.has_key('Bcc'): + to_addrs.extend( map(lambda x: x.strip(), raw_message['Bcc'].split(','))) + +def send_msg( message, recipients = None ): + if recipients == None: + recipients = to_addrs + relay = (cfg['relay']['host'], int(cfg['relay']['port'])) + smtp = smtplib.SMTP(relay[0], relay[1]) + smtp.sendmail( from_addr, recipients, message.as_string() ) + sys.exit(0) + +gpg_to = list() +keys = GnuPG.public_keys( cfg['gpg']['keyhome'] ) +for to in to_addrs: + domain = to.split('@')[1] + if domain in cfg['default']['domains'].split(','): + if to in keys: + gpg_to.append( (to, to) ) + elif cfg.has_key('keymap') and cfg['keymap'].has_key(to): + gpg_to.append( (to, cfg['keymap'][to]) ) + +if gpg_to == list(): + if cfg['default'].has_key('add_header') and cfg['default']['add_header'] == 'yes': + raw_message['X-GPG-Mailgate'] = 'Not encrypted, public key not found' + send_msg( raw_message ) + +if raw_message.is_multipart(): + payload = list() + for part in raw_message.get_payload(): + if part.get_content_type() == "text/plain": + payload.append(part) + raw_message.set_payload( payload ) + +if cfg.has_key('logging') and cfg['logging'].has_key('file'): + log = open(cfg['logging']['file'], 'a') + log.write("Encrypting email to: %s\n" % ' '.join( map(lambda x: x[0], gpg_to) )) + log.close() + +if cfg['default'].has_key('add_header') and cfg['default']['add_header'] == 'yes': + raw_message['X-GPG-Mailgate'] = 'Encrypted by GPG Mailgate 0.1' + +gpg = GnuPG.GPGEncryptor( cfg['gpg']['keyhome'], map(lambda x: x[1], gpg_to) ) +gpg.update( raw_message.get_payload() ) +raw_message.set_payload( gpg.encrypt() ) +send_msg( raw_message, map(lambda x: x[0], gpg_to) )