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 if (time.time() - time.mktime(time.strptime(line[1], "%Y-%m-%d"))) > age:
111 # See if this user is in the group list
112 def IsInGroup(DnRecord):
116 # See if the primary group is in the list
117 if Allowed.has_key(GetAttr(DnRecord, "gidNumber")) != 0:
120 # Check the host based ACL
121 if DnRecord[1].has_key("allowedHost") != 0:
122 for I in DnRecord[1]["allowedHost"]:
126 # See if there are supplementary groups
127 if DnRecord[1].has_key("supplementaryGid") == 0:
131 addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord, "uid"))
133 if Allowed.has_key(g):
137 def Die(File, F, Fdb):
143 os.remove(File + ".tmp")
147 os.remove(File + ".tdb.tmp")
151 def Done(File, F, Fdb):
154 os.rename(File + ".tmp", File)
157 os.rename(File + ".tdb.tmp", File + ".tdb")
159 # Generate the password list
160 def GenPasswd(l, File, HomePrefix, PwdMarker):
163 F = open(File + ".tdb.tmp", "w")
166 # Fetch all the users
170 for x in PasswdAttrs:
171 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
174 # Do not let people try to buffer overflow some busted passwd parser.
175 if len(GetAttr(x, "gecos")) > 100 or len(GetAttr(x, "loginShell")) > 50:
178 userlist[GetAttr(x, "uid")] = int(GetAttr(x, "gidNumber"))
179 Line = "%s:%s:%s:%s:%s:%s%s:%s" % (GetAttr(x, "uid"),\
181 GetAttr(x, "uidNumber"), GetAttr(x, "gidNumber"),\
182 GetAttr(x, "gecos"), HomePrefix, GetAttr(x, "uid"),\
183 GetAttr(x, "loginShell"))
185 Line = Sanitize(Line) + "\n"
186 F.write("0%u %s" % (I, Line))
187 F.write(".%s %s" % (GetAttr(x, "uid"), Line))
188 F.write("=%s %s" % (GetAttr(x, "uidNumber"), Line))
191 # Oops, something unspeakable happened.
197 # Return the list of users so we know which keys to export
200 # Generate the shadow list
201 def GenShadow(l, File):
204 OldMask = os.umask(0077)
205 F = open(File + ".tdb.tmp", "w", 0600)
208 # Fetch all the users
212 for x in PasswdAttrs:
213 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
216 Pass = GetAttr(x, "userPassword")
217 if Pass[0:7] != "{crypt}" or len(Pass) > 50:
222 # If the account is locked, mark it as such in shadow
223 # See Debian Bug #308229 for why we set it to 1 instead of 0
224 if (GetAttr(x, "userPassword").find("*LK*") != -1) \
225 or GetAttr(x, "userPassword").startswith("!"):
228 ShadowExpire = GetAttr(x, "shadowExpire")
230 Line = "%s:%s:%s:%s:%s:%s:%s:%s:" % (GetAttr(x, "uid"),\
231 Pass, GetAttr(x, "shadowLastChange"),\
232 GetAttr(x, "shadowMin"), GetAttr(x, "shadowMax"),\
233 GetAttr(x, "shadowWarning"), GetAttr(x, "shadowInactive"),\
235 Line = Sanitize(Line) + "\n"
236 F.write("0%u %s" % (I, Line))
237 F.write(".%s %s" % (GetAttr(x, "uid"), Line))
240 # Oops, something unspeakable happened.
246 # Generate the sudo passwd file
247 def GenShadowSudo(l, File, untrusted):
250 OldMask = os.umask(0077)
251 F = open(File + ".tmp", "w", 0600)
254 # Fetch all the users
257 for x in PasswdAttrs:
259 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
262 if x[1].has_key('sudoPassword'):
263 for entry in x[1]['sudoPassword']:
264 Match = re.compile('^('+UUID_FORMAT+') (confirmed:[0-9a-f]{40}|unconfirmed) ([a-z0-9.,*]+) ([^ ]+)$').match(entry)
267 uuid = Match.group(1)
268 status = Match.group(2)
269 hosts = Match.group(3)
270 cryptedpass = Match.group(4)
272 if status != 'confirmed:'+make_passwd_hmac('password-is-confirmed', 'sudo', x[1]['uid'][0], uuid, hosts, cryptedpass):
274 for_all = hosts == "*"
275 for_this_host = CurrentHost in hosts.split(',')
276 if not (for_all or for_this_host):
278 # ignore * passwords for untrusted hosts, but copy host specific passwords
279 if for_all and untrusted:
282 if for_this_host: # this makes sure we take a per-host entry over the for-all entry
287 Line = "%s:%s" % (GetAttr(x, "uid"), Pass)
288 Line = Sanitize(Line) + "\n"
289 F.write("%s" % (Line))
291 # Oops, something unspeakable happened.
297 # Generate the shadow list
299 # Fetch all the users
304 safe_rmtree(os.path.join(GlobalDir, 'userkeys'))
305 safe_makedirs(os.path.join(GlobalDir, 'userkeys'))
307 for x in PasswdAttrs:
309 if x[1].has_key("uidNumber") == 0 or \
310 x[1].has_key("sshRSAAuthKey") == 0:
313 User = GetAttr(x, "uid")
317 OldMask = os.umask(0077)
318 File = os.path.join(GlobalDir, 'userkeys', User)
319 F = open(File + ".tmp", "w", 0600)
322 for I in x[1]["sshRSAAuthKey"]:
323 MultipleLine = "%s" % I
324 MultipleLine = Sanitize(MultipleLine) + "\n"
325 F.write(MultipleLine)
328 userfiles.append(os.path.basename(File))
330 # Oops, something unspeakable happened.
333 Die(masterFileName, masterFile, None)
338 def GenSSHtarballs(userlist, SSHFiles, grouprevmap, target):
339 OldMask = os.umask(0077)
340 tf = tarfile.open(name=os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), mode='w:gz')
342 for f in userlist.keys():
343 if f not in SSHFiles:
345 # If we're not exporting their primary group, don't export
348 if userlist[f] in grouprevmap.keys():
349 grname = grouprevmap[userlist[f]]
352 if int(userlist[f]) <= 100:
353 # In these cases, look it up in the normal way so we
354 # deal with cases where, for instance, users are in group
355 # users as their primary group.
356 grname = grp.getgrgid(userlist[f])[0]
361 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])
364 to = tf.gettarinfo(os.path.join(GlobalDir, 'userkeys', f), f)
365 # These will only be used where the username doesn't
366 # exist on the target system for some reason; hence,
367 # in those cases, the safest thing is for the file to
368 # be owned by root but group nobody. This deals with
369 # the bloody obscure case where the group fails to exist
370 # whilst the user does (in which case we want to avoid
371 # ending up with a file which is owned user:root to avoid
372 # a fairly obvious attack vector)
375 # Using the username / groupname fields avoids any need
376 # to give a shit^W^W^Wcare about the UIDoffset stuff.
380 tf.addfile(to, file(os.path.join(GlobalDir, 'userkeys', f)))
383 os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
385 # add a list of groups to existing groups,
386 # including all subgroups thereof, recursively.
387 # basically this proceduces the transitive hull of the groups in
389 def addGroups(existingGroups, newGroups, uid):
390 for group in newGroups:
391 # if it's a <group>@host, split it and verify it's on the current host.
392 s = group.split('@', 1)
393 if len(s) == 2 and s[1] != CurrentHost:
397 # let's see if we handled this group already
398 if group in existingGroups:
401 if not GroupIDMap.has_key(group):
402 print "Group", group, "does not exist but", uid, "is in it"
405 existingGroups.append(group)
407 if SubGroupMap.has_key(group):
408 addGroups(existingGroups, SubGroupMap[group], uid)
410 # Generate the group list
411 def GenGroup(l, File):
415 F = open(File + ".tdb.tmp", "w")
417 # Generate the GroupMap
419 for x in GroupIDMap.keys():
422 # Fetch all the users
425 # Sort them into a list of groups having a set of users
426 for x in PasswdAttrs:
427 uid = GetAttr(x, "uid")
428 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
430 if x[1].has_key("supplementaryGid") == 0:
434 addGroups(supgroups, x[1]["supplementaryGid"], uid)
436 GroupMap[g].append(uid)
438 # Output the group file.
440 for x in GroupMap.keys():
441 grouprevmap[GroupIDMap[x]] = x
442 if GroupIDMap.has_key(x) == 0:
444 Line = "%s:x:%u:" % (x, GroupIDMap[x])
446 for I in GroupMap[x]:
447 Line = Line + ("%s%s" % (Comma, I))
449 Line = Sanitize(Line) + "\n"
450 F.write("0%u %s" % (J, Line))
451 F.write(".%s %s" % (x, Line))
452 F.write("=%u %s" % (GroupIDMap[x], Line))
455 # Oops, something unspeakable happened.
465 for x in PasswdAttrs:
466 if x[1].has_key("emailForward") == 0:
469 if IsInGroup(x) == 0:
470 x[1].pop("emailForward")
473 # Do not allow people to try to buffer overflow busted parsers
474 if len(GetAttr(x, "emailForward")) > 200:
475 x[1].pop("emailForward")
478 # Check the forwarding address
479 if EmailCheck.match(GetAttr(x, "emailForward")) == None:
480 x[1].pop("emailForward")
482 # Generate the email forwarding list
483 def GenForward(l, File):
486 OldMask = os.umask(0022)
487 F = open(File + ".tmp", "w", 0644)
490 # Fetch all the users
493 # Write out the email address for each user
494 for x in PasswdAttrs:
495 if x[1].has_key("emailForward") == 0:
498 Line = "%s: %s" % (GetAttr(x, "uid"), GetAttr(x, "emailForward"))
499 Line = Sanitize(Line) + "\n"
502 # Oops, something unspeakable happened.
508 def GenAllForward(l, File):
511 OldMask = os.umask(0022)
512 Fdb = os.popen("cdbmake %s %s.tmp"%(File, File), "w")
515 # Fetch all the users
518 # Write out the email address for each user
519 for x in PasswdAttrs:
520 if x[1].has_key("emailForward") == 0:
523 # Do not allow people to try to buffer overflow busted parsers
524 Forward = GetAttr(x, "emailForward")
526 User = GetAttr(x, "uid")
527 Fdb.write("+%d,%d:%s->%s\n" % (len(User), len(Forward), User, Forward))
530 # Oops, something unspeakable happened.
534 if Fdb.close() != None:
535 raise "cdbmake gave an error"
537 # Generate the anon XEarth marker file
538 def GenMarkers(l, File):
541 F = open(File + ".tmp", "w")
543 # Fetch all the users
546 # Write out the position for each user
547 for x in PasswdAttrs:
548 if x[1].has_key("latitude") == 0 or x[1].has_key("longitude") == 0:
551 Line = "%8s %8s \"\""%(DecDegree(GetAttr(x, "latitude"), 1), DecDegree(GetAttr(x, "longitude"), 1))
552 Line = Sanitize(Line) + "\n"
557 # Oops, something unspeakable happened.
563 # Generate the debian-private subscription list
564 def GenPrivate(l, File):
567 F = open(File + ".tmp", "w")
569 # Fetch all the users
572 # Write out the position for each user
573 for x in PasswdAttrs:
574 if x[1].has_key("privateSub") == 0:
577 # If the account has no PGP key, do not write it
578 if x[1].has_key("keyFingerPrint") == 0:
581 # Must be in the Debian group (yuk, hard coded for now)
582 if GetAttr(x, "gidNumber") != "800":
586 Line = "%s"%(GetAttr(x, "privateSub"))
587 Line = Sanitize(Line) + "\n"
592 # Oops, something unspeakable happened.
598 # Generate a list of locked accounts
599 def GenDisabledAccounts(l, File):
602 F = open(File + ".tmp", "w")
604 # Fetch all the users
609 for x in PasswdAttrs:
610 if x[1].has_key("uidNumber") == 0:
613 Pass = GetAttr(x, "userPassword")
615 # *LK* is the reference value for a locked account
616 # password starting with ! is also a locked account
617 if Pass.find("*LK*") != -1 or Pass.startswith("!"):
618 # Format is <login>:<reason>
619 Line = "%s:%s" % (GetAttr(x, "uid"), "Account is locked")
622 F.write(Sanitize(Line) + "\n")
624 DisabledUsers.append(x)
626 # Oops, something unspeakable happened.
632 # Generate the list of local addresses that refuse all mail
633 def GenMailDisable(l, File):
636 F = open(File + ".tmp", "w")
638 # Fetch all the users
641 for x in PasswdAttrs:
644 if x[1].has_key("mailDisableMessage"):
645 Reason = GetAttr(x, "mailDisableMessage")
649 # Must be in the Debian group (yuk, hard coded for now)
650 if GetAttr(x, "gidNumber") != "800":
654 Line = "%s: %s"%(GetAttr(x, "uid"), Reason)
655 Line = Sanitize(Line) + "\n"
660 # Oops, something unspeakable happened.
666 # Generate a list of uids that should have boolean affects applied
667 def GenMailBool(l, File, Key):
670 F = open(File + ".tmp", "w")
672 # Fetch all the users
675 for x in PasswdAttrs:
678 if x[1].has_key(Key) == 0:
681 # Must be in the Debian group (yuk, hard coded for now)
682 if GetAttr(x, "gidNumber") != "800":
685 if GetAttr(x, Key) != "TRUE":
689 Line = "%s"%(GetAttr(x, "uid"))
690 Line = Sanitize(Line) + "\n"
695 # Oops, something unspeakable happened.
701 # Generate a list of hosts for RBL or whitelist purposes.
702 def GenMailList(l, File, Key):
705 F = open(File + ".tmp", "w")
707 # Fetch all the users
710 for x in PasswdAttrs:
713 if x[1].has_key(Key) == 0:
716 # Must be in the Debian group (yuk, hard coded for now)
717 if GetAttr(x, "gidNumber") != "800":
724 if Key == "mailWhitelist":
725 if re.match('^[-\w.]+(/[\d]+)?$', z) == None:
728 if re.match('^[-\w.]+$', z) == None:
732 Line = GetAttr(x, "uid")
736 if Key == "mailRHSBL":
737 Line += "/$sender_address_domain"
740 Line = Sanitize(Line) + "\n"
745 # Oops, something unspeakable happened.
751 def isRoleAccount(pwEntry):
752 if not pwEntry.has_key("objectClass"):
753 raise "pwEntry has no objectClass"
754 oc = pwEntry['objectClass']
756 i = oc.index('debianRoleAccount')
761 # Generate the DNS Zone file
762 def GenDNS(l, File, HomePrefix):
765 F = open(File + ".tmp", "w")
767 # Fetch all the users
770 # Write out the zone file entry for each user
771 for x in PasswdAttrs:
772 if x[1].has_key("dnsZoneEntry") == 0:
775 # If the account has no PGP key, do not write it
776 if x[1].has_key("keyFingerPrint") == 0 and not isRoleAccount(x[1]):
779 F.write("; %s\n"%(EmailAddress(x)))
780 for z in x[1]["dnsZoneEntry"]:
781 Split = z.lower().split()
782 if Split[1].lower() == 'in':
783 for y in range(0, len(Split)):
786 Line = " ".join(Split) + "\n"
789 Host = Split[0] + DNSZone
790 if BSMTPCheck.match(Line) != None:
791 F.write("; Has BSMTP\n")
793 # Write some identification information
794 if Split[2].lower() == "a":
795 Line = "%s IN TXT \"%s\"\n"%(Split[0], EmailAddress(x))
796 for y in x[1]["keyFingerPrint"]:
797 Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0], FormatPGPKey(y))
800 Line = "; Err %s"%(str(Split))
805 F.write("; Errors\n")
808 # Oops, something unspeakable happened.
814 # Generate the DNS SSHFP records
815 def GenSSHFP(l, File, HomePrefix):
818 F = open(File + ".tmp", "w")
820 # Fetch all the hosts
822 if HostAttrs == None:
823 raise UDEmptyList, "No Hosts"
826 if x[1].has_key("hostname") == 0 or \
827 x[1].has_key("sshRSAHostKey") == 0:
829 Host = GetAttr(x, "hostname")
831 for I in x[1]["sshRSAHostKey"]:
833 if Split[0] == 'ssh-rsa':
835 if Split[0] == 'ssh-dss':
837 if Algorithm == None:
839 Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
840 Line = "%s. IN SSHFP %u 1 %s" % (Host, Algorithm, Fingerprint)
841 Line = Sanitize(Line) + "\n"
843 # Oops, something unspeakable happened.
849 # Generate the BSMTP file
850 def GenBSMTP(l, File, HomePrefix):
853 F = open(File + ".tmp", "w")
855 # Fetch all the users
858 # Write out the zone file entry for each user
859 for x in PasswdAttrs:
860 if x[1].has_key("dnsZoneEntry") == 0:
863 # If the account has no PGP key, do not write it
864 if x[1].has_key("keyFingerPrint") == 0:
867 for z in x[1]["dnsZoneEntry"]:
868 Split = z.lower().split()
869 if Split[1].lower() == 'in':
870 for y in range(0, len(Split)):
873 Line = " ".join(Split) + "\n"
875 Host = Split[0] + DNSZone
876 if BSMTPCheck.match(Line) != None:
877 F.write("%s: user=%s group=Debian file=%s%s/bsmtp/%s\n"%(Host,
878 GetAttr(x, "uid"), HomePrefix, GetAttr(x, "uid"), Host))
881 F.write("; Errors\n")
884 # Oops, something unspeakable happened.
894 if not Host in HostToIPCache:
897 IPAdressesT = list(set([ (a[0], a[4][0]) for a in socket.getaddrinfo(Host, None)]))
898 except socket.gaierror, (code):
902 if not IPAdressesT is None:
903 for addr in IPAdressesT:
904 if addr[0] == socket.AF_INET:
905 IPAdresses += [addr[1], "::ffff:"+addr[1]]
907 IPAdresses += [addr[1]]
908 HostToIPCache[Host] = IPAdresses
909 return HostToIPCache[Host]
911 # Generate the ssh known hosts file
912 def GenSSHKnown(l, File, mode=None):
915 OldMask = os.umask(0022)
916 F = open(File + ".tmp", "w", 0644)
920 if HostAttrs == None:
921 raise UDEmptyList, "No Hosts"
924 if x[1].has_key("hostname") == 0 or \
925 x[1].has_key("sshRSAHostKey") == 0:
927 Host = GetAttr(x, "hostname")
929 if Host.endswith(HostDomain):
930 HostNames.append(Host[:-(len(HostDomain) + 1)])
932 # in the purpose field [[host|some other text]] (where some other text is optional)
933 # makes a hyperlink on the web thing. we now also add these hosts to the ssh known_hosts
934 # file. But so that we don't have to add everything we link we can add an asterisk
935 # and say [[*... to ignore it. In order to be able to add stuff to ssh without
936 # http linking it we also support [[-hostname]] entries.
937 for i in x[1].get("purpose", []):
938 m = PurposeHostField.match(i)
941 # we ignore [[*..]] entries
942 if m.startswith('*'):
944 if m.startswith('-'):
948 if m.endswith(HostDomain):
949 HostNames.append(m[:-(len(HostDomain) + 1)])
951 for I in x[1]["sshRSAHostKey"]:
952 if mode and mode == 'authorized_keys':
953 #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)
954 Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
956 Line = "%s %s" %(",".join(HostNames + HostToIP(Host)), I)
957 Line = Sanitize(Line) + "\n"
959 # Oops, something unspeakable happened.
965 # Generate the debianhosts file (list of all IP addresses)
966 def GenHosts(l, File):
969 OldMask = os.umask(0022)
970 F = open(File + ".tmp", "w", 0644)
973 # Fetch all the hosts
974 hostnames = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "hostname=*",
977 if hostnames == None:
978 raise UDEmptyList, "No Hosts"
982 host = GetAttr(x, "hostname", None)
986 addrs += socket.getaddrinfo(host, None, socket.AF_INET)
990 addrs += socket.getaddrinfo(host, None, socket.AF_INET6)
994 for addrinfo in addrs:
995 if addrinfo[0] in (socket.AF_INET, socket.AF_INET6):
996 addr = addrinfo[4][0]
998 print >> F, addrinfo[4][0]
1000 # Oops, something unspeakable happened.
1006 def GenKeyrings(l, OutDir):
1008 shutil.copy(k, OutDir)
1011 # Connect to the ldap server
1013 F = open(PassDir + "/pass-" + pwd.getpwuid(os.getuid())[0], "r")
1014 Pass = F.readline().strip().split(" ")
1016 l.simple_bind_s("uid=" + Pass[0] + "," + BaseDn, Pass[1])
1018 # Fetch all the groups
1020 Attrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "gid=*",\
1021 ["gid", "gidNumber", "subGroup"])
1023 # Generate the SubGroupMap and GroupIDMap
1025 if x[1].has_key("gidNumber") == 0:
1027 GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0])
1028 if x[1].has_key("subGroup") != 0:
1029 SubGroupMap.setdefault(x[1]["gid"][0], []).extend(x[1]["subGroup"])
1031 # Fetch all the users
1032 PasswdAttrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "uid=*",\
1033 ["uid", "uidNumber", "gidNumber", "supplementaryGid",\
1034 "gecos", "loginShell", "userPassword", "shadowLastChange",\
1035 "shadowMin", "shadowMax", "shadowWarning", "shadowInactive",
1036 "shadowExpire", "emailForward", "latitude", "longitude",\
1037 "allowedHost", "sshRSAAuthKey", "dnsZoneEntry", "cn", "sn",\
1038 "keyFingerPrint", "privateSub", "mailDisableMessage",\
1039 "mailGreylisting", "mailCallout", "mailRBL", "mailRHSBL",\
1040 "mailWhitelist", "sudoPassword", "objectClass", "accountStatus"])
1042 if PasswdAttrs is None:
1043 raise UDEmptyList, "No Users"
1045 # Fetch all the hosts
1046 HostAttrs = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "sshRSAHostKey=*",\
1047 ["hostname", "sshRSAHostKey", "purpose"])
1049 # Open the control file
1050 if len(sys.argv) == 1:
1051 F = open(GenerateConf, "r")
1053 F = open(sys.argv[1], "r")
1055 # Generate global things
1056 GlobalDir = GenerateDir + "/"
1057 GenDisabledAccounts(l, GlobalDir + "disabled-accounts")
1059 for x in PasswdAttrs:
1061 RetiredUsers.append(x)
1063 PasswdAttrs = filter(lambda x: not x in RetiredUsers, PasswdAttrs)
1067 GenMailDisable(l, GlobalDir + "mail-disable")
1068 GenAllForward(l, GlobalDir + "mail-forward.cdb")
1069 GenPrivate(l, GlobalDir + "debian-private")
1070 #GenSSHKnown(l,GlobalDir+"authorized_keys", 'authorized_keys')
1071 GenMailBool(l, GlobalDir + "mail-greylist", "mailGreylisting")
1072 GenMailBool(l, GlobalDir + "mail-callout", "mailCallout")
1073 GenMailList(l, GlobalDir + "mail-rbl", "mailRBL")
1074 GenMailList(l, GlobalDir + "mail-rhsbl", "mailRHSBL")
1075 GenMailList(l, GlobalDir + "mail-whitelist", "mailWhitelist")
1076 GenKeyrings(l, GlobalDir)
1079 GenForward(l, GlobalDir + "forward-alias")
1081 PasswdAttrs = filter(lambda x: not x in DisabledUsers, PasswdAttrs)
1083 SSHFiles = GenSSHShadow()
1084 GenMarkers(l, GlobalDir + "markers")
1085 GenSSHKnown(l, GlobalDir + "ssh_known_hosts")
1086 GenHosts(l, GlobalDir + "debianhosts")
1098 Split = Line.split(" ")
1099 OutDir = GenerateDir + '/' + Split[0] + '/'
1105 # Get the group list and convert any named groups to numerics
1113 if GroupIDMap.has_key(I):
1114 GroupList[str(GroupIDMap[I])] = None
1119 CurrentHost = Split[0]
1121 DoLink(GlobalDir, OutDir, "debianhosts")
1122 DoLink(GlobalDir, OutDir, "ssh_known_hosts")
1123 DoLink(GlobalDir, OutDir, "disabled-accounts")
1126 if ExtraList.has_key("[NOPASSWD]"):
1127 userlist = GenPasswd(l, OutDir + "passwd", Split[1], "*")
1129 userlist = GenPasswd(l, OutDir + "passwd", Split[1], "x")
1131 grouprevmap = GenGroup(l, OutDir + "group")
1132 GenShadowSudo(l, OutDir + "sudo-passwd", ExtraList.has_key("[UNTRUSTED]") or ExtraList.has_key("[NOPASSWD]"))
1134 # Now we know who we're allowing on the machine, export
1135 # the relevant ssh keys
1136 GenSSHtarballs(userlist, SSHFiles, grouprevmap, os.path.join(OutDir, 'ssh-keys.tar.gz'))
1138 if ExtraList.has_key("[UNTRUSTED]"):
1139 print "[UNTRUSTED] tag is obsolete and may be removed in the future."
1141 if not ExtraList.has_key("[NOPASSWD]"):
1142 GenShadow(l, OutDir + "shadow")
1144 # Link in global things
1145 if not ExtraList.has_key("[NOMARKERS]"):
1146 DoLink(GlobalDir, OutDir, "markers")
1147 DoLink(GlobalDir, OutDir, "mail-forward.cdb")
1148 DoLink(GlobalDir, OutDir, "mail-disable")
1149 DoLink(GlobalDir, OutDir, "mail-greylist")
1150 DoLink(GlobalDir, OutDir, "mail-callout")
1151 DoLink(GlobalDir, OutDir, "mail-rbl")
1152 DoLink(GlobalDir, OutDir, "mail-rhsbl")
1153 DoLink(GlobalDir, OutDir, "mail-whitelist")
1156 DoLink(GlobalDir, OutDir, "forward-alias")
1158 if ExtraList.has_key("[DNS]"):
1159 GenDNS(l, OutDir + "dns-zone", Split[1])
1160 GenSSHFP(l, OutDir + "dns-sshfp", Split[1])
1162 if ExtraList.has_key("[BSMTP]"):
1163 GenBSMTP(l, OutDir + "bsmtp", Split[1])
1165 if ExtraList.has_key("[PRIVATE]"):
1166 DoLink(GlobalDir, OutDir, "debian-private")
1168 if ExtraList.has_key("[KEYRING]"):
1170 DoLink(GlobalDir, OutDir, os.path.basename(k))
1174 posix.remove(OutDir + os.path.basename(k))
1180 # vim:set shiftwidth=3: