ud-mailgate: remove exception for münchen.debian.net
[mirror/userdir-ldap.git] / ud-echelon
index 6434f0e..38e0718 100755 (executable)
 #!/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");
+def TryMatcher(mail):
+   Sender = mail["From"];
    if Sender == None:
       return None;
       
@@ -116,11 +64,21 @@ def TryMatcher(Email):
       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 == 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;
@@ -130,31 +88,33 @@ try:
    # 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 == 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);
+   User = TryGPG(mail);
    if User == 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:
@@ -162,9 +122,12 @@ try:
       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 == 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));