GPG Mailgate 0.1

This commit is contained in:
mcmaster 2010-01-20 15:53:25 -05:00
commit 782cda3639
4 changed files with 161 additions and 0 deletions

43
GnuPG/__init__.py Normal file
View file

@ -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()

26
INSTALL Normal file
View file

@ -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.

23
gpg-mailgate.conf.sample Normal file
View file

@ -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 <user@example.com>
# sub 2048g/BBBBBBBBBBBBBBBB 2007-10-22
# You want the AAAAAAAAAAAAAAAA not BBBBBBBBBBBBBBBB.
#user@example.com <gpg key id>

69
gpg-mailgate.py Executable file
View file

@ -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) )