EX_TEMPFAIL = 75;
EX_PERMFAIL = 65; # EX_DATAERR
+Debug = "";
# Try to extract a key fingerprint from a PGP siged message
def TryGPG(Email):
if string.find(Msg[0],"-----BEGIN PGP SIGNED MESSAGE-----") == -1:
return None;
+ print Msg[0];
Res = GPGCheckSig(Msg[0]);
# Failed to find a matching sig
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);
-
# Try to guess the name from the email address
def TryMatcher(Email):
Sender = Email.getheader("From");
return (UID[0],"FROM",Sender);
# 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;
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();
+ if Debug == None:
+ 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();
+ else:
+ l.simple_bind_s("","");
# Try to decode
ErrType = EX_TEMPFAIL;
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"));
Msg = "[%s] \"%s\" \"%s\" \"%s\""%(Now,User[2],List,MsgID);
Split = re.split("[:\n]",Line);
UnknownMap[Split[0]] = string.strip(Split[1]);
-# Convert the PGP name string to a uid value
-def GetUID(l,Name):
- # 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]):
- print "unknown map hit for",Name;
- return UnknownMap[Name[1] + '@' + Name[2]];
-
- # Then the cruft component (ie there was no email address to match)
- if UnknownMap.has_key(Name[2]):
- print "unknown map hit for",Name;
- return UnknownMap[Name[2]];
-
- # 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:
- print "Filter failure:","(&(cn=%s)(sn=%s))"%(cn,sn);
- return None;
-
- # 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):
- print EmailAppend,"hit for",Name;
- return Name[1];
-
- # Attempt to give some best guess suggestions for use in editing the
- # override file.
- print "None for",Name;
- Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"(sn~=%s)"%(sn),["uid","sn","cn"]);
- for x in Attrs:
- print " But might be:",x[1]["cn"][0],x[1]["sn"][0],"<" + x[1]["uid"][0] + "@debian.org>";
- else:
- return Attrs[0][1]["uid"][0];
-
- return None;
-
# Process options
AdminUser = pwd.getpwuid(posix.getuid())[0];
(options, arguments) = getopt.getopt(sys.argv[1:], "au:m:n")
# print "Ignoring keyID",Split2[9],"belonging to",KeyMap[Split2[9]][0];
KeyMap[Split2[9]][1] = 1;
continue;
-
- Match = AddressSplit.match(Split[9]);
- if Match == None:
- UID = GetUID(l,("","",Split[9]));
- else:
- UID = GetUID(l,Match.groups());
-
- if UID == None:
+
+ UID = GetUID(l,SplitEmail(Split[9]),UnknownMap);
+ if UID[0] == None:
+ print "None for",SplitEmail(Split[9]),"'%s'"%(Split[9]);
+ if UID[1] != None:
+ for x in UID[1]: print x;
print "MISSING 0x" + Split2[9];
continue;
+ UID = UID[0]
Rec = [(ldap.MOD_ADD,"keyfingerprint",Split2[9])];
Dn = "uid=" + UID + "," + BaseDn;
print "Adding key 0x"+Split2[9],"to",UID;
# Look for unmatched keys
for x in KeyMap.keys():
if KeyMap[x][1] == 0:
- print "key 0x",x,"belonging to",KeyMap[x][0],"removed";
+ print "key 0x%s belonging to %s removed"%(x,KeyMap[x][0]);
if KeyCount.has_key(KeyMap[x][0]) :
KeyCount[KeyMap[x][0]] = KeyCount[KeyMap[x][0]] - 1
if KeyCount[KeyMap[x][0]] <= 0:
#!/usr/bin/env python
# -*- mode: python -*-
-# This script tries to match key fingerprints from a keyring with user
-# name in a directory. When an unassigned key is found a heuristic match
-# against the keys given cn/sn and the directory is performed to try to get
-# a matching. Generally this works about 90% of the time, matching is fairly
-# strict. In the event a non-match a fuzzy sounds-alike search is performed
-# and the results printed to aide the user.
-#
-# GPG is automatically invoked with the correct magic special options,
-# pass the names of all the valid key rings on the command line.
-#
-# The output report will list what actions were taken. Keys that are present
-# in the directory but not in the key ring will be removed from the
-# directory.
import string, re, time, ldap, getopt, sys, pwd, posix;
from userdir_gpg import *;
for (switch, val) in options:
if (switch == '-o'):
Output = val
- elif (switch == '-m'):
- LoadOverride(val);
- elif (switch == '-a'):
- NoAct = 0;
if len(arguments) == 0:
print "Give some keyrings to probe";
Args.append("./"+x);
else:
Args.append(x);
+Args.append("--fast-list-mode");
Args.append("--list-sigs");
Args = Args + GPGSearchOptions + [" 2> /dev/null"]
-print string.join(Args," ")
-#Keys = os.popen(string.join(Args," "),"r");
-Keys = os.popen("cat sigs","r");
+Keys = os.popen(string.join(Args," "),"r");
# Loop over the GPG key file
HaveKeys = {};
Args = Args + GPGSearchOptions + [" 2> /dev/null"]
Keys = os.popen(string.join(Args," "),"r");
-print "Reading keys from output";
+print "Reading keys from output ring";
while(1):
Line = Keys.readline();
if Line == "":
OldI = I;
I = I - 20;
if I < 0: I = 0;
- print string.join(Args+KeysToFetch[I:OldI]," ")
+ print string.join(Args+KeysToFetch[I:OldI]," ")
+ Fetcher = os.popen(string.join(Args+KeysToFetch[I:OldI]," "),"r");
+ while(1):
+ Line = Fetcher.readline();
+ if Line == "":
+ break;
+ print Line;
+ Fetcher.close();
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 = ""):
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('');
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:
- return (Res1[0],"",Res1[1]);
+ 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);
+
+