X-Git-Url: https://git.adam-barratt.org.uk/?a=blobdiff_plain;f=userdir_gpg.py;h=1f3b1cb2a52024571d86456fcf564305225255f2;hb=9e1e7b0639b1265bf39acd330122f40123451c56;hp=39667d2c1f8ae25db0976eaaab8fc1650608a153;hpb=8ea8b0937fb83d1db795b20b96acccff2ab4025a;p=mirror%2Fuserdir-ldap.git diff --git a/userdir_gpg.py b/userdir_gpg.py index 39667d2..1f3b1cb 100644 --- a/userdir_gpg.py +++ b/userdir_gpg.py @@ -1,5 +1,18 @@ - #!/usr/bin/env python -# -*- mode: python -*- +# Copyright (c) 1999-2001 Jason Gunthorpe +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # GPG issues - # - gpgm with a status FD being fed keymaterial and other interesting @@ -17,10 +30,10 @@ import rfc822, time, fcntl, FCNTL, anydbm # General GPG options GPGPath = "gpg" -GPGBasicOptions = ["--no-options","--batch","--load-extension","rsa",\ +# "--load-extension","rsa", +GPGBasicOptions = ["--no-options","--batch", "--no-default-keyring","--always-trust"]; -GPGKeyRings = ["--keyring","/usr/share/keyrings/debian-keyring.pgp",\ - "--keyring","/usr/share/keyrings/debian-keyring.gpg"]; +GPGKeyRings = []; GPGSigOptions = ["--output","-"]; GPGSearchOptions = ["--dry-run","--with-colons","--fingerprint"]; GPGEncryptOptions = ["--output","-","--quiet","--always-trust",\ @@ -34,6 +47,12 @@ CleanCutOff = 7*24*60*60; AgeCutOff = 4*24*60*60; FutureCutOff = 3*24*60*60; +# Set the keyrings, the input is a list of keyrings +def SetKeyrings(Rings): + for x in Rings: + GPGKeyRings.append("--keyring"); + GPGKeyRings.append(x); + # GetClearSig takes an un-seekable email message stream (mimetools.Message) # and returns a standard PGP '---BEGIN PGP SIGNED MESSAGE---' bounded # clear signed text. @@ -44,7 +63,10 @@ FutureCutOff = 3*24*60*60; # present in the signature text! The return result is a tuple, the first # element is the text itself the second is a mime flag indicating if the # result should be mime processed after sig checking. -def GetClearSig(Msg): +# +# Paranoid will check the message text to make sure that all the plaintext is +# in fact signed (bounded by a PGP packet) +def GetClearSig(Msg,Paranoid = 0): Error = 'MIME Error'; # See if this is a MIME encoded multipart signed message if Msg.gettype() == "multipart/signed": @@ -60,6 +82,16 @@ def GetClearSig(Msg): mf = multifile.MultiFile(SkMessage) mf.push(Msg.getparam("boundary")); + # Check the first bit of the message.. + if Paranoid != 0: + Pos = mf.tell(); + while 1: + x = mf.readline(); + if not x: break; + if len(string.strip(x)) != 0: + raise Error,"Unsigned text in message (at start)"; + mf.seek(Pos); + # Get the first part of the multipart message if not mf.next(): raise Error, "Invalid pgp/mime encoding [no section]"; @@ -68,7 +100,7 @@ def GetClearSig(Msg): Signed = StringIO.StringIO(); Signed.write(mf.read()); InnerMsg = mimetools.Message(Signed); - + # Make sure it is the right type if InnerMsg.gettype() != "text/plain": raise Error, "Invalid pgp/mime encoding [wrong plaintext type]"; @@ -81,13 +113,63 @@ def GetClearSig(Msg): raise Error, "Invalid pgp/mime encoding [wrong signature type]"; Signature = string.joinfields(mf.readlines(),''); + # Check the last bit of the message.. + if Paranoid != 0: + mf.pop(); + Pos = mf.tell(); + while 1: + x = mf.readline(); + if not x: break; + if len(string.strip(x)) != 0: + raise Error,"Unsigned text in message (at end)"; + mf.seek(Pos); + # Append the PGP boundary header and the signature text to re-form the # original signed block [needs to convert to \r\n] - Output = "-----BEGIN PGP SIGNED MESSAGE-----\r\n\r\n" + Signed.getvalue() + Signature; + Output = "-----BEGIN PGP SIGNED MESSAGE-----\r\n"; + # Semi-evil hack to get the proper hash type inserted in the message + if Msg.getparam('micalg') != None: + Output = Output + "Hash: MD5,SHA1,%s\r\n"%(string.upper(Msg.getparam('micalg')[4:])); + Output = Output + "\r\n"; + Output = Output + string.replace(Signed.getvalue(),"\n-","\n- -") + Signature; return (Output,1); else: - # Just return the message body - return (string.joinfields(Msg.fp.readlines(),''),0); + if Paranoid == 0: + # Just return the message body + return (string.joinfields(Msg.fp.readlines(),''),0); + + Body = ""; + State = 1; + for x in Msg.fp.readlines(): + Body = Body + x; + Tmp = string.strip(x); + if len(Tmp) == 0: + continue; + + # Leading up to the signature + if State == 1: + if Tmp == "-----BEGIN PGP SIGNED MESSAGE-----": + State = 2; + else: + raise Error,"Unsigned text in message (at start)"; + continue; + + # In the signature plain text + if State == 2: + if Tmp == "-----BEGIN PGP SIGNATURE-----": + State = 3; + continue; + + # In the signature + if State == 3: + if Tmp == "-----END PGP SIGNATURE-----": + State = 4; + continue; + + # Past the end + if State == 4: + raise Error,"Unsigned text in message (at end)"; + return (Body,0); # This opens GPG in 'write filter' mode. It takes Message and sends it # to GPGs standard input, pipes the standard output to a temp file along @@ -337,6 +419,7 @@ def GPGKeySearch(SearchCriteria): Result = []; Owner = ""; KeyID = ""; + Hits = {}; try: Strm = os.popen(string.join(Args," "),"r"); @@ -355,6 +438,9 @@ def GPGKeySearch(SearchCriteria): # Output the key if Split[0] == 'fpr': + if Hits.has_key(Split[9]): + continue; + Hits[Split[9]] = None; Result.append( (KeyID,Split[9],Owner,Length) ); finally: if Strm != None: