# Some routines and configuration that are used by the ldap progams
-import termios, TERMIOS, re, string, imp, ldap, sys, whrandom, crypt;
+import termios, re, string, imp, ldap, sys, whrandom, crypt, rfc822;
+import userdir_gpg
try:
File = open("/etc/userdir-ldap/userdir-ldap.conf");
ConfModule = imp.load_source("userdir_config","/etc/userdir-ldap.conf",File);
File.close();
+# Cheap hack
BaseDn = ConfModule.basedn;
-BaseDn = ConfModule.basedn;
+HostBaseDn = ConfModule.hostbasedn;
LDAPServer = ConfModule.ldaphost;
EmailAppend = ConfModule.emailappend;
AdminUser = ConfModule.adminuser;
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+) ?(.+)$');
+SSH2AuthSplit = re.compile('^(.* )?ssh-(dss|rsa) ([a-zA-Z0-9=/+]+) ?(.+)$');
#'^([^\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 = ""):
# Function to prompt for a password
def getpass(prompt = "Password: "):
- import termios, TERMIOS, sys;
+ import termios, sys;
fd = sys.stdin.fileno();
old = termios.tcgetattr(fd);
new = termios.tcgetattr(fd);
- new[3] = new[3] & ~TERMIOS.ECHO; # lflags
+ new[3] = new[3] & ~termios.ECHO; # lflags
try:
- termios.tcsetattr(fd, TERMIOS.TCSADRAIN, new);
+ termios.tcsetattr(fd, termios.TCSADRAIN, new);
passwd = raw_input(prompt);
finally:
- termios.tcsetattr(fd, TERMIOS.TCSADRAIN, old);
+ termios.tcsetattr(fd, termios.TCSADRAIN, old);
print;
return passwd;
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('');
SaltVals = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/.";
Rand = open("/dev/urandom");
Password = "";
- for i in range(0,10):
+ for i in range(0,15):
Password = Password + SaltVals[ord(Rand.read(1)[0]) % len(SaltVals)];
return Password;
def HashPass(Password):
# Hash it telling glibc to use the MD5 algorithm - if you dont have
# glibc then just change Salt = "$1$" to Salt = "";
- SaltVals = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/.";
+ SaltVals = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.";
Salt = "$1$";
+ Rand = open("/dev/urandom");
for x in range(0,10):
- Salt = Salt + SaltVals[whrandom.randint(0,len(SaltVals)-1)];
+ Salt = Salt + SaltVals[ord(Rand.read(1)[0]) % len(SaltVals)];
Pass = crypt.crypt(Password,Salt);
if len(Pass) < 14:
raise "Password Error", "MD5 password hashing failed, not changing the password!";
# Convert a lat/long attribute into Decimal degrees
def DecDegree(Posn,Anon=0):
- Parts = re.match('[+-]?(\d*)\\.?(\d*)?',Posn).groups();
+ Parts = re.match('[-+]?(\d*)\\.?(\d*)',Posn).groups();
Val = string.atof(Posn);
if (abs(Val) >= 1806060.0):
return "+" + Str;
return Str;
+def FormatSSH2Auth(Str):
+ Match = SSH2AuthSplit.match(Str);
+ if Match == None:
+ return "<unknown format>";
+ G = Match.groups();
+
+ if G[0] == None:
+ return "ssh-%s %s..%s %s"%(G[1],G[2][:8],G[2][-8:],G[3]);
+ return "%s ssh-%s %s..%s %s"%(G[0],G[1],G[2][:8],G[2][-8:],G[3]);
+
def FormatSSHAuth(Str):
Match = SSHAuthSplit.match(Str);
if Match == None:
- return "<unknown format>";
+ return FormatSSH2Auth(Str);
G = Match.groups();
# No options
I = I + 4;
else:
Res = Str;
- return Res;
+ return string.strip(Res);
+
+# Take an email address and split it into 3 parts, (Name,UID,Domain)
+def SplitEmail(Addr):
+ # Is not an email address at all
+ if string.find(Addr,'@') == -1:
+ return (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]);
+
+ # Then the name component (another ie there was no email address to match)
+ if UnknownMap.has_key(Name[0]):
+ Stat = "unknown map hit for"+str(Name);
+ return (UnknownMap[Name[0]],[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);
+
+