3 # Generates passwd, shadow and group files from the ldap directory.
5 # Copyright (c) 2000-2001 Jason Gunthorpe <jgg@debian.org>
6 # Copyright (c) 2003-2004 James Troup <troup@debian.org>
7 # Copyright (c) 2004-2005,7 Joey Schulze <joey@infodrom.org>
8 # Copyright (c) 2001-2007 Ryan Murray <rmurray@debian.org>
9 # Copyright (c) 2008 Peter Palfrader <peter@palfrader.org>
10 # Copyright (c) 2008 Andreas Barth <aba@not.so.argh.org>
11 # Copyright (c) 2008 Mark Hymers <mhy@debian.org>
12 # Copyright (c) 2008 Luk Claes <luk@debian.org>
13 # Copyright (c) 2008 Thomas Viehmann <tv@beamnet.de>
14 # Copyright (c) 2009 Stephen Gran <steve@lobefin.net>
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 import string, re, time, ldap, getopt, sys, os, pwd, posix, socket, base64, sha, shutil, errno, tarfile, grp
31 from userdir_ldap import *
32 from userdir_exceptions import *
45 UUID_FORMAT = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
47 EmailCheck = re.compile("^([^ <>@]+@[^ ,<>@]+)?$")
48 BSMTPCheck = re.compile(".*mx 0 (gluck)\.debian\.org\..*",re.DOTALL)
49 PurposeHostField = re.compile(r"\[\[([\*\-]?[a-z0-9.\-]*)(?:\|.*)?\]\]")
50 DNSZone = ".debian.net"
51 Keyrings = ConfModule.sync_keyrings.split(":")
53 def safe_makedirs(dir):
57 if e.errno == errno.EEXIST:
66 if e.errno == errno.ENOENT:
72 return Str.translate(string.maketrans("\n\r\t", "$$$"))
74 def DoLink(From, To, File):
76 posix.remove(To + File)
79 posix.link(From + File, To + File)
81 def IsRetired(DnRecord):
83 Looks for accountStatus in the LDAP record and tries to
84 match it against one of the known retired statuses
87 status = GetAttr(DnRecord, "accountStatus", None)
94 if status == "inactive":
97 elif status == "memorial":
100 elif status == "retiring":
101 # We'll give them a few extra days over what we said
102 age = 6 * 31 * 24 * 60 * 60
104 return (time.time() - time.mktime(time.strptime(line[1], "%Y-%m-%d"))) > age
114 return int(GetAttr(x, "gidNumber", 0)) == 800
118 # See if this user is in the group list
119 def IsInGroup(DnRecord):
123 # See if the primary group is in the list
124 if Allowed.has_key(GetAttr(DnRecord, "gidNumber")) != 0:
127 # Check the host based ACL
128 if DnRecord[1].has_key("allowedHost") != 0:
129 for I in DnRecord[1]["allowedHost"]:
133 # See if there are supplementary groups
134 if DnRecord[1].has_key("supplementaryGid") == 0:
138 addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord, "uid"))
140 if Allowed.has_key(g):
144 def Die(File, F, Fdb):
150 os.remove(File + ".tmp")
154 os.remove(File + ".tdb.tmp")
158 def Done(File, F, Fdb):
161 os.rename(File + ".tmp", File)
164 os.rename(File + ".tdb.tmp", File + ".tdb")
166 # Generate the password list
167 def GenPasswd(File, HomePrefix, PwdMarker):
170 F = open(File + ".tdb.tmp", "w")
173 # Fetch all the users
177 for x in PasswdAttrs:
178 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
181 # Do not let people try to buffer overflow some busted passwd parser.
182 if len(GetAttr(x, "gecos")) > 100 or len(GetAttr(x, "loginShell")) > 50:
185 userlist[GetAttr(x, "uid")] = int(GetAttr(x, "gidNumber"))
186 Line = "%s:%s:%s:%s:%s:%s%s:%s" % (GetAttr(x, "uid"),\
188 GetAttr(x, "uidNumber"), GetAttr(x, "gidNumber"),\
189 GetAttr(x, "gecos"), HomePrefix, GetAttr(x, "uid"),\
190 GetAttr(x, "loginShell"))
192 Line = Sanitize(Line) + "\n"
193 F.write("0%u %s" % (I, Line))
194 F.write(".%s %s" % (GetAttr(x, "uid"), Line))
195 F.write("=%s %s" % (GetAttr(x, "uidNumber"), Line))
198 # Oops, something unspeakable happened.
204 # Return the list of users so we know which keys to export
207 # Generate the shadow list
211 OldMask = os.umask(0077)
212 F = open(File + ".tdb.tmp", "w", 0600)
215 # Fetch all the users
219 for x in PasswdAttrs:
220 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
223 Pass = GetAttr(x, "userPassword")
224 if Pass[0:7] != "{crypt}" or len(Pass) > 50:
229 # If the account is locked, mark it as such in shadow
230 # See Debian Bug #308229 for why we set it to 1 instead of 0
231 if (GetAttr(x, "userPassword").find("*LK*") != -1) \
232 or GetAttr(x, "userPassword").startswith("!"):
235 ShadowExpire = GetAttr(x, "shadowExpire")
237 Line = "%s:%s:%s:%s:%s:%s:%s:%s:" % (GetAttr(x, "uid"),\
238 Pass, GetAttr(x, "shadowLastChange"),\
239 GetAttr(x, "shadowMin"), GetAttr(x, "shadowMax"),\
240 GetAttr(x, "shadowWarning"), GetAttr(x, "shadowInactive"),\
242 Line = Sanitize(Line) + "\n"
243 F.write("0%u %s" % (I, Line))
244 F.write(".%s %s" % (GetAttr(x, "uid"), Line))
247 # Oops, something unspeakable happened.
253 # Generate the sudo passwd file
254 def GenShadowSudo(File, untrusted):
257 OldMask = os.umask(0077)
258 F = open(File + ".tmp", "w", 0600)
261 # Fetch all the users
264 for x in PasswdAttrs:
266 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
269 if x[1].has_key('sudoPassword'):
270 for entry in x[1]['sudoPassword']:
271 Match = re.compile('^('+UUID_FORMAT+') (confirmed:[0-9a-f]{40}|unconfirmed) ([a-z0-9.,*]+) ([^ ]+)$').match(entry)
274 uuid = Match.group(1)
275 status = Match.group(2)
276 hosts = Match.group(3)
277 cryptedpass = Match.group(4)
279 if status != 'confirmed:'+make_passwd_hmac('password-is-confirmed', 'sudo', x[1]['uid'][0], uuid, hosts, cryptedpass):
281 for_all = hosts == "*"
282 for_this_host = CurrentHost in hosts.split(',')
283 if not (for_all or for_this_host):
285 # ignore * passwords for untrusted hosts, but copy host specific passwords
286 if for_all and untrusted:
289 if for_this_host: # this makes sure we take a per-host entry over the for-all entry
294 Line = "%s:%s" % (GetAttr(x, "uid"), Pass)
295 Line = Sanitize(Line) + "\n"
296 F.write("%s" % (Line))
298 # Oops, something unspeakable happened.
304 # Generate the shadow list
306 # Fetch all the users
311 safe_rmtree(os.path.join(GlobalDir, 'userkeys'))
312 safe_makedirs(os.path.join(GlobalDir, 'userkeys'))
314 for x in PasswdAttrs:
316 if x[1].has_key("uidNumber") == 0 or \
317 x[1].has_key("sshRSAAuthKey") == 0:
320 User = GetAttr(x, "uid")
324 OldMask = os.umask(0077)
325 File = os.path.join(GlobalDir, 'userkeys', User)
326 F = open(File + ".tmp", "w", 0600)
329 for I in x[1]["sshRSAAuthKey"]:
330 MultipleLine = "%s" % I
331 MultipleLine = Sanitize(MultipleLine) + "\n"
332 F.write(MultipleLine)
335 userfiles.append(os.path.basename(File))
337 # Oops, something unspeakable happened.
340 Die(masterFileName, masterFile, None)
345 def GenSSHtarballs(userlist, SSHFiles, grouprevmap, target):
346 OldMask = os.umask(0077)
347 tf = tarfile.open(name=os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), mode='w:gz')
349 for f in userlist.keys():
350 if f not in SSHFiles:
352 # If we're not exporting their primary group, don't export
355 if userlist[f] in grouprevmap.keys():
356 grname = grouprevmap[userlist[f]]
359 if int(userlist[f]) <= 100:
360 # In these cases, look it up in the normal way so we
361 # deal with cases where, for instance, users are in group
362 # users as their primary group.
363 grname = grp.getgrgid(userlist[f])[0]
368 print "User %s is supposed to have their key exported to host %s but their primary group (gid: %d) isn't in LDAP" % (f, CurrentHost, userlist[f])
371 to = tf.gettarinfo(os.path.join(GlobalDir, 'userkeys', f), f)
372 # These will only be used where the username doesn't
373 # exist on the target system for some reason; hence,
374 # in those cases, the safest thing is for the file to
375 # be owned by root but group nobody. This deals with
376 # the bloody obscure case where the group fails to exist
377 # whilst the user does (in which case we want to avoid
378 # ending up with a file which is owned user:root to avoid
379 # a fairly obvious attack vector)
382 # Using the username / groupname fields avoids any need
383 # to give a shit^W^W^Wcare about the UIDoffset stuff.
387 tf.addfile(to, file(os.path.join(GlobalDir, 'userkeys', f)))
390 os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
392 # add a list of groups to existing groups,
393 # including all subgroups thereof, recursively.
394 # basically this proceduces the transitive hull of the groups in
396 def addGroups(existingGroups, newGroups, uid):
397 for group in newGroups:
398 # if it's a <group>@host, split it and verify it's on the current host.
399 s = group.split('@', 1)
400 if len(s) == 2 and s[1] != CurrentHost:
404 # let's see if we handled this group already
405 if group in existingGroups:
408 if not GroupIDMap.has_key(group):
409 print "Group", group, "does not exist but", uid, "is in it"
412 existingGroups.append(group)
414 if SubGroupMap.has_key(group):
415 addGroups(existingGroups, SubGroupMap[group], uid)
417 # Generate the group list
422 F = open(File + ".tdb.tmp", "w")
424 # Generate the GroupMap
426 for x in GroupIDMap.keys():
429 # Fetch all the users
432 # Sort them into a list of groups having a set of users
433 for x in PasswdAttrs:
434 uid = GetAttr(x, "uid")
435 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
437 if x[1].has_key("supplementaryGid") == 0:
441 addGroups(supgroups, x[1]["supplementaryGid"], uid)
443 GroupMap[g].append(uid)
445 # Output the group file.
447 for x in GroupMap.keys():
448 grouprevmap[GroupIDMap[x]] = x
449 if GroupIDMap.has_key(x) == 0:
451 Line = "%s:x:%u:" % (x, GroupIDMap[x])
453 for I in GroupMap[x]:
454 Line = Line + ("%s%s" % (Comma, I))
456 Line = Sanitize(Line) + "\n"
457 F.write("0%u %s" % (J, Line))
458 F.write(".%s %s" % (x, Line))
459 F.write("=%u %s" % (GroupIDMap[x], Line))
462 # Oops, something unspeakable happened.
472 for x in DebianUsers:
473 if x[1].has_key("emailForward") == 0:
476 if IsInGroup(x) == 0:
477 x[1].pop("emailForward")
480 # Do not allow people to try to buffer overflow busted parsers
481 if len(GetAttr(x, "emailForward")) > 200:
482 x[1].pop("emailForward")
485 # Check the forwarding address
486 if EmailCheck.match(GetAttr(x, "emailForward")) == None:
487 x[1].pop("emailForward")
489 # Generate the email forwarding list
490 def GenForward(File):
493 OldMask = os.umask(0022)
494 F = open(File + ".tmp", "w", 0644)
497 # Fetch all the users
500 # Write out the email address for each user
501 for x in DebianUsers:
502 if x[1].has_key("emailForward") == 0:
505 Line = "%s: %s" % (GetAttr(x, "uid"), GetAttr(x, "emailForward"))
506 Line = Sanitize(Line) + "\n"
509 # Oops, something unspeakable happened.
515 def GenAllForward(File):
518 OldMask = os.umask(0022)
519 Fdb = os.popen("cdbmake %s %s.tmp"%(File, File), "w")
522 # Fetch all the users
525 # Write out the email address for each user
526 for x in DebianUsers:
527 if x[1].has_key("emailForward") == 0:
530 # Do not allow people to try to buffer overflow busted parsers
531 Forward = GetAttr(x, "emailForward")
533 User = GetAttr(x, "uid")
534 Fdb.write("+%d,%d:%s->%s\n" % (len(User), len(Forward), User, Forward))
537 # Oops, something unspeakable happened.
541 if Fdb.close() != None:
542 raise "cdbmake gave an error"
544 # Generate the anon XEarth marker file
545 def GenMarkers(File):
548 F = open(File + ".tmp", "w")
550 # Fetch all the users
553 # Write out the position for each user
554 for x in DebianUsers:
555 if x[1].has_key("latitude") == 0 or x[1].has_key("longitude") == 0:
558 Line = "%8s %8s \"\""%(DecDegree(GetAttr(x, "latitude"), 1), DecDegree(GetAttr(x, "longitude"), 1))
559 Line = Sanitize(Line) + "\n"
564 # Oops, something unspeakable happened.
570 # Generate the debian-private subscription list
571 def GenPrivate(File):
574 F = open(File + ".tmp", "w")
576 # Fetch all the users
579 # Write out the position for each user
580 for x in DebianUsers:
581 if x[1].has_key("privateSub") == 0:
584 # If the account has no PGP key, do not write it
585 if x[1].has_key("keyFingerPrint") == 0:
589 Line = "%s"%(GetAttr(x, "privateSub"))
590 Line = Sanitize(Line) + "\n"
595 # Oops, something unspeakable happened.
601 # Generate a list of locked accounts
602 def GenDisabledAccounts(File):
605 F = open(File + ".tmp", "w")
607 # Fetch all the users
612 for x in PasswdAttrs:
613 if x[1].has_key("uidNumber") == 0:
616 Pass = GetAttr(x, "userPassword")
618 # *LK* is the reference value for a locked account
619 # password starting with ! is also a locked account
620 if Pass.find("*LK*") != -1 or Pass.startswith("!"):
621 # Format is <login>:<reason>
622 Line = "%s:%s" % (GetAttr(x, "uid"), "Account is locked")
625 F.write(Sanitize(Line) + "\n")
627 DisabledUsers.append(x)
629 # Oops, something unspeakable happened.
635 # Generate the list of local addresses that refuse all mail
636 def GenMailDisable(File):
639 F = open(File + ".tmp", "w")
641 # Fetch all the users
644 for x in DebianUsers:
647 if x[1].has_key("mailDisableMessage"):
648 Reason = GetAttr(x, "mailDisableMessage")
653 Line = "%s: %s"%(GetAttr(x, "uid"), Reason)
654 Line = Sanitize(Line) + "\n"
659 # Oops, something unspeakable happened.
665 # Generate a list of uids that should have boolean affects applied
666 def GenMailBool(File, Key):
669 F = open(File + ".tmp", "w")
671 # Fetch all the users
674 for x in DebianUsers:
677 if x[1].has_key(Key) == 0:
680 if GetAttr(x, Key) != "TRUE":
684 Line = "%s"%(GetAttr(x, "uid"))
685 Line = Sanitize(Line) + "\n"
690 # Oops, something unspeakable happened.
696 # Generate a list of hosts for RBL or whitelist purposes.
697 def GenMailList(File, Key):
700 F = open(File + ".tmp", "w")
702 # Fetch all the users
705 for x in DebianUsers:
708 if x[1].has_key(Key) == 0:
715 if Key == "mailWhitelist":
716 if re.match('^[-\w.]+(/[\d]+)?$', z) == None:
719 if re.match('^[-\w.]+$', z) == None:
723 Line = GetAttr(x, "uid")
727 if Key == "mailRHSBL":
728 Line += "/$sender_address_domain"
731 Line = Sanitize(Line) + "\n"
736 # Oops, something unspeakable happened.
742 def isRoleAccount(pwEntry):
743 if not pwEntry.has_key("objectClass"):
744 raise "pwEntry has no objectClass"
745 oc = pwEntry['objectClass']
747 i = oc.index('debianRoleAccount')
752 # Generate the DNS Zone file
753 def GenDNS(File, HomePrefix):
756 F = open(File + ".tmp", "w")
758 # Fetch all the users
761 # Write out the zone file entry for each user
762 for x in PasswdAttrs:
763 if x[1].has_key("dnsZoneEntry") == 0:
766 # If the account has no PGP key, do not write it
767 if x[1].has_key("keyFingerPrint") == 0 and not isRoleAccount(x[1]):
770 F.write("; %s\n"%(EmailAddress(x)))
771 for z in x[1]["dnsZoneEntry"]:
772 Split = z.lower().split()
773 if Split[1].lower() == 'in':
774 for y in range(0, len(Split)):
777 Line = " ".join(Split) + "\n"
780 Host = Split[0] + DNSZone
781 if BSMTPCheck.match(Line) != None:
782 F.write("; Has BSMTP\n")
784 # Write some identification information
785 if Split[2].lower() == "a":
786 Line = "%s IN TXT \"%s\"\n"%(Split[0], EmailAddress(x))
787 for y in x[1]["keyFingerPrint"]:
788 Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0], FormatPGPKey(y))
791 Line = "; Err %s"%(str(Split))
796 F.write("; Errors\n")
799 # Oops, something unspeakable happened.
805 # Generate the DNS SSHFP records
806 def GenSSHFP(File, HomePrefix):
809 F = open(File + ".tmp", "w")
811 # Fetch all the hosts
813 if HostAttrs == None:
814 raise UDEmptyList, "No Hosts"
817 if x[1].has_key("hostname") == 0 or \
818 x[1].has_key("sshRSAHostKey") == 0:
820 Host = GetAttr(x, "hostname")
822 for I in x[1]["sshRSAHostKey"]:
824 if Split[0] == 'ssh-rsa':
826 if Split[0] == 'ssh-dss':
828 if Algorithm == None:
830 Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
831 Line = "%s. IN SSHFP %u 1 %s" % (Host, Algorithm, Fingerprint)
832 Line = Sanitize(Line) + "\n"
834 # Oops, something unspeakable happened.
840 # Generate the BSMTP file
841 def GenBSMTP(File, HomePrefix):
844 F = open(File + ".tmp", "w")
846 # Fetch all the users
849 # Write out the zone file entry for each user
850 for x in DebianUsers:
851 if x[1].has_key("dnsZoneEntry") == 0:
854 # If the account has no PGP key, do not write it
855 if x[1].has_key("keyFingerPrint") == 0:
858 for z in x[1]["dnsZoneEntry"]:
859 Split = z.lower().split()
860 if Split[1].lower() == 'in':
861 for y in range(0, len(Split)):
864 Line = " ".join(Split) + "\n"
866 Host = Split[0] + DNSZone
867 if BSMTPCheck.match(Line) != None:
868 F.write("%s: user=%s group=Debian file=%s%s/bsmtp/%s\n"%(Host,
869 GetAttr(x, "uid"), HomePrefix, GetAttr(x, "uid"), Host))
872 F.write("; Errors\n")
875 # Oops, something unspeakable happened.
885 if not Host in HostToIPCache:
888 IPAdressesT = list(set([ (a[0], a[4][0]) for a in socket.getaddrinfo(Host, None)]))
889 except socket.gaierror, (code):
893 if not IPAdressesT is None:
894 for addr in IPAdressesT:
895 if addr[0] == socket.AF_INET:
896 IPAdresses += [addr[1], "::ffff:"+addr[1]]
898 IPAdresses += [addr[1]]
899 HostToIPCache[Host] = IPAdresses
900 return HostToIPCache[Host]
902 # Generate the ssh known hosts file
903 def GenSSHKnown(File, mode=None):
906 OldMask = os.umask(0022)
907 F = open(File + ".tmp", "w", 0644)
911 if HostAttrs == None:
912 raise UDEmptyList, "No Hosts"
915 if x[1].has_key("hostname") == 0 or \
916 x[1].has_key("sshRSAHostKey") == 0:
918 Host = GetAttr(x, "hostname")
920 if Host.endswith(HostDomain):
921 HostNames.append(Host[:-(len(HostDomain) + 1)])
923 # in the purpose field [[host|some other text]] (where some other text is optional)
924 # makes a hyperlink on the web thing. we now also add these hosts to the ssh known_hosts
925 # file. But so that we don't have to add everything we link we can add an asterisk
926 # and say [[*... to ignore it. In order to be able to add stuff to ssh without
927 # http linking it we also support [[-hostname]] entries.
928 for i in x[1].get("purpose", []):
929 m = PurposeHostField.match(i)
932 # we ignore [[*..]] entries
933 if m.startswith('*'):
935 if m.startswith('-'):
939 if m.endswith(HostDomain):
940 HostNames.append(m[:-(len(HostDomain) + 1)])
942 for I in x[1]["sshRSAHostKey"]:
943 if mode and mode == 'authorized_keys':
944 #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)
945 Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
947 Line = "%s %s" %(",".join(HostNames + HostToIP(Host)), I)
948 Line = Sanitize(Line) + "\n"
950 # Oops, something unspeakable happened.
956 # Generate the debianhosts file (list of all IP addresses)
957 def GenHosts(l, File):
960 OldMask = os.umask(0022)
961 F = open(File + ".tmp", "w", 0644)
964 # Fetch all the hosts
965 hostnames = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "hostname=*",
968 if hostnames == None:
969 raise UDEmptyList, "No Hosts"
973 host = GetAttr(x, "hostname", None)
977 addrs += socket.getaddrinfo(host, None, socket.AF_INET)
981 addrs += socket.getaddrinfo(host, None, socket.AF_INET6)
985 for addrinfo in addrs:
986 if addrinfo[0] in (socket.AF_INET, socket.AF_INET6):
987 addr = addrinfo[4][0]
989 print >> F, addrinfo[4][0]
991 # Oops, something unspeakable happened.
997 def GenKeyrings(OutDir):
999 shutil.copy(k, OutDir)
1002 # Connect to the ldap server
1004 F = open(PassDir + "/pass-" + pwd.getpwuid(os.getuid())[0], "r")
1005 Pass = F.readline().strip().split(" ")
1007 l.simple_bind_s("uid=" + Pass[0] + "," + BaseDn, Pass[1])
1009 # Fetch all the groups
1011 Attrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "gid=*",\
1012 ["gid", "gidNumber", "subGroup"])
1014 # Generate the SubGroupMap and GroupIDMap
1016 if x[1].has_key("gidNumber") == 0:
1018 GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0])
1019 if x[1].has_key("subGroup") != 0:
1020 SubGroupMap.setdefault(x[1]["gid"][0], []).extend(x[1]["subGroup"])
1022 # Fetch all the users
1023 PasswdAttrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "uid=*",\
1024 ["uid", "uidNumber", "gidNumber", "supplementaryGid",\
1025 "gecos", "loginShell", "userPassword", "shadowLastChange",\
1026 "shadowMin", "shadowMax", "shadowWarning", "shadowInactive",
1027 "shadowExpire", "emailForward", "latitude", "longitude",\
1028 "allowedHost", "sshRSAAuthKey", "dnsZoneEntry", "cn", "sn",\
1029 "keyFingerPrint", "privateSub", "mailDisableMessage",\
1030 "mailGreylisting", "mailCallout", "mailRBL", "mailRHSBL",\
1031 "mailWhitelist", "sudoPassword", "objectClass", "accountStatus"])
1033 if PasswdAttrs is None:
1034 raise UDEmptyList, "No Users"
1036 # Fetch all the hosts
1037 HostAttrs = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "sshRSAHostKey=*",\
1038 ["hostname", "sshRSAHostKey", "purpose"])
1040 # Open the control file
1041 if len(sys.argv) == 1:
1042 F = open(GenerateConf, "r")
1044 F = open(sys.argv[1], "r")
1046 # Generate global things
1047 GlobalDir = GenerateDir + "/"
1048 GenDisabledAccounts(GlobalDir + "disabled-accounts")
1050 PasswdAttrs = filter(not IsRetired, PasswdAttrs)
1051 DebianUsers = filter(IsGidDebian, PasswdAttrs)
1055 GenMailDisable(GlobalDir + "mail-disable")
1056 GenAllForward(GlobalDir + "mail-forward.cdb")
1057 GenPrivate(GlobalDir + "debian-private")
1058 #GenSSHKnown(l,GlobalDir+"authorized_keys", 'authorized_keys')
1059 GenMailBool(GlobalDir + "mail-greylist", "mailGreylisting")
1060 GenMailBool(GlobalDir + "mail-callout", "mailCallout")
1061 GenMailList(GlobalDir + "mail-rbl", "mailRBL")
1062 GenMailList(GlobalDir + "mail-rhsbl", "mailRHSBL")
1063 GenMailList(GlobalDir + "mail-whitelist", "mailWhitelist")
1064 GenKeyrings(GlobalDir)
1067 GenForward(GlobalDir + "forward-alias")
1069 PasswdAttrs = filter(lambda x: not x in DisabledUsers, PasswdAttrs)
1071 SSHFiles = GenSSHShadow()
1072 GenMarkers(GlobalDir + "markers")
1073 GenSSHKnown(GlobalDir + "ssh_known_hosts")
1074 GenHosts(l, GlobalDir + "debianhosts")
1086 Split = Line.split(" ")
1087 OutDir = GenerateDir + '/' + Split[0] + '/'
1093 # Get the group list and convert any named groups to numerics
1101 if GroupIDMap.has_key(I):
1102 GroupList[str(GroupIDMap[I])] = None
1107 CurrentHost = Split[0]
1109 DoLink(GlobalDir, OutDir, "debianhosts")
1110 DoLink(GlobalDir, OutDir, "ssh_known_hosts")
1111 DoLink(GlobalDir, OutDir, "disabled-accounts")
1114 if ExtraList.has_key("[NOPASSWD]"):
1115 userlist = GenPasswd(OutDir + "passwd", Split[1], "*")
1117 userlist = GenPasswd(OutDir + "passwd", Split[1], "x")
1119 grouprevmap = GenGroup(OutDir + "group")
1120 GenShadowSudo(OutDir + "sudo-passwd", ExtraList.has_key("[UNTRUSTED]") or ExtraList.has_key("[NOPASSWD]"))
1122 # Now we know who we're allowing on the machine, export
1123 # the relevant ssh keys
1124 GenSSHtarballs(userlist, SSHFiles, grouprevmap, os.path.join(OutDir, 'ssh-keys.tar.gz'))
1126 if ExtraList.has_key("[UNTRUSTED]"):
1127 print "[UNTRUSTED] tag is obsolete and may be removed in the future."
1129 if not ExtraList.has_key("[NOPASSWD]"):
1130 GenShadow(OutDir + "shadow")
1132 # Link in global things
1133 if not ExtraList.has_key("[NOMARKERS]"):
1134 DoLink(GlobalDir, OutDir, "markers")
1135 DoLink(GlobalDir, OutDir, "mail-forward.cdb")
1136 DoLink(GlobalDir, OutDir, "mail-disable")
1137 DoLink(GlobalDir, OutDir, "mail-greylist")
1138 DoLink(GlobalDir, OutDir, "mail-callout")
1139 DoLink(GlobalDir, OutDir, "mail-rbl")
1140 DoLink(GlobalDir, OutDir, "mail-rhsbl")
1141 DoLink(GlobalDir, OutDir, "mail-whitelist")
1144 DoLink(GlobalDir, OutDir, "forward-alias")
1146 if ExtraList.has_key("[DNS]"):
1147 GenDNS(OutDir + "dns-zone", Split[1])
1148 GenSSHFP(OutDir + "dns-sshfp", Split[1])
1150 if ExtraList.has_key("[BSMTP]"):
1151 GenBSMTP(OutDir + "bsmtp", Split[1])
1153 if ExtraList.has_key("[PRIVATE]"):
1154 DoLink(GlobalDir, OutDir, "debian-private")
1156 if ExtraList.has_key("[KEYRING]"):
1158 DoLink(GlobalDir, OutDir, os.path.basename(k))
1162 posix.remove(OutDir + os.path.basename(k))
1168 # vim:set shiftwidth=3: