#!/usr/bin/env python
# -*- mode: python -*-
-import userdir_gpg, userdir_ldap, sys, traceback, time, ldap, posix;
-import string, pwd
+import userdir_gpg, userdir_ldap, sys, traceback, time, ldap, os, getopt;
+import pwd
+import email, email.parser
from userdir_gpg import *;
from userdir_ldap import *;
EX_TEMPFAIL = 75;
EX_PERMFAIL = 65; # EX_DATAERR
+Debug = None;
# Try to extract a key fingerprint from a PGP siged message
-def TryGPG(Email):
+def TryGPG(mail):
# Try to get a pgp text
- Msg = GetClearSig(Email);
- if string.find(Msg[0],"-----BEGIN PGP SIGNED MESSAGE-----") == -1:
+ try:
+ Msg = GetClearSig(mail, lax_multipart=True);
+ except:
+ # Log an exception.. but continue. This is to deal with 'sort of'
+ # PGP-MIME things
+ S = "%s: %s -> %s\n" %(Now,MsgID,ErrMsg);
+ S = S + " %s: %s\n" %(sys.exc_type,sys.exc_value);
+ ErrLog.write(S);
return None;
-
- Res = GPGCheckSig(Msg[0]);
+
+ if Msg[0].find("-----BEGIN PGP SIGNED MESSAGE-----") == -1:
+ return None;
+
+ pgp = GPGCheckSig2(Msg[0]);
# Failed to find a matching sig
- if Res[0] != None:
+ if not pgp.ok:
+ S = "%s: %s -> PGP Checking failed '%s': %s %s\n" %(Now,MsgID,mail["From"],str(pgp.why),str(pgp.key_info));
+ ErrLog.write(S);
return None;
# Search for the matching key fingerprint
- Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyfingerprint=" + Res[2][1]);
+ Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"keyFingerPrint=" + pgp.key_fpr);
if len(Attrs) == 0:
return None;
if len(Attrs) != 1:
raise Error, "Oddly your key fingerprint is assigned to more than one account.."
- return (Attrs[0][1]["uid"][0],"PGP",FormatPGPKey(Res[2][1]));
-
-# Convert the PGP name string to a uid value
-def GetUID(l,Name,UnknownMap = {}):
- # Crack up the email address into a best guess first/middle/last name
- (cn,mn,sn) = NameSplit(re.sub('["]','',Name[0]))
-
- # Brackets anger the ldap searcher
- cn = re.sub('[(")]','?',cn);
- sn = re.sub('[(")]','?',sn);
-
- # First check the unknown map for the email address
- if UnknownMap.has_key(Name[1] + '@' + Name[2]):
- Stat = "unknown map hit for "+str(Name);
- return (UnknownMap[Name[1] + '@' + Name[2]],[Stat]);
-
- # Then the cruft component (ie there was no email address to match)
- if UnknownMap.has_key(Name[2]):
- Stat = "unknown map hit for"+str(Name);
- return (UnknownMap[Name[2]],[Stat]);
-
- # Search for a possible first/last name hit
- try:
- Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"(&(cn=%s)(sn=%s))"%(cn,sn),["uid"]);
- except ldap.FILTER_ERROR:
- Stat = "Filter failure: (&(cn=%s)(sn=%s))"%(cn,sn);
- return (None,[Stat]);
-
- # Try matching on the email address
- if (len(Attrs) != 1):
- try:
- Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"emailforward=%s"%(Name[2]),["uid"]);
- except ldap.FILTER_ERROR:
- pass;
-
- # Hmm, more than one/no return
- if (len(Attrs) != 1):
- # Key claims a local address
- if Name[2] == EmailAppend:
-
- # Pull out the record for the claimed user
- Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"(uid=%s)"%(Name[1]),["uid","sn","cn"]);
-
- # We require the UID surname to be someplace in the key name, this
- # deals with special purpose keys like 'James Troup (Alternate Debian key)'
- # Some people put their names backwards on their key too.. check that as well
- if len(Attrs) == 1 and \
- (string.find(string.lower(sn),string.lower(Attrs[0][1]["sn"][0])) != -1 or \
- string.find(string.lower(cn),string.lower(Attrs[0][1]["sn"][0])) != -1):
- Stat = EmailAppend+" hit for "+str(Name);
- return (Name[1],[Stat]);
-
- # Attempt to give some best guess suggestions for use in editing the
- # override file.
- Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"(sn~=%s)"%(sn),["uid","sn","cn"]);
-
- Stat = [];
- if len(Attrs) != 0:
- Stat = ["None for %s"%(str(Name))];
- for x in Attrs:
- Stat.append("But might be: %s %s <%s@debian.org>"%(x[1]["cn"][0],x[1]["sn"][0],x[1]["uid"][0]));
- return (None,Stat);
- else:
- return (Attrs[0][1]["uid"][0],None);
-
- return (None,None);
+ return (Attrs[0][1]["uid"][0],"PGP",FormatPGPKey(pgp.key_fpr));
# Try to guess the name from the email address
-def TryMatcher(Email):
- Sender = Email.getheader("From");
- if Sender == None:
+def TryMatcher(mail):
+ Sender = mail["From"];
+ if Sender is None:
return None;
# Split up the address and invoke the matcher routine
UID = GetUID(l,SplitEmail(Sender));
- if UID[0] == None:
- if UID[1] == None or len(UID[1]) == 0:
+ if UID[0] is None:
+ if UID[1] is None or len(UID[1]) == 0:
return None;
# Print out an error message
return None;
return (UID[0],"FROM",Sender);
+
+# Process options
+(options, arguments) = getopt.getopt(sys.argv[1:], "dr")
+for (switch, val) in options:
+ if (switch == '-d'):
+ Debug = "";
# Open the log files
-MainLog = open(Ech_MainLog,"a+",0);
-ErrLog = open(Ech_ErrorLog,"a+",0);
-
+if Debug is None:
+ MainLog = open(Ech_MainLog,"a+",0);
+ ErrLog = open(Ech_ErrorLog,"a+",0);
+else:
+ MainLog = open("/dev/stdout","a+",0);
+ ErrLog = open("/dev/stdout","a+",0);
+
# Start of main program
ErrMsg = "Indeterminate Error";
ErrType = EX_TEMPFAIL;
# Get the email
ErrType = EX_PERMFAIL;
ErrMsg = "Failed to understand the email or find a signature:";
- Email = mimetools.Message(sys.stdin,0);
- MsgID = Email.getheader("Message-ID");
-
+ mail = email.parser.Parser().parse(sys.stdin);
+ MsgID = mail["Message-ID"]
+
# Connect to the ldap server
ErrType = EX_TEMPFAIL;
ErrMsg = "An error occured while performing the LDAP lookup";
global l;
- l = ldap.open(LDAPServer);
- F = open(PassDir+"/pass-"+pwd.getpwuid(posix.getuid())[0],"r");
- AccessPass = string.split(string.strip(F.readline())," ");
- l.simple_bind_s("uid="+AccessPass[0]+","+BaseDn,AccessPass[1]);
- F.close();
+ l = connectLDAP()
+ if Debug is None:
+ F = open(PassDir+"/pass-"+pwd.getpwuid(os.getuid())[0],"r");
+ AccessPass = F.readline().strip().split(" ")
+ l.simple_bind_s("uid="+AccessPass[0]+","+BaseDn,AccessPass[1]);
+ F.close();
+ else:
+ l.simple_bind_s("","");
# Try to decode
ErrType = EX_TEMPFAIL;
ErrMsg = "An error occured while trying GPG decoding";
- User = TryGPG(Email);
- if User == None:
+ User = TryGPG(mail);
+ if User is None:
ErrMsg = "An error occured while trying Matcher decoding";
- User = TryMatcher(Email);
+ User = TryMatcher(mail);
# Get any mailing list information
- List = Email.getheader("X-Mailing-List");
- if List == None:
- List = "-";
+ List = mail['X-Mailing-List']
+ if not List: List = "-";
# Tada, write a log message
- if User != None:
+ if User is not None:
Msg = "[%s] \"%s\" \"%s\" \"%s\""%(Now,User[2],List,MsgID);
MainLog.write("%s %s %s\n"%(User[0],User[1],Msg));
Dn = "uid=" + User[0] + "," + BaseDn;
Rec = [(ldap.MOD_REPLACE,"activity-%s"%(User[1]),Msg)];
- l.modify_s(Dn,Rec);
+ if Debug is None:
+ l.modify_s(Dn,Rec);
+ else:
+ print Rec;
else:
- User = ("-","UKN",Email.getheader("From"));
+ User = ("-","UKN",mail["From"]);
Msg = "[%s] \"%s\" \"%s\" \"%s\""%(Now,User[2],List,MsgID);
MainLog.write("%s %s %s\n"%(User[0],User[1],Msg));