posix -> os
[mirror/userdir-ldap.git] / userdir_ldap.py
index 32b830e..07bc6b1 100644 (file)
@@ -1,5 +1,6 @@
 # Some routines and configuration that are used by the ldap progams
-import termios, TERMIOS, re, string, imp, ldap, sys, whrandom, crypt;
+import termios, TERMIOS, re, string, imp, ldap, sys, whrandom, crypt, rfc822;
+import userdir_gpg
 
 try:
    File = open("/etc/userdir-ldap/userdir-ldap.conf");
@@ -8,6 +9,7 @@ except:
 ConfModule = imp.load_source("userdir_config","/etc/userdir-ldap.conf",File);
 File.close();
 
+# Cheap hack
 BaseDn = ConfModule.basedn;
 BaseDn = ConfModule.basedn;
 LDAPServer = ConfModule.ldaphost;
@@ -18,15 +20,22 @@ GenerateConf = ConfModule.generateconf;
 DefaultGID = ConfModule.defaultgid;
 TemplatesDir = ConfModule.templatesdir;
 PassDir = ConfModule.passdir;
+Ech_ErrorLog = ConfModule.ech_errorlog;
+Ech_MainLog = ConfModule.ech_mainlog;
+
+# Break up the keyring list
+userdir_gpg.SetKeyrings(string.split(ConfModule.keyrings,":"));
 
 # This is a list of common last-name prefixes
 LastNamesPre = {"van": None, "le": None, "de": None, "di": None};
 
 # SSH Key splitting. The result is:
 # (options,size,modulous,exponent,comment)
-SSHAuthSplit = re.compile('^(.* )?(\d+) (\d+) (\d+) (.+)$');
+SSHAuthSplit = re.compile('^(.* )?(\d+) (\d+) (\d+) ?(.+)$');
 #'^([^\d](?:[^ "]+(?:".*")?)*)? ?(\d+) (\d+) (\d+) (.+)$');
 
+AddressSplit = re.compile("(.*).*<([^@]*)@([^>]*)>");
+
 # Safely get an attribute from a tuple representing a dn and an attribute
 # list. It returns the first attribute if there are multi.
 def GetAttr(DnRecord,Attribute,Default = ""):
@@ -98,10 +107,9 @@ def NameSplit(Name):
          break;
         
    # Merge any of the middle initials
-   if len(Words) > 2:
-      while len(Words[2]) == 2 and Words[2][1] == '.':
-         Words[1] = Words[1] +  Words[2];
-         del Words[2];
+   while len(Words) > 2 and len(Words[2]) == 2 and Words[2][1] == '.':
+      Words[1] = Words[1] +  Words[2];
+      del Words[2];
 
    while len(Words) < 2:
       Words.append('');
@@ -214,3 +222,117 @@ def FormatSSHAuth(Str):
    if G[0] == None:
       return "%s %s %s..%s %s"%(G[1],G[2],G[3][:8],G[3][-8:],G[4]);
    return "%s %s %s %s..%s %s"%(G[0],G[1],G[2],G[3][:8],G[3][-8:],G[4]);
+
+def FormatPGPKey(Str):
+   Res = "";
+
+   # PGP 2.x Print
+   if (len(Str) == 32):
+      I = 0;
+      while (I < len(Str)):
+         if I+2 == 32/2:
+            Res = "%s %s%s "%(Res,Str[I],Str[I+1]);
+         else:
+            Res = "%s%s%s "%(Res,Str[I],Str[I+1]);
+         I = I + 2;
+   elif (len(Str) == 40):
+      # OpenPGP Print
+      I = 0;
+      while (I < len(Str)):
+         if I+4 == 40/2:
+            Res = "%s %s%s%s%s "%(Res,Str[I],Str[I+1],Str[I+2],Str[I+3]);
+         else:
+            Res = "%s%s%s%s%s "%(Res,Str[I],Str[I+1],Str[I+2],Str[I+3]);
+         I = I + 4;
+   else:
+      Res = Str;
+   return string.strip(Res);
+
+# Take an email address and split it into 3 parts, (Name,UID,Domain)
+def SplitEmail(Addr):
+   Res1 = rfc822.AddrlistClass(Addr).getaddress();
+   if len(Res1) != 1:
+      return ("","",Addr);
+   Res1 = Res1[0];
+   if Res1[1] == None:
+      return (Res1[0],"","");
+
+   # If there is no @ then the address was not parsed well. Try the alternate
+   # Parsing scheme. This is particularly important when scanning PGP keys.
+   Res2 = string.split(Res1[1],"@");
+   if len(Res2) != 2:
+      Match = AddressSplit.match(Addr);
+      if Match == None:
+         return ("","",Addr);
+      return Match.groups();
+
+   return (Res1[0],Res2[0],Res2[1]);
+
+# Convert the PGP name string to a uid value. The return is a tuple of
+# (uid,[message strings]). UnknownMpa is a hash from email to uid that 
+# overrides normal searching.
+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);
+
+