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 *
44 UUID_FORMAT = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
46 EmailCheck = re.compile("^([^ <>@]+@[^ ,<>@]+)?$")
47 BSMTPCheck = re.compile(".*mx 0 (gluck)\.debian\.org\..*",re.DOTALL)
48 PurposeHostField = re.compile(r"\[\[([\*\-]?[a-z0-9.\-]*)(?:\|.*)?\]\]")
49 DNSZone = ".debian.net"
50 Keyrings = ConfModule.sync_keyrings.split(":")
52 def safe_makedirs(dir):
56 if e.errno == errno.EEXIST:
65 if e.errno == errno.ENOENT:
71 return Str.translate(string.maketrans("\n\r\t", "$$$"))
73 def DoLink(From, To, File):
75 posix.remove(To + File)
78 posix.link(From + File, To + File)
80 def IsRetired(DnRecord):
82 Looks for accountStatus in the LDAP record and tries to
83 match it against one of the known retired statuses
86 status = GetAttr(DnRecord, "accountStatus", None)
93 if status == "inactive":
96 elif status == "memorial":
99 elif status == "retiring":
100 # We'll give them a few extra days over what we said
101 age = 6 * 31 * 24 * 60 * 60
103 if (time.time() - time.mktime(time.strptime(line[1], "%Y-%m-%d"))) > age:
112 return int(GetAttr(x, "gidNumber", 0)) == 800
116 # See if this user is in the group list
117 def IsInGroup(DnRecord):
121 # See if the primary group is in the list
122 if Allowed.has_key(GetAttr(DnRecord, "gidNumber")) != 0:
125 # Check the host based ACL
126 if DnRecord[1].has_key("allowedHost") != 0:
127 for I in DnRecord[1]["allowedHost"]:
131 # See if there are supplementary groups
132 if DnRecord[1].has_key("supplementaryGid") == 0:
136 addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord, "uid"))
138 if Allowed.has_key(g):
142 def Die(File, F, Fdb):
148 os.remove(File + ".tmp")
152 os.remove(File + ".tdb.tmp")
156 def Done(File, F, Fdb):
159 os.rename(File + ".tmp", File)
162 os.rename(File + ".tdb.tmp", File + ".tdb")
164 # Generate the password list
165 def GenPasswd(File, HomePrefix, PwdMarker):
168 F = open(File + ".tdb.tmp", "w")
171 # Fetch all the users
175 for x in PasswdAttrs:
176 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
179 # Do not let people try to buffer overflow some busted passwd parser.
180 if len(GetAttr(x, "gecos")) > 100 or len(GetAttr(x, "loginShell")) > 50:
183 userlist[GetAttr(x, "uid")] = int(GetAttr(x, "gidNumber"))
184 Line = "%s:%s:%s:%s:%s:%s%s:%s" % (GetAttr(x, "uid"),\
186 GetAttr(x, "uidNumber"), GetAttr(x, "gidNumber"),\
187 GetAttr(x, "gecos"), HomePrefix, GetAttr(x, "uid"),\
188 GetAttr(x, "loginShell"))
190 Line = Sanitize(Line) + "\n"
191 F.write("0%u %s" % (I, Line))
192 F.write(".%s %s" % (GetAttr(x, "uid"), Line))
193 F.write("=%s %s" % (GetAttr(x, "uidNumber"), Line))
196 # Oops, something unspeakable happened.
202 # Return the list of users so we know which keys to export
205 # Generate the shadow list
209 OldMask = os.umask(0077)
210 F = open(File + ".tdb.tmp", "w", 0600)
213 # Fetch all the users
217 for x in PasswdAttrs:
218 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
221 Pass = GetAttr(x, "userPassword")
222 if Pass[0:7] != "{crypt}" or len(Pass) > 50:
227 # If the account is locked, mark it as such in shadow
228 # See Debian Bug #308229 for why we set it to 1 instead of 0
229 if (GetAttr(x, "userPassword").find("*LK*") != -1) \
230 or GetAttr(x, "userPassword").startswith("!"):
233 ShadowExpire = GetAttr(x, "shadowExpire")
235 Line = "%s:%s:%s:%s:%s:%s:%s:%s:" % (GetAttr(x, "uid"),\
236 Pass, GetAttr(x, "shadowLastChange"),\
237 GetAttr(x, "shadowMin"), GetAttr(x, "shadowMax"),\
238 GetAttr(x, "shadowWarning"), GetAttr(x, "shadowInactive"),\
240 Line = Sanitize(Line) + "\n"
241 F.write("0%u %s" % (I, Line))
242 F.write(".%s %s" % (GetAttr(x, "uid"), Line))
245 # Oops, something unspeakable happened.
251 # Generate the sudo passwd file
252 def GenShadowSudo(File, untrusted):
255 OldMask = os.umask(0077)
256 F = open(File + ".tmp", "w", 0600)
259 # Fetch all the users
262 for x in PasswdAttrs:
264 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
267 if x[1].has_key('sudoPassword'):
268 for entry in x[1]['sudoPassword']:
269 Match = re.compile('^('+UUID_FORMAT+') (confirmed:[0-9a-f]{40}|unconfirmed) ([a-z0-9.,*]+) ([^ ]+)$').match(entry)
272 uuid = Match.group(1)
273 status = Match.group(2)
274 hosts = Match.group(3)
275 cryptedpass = Match.group(4)
277 if status != 'confirmed:'+make_passwd_hmac('password-is-confirmed', 'sudo', x[1]['uid'][0], uuid, hosts, cryptedpass):
279 for_all = hosts == "*"
280 for_this_host = CurrentHost in hosts.split(',')
281 if not (for_all or for_this_host):
283 # ignore * passwords for untrusted hosts, but copy host specific passwords
284 if for_all and untrusted:
287 if for_this_host: # this makes sure we take a per-host entry over the for-all entry
292 Line = "%s:%s" % (GetAttr(x, "uid"), Pass)
293 Line = Sanitize(Line) + "\n"
294 F.write("%s" % (Line))
296 # Oops, something unspeakable happened.
302 # Generate the shadow list
304 # Fetch all the users
309 safe_rmtree(os.path.join(GlobalDir, 'userkeys'))
310 safe_makedirs(os.path.join(GlobalDir, 'userkeys'))
312 for x in PasswdAttrs:
314 if x[1].has_key("uidNumber") == 0 or \
315 x[1].has_key("sshRSAAuthKey") == 0:
318 User = GetAttr(x, "uid")
322 OldMask = os.umask(0077)
323 File = os.path.join(GlobalDir, 'userkeys', User)
324 F = open(File + ".tmp", "w", 0600)
327 for I in x[1]["sshRSAAuthKey"]:
328 MultipleLine = "%s" % I
329 MultipleLine = Sanitize(MultipleLine) + "\n"
330 F.write(MultipleLine)
333 userfiles.append(os.path.basename(File))
335 # Oops, something unspeakable happened.
338 Die(masterFileName, masterFile, None)
343 def GenSSHtarballs(userlist, SSHFiles, grouprevmap, target):
344 OldMask = os.umask(0077)
345 tf = tarfile.open(name=os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), mode='w:gz')
347 for f in userlist.keys():
348 if f not in SSHFiles:
350 # If we're not exporting their primary group, don't export
353 if userlist[f] in grouprevmap.keys():
354 grname = grouprevmap[userlist[f]]
357 if int(userlist[f]) <= 100:
358 # In these cases, look it up in the normal way so we
359 # deal with cases where, for instance, users are in group
360 # users as their primary group.
361 grname = grp.getgrgid(userlist[f])[0]
366 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])
369 to = tf.gettarinfo(os.path.join(GlobalDir, 'userkeys', f), f)
370 # These will only be used where the username doesn't
371 # exist on the target system for some reason; hence,
372 # in those cases, the safest thing is for the file to
373 # be owned by root but group nobody. This deals with
374 # the bloody obscure case where the group fails to exist
375 # whilst the user does (in which case we want to avoid
376 # ending up with a file which is owned user:root to avoid
377 # a fairly obvious attack vector)
380 # Using the username / groupname fields avoids any need
381 # to give a shit^W^W^Wcare about the UIDoffset stuff.
385 tf.addfile(to, file(os.path.join(GlobalDir, 'userkeys', f)))
388 os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
390 # add a list of groups to existing groups,
391 # including all subgroups thereof, recursively.
392 # basically this proceduces the transitive hull of the groups in
394 def addGroups(existingGroups, newGroups, uid):
395 for group in newGroups:
396 # if it's a <group>@host, split it and verify it's on the current host.
397 s = group.split('@', 1)
398 if len(s) == 2 and s[1] != CurrentHost:
402 # let's see if we handled this group already
403 if group in existingGroups:
406 if not GroupIDMap.has_key(group):
407 print "Group", group, "does not exist but", uid, "is in it"
410 existingGroups.append(group)
412 if SubGroupMap.has_key(group):
413 addGroups(existingGroups, SubGroupMap[group], uid)
415 # Generate the group list
420 F = open(File + ".tdb.tmp", "w")
422 # Generate the GroupMap
424 for x in GroupIDMap.keys():
427 # Fetch all the users
430 # Sort them into a list of groups having a set of users
431 for x in PasswdAttrs:
432 uid = GetAttr(x, "uid")
433 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
435 if x[1].has_key("supplementaryGid") == 0:
439 addGroups(supgroups, x[1]["supplementaryGid"], uid)
441 GroupMap[g].append(uid)
443 # Output the group file.
445 for x in GroupMap.keys():
446 grouprevmap[GroupIDMap[x]] = x
447 if GroupIDMap.has_key(x) == 0:
449 Line = "%s:x:%u:" % (x, GroupIDMap[x])
451 for I in GroupMap[x]:
452 Line = Line + ("%s%s" % (Comma, I))
454 Line = Sanitize(Line) + "\n"
455 F.write("0%u %s" % (J, Line))
456 F.write(".%s %s" % (x, Line))
457 F.write("=%u %s" % (GroupIDMap[x], Line))
460 # Oops, something unspeakable happened.
470 for x in DebianUsers:
471 if x[1].has_key("emailForward") == 0:
474 if IsInGroup(x) == 0:
475 x[1].pop("emailForward")
478 # Do not allow people to try to buffer overflow busted parsers
479 if len(GetAttr(x, "emailForward")) > 200:
480 x[1].pop("emailForward")
483 # Check the forwarding address
484 if EmailCheck.match(GetAttr(x, "emailForward")) == None:
485 x[1].pop("emailForward")
487 # Generate the email forwarding list
488 def GenForward(File):
491 OldMask = os.umask(0022)
492 F = open(File + ".tmp", "w", 0644)
495 # Fetch all the users
498 # Write out the email address for each user
499 for x in DebianUsers:
500 if x[1].has_key("emailForward") == 0:
503 Line = "%s: %s" % (GetAttr(x, "uid"), GetAttr(x, "emailForward"))
504 Line = Sanitize(Line) + "\n"
507 # Oops, something unspeakable happened.
513 def GenAllForward(File):
516 OldMask = os.umask(0022)
517 Fdb = os.popen("cdbmake %s %s.tmp"%(File, File), "w")
520 # Fetch all the users
523 # Write out the email address for each user
524 for x in DebianUsers:
525 if x[1].has_key("emailForward") == 0:
528 # Do not allow people to try to buffer overflow busted parsers
529 Forward = GetAttr(x, "emailForward")
531 User = GetAttr(x, "uid")
532 Fdb.write("+%d,%d:%s->%s\n" % (len(User), len(Forward), User, Forward))
535 # Oops, something unspeakable happened.
539 if Fdb.close() != None:
540 raise "cdbmake gave an error"
542 # Generate the anon XEarth marker file
543 def GenMarkers(File):
546 F = open(File + ".tmp", "w")
548 # Fetch all the users
551 # Write out the position for each user
552 for x in DebianUsers:
553 if x[1].has_key("latitude") == 0 or x[1].has_key("longitude") == 0:
556 Line = "%8s %8s \"\""%(DecDegree(GetAttr(x, "latitude"), 1), DecDegree(GetAttr(x, "longitude"), 1))
557 Line = Sanitize(Line) + "\n"
562 # Oops, something unspeakable happened.
568 # Generate the debian-private subscription list
569 def GenPrivate(File):
572 F = open(File + ".tmp", "w")
574 # Fetch all the users
577 # Write out the position for each user
578 for x in DebianUsers:
579 if x[1].has_key("privateSub") == 0:
582 # If the account has no PGP key, do not write it
583 if x[1].has_key("keyFingerPrint") == 0:
587 Line = "%s"%(GetAttr(x, "privateSub"))
588 Line = Sanitize(Line) + "\n"
593 # Oops, something unspeakable happened.
599 # Generate a list of locked accounts
600 def GenDisabledAccounts(File):
603 F = open(File + ".tmp", "w")
605 # Fetch all the users
610 for x in PasswdAttrs:
611 if x[1].has_key("uidNumber") == 0:
614 Pass = GetAttr(x, "userPassword")
616 # *LK* is the reference value for a locked account
617 # password starting with ! is also a locked account
618 if Pass.find("*LK*") != -1 or Pass.startswith("!"):
619 # Format is <login>:<reason>
620 Line = "%s:%s" % (GetAttr(x, "uid"), "Account is locked")
623 F.write(Sanitize(Line) + "\n")
625 DisabledUsers.append(x)
627 # Oops, something unspeakable happened.
633 # Generate the list of local addresses that refuse all mail
634 def GenMailDisable(File):
637 F = open(File + ".tmp", "w")
639 # Fetch all the users
642 for x in DebianUsers:
645 if x[1].has_key("mailDisableMessage"):
646 Reason = GetAttr(x, "mailDisableMessage")
651 Line = "%s: %s"%(GetAttr(x, "uid"), Reason)
652 Line = Sanitize(Line) + "\n"
657 # Oops, something unspeakable happened.
663 # Generate a list of uids that should have boolean affects applied
664 def GenMailBool(File, Key):
667 F = open(File + ".tmp", "w")
669 # Fetch all the users
672 for x in DebianUsers:
675 if x[1].has_key(Key) == 0:
678 if GetAttr(x, Key) != "TRUE":
682 Line = "%s"%(GetAttr(x, "uid"))
683 Line = Sanitize(Line) + "\n"
688 # Oops, something unspeakable happened.
694 # Generate a list of hosts for RBL or whitelist purposes.
695 def GenMailList(File, Key):
698 F = open(File + ".tmp", "w")
700 # Fetch all the users
703 for x in DebianUsers:
706 if x[1].has_key(Key) == 0:
713 if Key == "mailWhitelist":
714 if re.match('^[-\w.]+(/[\d]+)?$', z) == None:
717 if re.match('^[-\w.]+$', z) == None:
721 Line = GetAttr(x, "uid")
725 if Key == "mailRHSBL":
726 Line += "/$sender_address_domain"
729 Line = Sanitize(Line) + "\n"
734 # Oops, something unspeakable happened.
740 def isRoleAccount(pwEntry):
741 if not pwEntry.has_key("objectClass"):
742 raise "pwEntry has no objectClass"
743 oc = pwEntry['objectClass']
745 i = oc.index('debianRoleAccount')
750 # Generate the DNS Zone file
751 def GenDNS(File, HomePrefix):
754 F = open(File + ".tmp", "w")
756 # Fetch all the users
759 # Write out the zone file entry for each user
760 for x in PasswdAttrs:
761 if x[1].has_key("dnsZoneEntry") == 0:
764 # If the account has no PGP key, do not write it
765 if x[1].has_key("keyFingerPrint") == 0 and not isRoleAccount(x[1]):
768 F.write("; %s\n"%(EmailAddress(x)))
769 for z in x[1]["dnsZoneEntry"]:
770 Split = z.lower().split()
771 if Split[1].lower() == 'in':
772 for y in range(0, len(Split)):
775 Line = " ".join(Split) + "\n"
778 Host = Split[0] + DNSZone
779 if BSMTPCheck.match(Line) != None:
780 F.write("; Has BSMTP\n")
782 # Write some identification information
783 if Split[2].lower() == "a":
784 Line = "%s IN TXT \"%s\"\n"%(Split[0], EmailAddress(x))
785 for y in x[1]["keyFingerPrint"]:
786 Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0], FormatPGPKey(y))
789 Line = "; Err %s"%(str(Split))
794 F.write("; Errors\n")
797 # Oops, something unspeakable happened.
803 # Generate the DNS SSHFP records
804 def GenSSHFP(File, HomePrefix):
807 F = open(File + ".tmp", "w")
809 # Fetch all the hosts
811 if HostAttrs == None:
812 raise UDEmptyList, "No Hosts"
815 if x[1].has_key("hostname") == 0 or \
816 x[1].has_key("sshRSAHostKey") == 0:
818 Host = GetAttr(x, "hostname")
820 for I in x[1]["sshRSAHostKey"]:
822 if Split[0] == 'ssh-rsa':
824 if Split[0] == 'ssh-dss':
826 if Algorithm == None:
828 Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
829 Line = "%s. IN SSHFP %u 1 %s" % (Host, Algorithm, Fingerprint)
830 Line = Sanitize(Line) + "\n"
832 # Oops, something unspeakable happened.
838 # Generate the BSMTP file
839 def GenBSMTP(File, HomePrefix):
842 F = open(File + ".tmp", "w")
844 # Fetch all the users
847 # Write out the zone file entry for each user
848 for x in DebianUsers:
849 if x[1].has_key("dnsZoneEntry") == 0:
852 # If the account has no PGP key, do not write it
853 if x[1].has_key("keyFingerPrint") == 0:
856 for z in x[1]["dnsZoneEntry"]:
857 Split = z.lower().split()
858 if Split[1].lower() == 'in':
859 for y in range(0, len(Split)):
862 Line = " ".join(Split) + "\n"
864 Host = Split[0] + DNSZone
865 if BSMTPCheck.match(Line) != None:
866 F.write("%s: user=%s group=Debian file=%s%s/bsmtp/%s\n"%(Host,
867 GetAttr(x, "uid"), HomePrefix, GetAttr(x, "uid"), Host))
870 F.write("; Errors\n")
873 # Oops, something unspeakable happened.
883 if not Host in HostToIPCache:
886 IPAdressesT = list(set([ (a[0], a[4][0]) for a in socket.getaddrinfo(Host, None)]))
887 except socket.gaierror, (code):
891 if not IPAdressesT is None:
892 for addr in IPAdressesT:
893 if addr[0] == socket.AF_INET:
894 IPAdresses += [addr[1], "::ffff:"+addr[1]]
896 IPAdresses += [addr[1]]
897 HostToIPCache[Host] = IPAdresses
898 return HostToIPCache[Host]
900 # Generate the ssh known hosts file
901 def GenSSHKnown(File, mode=None):
904 OldMask = os.umask(0022)
905 F = open(File + ".tmp", "w", 0644)
909 if HostAttrs == None:
910 raise UDEmptyList, "No Hosts"
913 if x[1].has_key("hostname") == 0 or \
914 x[1].has_key("sshRSAHostKey") == 0:
916 Host = GetAttr(x, "hostname")
918 if Host.endswith(HostDomain):
919 HostNames.append(Host[:-(len(HostDomain) + 1)])
921 # in the purpose field [[host|some other text]] (where some other text is optional)
922 # makes a hyperlink on the web thing. we now also add these hosts to the ssh known_hosts
923 # file. But so that we don't have to add everything we link we can add an asterisk
924 # and say [[*... to ignore it. In order to be able to add stuff to ssh without
925 # http linking it we also support [[-hostname]] entries.
926 for i in x[1].get("purpose", []):
927 m = PurposeHostField.match(i)
930 # we ignore [[*..]] entries
931 if m.startswith('*'):
933 if m.startswith('-'):
937 if m.endswith(HostDomain):
938 HostNames.append(m[:-(len(HostDomain) + 1)])
940 for I in x[1]["sshRSAHostKey"]:
941 if mode and mode == 'authorized_keys':
942 #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)
943 Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
945 Line = "%s %s" %(",".join(HostNames + HostToIP(Host)), I)
946 Line = Sanitize(Line) + "\n"
948 # Oops, something unspeakable happened.
954 # Generate the debianhosts file (list of all IP addresses)
955 def GenHosts(l, File):
958 OldMask = os.umask(0022)
959 F = open(File + ".tmp", "w", 0644)
962 # Fetch all the hosts
963 hostnames = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "hostname=*",
966 if hostnames == None:
967 raise UDEmptyList, "No Hosts"
971 host = GetAttr(x, "hostname", None)
975 addrs += socket.getaddrinfo(host, None, socket.AF_INET)
979 addrs += socket.getaddrinfo(host, None, socket.AF_INET6)
983 for addrinfo in addrs:
984 if addrinfo[0] in (socket.AF_INET, socket.AF_INET6):
985 addr = addrinfo[4][0]
987 print >> F, addrinfo[4][0]
989 # Oops, something unspeakable happened.
995 def GenKeyrings(OutDir):
997 shutil.copy(k, OutDir)
1000 # Connect to the ldap server
1002 F = open(PassDir + "/pass-" + pwd.getpwuid(os.getuid())[0], "r")
1003 Pass = F.readline().strip().split(" ")
1005 l.simple_bind_s("uid=" + Pass[0] + "," + BaseDn, Pass[1])
1007 # Fetch all the groups
1009 Attrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "gid=*",\
1010 ["gid", "gidNumber", "subGroup"])
1012 # Generate the SubGroupMap and GroupIDMap
1014 if x[1].has_key("gidNumber") == 0:
1016 GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0])
1017 if x[1].has_key("subGroup") != 0:
1018 SubGroupMap.setdefault(x[1]["gid"][0], []).extend(x[1]["subGroup"])
1020 # Fetch all the users
1021 PasswdAttrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "uid=*",\
1022 ["uid", "uidNumber", "gidNumber", "supplementaryGid",\
1023 "gecos", "loginShell", "userPassword", "shadowLastChange",\
1024 "shadowMin", "shadowMax", "shadowWarning", "shadowInactive",
1025 "shadowExpire", "emailForward", "latitude", "longitude",\
1026 "allowedHost", "sshRSAAuthKey", "dnsZoneEntry", "cn", "sn",\
1027 "keyFingerPrint", "privateSub", "mailDisableMessage",\
1028 "mailGreylisting", "mailCallout", "mailRBL", "mailRHSBL",\
1029 "mailWhitelist", "sudoPassword", "objectClass", "accountStatus"])
1031 if PasswdAttrs is None:
1032 raise UDEmptyList, "No Users"
1034 # Fetch all the hosts
1035 HostAttrs = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "sshRSAHostKey=*",\
1036 ["hostname", "sshRSAHostKey", "purpose"])
1038 # Open the control file
1039 if len(sys.argv) == 1:
1040 F = open(GenerateConf, "r")
1042 F = open(sys.argv[1], "r")
1044 # Generate global things
1045 GlobalDir = GenerateDir + "/"
1046 GenDisabledAccounts(GlobalDir + "disabled-accounts")
1048 PasswdAttrs = filter(not IsRetired, PasswdAttrs)
1049 DebianUsers = filter(IsGidDebian, PasswdAttrs)
1053 GenMailDisable(GlobalDir + "mail-disable")
1054 GenAllForward(GlobalDir + "mail-forward.cdb")
1055 GenPrivate(GlobalDir + "debian-private")
1056 #GenSSHKnown(l,GlobalDir+"authorized_keys", 'authorized_keys')
1057 GenMailBool(GlobalDir + "mail-greylist", "mailGreylisting")
1058 GenMailBool(GlobalDir + "mail-callout", "mailCallout")
1059 GenMailList(GlobalDir + "mail-rbl", "mailRBL")
1060 GenMailList(GlobalDir + "mail-rhsbl", "mailRHSBL")
1061 GenMailList(GlobalDir + "mail-whitelist", "mailWhitelist")
1062 GenKeyrings(GlobalDir)
1065 GenForward(GlobalDir + "forward-alias")
1067 PasswdAttrs = filter(lambda x: not x in DisabledUsers, PasswdAttrs)
1069 SSHFiles = GenSSHShadow()
1070 GenMarkers(GlobalDir + "markers")
1071 GenSSHKnown(GlobalDir + "ssh_known_hosts")
1072 GenHosts(l, GlobalDir + "debianhosts")
1084 Split = Line.split(" ")
1085 OutDir = GenerateDir + '/' + Split[0] + '/'
1091 # Get the group list and convert any named groups to numerics
1099 if GroupIDMap.has_key(I):
1100 GroupList[str(GroupIDMap[I])] = None
1105 CurrentHost = Split[0]
1107 DoLink(GlobalDir, OutDir, "debianhosts")
1108 DoLink(GlobalDir, OutDir, "ssh_known_hosts")
1109 DoLink(GlobalDir, OutDir, "disabled-accounts")
1112 if ExtraList.has_key("[NOPASSWD]"):
1113 userlist = GenPasswd(OutDir + "passwd", Split[1], "*")
1115 userlist = GenPasswd(OutDir + "passwd", Split[1], "x")
1117 grouprevmap = GenGroup(OutDir + "group")
1118 GenShadowSudo(OutDir + "sudo-passwd", ExtraList.has_key("[UNTRUSTED]") or ExtraList.has_key("[NOPASSWD]"))
1120 # Now we know who we're allowing on the machine, export
1121 # the relevant ssh keys
1122 GenSSHtarballs(userlist, SSHFiles, grouprevmap, os.path.join(OutDir, 'ssh-keys.tar.gz'))
1124 if ExtraList.has_key("[UNTRUSTED]"):
1125 print "[UNTRUSTED] tag is obsolete and may be removed in the future."
1127 if not ExtraList.has_key("[NOPASSWD]"):
1128 GenShadow(OutDir + "shadow")
1130 # Link in global things
1131 if not ExtraList.has_key("[NOMARKERS]"):
1132 DoLink(GlobalDir, OutDir, "markers")
1133 DoLink(GlobalDir, OutDir, "mail-forward.cdb")
1134 DoLink(GlobalDir, OutDir, "mail-disable")
1135 DoLink(GlobalDir, OutDir, "mail-greylist")
1136 DoLink(GlobalDir, OutDir, "mail-callout")
1137 DoLink(GlobalDir, OutDir, "mail-rbl")
1138 DoLink(GlobalDir, OutDir, "mail-rhsbl")
1139 DoLink(GlobalDir, OutDir, "mail-whitelist")
1142 DoLink(GlobalDir, OutDir, "forward-alias")
1144 if ExtraList.has_key("[DNS]"):
1145 GenDNS(OutDir + "dns-zone", Split[1])
1146 GenSSHFP(OutDir + "dns-sshfp", Split[1])
1148 if ExtraList.has_key("[BSMTP]"):
1149 GenBSMTP(OutDir + "bsmtp", Split[1])
1151 if ExtraList.has_key("[PRIVATE]"):
1152 DoLink(GlobalDir, OutDir, "debian-private")
1154 if ExtraList.has_key("[KEYRING]"):
1156 DoLink(GlobalDir, OutDir, os.path.basename(k))
1160 posix.remove(OutDir + os.path.basename(k))
1166 # vim:set shiftwidth=3: