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
305 safe_rmtree(os.path.join(GlobalDir, 'userkeys'))
306 safe_makedirs(os.path.join(GlobalDir, 'userkeys'))
308 for x in PasswdAttrs:
310 if x in DisabledUsers:
313 if x[1].has_key("uidNumber") == 0 or \
314 x[1].has_key("sshRSAAuthKey") == 0:
317 User = GetAttr(x, "uid")
321 OldMask = os.umask(0077)
322 File = os.path.join(GlobalDir, 'userkeys', User)
323 F = open(File + ".tmp", "w", 0600)
326 for I in x[1]["sshRSAAuthKey"]:
327 MultipleLine = "%s" % I
328 MultipleLine = Sanitize(MultipleLine) + "\n"
329 F.write(MultipleLine)
332 userfiles.append(os.path.basename(File))
334 # Oops, something unspeakable happened.
337 Die(masterFileName, masterFile, None)
342 def GenSSHtarballs(userlist, SSHFiles, grouprevmap, target):
343 OldMask = os.umask(0077)
344 tf = tarfile.open(name=os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), mode='w:gz')
346 for f in userlist.keys():
347 if f not in SSHFiles:
349 # If we're not exporting their primary group, don't export
352 if userlist[f] in grouprevmap.keys():
353 grname = grouprevmap[userlist[f]]
356 if int(userlist[f]) <= 100:
357 # In these cases, look it up in the normal way so we
358 # deal with cases where, for instance, users are in group
359 # users as their primary group.
360 grname = grp.getgrgid(userlist[f])[0]
365 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])
368 to = tf.gettarinfo(os.path.join(GlobalDir, 'userkeys', f), f)
369 # These will only be used where the username doesn't
370 # exist on the target system for some reason; hence,
371 # in those cases, the safest thing is for the file to
372 # be owned by root but group nobody. This deals with
373 # the bloody obscure case where the group fails to exist
374 # whilst the user does (in which case we want to avoid
375 # ending up with a file which is owned user:root to avoid
376 # a fairly obvious attack vector)
379 # Using the username / groupname fields avoids any need
380 # to give a shit^W^W^Wcare about the UIDoffset stuff.
384 tf.addfile(to, file(os.path.join(GlobalDir, 'userkeys', f)))
387 os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
389 # add a list of groups to existing groups,
390 # including all subgroups thereof, recursively.
391 # basically this proceduces the transitive hull of the groups in
393 def addGroups(existingGroups, newGroups, uid):
394 for group in newGroups:
395 # if it's a <group>@host, split it and verify it's on the current host.
396 s = group.split('@', 1)
397 if len(s) == 2 and s[1] != CurrentHost:
401 # let's see if we handled this group already
402 if group in existingGroups:
405 if not GroupIDMap.has_key(group):
406 print "Group", group, "does not exist but", uid, "is in it"
409 existingGroups.append(group)
411 if SubGroupMap.has_key(group):
412 addGroups(existingGroups, SubGroupMap[group], uid)
414 # Generate the group list
415 def GenGroup(l, File):
419 F = open(File + ".tdb.tmp", "w")
421 # Generate the GroupMap
423 for x in GroupIDMap.keys():
426 # Fetch all the users
429 # Sort them into a list of groups having a set of users
430 for x in PasswdAttrs:
431 uid = GetAttr(x, "uid")
432 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
434 if x[1].has_key("supplementaryGid") == 0:
438 addGroups(supgroups, x[1]["supplementaryGid"], uid)
440 GroupMap[g].append(uid)
442 # Output the group file.
444 for x in GroupMap.keys():
445 grouprevmap[GroupIDMap[x]] = x
446 if GroupIDMap.has_key(x) == 0:
448 Line = "%s:x:%u:" % (x, GroupIDMap[x])
450 for I in GroupMap[x]:
451 Line = Line + ("%s%s" % (Comma, I))
453 Line = Sanitize(Line) + "\n"
454 F.write("0%u %s" % (J, Line))
455 F.write(".%s %s" % (x, Line))
456 F.write("=%u %s" % (GroupIDMap[x], Line))
459 # Oops, something unspeakable happened.
469 for x in PasswdAttrs:
470 if x[1].has_key("emailForward") == 0:
473 if IsInGroup(x) == 0:
474 x[1].pop("emailForward")
477 # Do not allow people to try to buffer overflow busted parsers
478 if len(GetAttr(x, "emailForward")) > 200:
479 x[1].pop("emailForward")
482 # Check the forwarding address
483 if EmailCheck.match(GetAttr(x, "emailForward")) == None:
484 x[1].pop("emailForward")
486 # Generate the email forwarding list
487 def GenForward(l, File):
490 OldMask = os.umask(0022)
491 F = open(File + ".tmp", "w", 0644)
494 # Fetch all the users
497 # Write out the email address for each user
498 for x in PasswdAttrs:
499 if x[1].has_key("emailForward") == 0:
502 Line = "%s: %s" % (GetAttr(x, "uid"), GetAttr(x, "emailForward"))
503 Line = Sanitize(Line) + "\n"
506 # Oops, something unspeakable happened.
512 def GenAllForward(l, File):
515 OldMask = os.umask(0022)
516 Fdb = os.popen("cdbmake %s %s.tmp"%(File, File), "w")
519 # Fetch all the users
522 # Write out the email address for each user
523 for x in PasswdAttrs:
524 if x[1].has_key("emailForward") == 0:
527 # Do not allow people to try to buffer overflow busted parsers
528 Forward = GetAttr(x, "emailForward")
530 User = GetAttr(x, "uid")
531 Fdb.write("+%d,%d:%s->%s\n" % (len(User), len(Forward), User, Forward))
534 # Oops, something unspeakable happened.
538 if Fdb.close() != None:
539 raise "cdbmake gave an error"
541 # Generate the anon XEarth marker file
542 def GenMarkers(l, File):
545 F = open(File + ".tmp", "w")
547 # Fetch all the users
550 # Write out the position for each user
551 for x in PasswdAttrs:
552 if x[1].has_key("latitude") == 0 or x[1].has_key("longitude") == 0:
555 Line = "%8s %8s \"\""%(DecDegree(GetAttr(x, "latitude"), 1), DecDegree(GetAttr(x, "longitude"), 1))
556 Line = Sanitize(Line) + "\n"
561 # Oops, something unspeakable happened.
567 # Generate the debian-private subscription list
568 def GenPrivate(l, File):
571 F = open(File + ".tmp", "w")
573 # Fetch all the users
576 # Write out the position for each user
577 for x in PasswdAttrs:
578 if x[1].has_key("privateSub") == 0:
581 # If the account has no PGP key, do not write it
582 if x[1].has_key("keyFingerPrint") == 0:
585 # Must be in the Debian group (yuk, hard coded for now)
586 if GetAttr(x, "gidNumber") != "800":
590 Line = "%s"%(GetAttr(x, "privateSub"))
591 Line = Sanitize(Line) + "\n"
596 # Oops, something unspeakable happened.
602 # Generate a list of locked accounts
603 def GenDisabledAccounts(l, File):
606 F = open(File + ".tmp", "w")
608 # Fetch all the users
613 for x in PasswdAttrs:
614 if x[1].has_key("uidNumber") == 0:
617 Pass = GetAttr(x, "userPassword")
619 # *LK* is the reference value for a locked account
620 # password starting with ! is also a locked account
621 if Pass.find("*LK*") != -1 or Pass.startswith("!"):
622 # Format is <login>:<reason>
623 Line = "%s:%s" % (GetAttr(x, "uid"), "Account is locked")
626 F.write(Sanitize(Line) + "\n")
628 DisabledUsers.append(x)
630 # Oops, something unspeakable happened.
636 # Generate the list of local addresses that refuse all mail
637 def GenMailDisable(l, File):
640 F = open(File + ".tmp", "w")
642 # Fetch all the users
645 for x in PasswdAttrs:
648 if x[1].has_key("mailDisableMessage"):
649 Reason = GetAttr(x, "mailDisableMessage")
653 # Must be in the Debian group (yuk, hard coded for now)
654 if GetAttr(x, "gidNumber") != "800":
658 Line = "%s: %s"%(GetAttr(x, "uid"), Reason)
659 Line = Sanitize(Line) + "\n"
664 # Oops, something unspeakable happened.
670 # Generate a list of uids that should have boolean affects applied
671 def GenMailBool(l, File, Key):
674 F = open(File + ".tmp", "w")
676 # Fetch all the users
679 for x in PasswdAttrs:
682 if x[1].has_key(Key) == 0:
685 # Must be in the Debian group (yuk, hard coded for now)
686 if GetAttr(x, "gidNumber") != "800":
689 if GetAttr(x, Key) != "TRUE":
693 Line = "%s"%(GetAttr(x, "uid"))
694 Line = Sanitize(Line) + "\n"
699 # Oops, something unspeakable happened.
705 # Generate a list of hosts for RBL or whitelist purposes.
706 def GenMailList(l, File, Key):
709 F = open(File + ".tmp", "w")
711 # Fetch all the users
714 for x in PasswdAttrs:
717 if x[1].has_key(Key) == 0:
720 # Must be in the Debian group (yuk, hard coded for now)
721 if GetAttr(x, "gidNumber") != "800":
728 if Key == "mailWhitelist":
729 if re.match('^[-\w.]+(/[\d]+)?$', z) == None:
732 if re.match('^[-\w.]+$', z) == None:
736 Line = GetAttr(x, "uid")
740 if Key == "mailRHSBL":
741 Line += "/$sender_address_domain"
744 Line = Sanitize(Line) + "\n"
749 # Oops, something unspeakable happened.
755 def isRoleAccount(pwEntry):
756 if not pwEntry.has_key("objectClass"):
757 raise "pwEntry has no objectClass"
758 oc = pwEntry['objectClass']
760 i = oc.index('debianRoleAccount')
765 # Generate the DNS Zone file
766 def GenDNS(l, File, HomePrefix):
769 F = open(File + ".tmp", "w")
771 # Fetch all the users
774 # Write out the zone file entry for each user
775 for x in PasswdAttrs:
776 if x[1].has_key("dnsZoneEntry") == 0:
779 # If the account has no PGP key, do not write it
780 if x[1].has_key("keyFingerPrint") == 0 and not isRoleAccount(x[1]):
783 F.write("; %s\n"%(EmailAddress(x)))
784 for z in x[1]["dnsZoneEntry"]:
785 Split = z.lower().split()
786 if Split[1].lower() == 'in':
787 for y in range(0, len(Split)):
790 Line = " ".join(Split) + "\n"
793 Host = Split[0] + DNSZone
794 if BSMTPCheck.match(Line) != None:
795 F.write("; Has BSMTP\n")
797 # Write some identification information
798 if Split[2].lower() == "a":
799 Line = "%s IN TXT \"%s\"\n"%(Split[0], EmailAddress(x))
800 for y in x[1]["keyFingerPrint"]:
801 Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0], FormatPGPKey(y))
804 Line = "; Err %s"%(str(Split))
809 F.write("; Errors\n")
812 # Oops, something unspeakable happened.
818 # Generate the DNS SSHFP records
819 def GenSSHFP(l, File, HomePrefix):
822 F = open(File + ".tmp", "w")
824 # Fetch all the hosts
826 if HostAttrs == None:
827 raise UDEmptyList, "No Hosts"
830 if x[1].has_key("hostname") == 0 or \
831 x[1].has_key("sshRSAHostKey") == 0:
833 Host = GetAttr(x, "hostname")
835 for I in x[1]["sshRSAHostKey"]:
837 if Split[0] == 'ssh-rsa':
839 if Split[0] == 'ssh-dss':
841 if Algorithm == None:
843 Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
844 Line = "%s. IN SSHFP %u 1 %s" % (Host, Algorithm, Fingerprint)
845 Line = Sanitize(Line) + "\n"
847 # Oops, something unspeakable happened.
853 # Generate the BSMTP file
854 def GenBSMTP(l, File, HomePrefix):
857 F = open(File + ".tmp", "w")
859 # Fetch all the users
862 # Write out the zone file entry for each user
863 for x in PasswdAttrs:
864 if x[1].has_key("dnsZoneEntry") == 0:
867 # If the account has no PGP key, do not write it
868 if x[1].has_key("keyFingerPrint") == 0:
871 for z in x[1]["dnsZoneEntry"]:
872 Split = z.lower().split()
873 if Split[1].lower() == 'in':
874 for y in range(0, len(Split)):
877 Line = " ".join(Split) + "\n"
879 Host = Split[0] + DNSZone
880 if BSMTPCheck.match(Line) != None:
881 F.write("%s: user=%s group=Debian file=%s%s/bsmtp/%s\n"%(Host,
882 GetAttr(x, "uid"), HomePrefix, GetAttr(x, "uid"), Host))
885 F.write("; Errors\n")
888 # Oops, something unspeakable happened.
898 if not Host in HostToIPCache:
901 IPAdressesT = list(set([ (a[0], a[4][0]) for a in socket.getaddrinfo(Host, None)]))
902 except socket.gaierror, (code):
906 if not IPAdressesT is None:
907 for addr in IPAdressesT:
908 if addr[0] == socket.AF_INET:
909 IPAdresses += [addr[1], "::ffff:"+addr[1]]
911 IPAdresses += [addr[1]]
912 HostToIPCache[Host] = IPAdresses
913 return HostToIPCache[Host]
915 # Generate the ssh known hosts file
916 def GenSSHKnown(l, File, mode=None):
919 OldMask = os.umask(0022)
920 F = open(File + ".tmp", "w", 0644)
924 if HostAttrs == None:
925 raise UDEmptyList, "No Hosts"
928 if x[1].has_key("hostname") == 0 or \
929 x[1].has_key("sshRSAHostKey") == 0:
931 Host = GetAttr(x, "hostname")
933 if Host.endswith(HostDomain):
934 HostNames.append(Host[:-(len(HostDomain) + 1)])
936 # in the purpose field [[host|some other text]] (where some other text is optional)
937 # makes a hyperlink on the web thing. we now also add these hosts to the ssh known_hosts
938 # file. But so that we don't have to add everything we link we can add an asterisk
939 # and say [[*... to ignore it. In order to be able to add stuff to ssh without
940 # http linking it we also support [[-hostname]] entries.
941 for i in x[1].get("purpose", []):
942 m = PurposeHostField.match(i)
945 # we ignore [[*..]] entries
946 if m.startswith('*'):
948 if m.startswith('-'):
952 if m.endswith(HostDomain):
953 HostNames.append(m[:-(len(HostDomain) + 1)])
955 for I in x[1]["sshRSAHostKey"]:
956 if mode and mode == 'authorized_keys':
957 #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)
958 Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
960 Line = "%s %s" %(",".join(HostNames + HostToIP(Host)), I)
961 Line = Sanitize(Line) + "\n"
963 # Oops, something unspeakable happened.
969 # Generate the debianhosts file (list of all IP addresses)
970 def GenHosts(l, File):
973 OldMask = os.umask(0022)
974 F = open(File + ".tmp", "w", 0644)
977 # Fetch all the hosts
978 hostnames = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "hostname=*",
981 if hostnames == None:
982 raise UDEmptyList, "No Hosts"
986 host = GetAttr(x, "hostname", None)
990 addrs += socket.getaddrinfo(host, None, socket.AF_INET)
994 addrs += socket.getaddrinfo(host, None, socket.AF_INET6)
998 for addrinfo in addrs:
999 if addrinfo[0] in (socket.AF_INET, socket.AF_INET6):
1000 addr = addrinfo[4][0]
1001 if addr not in seen:
1002 print >> F, addrinfo[4][0]
1004 # Oops, something unspeakable happened.
1010 def GenKeyrings(l, OutDir):
1012 shutil.copy(k, OutDir)
1015 # Connect to the ldap server
1017 F = open(PassDir + "/pass-" + pwd.getpwuid(os.getuid())[0], "r")
1018 Pass = F.readline().strip().split(" ")
1020 l.simple_bind_s("uid=" + Pass[0] + "," + BaseDn, Pass[1])
1022 # Fetch all the groups
1024 Attrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "gid=*",\
1025 ["gid", "gidNumber", "subGroup"])
1027 # Generate the SubGroupMap and GroupIDMap
1029 if x[1].has_key("gidNumber") == 0:
1031 GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0])
1032 if x[1].has_key("subGroup") != 0:
1033 SubGroupMap.setdefault(x[1]["gid"][0], []).extend(x[1]["subGroup"])
1035 # Fetch all the users
1036 PasswdAttrs = l.search_s(BaseDn, ldap.SCOPE_ONELEVEL, "uid=*",\
1037 ["uid", "uidNumber", "gidNumber", "supplementaryGid",\
1038 "gecos", "loginShell", "userPassword", "shadowLastChange",\
1039 "shadowMin", "shadowMax", "shadowWarning", "shadowInactive",
1040 "shadowExpire", "emailForward", "latitude", "longitude",\
1041 "allowedHost", "sshRSAAuthKey", "dnsZoneEntry", "cn", "sn",\
1042 "keyFingerPrint", "privateSub", "mailDisableMessage",\
1043 "mailGreylisting", "mailCallout", "mailRBL", "mailRHSBL",\
1044 "mailWhitelist", "sudoPassword", "objectClass", "accountStatus"])
1046 if PasswdAttrs is None:
1047 raise UDEmptyList, "No Users"
1049 # Fetch all the hosts
1050 HostAttrs = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "sshRSAHostKey=*",\
1051 ["hostname", "sshRSAHostKey", "purpose"])
1053 # Open the control file
1054 if len(sys.argv) == 1:
1055 F = open(GenerateConf, "r")
1057 F = open(sys.argv[1], "r")
1059 # Generate global things
1060 GlobalDir = GenerateDir + "/"
1061 GenMailDisable(l, GlobalDir + "mail-disable")
1063 for x in PasswdAttrs:
1065 RetiredUsers.append(x)
1067 PasswdAttrs = filter(lambda x: not x in RetiredUsers, PasswdAttrs)
1071 SSHFiles = GenSSHShadow(l)
1072 GenAllForward(l, GlobalDir + "mail-forward.cdb")
1073 GenMarkers(l, GlobalDir + "markers")
1074 GenPrivate(l, GlobalDir + "debian-private")
1075 GenDisabledAccounts(l, GlobalDir + "disabled-accounts")
1076 GenSSHKnown(l, GlobalDir + "ssh_known_hosts")
1077 #GenSSHKnown(l,GlobalDir+"authorized_keys", 'authorized_keys')
1078 GenHosts(l, GlobalDir + "debianhosts")
1079 GenMailBool(l, GlobalDir + "mail-greylist", "mailGreylisting")
1080 GenMailBool(l, GlobalDir + "mail-callout", "mailCallout")
1081 GenMailList(l, GlobalDir + "mail-rbl", "mailRBL")
1082 GenMailList(l, GlobalDir + "mail-rhsbl", "mailRHSBL")
1083 GenMailList(l, GlobalDir + "mail-whitelist", "mailWhitelist")
1084 GenKeyrings(l, GlobalDir)
1087 GenForward(l, GlobalDir + "forward-alias")
1089 PasswdAttrs = filter(lambda x: not x in DisabledUsers, PasswdAttrs)
1101 Split = Line.split(" ")
1102 OutDir = GenerateDir + '/' + Split[0] + '/'
1108 # Get the group list and convert any named groups to numerics
1116 if GroupIDMap.has_key(I):
1117 GroupList[str(GroupIDMap[I])] = None
1122 CurrentHost = Split[0]
1124 DoLink(GlobalDir, OutDir, "debianhosts")
1125 DoLink(GlobalDir, OutDir, "ssh_known_hosts")
1126 DoLink(GlobalDir, OutDir, "disabled-accounts")
1129 if ExtraList.has_key("[NOPASSWD]"):
1130 userlist = GenPasswd(l, OutDir + "passwd", Split[1], "*")
1132 userlist = GenPasswd(l, OutDir + "passwd", Split[1], "x")
1134 grouprevmap = GenGroup(l, OutDir + "group")
1135 GenShadowSudo(l, OutDir + "sudo-passwd", ExtraList.has_key("[UNTRUSTED]") or ExtraList.has_key("[NOPASSWD]"))
1137 # Now we know who we're allowing on the machine, export
1138 # the relevant ssh keys
1139 GenSSHtarballs(userlist, SSHFiles, grouprevmap, os.path.join(OutDir, 'ssh-keys.tar.gz'))
1141 if ExtraList.has_key("[UNTRUSTED]"):
1142 print "[UNTRUSTED] tag is obsolete and may be removed in the future."
1144 if not ExtraList.has_key("[NOPASSWD]"):
1145 GenShadow(l, OutDir + "shadow")
1147 # Link in global things
1148 if not ExtraList.has_key("[NOMARKERS]"):
1149 DoLink(GlobalDir, OutDir, "markers")
1150 DoLink(GlobalDir, OutDir, "mail-forward.cdb")
1151 DoLink(GlobalDir, OutDir, "mail-disable")
1152 DoLink(GlobalDir, OutDir, "mail-greylist")
1153 DoLink(GlobalDir, OutDir, "mail-callout")
1154 DoLink(GlobalDir, OutDir, "mail-rbl")
1155 DoLink(GlobalDir, OutDir, "mail-rhsbl")
1156 DoLink(GlobalDir, OutDir, "mail-whitelist")
1159 DoLink(GlobalDir, OutDir, "forward-alias")
1161 if ExtraList.has_key("[DNS]"):
1162 GenDNS(l, OutDir + "dns-zone", Split[1])
1163 GenSSHFP(l, OutDir + "dns-sshfp", Split[1])
1165 if ExtraList.has_key("[BSMTP]"):
1166 GenBSMTP(l, OutDir + "bsmtp", Split[1])
1168 if ExtraList.has_key("[PRIVATE]"):
1169 DoLink(GlobalDir, OutDir, "debian-private")
1171 if ExtraList.has_key("[KEYRING]"):
1173 DoLink(GlobalDir, OutDir, os.path.basename(k))
1177 posix.remove(OutDir + os.path.basename(k))
1183 # vim:set shiftwidth=3: