# Copyright (c) 2008 Peter Palfrader <peter@palfrader.org>
# Copyright (c) 2008 Andreas Barth <aba@not.so.argh.org>
# Copyright (c) 2008 Mark Hymers <mhy@debian.org>
+# Copyright (c) 2008 Luk Claes <luk@debian.org>
+# Copyright (c) 2008 Thomas Viehmann <tv@beamnet.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
PasswdAttrs = None;
GroupIDMap = {};
+SubGroupMap = {};
Allowed = None;
CurrentHost = "";
EmailCheck = re.compile("^([^ <>@]+@[^ ,<>@]+)?$");
BSMTPCheck = re.compile(".*mx 0 (gluck)\.debian\.org\..*",re.DOTALL);
+PurposeHostField = re.compile(r".*\[\[([\*\-]?[a-z0-9.\-]*)(?:\|.*)?\]\]")
DNSZone = ".debian.net"
Keyrings = ConfModule.sync_keyrings.split(":")
if DnRecord[1].has_key("supplementaryGid") == 0:
return 0;
- # Check the supplementary groups
- for I in DnRecord[1]["supplementaryGid"]:
- s = I.split('@', 1)
- group = s[0]
- if len(s) == 2 and s[1] != CurrentHost:
- continue;
- if Allowed.has_key(group):
+ supgroups=[]
+ addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord,"uid"))
+ for g in supgroups:
+ if Allowed.has_key(g):
return 1;
return 0;
tf.close()
os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
+# add a list of groups to existing groups,
+# including all subgroups thereof, recursively.
+# basically this proceduces the transitive hull of the groups in
+# addgroups.
+def addGroups(existingGroups, newGroups, uid):
+ for group in newGroups:
+ # if it's a <group>@host, split it and verify it's on the current host.
+ s = group.split('@', 1)
+ if len(s) == 2 and s[1] != CurrentHost:
+ continue;
+ group = s[0]
+
+ # let's see if we handled this group already
+ if group in existingGroups:
+ continue
+
+ if not GroupIDMap.has_key(group):
+ print "Group", group, "does not exist but", uid, "is in it"
+ continue
+
+ existingGroups.append(group)
+
+ if SubGroupMap.has_key(group):
+ addGroups(existingGroups, SubGroupMap[group], uid)
+
# Generate the group list
def GenGroup(l,File):
grouprevmap = {}
# 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:
continue;
if x[1].has_key("supplementaryGid") == 0:
continue;
- for I in x[1]["supplementaryGid"]:
- s = I.split('@', 1)
- group = s[0]
- if len(s) == 2 and s[1] != CurrentHost:
- continue;
- if GroupMap.has_key(group):
- GroupMap[group].append(GetAttr(x,"uid"));
- else:
- print "Group does not exist ",group,"but",GetAttr(x,"uid"),"is in it";
+ supgroups=[]
+ addGroups(supgroups, x[1]["supplementaryGid"], uid)
+ for g in supgroups:
+ GroupMap[g].append(uid);
# Output the group file.
J = 0;
raise;
Done(File,F,None);
+def isRoleAccount(pwEntry):
+ if not pwEntry.has_key("objectClass"):
+ raise "pwEntry has no objectClass"
+ oc = pwEntry['objectClass']
+ try:
+ i = oc.index('debianRoleAccount')
+ return True
+ except ValueError:
+ return False
+
# Generate the DNS Zone file
def GenDNS(l,File,HomePrefix):
F = None;
continue;
# If the account has no PGP key, do not write it
- if x[1].has_key("keyFingerPrint") == 0:
+ if x[1].has_key("keyFingerPrint") == 0 and not isRoleAccount(x[1]):
continue;
try:
F.write("; %s\n"%(EmailAddress(x)));
except socket.gaierror, (code):
if code[0] != -2: raise
IPAdresses = []
- for addr in IPAdressesT:
- if addr[0] == socket.AF_INET: IPAdresses += [addr[1], "::ffff:"+addr[1]]
- else: IPAdresses += [addr[1]]
+ 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]
continue;
Host = GetAttr(x,"hostname");
HostNames = [ Host ]
- SHost = Host.find(".")
- if SHost != None: HostNames += [Host[0:SHost]]
+ if Host.endswith(HostDomain):
+ 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",[]):
+ m = PurposeHostField.match(i)
+ if m:
+ m = m.group(1)
+ # we ignore [[*..]] entries
+ if m.startswith('*'):
+ continue;
+ if m.startswith('-'):
+ m = m[1:]
+ if m:
+ HostNames.append(m)
+ if m.endswith(HostDomain):
+ HostNames.append(m[:-(len(HostDomain)+1)])
for I in x[1]["sshRSAHostKey"]:
if mode and mode == 'authorized_keys':
# Generate the debianhosts file (list of all IP addresses)
def GenHosts(l,File):
- F = None;
+ F = None
try:
- OldMask = os.umask(0022);
- 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 "No Hosts";
-
- for x in HostNames:
- if x[1].has_key("hostname") == 0:
- continue;
- Host = GetAttr(x,"hostname");
- try:
- Addr = socket.gethostbyname(Host);
- F.write(Addr + "\n");
- except:
- pass
+ OldMask = os.umask(0022)
+ 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 "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)
# 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):
for k in Keyrings:
# Fetch all the groups
GroupIDMap = {};
Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"gid=*",\
- ["gid","gidNumber"]);
+ ["gid","gidNumber","subGroup"]);
-# Generate the GroupMap and GroupIDMap
+# Generate the SubGroupMap and GroupIDMap
for x in Attrs:
if x[1].has_key("gidNumber") == 0:
continue;
GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0]);
+ if x[1].has_key("subGroup") != 0:
+ SubGroupMap.setdefault(x[1]["gid"][0], []).extend(x[1]["subGroup"]);
# Fetch all the users
PasswdAttrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=*",\
"allowedHost","sshRSAAuthKey","dnsZoneEntry","cn","sn",\
"keyFingerPrint","privateSub","mailDisableMessage",\
"mailGreylisting","mailCallout","mailRBL","mailRHSBL",\
- "mailWhitelist", "sudoPassword"]);
+ "mailWhitelist", "sudoPassword", "objectClass"]);
# Fetch all the hosts
HostAttrs = l.search_s(HostBaseDn,ldap.SCOPE_ONELEVEL,"sshRSAHostKey=*",\
- ["hostname","sshRSAHostKey"]);
+ ["hostname","sshRSAHostKey","purpose"]);
# Open the control file
if len(sys.argv) == 1: