# Copyright (c) 2008 Luk Claes <luk@debian.org>
# Copyright (c) 2008 Thomas Viehmann <tv@beamnet.de>
# Copyright (c) 2009 Stephen Gran <steve@lobefin.net>
+# Copyright (c) 2010 Helmut Grohne <helmut@subdivi.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
import string, re, time, ldap, getopt, sys, os, pwd, posix, socket, base64, sha, shutil, errno, tarfile, grp
from userdir_ldap import *
from userdir_exceptions import *
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO
global Allowed
global CurrentHost
PasswdAttrs = None
+DebianUsers = None
DisabledUsers = []
-RetiredUsers = []
GroupIDMap = {}
SubGroupMap = {}
Allowed = None
UUID_FORMAT = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
EmailCheck = re.compile("^([^ <>@]+@[^ ,<>@]+)?$")
-BSMTPCheck = re.compile(".*mx 0 (gluck)\.debian\.org\..*",re.DOTALL)
-PurposeHostField = re.compile(r"\[\[([\*\-]?[a-z0-9.\-]*)(?:\|.*)?\]\]")
+BSMTPCheck = re.compile(".*mx 0 (master)\.debian\.org\..*",re.DOTALL)
+PurposeHostField = re.compile(r".*\[\[([\*\-]?[a-z0-9.\-]*)(?:\|.*)?\]\]")
+IsV6Addr = re.compile("^[a-fA-F0-9:]+$")
+IsDebianHost = re.compile(ConfModule.dns_hostmatch)
DNSZone = ".debian.net"
Keyrings = ConfModule.sync_keyrings.split(":")
raise e
def Sanitize(Str):
- return Str.translate(string.maketrans("\n\r\t","$$$"))
+ return Str.translate(string.maketrans("\n\r\t", "$$$"))
-def DoLink(From,To,File):
+def DoLink(From, To, File):
try:
- posix.remove(To+File)
+ posix.remove(To + File)
except:
pass
- posix.link(From+File,To+File)
+ posix.link(From + File, To + File)
def IsRetired(DnRecord):
"""
match it against one of the known retired statuses
"""
- status = GetAttr(DnRecord,"accountStatus", None)
+ status = GetAttr(DnRecord, "accountStatus", None)
if status is None:
return False
# We'll give them a few extra days over what we said
age = 6 * 31 * 24 * 60 * 60
try:
- if (time.time() - time.mktime(time.strptime(line[1], "%Y-%m-%d"))) > age:
- return True
+ return (time.time() - time.mktime(time.strptime(line[1], "%Y-%m-%d"))) > age
except IndexError:
return False
+ except ValueError:
+ return False
return False
+def IsGidDebian(x):
+ try:
+ return int(GetAttr(x, "gidNumber", 0)) == 800
+ except ValueError:
+ return False
+
# See if this user is in the group list
def IsInGroup(DnRecord):
- if Allowed == None:
- return 1
+ if Allowed is None:
+ return True
# See if the primary group is in the list
- if Allowed.has_key(GetAttr(DnRecord,"gidNumber")) != 0:
- return 1
+ if Allowed.has_key(GetAttr(DnRecord, "gidNumber")) != 0:
+ return True
# Check the host based ACL
if DnRecord[1].has_key("allowedHost") != 0:
- for I in DnRecord[1]["allowedHost"]:
- if CurrentHost == I:
- return 1
+ if CurrentHost in DnRecord[1]["allowedHost"]:
+ return True
# See if there are supplementary groups
if DnRecord[1].has_key("supplementaryGid") == 0:
- return 0
+ return False
supgroups=[]
- addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord,"uid"))
+ addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord, "uid"))
for g in supgroups:
if Allowed.has_key(g):
- return 1
- return 0
+ return True
+ return False
-def Die(File,F,Fdb):
+def Die(File, F, Fdb):
if F != None:
F.close()
if Fdb != None:
except:
pass
-def Done(File,F,Fdb):
+def Done(File, F, Fdb):
if F != None:
F.close()
- os.rename(File + ".tmp",File)
+ os.rename(File + ".tmp", File)
if Fdb != None:
Fdb.close()
- os.rename(File + ".tdb.tmp",File+".tdb")
+ os.rename(File + ".tdb.tmp", File + ".tdb")
# Generate the password list
-def GenPasswd(l,File,HomePrefix,PwdMarker):
+def GenPasswd(File, HomePrefix, PwdMarker):
F = None
try:
- F = open(File + ".tdb.tmp","w")
+ F = open(File + ".tdb.tmp", "w")
userlist = {}
# Fetch all the users
I = 0
for x in PasswdAttrs:
- if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
+ if x[1].has_key("uidNumber") == 0 or not IsInGroup(x):
continue
# Do not let people try to buffer overflow some busted passwd parser.
- if len(GetAttr(x,"gecos")) > 100 or len(GetAttr(x,"loginShell")) > 50:
+ if len(GetAttr(x, "gecos")) > 100 or len(GetAttr(x, "loginShell")) > 50:
continue
userlist[GetAttr(x, "uid")] = int(GetAttr(x, "gidNumber"))
- Line = "%s:%s:%s:%s:%s:%s%s:%s" % (GetAttr(x,"uid"),\
+ Line = "%s:%s:%s:%s:%s:%s%s:%s" % (GetAttr(x, "uid"),\
PwdMarker,\
- GetAttr(x,"uidNumber"),GetAttr(x,"gidNumber"),\
- GetAttr(x,"gecos"),HomePrefix,GetAttr(x,"uid"),\
- GetAttr(x,"loginShell"))
+ GetAttr(x, "uidNumber"), GetAttr(x, "gidNumber"),\
+ GetAttr(x, "gecos"), HomePrefix, GetAttr(x, "uid"),\
+ GetAttr(x, "loginShell"))
Line = Sanitize(Line) + "\n"
- F.write("0%u %s" % (I,Line))
- F.write(".%s %s" % (GetAttr(x,"uid"),Line))
- F.write("=%s %s" % (GetAttr(x,"uidNumber"),Line))
+ F.write("0%u %s" % (I, Line))
+ F.write(".%s %s" % (GetAttr(x, "uid"), Line))
+ F.write("=%s %s" % (GetAttr(x, "uidNumber"), Line))
I = I + 1
# Oops, something unspeakable happened.
except:
- Die(File,None,F)
+ Die(File, None, F)
raise
- Done(File,None,F)
+ Done(File, None, F)
# Return the list of users so we know which keys to export
return userlist
# Generate the shadow list
-def GenShadow(l,File):
+def GenShadow(File):
F = None
try:
OldMask = os.umask(0077)
- F = open(File + ".tdb.tmp","w",0600)
+ F = open(File + ".tdb.tmp", "w", 0600)
os.umask(OldMask)
# Fetch all the users
I = 0
for x in PasswdAttrs:
- if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
+ if x[1].has_key("uidNumber") == 0 or not IsInGroup(x):
continue
- Pass = GetAttr(x,"userPassword")
+ Pass = GetAttr(x, "userPassword")
if Pass[0:7] != "{crypt}" or len(Pass) > 50:
Pass = '*'
else:
# If the account is locked, mark it as such in shadow
# See Debian Bug #308229 for why we set it to 1 instead of 0
- if (GetAttr(x,"userPassword").find("*LK*") != -1) \
- or GetAttr(x,"userPassword").startswith("!"):
+ if (GetAttr(x, "userPassword").find("*LK*") != -1) \
+ or GetAttr(x, "userPassword").startswith("!"):
ShadowExpire = '1'
else:
- ShadowExpire = GetAttr(x,"shadowExpire")
+ ShadowExpire = GetAttr(x, "shadowExpire")
- Line = "%s:%s:%s:%s:%s:%s:%s:%s:" % (GetAttr(x,"uid"),\
- Pass,GetAttr(x,"shadowLastChange"),\
- GetAttr(x,"shadowMin"),GetAttr(x,"shadowMax"),\
- GetAttr(x,"shadowWarning"),GetAttr(x,"shadowInactive"),\
+ Line = "%s:%s:%s:%s:%s:%s:%s:%s:" % (GetAttr(x, "uid"),\
+ Pass, GetAttr(x, "shadowLastChange"),\
+ GetAttr(x, "shadowMin"), GetAttr(x, "shadowMax"),\
+ GetAttr(x, "shadowWarning"), GetAttr(x, "shadowInactive"),\
ShadowExpire)
Line = Sanitize(Line) + "\n"
- F.write("0%u %s" % (I,Line))
- F.write(".%s %s" % (GetAttr(x,"uid"),Line))
+ F.write("0%u %s" % (I, Line))
+ F.write(".%s %s" % (GetAttr(x, "uid"), Line))
I = I + 1
# Oops, something unspeakable happened.
except:
- Die(File,None,F)
+ Die(File, None, F)
raise
- Done(File,None,F)
+ Done(File, None, F)
# Generate the sudo passwd file
-def GenShadowSudo(l,File, untrusted):
+def GenShadowSudo(File, untrusted):
F = None
try:
OldMask = os.umask(0077)
- F = open(File + ".tmp","w",0600)
+ F = open(File + ".tmp", "w", 0600)
os.umask(OldMask)
# Fetch all the users
for x in PasswdAttrs:
Pass = '*'
- if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
+ if x[1].has_key("uidNumber") == 0 or not IsInGroup(x):
continue
if x[1].has_key('sudoPassword'):
continue
Pass = cryptedpass
if for_this_host: # this makes sure we take a per-host entry over the for-all entry
- break
+ break
if len(Pass) > 50:
Pass = '*'
- Line = "%s:%s" % (GetAttr(x,"uid"), Pass)
+ Line = "%s:%s" % (GetAttr(x, "uid"), Pass)
Line = Sanitize(Line) + "\n"
F.write("%s" % (Line))
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
# Generate the shadow list
-def GenSSHShadow(l):
+def GenSSHShadow():
# Fetch all the users
- singlefile = None
userfiles = []
global PasswdAttrs
for x in PasswdAttrs:
- if x in DisabledUsers:
- continue
-
if x[1].has_key("uidNumber") == 0 or \
x[1].has_key("sshRSAAuthKey") == 0:
continue
- User = GetAttr(x,"uid")
+ User = GetAttr(x, "uid")
F = None
try:
OldMask = os.umask(0077)
File = os.path.join(GlobalDir, 'userkeys', User)
- F = open(File + ".tmp","w",0600)
+ F = open(File + ".tmp", "w", 0600)
os.umask(OldMask)
for I in x[1]["sshRSAAuthKey"]:
MultipleLine = Sanitize(MultipleLine) + "\n"
F.write(MultipleLine)
- Done(File,F,None)
+ Done(File, F, None)
userfiles.append(os.path.basename(File))
# Oops, something unspeakable happened.
except IOError:
- Die(File,F,None)
- Die(masterFileName,masterFile,None)
- raise
+ Die(File, F, None)
+ Die(masterFileName, masterFile, None)
+ raise
return userfiles
to.uname = f
to.gname = grname
to.mode = 0400
- tf.addfile(to, file(os.path.join(GlobalDir, 'userkeys', f)))
+
+ contents = file(os.path.join(GlobalDir, 'userkeys', f)).read()
+ lines = []
+ for line in contents.splitlines():
+ if line.startswith("allowed_hosts=") and ' ' in line:
+ machines, line = line.split('=', 1)[1].split(' ', 1)
+ if CurrentHost not in machines.split(','):
+ continue # skip this key
+ lines.append(line)
+ if not lines:
+ continue # no keys for this host
+ contents = "\n".join(lines)
+ to.size = len(contents)
+ tf.addfile(to, StringIO(contents))
tf.close()
os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
# let's see if we handled this group already
if group in existingGroups:
- continue
+ continue
if not GroupIDMap.has_key(group):
print "Group", group, "does not exist but", uid, "is in it"
addGroups(existingGroups, SubGroupMap[group], uid)
# Generate the group list
-def GenGroup(l,File):
+def GenGroup(File):
grouprevmap = {}
F = None
try:
- F = open(File + ".tdb.tmp","w")
+ F = open(File + ".tdb.tmp", "w")
# Generate the GroupMap
GroupMap = {}
for x in GroupIDMap.keys():
GroupMap[x] = []
+ GroupHasPrimaryMembers = {}
# Fetch all the users
global PasswdAttrs
# Sort them into a list of groups having a set of users
for x in PasswdAttrs:
- uid = GetAttr(x,"uid")
- if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
+ uid = GetAttr(x, "uid")
+ if 'gidNumber' in x[1]:
+ GroupHasPrimaryMembers[ int(x[1]["gidNumber"][0]) ] = True
+ if x[1].has_key("uidNumber") == 0 or not IsInGroup(x):
continue
if x[1].has_key("supplementaryGid") == 0:
continue
# Output the group file.
J = 0
for x in GroupMap.keys():
- grouprevmap[GroupIDMap[x]] = x
if GroupIDMap.has_key(x) == 0:
continue
- Line = "%s:x:%u:" % (x,GroupIDMap[x])
+
+ if len(GroupMap[x]) == 0 and GroupIDMap[x] not in GroupHasPrimaryMembers:
+ continue
+
+ grouprevmap[GroupIDMap[x]] = x
+
+ Line = "%s:x:%u:" % (x, GroupIDMap[x])
Comma = ''
for I in GroupMap[x]:
- Line = Line + ("%s%s" % (Comma,I))
- Comma = ','
+ Line = Line + ("%s%s" % (Comma, I))
+ Comma = ','
Line = Sanitize(Line) + "\n"
- F.write("0%u %s" % (J,Line))
- F.write(".%s %s" % (x,Line))
- F.write("=%u %s" % (GroupIDMap[x],Line))
+ F.write("0%u %s" % (J, Line))
+ F.write(".%s %s" % (x, Line))
+ F.write("=%u %s" % (GroupIDMap[x], Line))
J = J + 1
# Oops, something unspeakable happened.
except:
- Die(File,None,F)
+ Die(File, None, F)
raise
- Done(File,None,F)
+ Done(File, None, F)
return grouprevmap
if x[1].has_key("emailForward") == 0:
continue
- if IsInGroup(x) == 0:
+ if not IsInGroup(x):
x[1].pop("emailForward")
continue
# Do not allow people to try to buffer overflow busted parsers
- if len(GetAttr(x,"emailForward")) > 200:
+ if len(GetAttr(x, "emailForward")) > 200:
x[1].pop("emailForward")
continue
# Check the forwarding address
- if EmailCheck.match(GetAttr(x,"emailForward")) == None:
+ if EmailCheck.match(GetAttr(x, "emailForward")) == None:
x[1].pop("emailForward")
# Generate the email forwarding list
-def GenForward(l,File):
+def GenForward(File):
F = None
try:
OldMask = os.umask(0022)
- F = open(File + ".tmp","w",0644)
+ F = open(File + ".tmp", "w", 0644)
os.umask(OldMask)
# Fetch all the users
if x[1].has_key("emailForward") == 0:
continue
- Line = "%s: %s" % (GetAttr(x,"uid"),GetAttr(x,"emailForward"))
+ Line = "%s: %s" % (GetAttr(x, "uid"), GetAttr(x, "emailForward"))
Line = Sanitize(Line) + "\n"
F.write(Line)
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
-def GenAllForward(l,File):
+def GenCDB(File, Users, Key):
Fdb = None
try:
OldMask = os.umask(0022)
- Fdb = os.popen("cdbmake %s %s.tmp"%(File,File),"w")
+ Fdb = os.popen("cdbmake %s %s.tmp"%(File, File), "w")
os.umask(OldMask)
-
- # Fetch all the users
- global PasswdAttrs
-
+
# Write out the email address for each user
- for x in PasswdAttrs:
- if x[1].has_key("emailForward") == 0:
+ for x in Users:
+ if not Key in x[1]:
continue
-
- # Do not allow people to try to buffer overflow busted parsers
- Forward = GetAttr(x,"emailForward")
-
- User = GetAttr(x,"uid")
- Fdb.write("+%d,%d:%s->%s\n"%(len(User),len(Forward),User,Forward))
-
+ Value = GetAttr(x, Key)
+ User = GetAttr(x, "uid")
+ Fdb.write("+%d,%d:%s->%s\n" % (len(User), len(Value), User, Value))
+
Fdb.write("\n")
# Oops, something unspeakable happened.
except:
raise "cdbmake gave an error"
# Generate the anon XEarth marker file
-def GenMarkers(l,File):
+def GenMarkers(File):
F = None
try:
- F = open(File + ".tmp","w")
+ F = open(File + ".tmp", "w")
# Fetch all the users
global PasswdAttrs
if x[1].has_key("latitude") == 0 or x[1].has_key("longitude") == 0:
continue
try:
- Line = "%8s %8s \"\""%(DecDegree(GetAttr(x,"latitude"),1),DecDegree(GetAttr(x,"longitude"),1))
+ Line = "%8s %8s \"\""%(DecDegree(GetAttr(x, "latitude"), 1), DecDegree(GetAttr(x, "longitude"), 1))
Line = Sanitize(Line) + "\n"
F.write(Line)
except:
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
# Generate the debian-private subscription list
-def GenPrivate(l,File):
+def GenPrivate(File):
F = None
try:
- F = open(File + ".tmp","w")
+ F = open(File + ".tmp", "w")
# Fetch all the users
- global PasswdAttrs
+ global DebianDDUsers
# Write out the position for each user
- for x in PasswdAttrs:
+ for x in DebianDDUsers:
if x[1].has_key("privateSub") == 0:
continue
if x[1].has_key("keyFingerPrint") == 0:
continue
- # Must be in the Debian group (yuk, hard coded for now)
- if GetAttr(x,"gidNumber") != "800":
- continue
-
try:
- Line = "%s"%(GetAttr(x,"privateSub"))
+ Line = "%s"%(GetAttr(x, "privateSub"))
Line = Sanitize(Line) + "\n"
F.write(Line)
except:
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
# Generate a list of locked accounts
-def GenDisabledAccounts(l,File):
+def GenDisabledAccounts(File):
F = None
try:
- F = open(File + ".tmp","w")
+ F = open(File + ".tmp", "w")
# Fetch all the users
global PasswdAttrs
if x[1].has_key("uidNumber") == 0:
continue
- Pass = GetAttr(x,"userPassword")
+ Pass = GetAttr(x, "userPassword")
Line = ""
# *LK* is the reference value for a locked account
# password starting with ! is also a locked account
if Pass.find("*LK*") != -1 or Pass.startswith("!"):
# Format is <login>:<reason>
- Line = "%s:%s" % (GetAttr(x,"uid"), "Account is locked")
+ Line = "%s:%s" % (GetAttr(x, "uid"), "Account is locked")
+ DisabledUsers.append(x)
if Line != "":
F.write(Sanitize(Line) + "\n")
- DisabledUsers.append(x)
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
# Generate the list of local addresses that refuse all mail
-def GenMailDisable(l,File):
+def GenMailDisable(File):
F = None
try:
- F = open(File + ".tmp","w")
+ F = open(File + ".tmp", "w")
# Fetch all the users
global PasswdAttrs
Reason = None
if x[1].has_key("mailDisableMessage"):
- Reason = GetAttr(x,"mailDisableMessage")
+ Reason = GetAttr(x, "mailDisableMessage")
else:
continue
- # Must be in the Debian group (yuk, hard coded for now)
- if GetAttr(x,"gidNumber") != "800":
- continue
-
try:
- Line = "%s: %s"%(GetAttr(x,"uid"),Reason)
+ Line = "%s: %s"%(GetAttr(x, "uid"), Reason)
Line = Sanitize(Line) + "\n"
F.write(Line)
except:
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
# Generate a list of uids that should have boolean affects applied
-def GenMailBool(l,File,Key):
+def GenMailBool(File, Key):
F = None
try:
- F = open(File + ".tmp","w")
+ F = open(File + ".tmp", "w")
# Fetch all the users
global PasswdAttrs
if x[1].has_key(Key) == 0:
continue
- # Must be in the Debian group (yuk, hard coded for now)
- if GetAttr(x,"gidNumber") != "800":
- continue
-
- if GetAttr(x,Key) != "TRUE":
+ if GetAttr(x, Key) != "TRUE":
continue
try:
- Line = "%s"%(GetAttr(x,"uid"))
+ Line = "%s"%(GetAttr(x, "uid"))
Line = Sanitize(Line) + "\n"
F.write(Line)
except:
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
# Generate a list of hosts for RBL or whitelist purposes.
-def GenMailList(l,File,Key):
+def GenMailList(File, Key):
F = None
try:
- F = open(File + ".tmp","w")
+ F = open(File + ".tmp", "w")
# Fetch all the users
global PasswdAttrs
if x[1].has_key(Key) == 0:
continue
- # Must be in the Debian group (yuk, hard coded for now)
- if GetAttr(x,"gidNumber") != "800":
- continue
-
try:
found = 0
Line = None
for z in x[1][Key]:
if Key == "mailWhitelist":
- if re.match('^[-\w.]+(/[\d]+)?$',z) == None:
- continue
+ if re.match('^[-\w.]+(/[\d]+)?$', z) == None:
+ continue
else:
- if re.match('^[-\w.]+$',z) == None:
- continue
+ if re.match('^[-\w.]+$', z) == None:
+ continue
if found == 0:
- found = 1
- Line = GetAttr(x,"uid")
+ found = 1
+ Line = GetAttr(x, "uid")
else:
Line += " "
Line += ": " + z
if Key == "mailRHSBL":
- Line += "/$sender_address_domain"
+ Line += "/$sender_address_domain"
if Line != None:
- Line = Sanitize(Line) + "\n"
- F.write(Line)
+ Line = Sanitize(Line) + "\n"
+ F.write(Line)
except:
pass
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
def isRoleAccount(pwEntry):
if not pwEntry.has_key("objectClass"):
return False
# Generate the DNS Zone file
-def GenDNS(l,File,HomePrefix):
+def GenDNS(File):
F = None
try:
- F = open(File + ".tmp","w")
+ F = open(File + ".tmp", "w")
+# global HostAttrs
+#
+# for x in HostAttrs:
+# if x[1].has_key("hostname") == 0 or \
+# x[1].has_key("architecture") == 0 or\
+# x[1].has_key("sshRSAHostKey") == 0:
+# continue
+#
+# if IsDebianHost.match(GetAttr(x, "hostname")) is not None:
+# continue
+#
+# DNSInfo = ExtractDNSInfo(x)
+# start = True
+# for Line in DNSInfo:
+# if start == True:
+# Line = "%s.\t%s" % (GetAttr(x, "hostname"), Line)
+# start = False
+# else:
+# Line = "\t\t\t%s" % (Line)
+# F.write(Line + "\n")
+
# Fetch all the users
global PasswdAttrs
for z in x[1]["dnsZoneEntry"]:
Split = z.lower().split()
if Split[1].lower() == 'in':
- for y in range(0,len(Split)):
+ for y in range(0, len(Split)):
if Split[y] == "$":
Split[y] = "\n\t"
Line = " ".join(Split) + "\n"
Host = Split[0] + DNSZone
if BSMTPCheck.match(Line) != None:
- F.write("; Has BSMTP\n")
+ F.write("; Has BSMTP\n")
# Write some identification information
if Split[2].lower() == "a":
- Line = "%s IN TXT \"%s\"\n"%(Split[0],EmailAddress(x))
+ Line = "%s IN TXT \"%s\"\n"%(Split[0], EmailAddress(x))
for y in x[1]["keyFingerPrint"]:
- Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0],FormatPGPKey(y))
+ Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0], FormatPGPKey(y))
F.write(Line)
else:
Line = "; Err %s"%(str(Split))
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
+
+def ExtractDNSInfo(x):
+
+ TTLprefix="\t"
+ if 'dnsTTL' in x[1]:
+ TTLprefix="%s\t"%(x[1]["dnsTTL"][0])
+
+ DNSInfo = []
+ if x[1].has_key("ipHostNumber"):
+ for I in x[1]["ipHostNumber"]:
+ if IsV6Addr.match(I) != None:
+ DNSInfo.append("%sIN\tAAAA\t%s" % (TTLprefix, I))
+ else:
+ DNSInfo.append("%sIN\tA\t%s" % (TTLprefix, I))
+
+ Algorithm = None
+
+ if 'sshRSAHostKey' in x[1]:
+ for I in x[1]["sshRSAHostKey"]:
+ Split = I.split()
+ if Split[0] == 'ssh-rsa':
+ Algorithm = 1
+ if Split[0] == 'ssh-dss':
+ Algorithm = 2
+ if Algorithm == None:
+ continue
+ Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
+ DNSInfo.append("%sIN\tSSHFP\t%u 1 %s" % (TTLprefix, Algorithm, Fingerprint))
+
+ if 'architecture' in x[1]:
+ Arch = GetAttr(x, "architecture")
+ Mach = ""
+ if x[1].has_key("machine"):
+ Mach = " " + GetAttr(x, "machine")
+ DNSInfo.append("%sIN\tHINFO\t\"%s%s\" \"%s\"" % (TTLprefix, Arch, Mach, "Debian GNU/Linux"))
+
+ if x[1].has_key("mXRecord"):
+ for I in x[1]["mXRecord"]:
+ DNSInfo.append("%sIN\tMX\t%s" % (TTLprefix, I))
-# Generate the DNS SSHFP records
-def GenSSHFP(l,File,HomePrefix):
+ return DNSInfo
+
+# Generate the DNS records
+def GenZoneRecords(File):
F = None
try:
- F = open(File + ".tmp","w")
-
+ F = open(File + ".tmp", "w")
+
# Fetch all the hosts
global HostAttrs
- if HostAttrs == None:
- raise UDEmptyList, "No Hosts"
-
+
for x in HostAttrs:
- if x[1].has_key("hostname") == 0 or \
- x[1].has_key("sshRSAHostKey") == 0:
+ if x[1].has_key("hostname") == 0:
continue
- Host = GetAttr(x,"hostname")
- Algorithm = None
- for I in x[1]["sshRSAHostKey"]:
- Split = I.split()
- if Split[0] == 'ssh-rsa':
- Algorithm = 1
- if Split[0] == 'ssh-dss':
- Algorithm = 2
- if Algorithm == None:
- continue
- Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
- Line = "%s. IN SSHFP %u 1 %s" % (Host,Algorithm,Fingerprint)
- Line = Sanitize(Line) + "\n"
- F.write(Line)
+
+ if IsDebianHost.match(GetAttr(x, "hostname")) is None:
+ continue
+
+ DNSInfo = ExtractDNSInfo(x)
+ start = True
+ for Line in DNSInfo:
+ if start == True:
+ Line = "%s.\t%s" % (GetAttr(x, "hostname"), Line)
+ start = False
+ else:
+ Line = "\t\t\t%s" % (Line)
+
+ F.write(Line + "\n")
+
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
# Generate the BSMTP file
-def GenBSMTP(l,File,HomePrefix):
+def GenBSMTP(File, HomePrefix):
F = None
try:
- F = open(File + ".tmp","w")
+ F = open(File + ".tmp", "w")
# Fetch all the users
global PasswdAttrs
for z in x[1]["dnsZoneEntry"]:
Split = z.lower().split()
if Split[1].lower() == 'in':
- for y in range(0,len(Split)):
+ for y in range(0, len(Split)):
if Split[y] == "$":
Split[y] = "\n\t"
Line = " ".join(Split) + "\n"
Host = Split[0] + DNSZone
if BSMTPCheck.match(Line) != None:
F.write("%s: user=%s group=Debian file=%s%s/bsmtp/%s\n"%(Host,
- GetAttr(x,"uid"),HomePrefix,GetAttr(x,"uid"),Host))
+ GetAttr(x, "uid"), HomePrefix, GetAttr(x, "uid"), Host))
except:
F.write("; Errors\n")
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
-# cache IP adresses
-HostToIPCache = {}
-def HostToIP(Host):
- global HostToIPCache
- if not Host in HostToIPCache:
- IPAdressesT = None
- try:
- IPAdressesT = list(set([ (a[0],a[4][0]) for a in socket.getaddrinfo(Host, None)]))
- except socket.gaierror, (code):
- if code[0] != -2:
- raise
- IPAdresses = []
- if not IPAdressesT is None:
- for addr in IPAdressesT:
- if addr[0] == socket.AF_INET:
- IPAdresses += [addr[1], "::ffff:"+addr[1]]
- else:
- IPAdresses += [addr[1]]
- HostToIPCache[Host] = IPAdresses
- return HostToIPCache[Host]
+def HostToIP(Host, mapped=True):
+
+ IPAdresses = []
+
+ if Host[1].has_key("ipHostNumber"):
+ for addr in Host[1]["ipHostNumber"]:
+ IPAdresses.append(addr)
+ if IsV6Addr.match(addr) is None and mapped == "True":
+ IPAdresses.append("::ffff:"+addr)
+
+ return IPAdresses
# Generate the ssh known hosts file
-def GenSSHKnown(l,File,mode=None):
+def GenSSHKnown(File, mode=None):
F = None
try:
OldMask = os.umask(0022)
- F = open(File + ".tmp","w",0644)
+ F = open(File + ".tmp", "w", 0644)
os.umask(OldMask)
global HostAttrs
- if HostAttrs == None:
- raise UDEmptyList, "No Hosts"
for x in HostAttrs:
if x[1].has_key("hostname") == 0 or \
x[1].has_key("sshRSAHostKey") == 0:
continue
- Host = GetAttr(x,"hostname")
+ Host = GetAttr(x, "hostname")
HostNames = [ Host ]
if Host.endswith(HostDomain):
- HostNames.append(Host[:-(len(HostDomain)+1)])
+ HostNames.append(Host[:-(len(HostDomain) + 1)])
# in the purpose field [[host|some other text]] (where some other text is optional)
# makes a hyperlink on the web thing. we now also add these hosts to the ssh known_hosts
# file. But so that we don't have to add everything we link we can add an asterisk
# and say [[*... to ignore it. In order to be able to add stuff to ssh without
# http linking it we also support [[-hostname]] entries.
- for i in x[1].get("purpose",[]):
+ for i in x[1].get("purpose", []):
m = PurposeHostField.match(i)
if m:
m = m.group(1)
if m:
HostNames.append(m)
if m.endswith(HostDomain):
- HostNames.append(m[:-(len(HostDomain)+1)])
+ HostNames.append(m[:-(len(HostDomain) + 1)])
for I in x[1]["sshRSAHostKey"]:
if mode and mode == 'authorized_keys':
- #Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,from="%s" %s' % (Host, ",".join(HNames + HostToIP(Host)), I)
- Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
+ hosts = HostToIP(x)
+ if 'sshdistAuthKeysHost' in x[1]:
+ hosts += x[1]['sshdistAuthKeysHost']
+ Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,from="%s" %s' % (Host, ",".join(hosts), I)
+ #Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
else:
- Line = "%s %s" %(",".join(HostNames + HostToIP(Host)), I)
+ Line = "%s %s" %(",".join(HostNames + HostToIP(x, False)), I)
Line = Sanitize(Line) + "\n"
F.write(Line)
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
+ Die(File, F, None)
raise
- Done(File,F,None)
+ Done(File, F, None)
# Generate the debianhosts file (list of all IP addresses)
-def GenHosts(l,File):
+def GenHosts(File):
F = None
try:
OldMask = os.umask(0022)
- F = open(File + ".tmp","w",0644)
+ F = open(File + ".tmp", "w", 0644)
os.umask(OldMask)
- # Fetch all the hosts
- hostnames = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "hostname=*",
- ["hostname"])
-
- if hostnames == None:
- raise UDEmptyList, "No Hosts"
-
seen = set()
- for x in hostnames:
- host = GetAttr(x,"hostname", None)
- if host:
- addrs = []
- try:
- addrs += socket.getaddrinfo(host, None, socket.AF_INET)
- except socket.error:
- pass
- try:
- addrs += socket.getaddrinfo(host, None, socket.AF_INET6)
- except socket.error:
- pass
-
- for addrinfo in addrs:
- if addrinfo[0] in (socket.AF_INET, socket.AF_INET6):
- addr = addrinfo[4][0]
- if addr not in seen:
- print >> F, addrinfo[4][0]
- seen.add(addr)
+
+ global HostAttrs
+
+ for x in HostAttrs:
+
+ if IsDebianHost.match(GetAttr(x, "hostname")) is None:
+ continue
+
+ if not 'ipHostNumber' in x[1]:
+ continue
+
+ addrs = x[1]["ipHostNumber"]
+ for addr in addrs:
+ if addr not in seen:
+ seen.add(addr)
+ addr = Sanitize(addr) + "\n"
+ F.write(addr)
+
# Oops, something unspeakable happened.
except:
- Die(File,F,None)
- raise
- Done(File,F,None)
+ Die(File, F, None)
+ raise
+ Done(File, F, None)
-def GenKeyrings(l,OutDir):
+def GenKeyrings(OutDir):
for k in Keyrings:
shutil.copy(k, OutDir)
-
# Connect to the ldap server
l = connectLDAP()
-F = open(PassDir+"/pass-"+pwd.getpwuid(os.getuid())[0],"r")
+F = open(PassDir + "/pass-" + pwd.getpwuid(os.getuid())[0], "r")
Pass = F.readline().strip().split(" ")
F.close()
-l.simple_bind_s("uid="+Pass[0]+","+BaseDn,Pass[1])
+l.simple_bind_s("uid=" + Pass[0] + "," + BaseDn, Pass[1])
# Fetch all the groups
GroupIDMap = {}
-Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"gid=*",\
- ["gid","gidNumber","subGroup"])
+Attrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "gid=*",\
+ ["gid", "gidNumber", "subGroup"])
# Generate the SubGroupMap and GroupIDMap
for x in Attrs:
+ if x[1].has_key("accountStatus") and x[1]['accountStatus'] == "disabled":
+ continue
if x[1].has_key("gidNumber") == 0:
continue
GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0])
SubGroupMap.setdefault(x[1]["gid"][0], []).extend(x[1]["subGroup"])
# Fetch all the users
-PasswdAttrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=*",\
- ["uid","uidNumber","gidNumber","supplementaryGid",\
- "gecos","loginShell","userPassword","shadowLastChange",\
- "shadowMin","shadowMax","shadowWarning","shadowInactive",
- "shadowExpire","emailForward","latitude","longitude",\
- "allowedHost","sshRSAAuthKey","dnsZoneEntry","cn","sn",\
- "keyFingerPrint","privateSub","mailDisableMessage",\
- "mailGreylisting","mailCallout","mailRBL","mailRHSBL",\
- "mailWhitelist", "sudoPassword", "objectClass", "accountStatus"])
+PasswdAttrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "uid=*",\
+ ["uid", "uidNumber", "gidNumber", "supplementaryGid",\
+ "gecos", "loginShell", "userPassword", "shadowLastChange",\
+ "shadowMin", "shadowMax", "shadowWarning", "shadowInactive",
+ "shadowExpire", "emailForward", "latitude", "longitude",\
+ "allowedHost", "sshRSAAuthKey", "dnsZoneEntry", "cn", "sn",\
+ "keyFingerPrint", "privateSub", "mailDisableMessage",\
+ "mailGreylisting", "mailCallout", "mailRBL", "mailRHSBL",\
+ "mailWhitelist", "sudoPassword", "objectClass", "accountStatus",\
+ "mailContentInspectionAction"])
if PasswdAttrs is None:
raise UDEmptyList, "No Users"
+PasswdAttrs.sort(lambda x, y: cmp((GetAttr(x, "uid")).lower(), (GetAttr(y, "uid")).lower()))
+
# Fetch all the hosts
-HostAttrs = l.search_s(HostBaseDn,ldap.SCOPE_ONELEVEL,"sshRSAHostKey=*",\
- ["hostname","sshRSAHostKey","purpose"])
+HostAttrs = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "objectClass=debianServer",\
+ ["hostname", "sshRSAHostKey", "purpose", "allowedGroups", "exportOptions",\
+ "mXRecord", "ipHostNumber", "dnsTTL", "machine", "architecture"])
-# Open the control file
-if len(sys.argv) == 1:
- F = open(GenerateConf,"r")
-else:
- F = open(sys.argv[1],"r")
+if HostAttrs == None:
+ raise UDEmptyList, "No Hosts"
-# Generate global things
-GlobalDir = GenerateDir+"/"
-GenMailDisable(l,GlobalDir+"mail-disable")
+HostAttrs.sort(lambda x, y: cmp((GetAttr(x, "hostname")).lower(), (GetAttr(y, "hostname")).lower()))
-for x in PasswdAttrs:
- if IsRetired(x):
- RetiredUsers.append(x)
+# Generate global things
+GlobalDir = GenerateDir + "/"
+GenDisabledAccounts(GlobalDir + "disabled-accounts")
-PasswdAttrs = filter(lambda x: not x in RetiredUsers, PasswdAttrs)
+PasswdAttrs = filter(lambda x: not IsRetired(x), PasswdAttrs)
+DebianDDUsers = filter(lambda x: IsGidDebian(x), PasswdAttrs)
CheckForward()
-SSHFiles = GenSSHShadow(l)
-GenAllForward(l,GlobalDir+"mail-forward.cdb")
-GenMarkers(l,GlobalDir+"markers")
-GenPrivate(l,GlobalDir+"debian-private")
-GenDisabledAccounts(l,GlobalDir+"disabled-accounts")
-GenSSHKnown(l,GlobalDir+"ssh_known_hosts")
-#GenSSHKnown(l,GlobalDir+"authorized_keys", 'authorized_keys')
-GenHosts(l,GlobalDir+"debianhosts")
-GenMailBool(l,GlobalDir+"mail-greylist","mailGreylisting")
-GenMailBool(l,GlobalDir+"mail-callout","mailCallout")
-GenMailList(l,GlobalDir+"mail-rbl","mailRBL")
-GenMailList(l,GlobalDir+"mail-rhsbl","mailRHSBL")
-GenMailList(l,GlobalDir+"mail-whitelist","mailWhitelist")
-GenKeyrings(l,GlobalDir)
+GenMailDisable(GlobalDir + "mail-disable")
+GenCDB(GlobalDir + "mail-forward.cdb", PasswdAttrs, 'emailForward')
+GenCDB(GlobalDir + "mail-contentinspectionaction.cdb", PasswdAttrs, 'mailContentInspectionAction')
+GenPrivate(GlobalDir + "debian-private")
+GenSSHKnown(GlobalDir+"authorized_keys", 'authorized_keys')
+GenMailBool(GlobalDir + "mail-greylist", "mailGreylisting")
+GenMailBool(GlobalDir + "mail-callout", "mailCallout")
+GenMailList(GlobalDir + "mail-rbl", "mailRBL")
+GenMailList(GlobalDir + "mail-rhsbl", "mailRHSBL")
+GenMailList(GlobalDir + "mail-whitelist", "mailWhitelist")
+GenKeyrings(GlobalDir)
# Compatibility.
-GenForward(l,GlobalDir+"forward-alias")
+GenForward(GlobalDir + "forward-alias")
PasswdAttrs = filter(lambda x: not x in DisabledUsers, PasswdAttrs)
-while(1):
- Line = F.readline()
- if Line == "":
- break
- Line = Line.strip()
- if Line == "":
- continue
- if Line[0] == '#':
+SSHFiles = GenSSHShadow()
+GenMarkers(GlobalDir + "markers")
+GenSSHKnown(GlobalDir + "ssh_known_hosts")
+GenHosts(GlobalDir + "debianhosts")
+
+for host in HostAttrs:
+ if not "hostname" in host[1]:
continue
- Split = Line.split(" ")
- OutDir = GenerateDir + '/' + Split[0] + '/'
+ CurrentHost = host[1]['hostname'][0]
+ OutDir = GenerateDir + '/' + CurrentHost + '/'
try:
os.mkdir(OutDir)
except:
# Get the group list and convert any named groups to numerics
GroupList = {}
+ for groupname in AllowedGroupsPreload.strip().split(" "):
+ GroupList[groupname] = True
+ if 'allowedGroups' in host[1]:
+ for groupname in host[1]['allowedGroups']:
+ GroupList[groupname] = True
+ for groupname in GroupList.keys():
+ if groupname in GroupIDMap:
+ GroupList[str(GroupIDMap[groupname])] = True
+
ExtraList = {}
- for I in Split[2:]:
- if I[0] == '[':
- ExtraList[I] = None
- continue
- GroupList[I] = None
- if GroupIDMap.has_key(I):
- GroupList[str(GroupIDMap[I])] = None
+ if 'exportOptions' in host[1]:
+ for extra in host[1]['exportOptions']:
+ ExtraList[extra.upper()] = True
Allowed = GroupList
if Allowed == {}:
- Allowed = None
- CurrentHost = Split[0]
+ Allowed = None
- DoLink(GlobalDir,OutDir,"debianhosts")
- DoLink(GlobalDir,OutDir,"ssh_known_hosts")
- DoLink(GlobalDir,OutDir,"disabled-accounts")
+ DoLink(GlobalDir, OutDir, "debianhosts")
+ DoLink(GlobalDir, OutDir, "ssh_known_hosts")
+ DoLink(GlobalDir, OutDir, "disabled-accounts")
sys.stdout.flush()
- if ExtraList.has_key("[NOPASSWD]"):
- userlist = GenPasswd(l,OutDir+"passwd",Split[1], "*")
+ if 'NOPASSWD' in ExtraList:
+ userlist = GenPasswd(OutDir + "passwd", HomePrefix, "*")
else:
- userlist = GenPasswd(l,OutDir+"passwd",Split[1], "x")
+ userlist = GenPasswd(OutDir + "passwd", HomePrefix, "x")
sys.stdout.flush()
- grouprevmap = GenGroup(l,OutDir+"group")
- GenShadowSudo(l, OutDir+"sudo-passwd", ExtraList.has_key("[UNTRUSTED]") or ExtraList.has_key("[NOPASSWD]"))
+ grouprevmap = GenGroup(OutDir + "group")
+ GenShadowSudo(OutDir + "sudo-passwd", ('UNTRUSTED' in ExtraList) or ('NOPASSWD' in ExtraList))
# Now we know who we're allowing on the machine, export
# the relevant ssh keys
GenSSHtarballs(userlist, SSHFiles, grouprevmap, os.path.join(OutDir, 'ssh-keys.tar.gz'))
- if ExtraList.has_key("[UNTRUSTED]"):
- print "[UNTRUSTED] tag is obsolete and may be removed in the future."
- continue
- if not ExtraList.has_key("[NOPASSWD]"):
- GenShadow(l,OutDir+"shadow")
+ if not 'NOPASSWD' in ExtraList:
+ GenShadow(OutDir + "shadow")
# Link in global things
- if not ExtraList.has_key("[NOMARKERS]"):
- DoLink(GlobalDir,OutDir,"markers")
- DoLink(GlobalDir,OutDir,"mail-forward.cdb")
- DoLink(GlobalDir,OutDir,"mail-disable")
- DoLink(GlobalDir,OutDir,"mail-greylist")
- DoLink(GlobalDir,OutDir,"mail-callout")
- DoLink(GlobalDir,OutDir,"mail-rbl")
- DoLink(GlobalDir,OutDir,"mail-rhsbl")
- DoLink(GlobalDir,OutDir,"mail-whitelist")
+ if not 'NOMARKERS' in ExtraList:
+ DoLink(GlobalDir, OutDir, "markers")
+ DoLink(GlobalDir, OutDir, "mail-forward.cdb")
+ DoLink(GlobalDir, OutDir, "mail-contentinspectionaction.cdb")
+ DoLink(GlobalDir, OutDir, "mail-disable")
+ DoLink(GlobalDir, OutDir, "mail-greylist")
+ DoLink(GlobalDir, OutDir, "mail-callout")
+ DoLink(GlobalDir, OutDir, "mail-rbl")
+ DoLink(GlobalDir, OutDir, "mail-rhsbl")
+ DoLink(GlobalDir, OutDir, "mail-whitelist")
+ GenCDB(OutDir + "user-forward.cdb", filter(lambda x: IsInGroup(x), PasswdAttrs), 'emailForward')
+ GenCDB(OutDir + "batv-tokens.cdb", filter(lambda x: IsInGroup(x), PasswdAttrs), 'bATVToken')
+ GenCDB(OutDir + "default-mail-options.cdb", filter(lambda x: IsInGroup(x), PasswdAttrs), 'mailDefaultOptions')
# Compatibility.
- DoLink(GlobalDir,OutDir,"forward-alias")
+ DoLink(GlobalDir, OutDir, "forward-alias")
+
+ if 'DNS' in ExtraList:
+ GenDNS(OutDir + "dns-zone")
+ GenZoneRecords(OutDir + "dns-sshfp")
- if ExtraList.has_key("[DNS]"):
- GenDNS(l,OutDir+"dns-zone",Split[1])
- GenSSHFP(l,OutDir+"dns-sshfp",Split[1])
+ if 'AUTHKEYS' in ExtraList:
+ DoLink(GlobalDir, OutDir, "authorized_keys")
- if ExtraList.has_key("[BSMTP]"):
- GenBSMTP(l,OutDir+"bsmtp",Split[1])
+ if 'BSMTP' in ExtraList:
+ GenBSMTP(OutDir + "bsmtp", HomePrefix)
- if ExtraList.has_key("[PRIVATE]"):
- DoLink(GlobalDir,OutDir,"debian-private")
+ if 'PRIVATE' in ExtraList:
+ DoLink(GlobalDir, OutDir, "debian-private")
- if ExtraList.has_key("[KEYRING]"):
+ if 'KEYRING' in ExtraList:
for k in Keyrings:
- DoLink(GlobalDir,OutDir,os.path.basename(k))
+ DoLink(GlobalDir, OutDir, os.path.basename(k))
else:
for k in Keyrings:
try:
- posix.remove(OutDir+os.path.basename(k))
+ posix.remove(OutDir + os.path.basename(k))
except:
pass