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>
15 # This program is free software; you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License as published by
17 # the Free Software Foundation; either version 2 of the License, or
18 # (at your option) any later version.
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 import string, re, time, ldap, getopt, sys, os, pwd, posix, socket, base64, sha, shutil, errno, tarfile, grp
30 from userdir_ldap import *
31 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):
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:
110 # See if this user is in the group list
111 def IsInGroup(DnRecord):
115 # See if the primary group is in the list
116 if Allowed.has_key(GetAttr(DnRecord,"gidNumber")) != 0:
119 # Check the host based ACL
120 if DnRecord[1].has_key("allowedHost") != 0:
121 for I in DnRecord[1]["allowedHost"]:
125 # See if there are supplementary groups
126 if DnRecord[1].has_key("supplementaryGid") == 0:
130 addGroups(supgroups, DnRecord[1]["supplementaryGid"], GetAttr(DnRecord,"uid"))
132 if Allowed.has_key(g):
142 os.remove(File + ".tmp")
146 os.remove(File + ".tdb.tmp")
150 def Done(File,F,Fdb):
153 os.rename(File + ".tmp",File)
156 os.rename(File + ".tdb.tmp",File+".tdb")
158 # Generate the password list
159 def GenPasswd(l,File,HomePrefix,PwdMarker):
162 F = open(File + ".tdb.tmp","w")
165 # Fetch all the users
169 for x in PasswdAttrs:
170 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
173 # Do not let people try to buffer overflow some busted passwd parser.
174 if len(GetAttr(x,"gecos")) > 100 or len(GetAttr(x,"loginShell")) > 50:
177 userlist[GetAttr(x, "uid")] = int(GetAttr(x, "gidNumber"))
178 Line = "%s:%s:%s:%s:%s:%s%s:%s" % (GetAttr(x,"uid"),\
180 GetAttr(x,"uidNumber"),GetAttr(x,"gidNumber"),\
181 GetAttr(x,"gecos"),HomePrefix,GetAttr(x,"uid"),\
182 GetAttr(x,"loginShell"))
184 Line = Sanitize(Line) + "\n"
185 F.write("0%u %s" % (I,Line))
186 F.write(".%s %s" % (GetAttr(x,"uid"),Line))
187 F.write("=%s %s" % (GetAttr(x,"uidNumber"),Line))
190 # Oops, something unspeakable happened.
196 # Return the list of users so we know which keys to export
199 # Generate the shadow list
200 def GenShadow(l,File):
203 OldMask = os.umask(0077)
204 F = open(File + ".tdb.tmp","w",0600)
207 # Fetch all the users
211 for x in PasswdAttrs:
212 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
215 Pass = GetAttr(x,"userPassword")
216 if Pass[0:7] != "{crypt}" or len(Pass) > 50:
221 # If the account is locked, mark it as such in shadow
222 # See Debian Bug #308229 for why we set it to 1 instead of 0
223 if (GetAttr(x,"userPassword").find("*LK*") != -1) \
224 or GetAttr(x,"userPassword").startswith("!"):
227 ShadowExpire = GetAttr(x,"shadowExpire")
229 Line = "%s:%s:%s:%s:%s:%s:%s:%s:" % (GetAttr(x,"uid"),\
230 Pass,GetAttr(x,"shadowLastChange"),\
231 GetAttr(x,"shadowMin"),GetAttr(x,"shadowMax"),\
232 GetAttr(x,"shadowWarning"),GetAttr(x,"shadowInactive"),\
234 Line = Sanitize(Line) + "\n"
235 F.write("0%u %s" % (I,Line))
236 F.write(".%s %s" % (GetAttr(x,"uid"),Line))
239 # Oops, something unspeakable happened.
245 # Generate the sudo passwd file
246 def GenShadowSudo(l,File, untrusted):
249 OldMask = os.umask(0077)
250 F = open(File + ".tmp","w",0600)
253 # Fetch all the users
256 for x in PasswdAttrs:
258 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
261 if x[1].has_key('sudoPassword'):
262 for entry in x[1]['sudoPassword']:
263 Match = re.compile('^('+UUID_FORMAT+') (confirmed:[0-9a-f]{40}|unconfirmed) ([a-z0-9.,*]+) ([^ ]+)$').match(entry)
266 uuid = Match.group(1)
267 status = Match.group(2)
268 hosts = Match.group(3)
269 cryptedpass = Match.group(4)
271 if status != 'confirmed:'+make_passwd_hmac('password-is-confirmed', 'sudo', x[1]['uid'][0], uuid, hosts, cryptedpass):
273 for_all = hosts == "*"
274 for_this_host = CurrentHost in hosts.split(',')
275 if not (for_all or for_this_host):
277 # ignore * passwords for untrusted hosts, but copy host specific passwords
278 if for_all and untrusted:
281 if for_this_host: # this makes sure we take a per-host entry over the for-all entry
286 Line = "%s:%s" % (GetAttr(x,"uid"), Pass)
287 Line = Sanitize(Line) + "\n"
288 F.write("%s" % (Line))
290 # Oops, something unspeakable happened.
296 # Generate the shadow list
298 # 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 in DisabledUsers:
312 if x[1].has_key("uidNumber") == 0 or \
313 x[1].has_key("sshRSAAuthKey") == 0:
316 User = GetAttr(x,"uid")
320 OldMask = os.umask(0077)
321 File = os.path.join(GlobalDir, 'userkeys', User)
322 F = open(File + ".tmp","w",0600)
325 for I in x[1]["sshRSAAuthKey"]:
326 MultipleLine = "%s" % I
327 MultipleLine = Sanitize(MultipleLine) + "\n"
328 F.write(MultipleLine)
331 userfiles.append(os.path.basename(File))
333 # Oops, something unspeakable happened.
336 Die(masterFileName,masterFile,None)
341 def GenSSHtarballs(userlist, SSHFiles, grouprevmap, target):
342 OldMask = os.umask(0077)
343 tf = tarfile.open(name=os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), mode='w:gz')
345 for f in userlist.keys():
346 if f not in SSHFiles:
348 # If we're not exporting their primary group, don't export
351 if userlist[f] in grouprevmap.keys():
352 grname = grouprevmap[userlist[f]]
355 if int(userlist[f]) <= 100:
356 # In these cases, look it up in the normal way so we
357 # deal with cases where, for instance, users are in group
358 # users as their primary group.
359 grname = grp.getgrgid(userlist[f])[0]
364 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])
367 to = tf.gettarinfo(os.path.join(GlobalDir, 'userkeys', f), f)
368 # These will only be used where the username doesn't
369 # exist on the target system for some reason; hence,
370 # in those cases, the safest thing is for the file to
371 # be owned by root but group nobody. This deals with
372 # the bloody obscure case where the group fails to exist
373 # whilst the user does (in which case we want to avoid
374 # ending up with a file which is owned user:root to avoid
375 # a fairly obvious attack vector)
378 # Using the username / groupname fields avoids any need
379 # to give a shit^W^W^Wcare about the UIDoffset stuff.
383 tf.addfile(to, file(os.path.join(GlobalDir, 'userkeys', f)))
386 os.rename(os.path.join(GlobalDir, 'ssh-keys-%s.tar.gz' % CurrentHost), target)
388 # add a list of groups to existing groups,
389 # including all subgroups thereof, recursively.
390 # basically this proceduces the transitive hull of the groups in
392 def addGroups(existingGroups, newGroups, uid):
393 for group in newGroups:
394 # if it's a <group>@host, split it and verify it's on the current host.
395 s = group.split('@', 1)
396 if len(s) == 2 and s[1] != CurrentHost:
400 # let's see if we handled this group already
401 if group in existingGroups:
404 if not GroupIDMap.has_key(group):
405 print "Group", group, "does not exist but", uid, "is in it"
408 existingGroups.append(group)
410 if SubGroupMap.has_key(group):
411 addGroups(existingGroups, SubGroupMap[group], uid)
413 # Generate the group list
414 def GenGroup(l,File):
418 F = open(File + ".tdb.tmp","w")
420 # Generate the GroupMap
422 for x in GroupIDMap.keys():
425 # Fetch all the users
428 # Sort them into a list of groups having a set of users
429 for x in PasswdAttrs:
430 uid = GetAttr(x,"uid")
431 if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
433 if x[1].has_key("supplementaryGid") == 0:
437 addGroups(supgroups, x[1]["supplementaryGid"], uid)
439 GroupMap[g].append(uid)
441 # Output the group file.
443 for x in GroupMap.keys():
444 grouprevmap[GroupIDMap[x]] = x
445 if GroupIDMap.has_key(x) == 0:
447 Line = "%s:x:%u:" % (x,GroupIDMap[x])
449 for I in GroupMap[x]:
450 Line = Line + ("%s%s" % (Comma,I))
452 Line = Sanitize(Line) + "\n"
453 F.write("0%u %s" % (J,Line))
454 F.write(".%s %s" % (x,Line))
455 F.write("=%u %s" % (GroupIDMap[x],Line))
458 # Oops, something unspeakable happened.
466 # Generate the email forwarding list
467 def GenForward(l,File):
470 OldMask = os.umask(0022)
471 F = open(File + ".tmp","w",0644)
474 # Fetch all the users
477 # Write out the email address for each user
478 for x in PasswdAttrs:
479 if x[1].has_key("emailForward") == 0 or IsInGroup(x) == 0:
482 # Do not allow people to try to buffer overflow busted parsers
483 if len(GetAttr(x,"emailForward")) > 200:
486 # Check the forwarding address
487 if EmailCheck.match(GetAttr(x,"emailForward")) == None:
489 Line = "%s: %s" % (GetAttr(x,"uid"),GetAttr(x,"emailForward"))
490 Line = Sanitize(Line) + "\n"
493 # Oops, something unspeakable happened.
499 def GenAllForward(l,File):
502 OldMask = os.umask(0022)
503 Fdb = os.popen("cdbmake %s %s.tmp"%(File,File),"w")
506 # Fetch all the users
509 # Write out the email address for each user
510 for x in PasswdAttrs:
511 if x[1].has_key("emailForward") == 0:
514 # Do not allow people to try to buffer overflow busted parsers
515 Forward = GetAttr(x,"emailForward")
516 if len(Forward) > 200:
519 # Check the forwarding address
520 if EmailCheck.match(Forward) == None:
523 User = GetAttr(x,"uid")
524 Fdb.write("+%d,%d:%s->%s\n"%(len(User),len(Forward),User,Forward))
527 # Oops, something unspeakable happened.
531 if Fdb.close() != None:
532 raise "cdbmake gave an error"
534 # Generate the anon XEarth marker file
535 def GenMarkers(l,File):
538 F = open(File + ".tmp","w")
540 # Fetch all the users
543 # Write out the position for each user
544 for x in PasswdAttrs:
545 if x[1].has_key("latitude") == 0 or x[1].has_key("longitude") == 0:
548 Line = "%8s %8s \"\""%(DecDegree(GetAttr(x,"latitude"),1),DecDegree(GetAttr(x,"longitude"),1))
549 Line = Sanitize(Line) + "\n"
554 # Oops, something unspeakable happened.
560 # Generate the debian-private subscription list
561 def GenPrivate(l,File):
564 F = open(File + ".tmp","w")
566 # Fetch all the users
569 # Write out the position for each user
570 for x in PasswdAttrs:
571 if x[1].has_key("privateSub") == 0:
574 # If the account has no PGP key, do not write it
575 if x[1].has_key("keyFingerPrint") == 0:
578 # Must be in the Debian group (yuk, hard coded for now)
579 if GetAttr(x,"gidNumber") != "800":
583 Line = "%s"%(GetAttr(x,"privateSub"))
584 Line = Sanitize(Line) + "\n"
589 # Oops, something unspeakable happened.
595 # Generate a list of locked accounts
596 def GenDisabledAccounts(l,File):
599 F = open(File + ".tmp","w")
601 # Fetch all the users
606 for x in PasswdAttrs:
607 if x[1].has_key("uidNumber") == 0:
610 Pass = GetAttr(x,"userPassword")
612 # *LK* is the reference value for a locked account
613 # password starting with ! is also a locked account
614 if Pass.find("*LK*") != -1 or Pass.startswith("!"):
615 # Format is <login>:<reason>
616 Line = "%s:%s" % (GetAttr(x,"uid"), "Account is locked")
619 F.write(Sanitize(Line) + "\n")
621 DisabledUsers.append(x)
623 # Oops, something unspeakable happened.
629 # Generate the list of local addresses that refuse all mail
630 def GenMailDisable(l,File):
633 F = open(File + ".tmp","w")
635 # Fetch all the users
638 for x in PasswdAttrs:
641 if x[1].has_key("mailDisableMessage"):
642 Reason = GetAttr(x,"mailDisableMessage")
646 # Must be in the Debian group (yuk, hard coded for now)
647 if GetAttr(x,"gidNumber") != "800":
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(l,File,Key):
667 F = open(File + ".tmp","w")
669 # Fetch all the users
672 for x in PasswdAttrs:
675 if x[1].has_key(Key) == 0:
678 # Must be in the Debian group (yuk, hard coded for now)
679 if GetAttr(x,"gidNumber") != "800":
682 if GetAttr(x,Key) != "TRUE":
686 Line = "%s"%(GetAttr(x,"uid"))
687 Line = Sanitize(Line) + "\n"
692 # Oops, something unspeakable happened.
698 # Generate a list of hosts for RBL or whitelist purposes.
699 def GenMailList(l,File,Key):
702 F = open(File + ".tmp","w")
704 # Fetch all the users
707 for x in PasswdAttrs:
710 if x[1].has_key(Key) == 0:
713 # Must be in the Debian group (yuk, hard coded for now)
714 if GetAttr(x,"gidNumber") != "800":
721 if Key == "mailWhitelist":
722 if re.match('^[-\w.]+(/[\d]+)?$',z) == None:
725 if re.match('^[-\w.]+$',z) == None:
729 Line = GetAttr(x,"uid")
733 if Key == "mailRHSBL":
734 Line += "/$sender_address_domain"
737 Line = Sanitize(Line) + "\n"
742 # Oops, something unspeakable happened.
748 def isRoleAccount(pwEntry):
749 if not pwEntry.has_key("objectClass"):
750 raise "pwEntry has no objectClass"
751 oc = pwEntry['objectClass']
753 i = oc.index('debianRoleAccount')
758 # Generate the DNS Zone file
759 def GenDNS(l,File,HomePrefix):
762 F = open(File + ".tmp","w")
764 # Fetch all the users
767 # Write out the zone file entry for each user
768 for x in PasswdAttrs:
769 if x[1].has_key("dnsZoneEntry") == 0:
772 # If the account has no PGP key, do not write it
773 if x[1].has_key("keyFingerPrint") == 0 and not isRoleAccount(x[1]):
776 F.write("; %s\n"%(EmailAddress(x)))
777 for z in x[1]["dnsZoneEntry"]:
778 Split = z.lower().split()
779 if Split[1].lower() == 'in':
780 for y in range(0,len(Split)):
783 Line = " ".join(Split) + "\n"
786 Host = Split[0] + DNSZone
787 if BSMTPCheck.match(Line) != None:
788 F.write("; Has BSMTP\n")
790 # Write some identification information
791 if Split[2].lower() == "a":
792 Line = "%s IN TXT \"%s\"\n"%(Split[0],EmailAddress(x))
793 for y in x[1]["keyFingerPrint"]:
794 Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0],FormatPGPKey(y))
797 Line = "; Err %s"%(str(Split))
802 F.write("; Errors\n")
805 # Oops, something unspeakable happened.
811 # Generate the DNS SSHFP records
812 def GenSSHFP(l,File,HomePrefix):
815 F = open(File + ".tmp","w")
817 # Fetch all the hosts
819 if HostAttrs == None:
820 raise UDEmptyList, "No Hosts"
823 if x[1].has_key("hostname") == 0 or \
824 x[1].has_key("sshRSAHostKey") == 0:
826 Host = GetAttr(x,"hostname")
828 for I in x[1]["sshRSAHostKey"]:
830 if Split[0] == 'ssh-rsa':
832 if Split[0] == 'ssh-dss':
834 if Algorithm == None:
836 Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
837 Line = "%s. IN SSHFP %u 1 %s" % (Host,Algorithm,Fingerprint)
838 Line = Sanitize(Line) + "\n"
840 # Oops, something unspeakable happened.
846 # Generate the BSMTP file
847 def GenBSMTP(l,File,HomePrefix):
850 F = open(File + ".tmp","w")
852 # Fetch all the users
855 # Write out the zone file entry for each user
856 for x in PasswdAttrs:
857 if x[1].has_key("dnsZoneEntry") == 0:
860 # If the account has no PGP key, do not write it
861 if x[1].has_key("keyFingerPrint") == 0:
864 for z in x[1]["dnsZoneEntry"]:
865 Split = z.lower().split()
866 if Split[1].lower() == 'in':
867 for y in range(0,len(Split)):
870 Line = " ".join(Split) + "\n"
872 Host = Split[0] + DNSZone
873 if BSMTPCheck.match(Line) != None:
874 F.write("%s: user=%s group=Debian file=%s%s/bsmtp/%s\n"%(Host,
875 GetAttr(x,"uid"),HomePrefix,GetAttr(x,"uid"),Host))
878 F.write("; Errors\n")
881 # Oops, something unspeakable happened.
891 if not Host in HostToIPCache:
894 IPAdressesT = list(set([ (a[0],a[4][0]) for a in socket.getaddrinfo(Host, None)]))
895 except socket.gaierror, (code):
899 if not IPAdressesT is None:
900 for addr in IPAdressesT:
901 if addr[0] == socket.AF_INET:
902 IPAdresses += [addr[1], "::ffff:"+addr[1]]
904 IPAdresses += [addr[1]]
905 HostToIPCache[Host] = IPAdresses
906 return HostToIPCache[Host]
908 # Generate the ssh known hosts file
909 def GenSSHKnown(l,File,mode=None):
912 OldMask = os.umask(0022)
913 F = open(File + ".tmp","w",0644)
917 if HostAttrs == None:
918 raise UDEmptyList, "No Hosts"
921 if x[1].has_key("hostname") == 0 or \
922 x[1].has_key("sshRSAHostKey") == 0:
924 Host = GetAttr(x,"hostname")
926 if Host.endswith(HostDomain):
927 HostNames.append(Host[:-(len(HostDomain)+1)])
929 # in the purpose field [[host|some other text]] (where some other text is optional)
930 # makes a hyperlink on the web thing. we now also add these hosts to the ssh known_hosts
931 # file. But so that we don't have to add everything we link we can add an asterisk
932 # and say [[*... to ignore it. In order to be able to add stuff to ssh without
933 # http linking it we also support [[-hostname]] entries.
934 for i in x[1].get("purpose",[]):
935 m = PurposeHostField.match(i)
938 # we ignore [[*..]] entries
939 if m.startswith('*'):
941 if m.startswith('-'):
945 if m.endswith(HostDomain):
946 HostNames.append(m[:-(len(HostDomain)+1)])
948 for I in x[1]["sshRSAHostKey"]:
949 if mode and mode == 'authorized_keys':
950 #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)
951 Line = 'command="rsync --server --sender -pr . /var/cache/userdir-ldap/hosts/%s",no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s' % (Host,I)
953 Line = "%s %s" %(",".join(HostNames + HostToIP(Host)), I)
954 Line = Sanitize(Line) + "\n"
956 # Oops, something unspeakable happened.
962 # Generate the debianhosts file (list of all IP addresses)
963 def GenHosts(l,File):
966 OldMask = os.umask(0022)
967 F = open(File + ".tmp","w",0644)
970 # Fetch all the hosts
971 hostnames = l.search_s(HostBaseDn, ldap.SCOPE_ONELEVEL, "hostname=*",
974 if hostnames == None:
975 raise UDEmptyList, "No Hosts"
979 host = GetAttr(x,"hostname", None)
983 addrs += socket.getaddrinfo(host, None, socket.AF_INET)
987 addrs += socket.getaddrinfo(host, None, socket.AF_INET6)
991 for addrinfo in addrs:
992 if addrinfo[0] in (socket.AF_INET, socket.AF_INET6):
993 addr = addrinfo[4][0]
995 print >> F, addrinfo[4][0]
997 # Oops, something unspeakable happened.
1003 def GenKeyrings(l,OutDir):
1005 shutil.copy(k, OutDir)
1008 # Connect to the ldap server
1010 F = open(PassDir+"/pass-"+pwd.getpwuid(os.getuid())[0],"r")
1011 Pass = F.readline().strip().split(" ")
1013 l.simple_bind_s("uid="+Pass[0]+","+BaseDn,Pass[1])
1015 # Fetch all the groups
1017 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"gid=*",\
1018 ["gid","gidNumber","subGroup"])
1020 # Generate the SubGroupMap and GroupIDMap
1022 if x[1].has_key("gidNumber") == 0:
1024 GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0])
1025 if x[1].has_key("subGroup") != 0:
1026 SubGroupMap.setdefault(x[1]["gid"][0], []).extend(x[1]["subGroup"])
1028 # Fetch all the users
1029 PasswdAttrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=*",\
1030 ["uid","uidNumber","gidNumber","supplementaryGid",\
1031 "gecos","loginShell","userPassword","shadowLastChange",\
1032 "shadowMin","shadowMax","shadowWarning","shadowInactive",
1033 "shadowExpire","emailForward","latitude","longitude",\
1034 "allowedHost","sshRSAAuthKey","dnsZoneEntry","cn","sn",\
1035 "keyFingerPrint","privateSub","mailDisableMessage",\
1036 "mailGreylisting","mailCallout","mailRBL","mailRHSBL",\
1037 "mailWhitelist", "sudoPassword", "objectClass", "accountStatus"])
1039 if PasswdAttrs is None:
1040 raise UDEmptyList, "No Users"
1042 # Fetch all the hosts
1043 HostAttrs = l.search_s(HostBaseDn,ldap.SCOPE_ONELEVEL,"sshRSAHostKey=*",\
1044 ["hostname","sshRSAHostKey","purpose"])
1046 # Open the control file
1047 if len(sys.argv) == 1:
1048 F = open(GenerateConf,"r")
1050 F = open(sys.argv[1],"r")
1052 # Generate global things
1053 GlobalDir = GenerateDir+"/"
1054 GenMailDisable(l,GlobalDir+"mail-disable")
1056 for x in PasswdAttrs:
1058 RetiredUsers.append(x)
1060 PasswdAttrs = filter(lambda x: not x in RetiredUsers, PasswdAttrs)
1062 SSHFiles = GenSSHShadow(l)
1063 GenAllForward(l,GlobalDir+"mail-forward.cdb")
1064 GenMarkers(l,GlobalDir+"markers")
1065 GenPrivate(l,GlobalDir+"debian-private")
1066 GenDisabledAccounts(l,GlobalDir+"disabled-accounts")
1067 GenSSHKnown(l,GlobalDir+"ssh_known_hosts")
1068 #GenSSHKnown(l,GlobalDir+"authorized_keys", 'authorized_keys')
1069 GenHosts(l,GlobalDir+"debianhosts")
1070 GenMailBool(l,GlobalDir+"mail-greylist","mailGreylisting")
1071 GenMailBool(l,GlobalDir+"mail-callout","mailCallout")
1072 GenMailList(l,GlobalDir+"mail-rbl","mailRBL")
1073 GenMailList(l,GlobalDir+"mail-rhsbl","mailRHSBL")
1074 GenMailList(l,GlobalDir+"mail-whitelist","mailWhitelist")
1075 GenKeyrings(l,GlobalDir)
1078 GenForward(l,GlobalDir+"forward-alias")
1080 PasswdAttrs = filter(lambda x: not x in DisabledUsers, PasswdAttrs)
1092 Split = Line.split(" ")
1093 OutDir = GenerateDir + '/' + Split[0] + '/'
1099 # Get the group list and convert any named groups to numerics
1107 if GroupIDMap.has_key(I):
1108 GroupList[str(GroupIDMap[I])] = None
1113 CurrentHost = Split[0]
1115 DoLink(GlobalDir,OutDir,"debianhosts")
1116 DoLink(GlobalDir,OutDir,"ssh_known_hosts")
1117 DoLink(GlobalDir,OutDir,"disabled-accounts")
1120 if ExtraList.has_key("[NOPASSWD]"):
1121 userlist = GenPasswd(l,OutDir+"passwd",Split[1], "*")
1123 userlist = GenPasswd(l,OutDir+"passwd",Split[1], "x")
1125 grouprevmap = GenGroup(l,OutDir+"group")
1126 GenShadowSudo(l, OutDir+"sudo-passwd", ExtraList.has_key("[UNTRUSTED]") or ExtraList.has_key("[NOPASSWD]"))
1128 # Now we know who we're allowing on the machine, export
1129 # the relevant ssh keys
1130 GenSSHtarballs(userlist, SSHFiles, grouprevmap, os.path.join(OutDir, 'ssh-keys.tar.gz'))
1132 if ExtraList.has_key("[UNTRUSTED]"):
1133 print "[UNTRUSTED] tag is obsolete and may be removed in the future."
1135 if not ExtraList.has_key("[NOPASSWD]"):
1136 GenShadow(l,OutDir+"shadow")
1138 # Link in global things
1139 if not ExtraList.has_key("[NOMARKERS]"):
1140 DoLink(GlobalDir,OutDir,"markers")
1141 DoLink(GlobalDir,OutDir,"mail-forward.cdb")
1142 DoLink(GlobalDir,OutDir,"mail-disable")
1143 DoLink(GlobalDir,OutDir,"mail-greylist")
1144 DoLink(GlobalDir,OutDir,"mail-callout")
1145 DoLink(GlobalDir,OutDir,"mail-rbl")
1146 DoLink(GlobalDir,OutDir,"mail-rhsbl")
1147 DoLink(GlobalDir,OutDir,"mail-whitelist")
1150 DoLink(GlobalDir,OutDir,"forward-alias")
1152 if ExtraList.has_key("[DNS]"):
1153 GenDNS(l,OutDir+"dns-zone",Split[1])
1154 GenSSHFP(l,OutDir+"dns-sshfp",Split[1])
1156 if ExtraList.has_key("[BSMTP]"):
1157 GenBSMTP(l,OutDir+"bsmtp",Split[1])
1159 if ExtraList.has_key("[PRIVATE]"):
1160 DoLink(GlobalDir,OutDir,"debian-private")
1162 if ExtraList.has_key("[KEYRING]"):
1164 DoLink(GlobalDir,OutDir,os.path.basename(k))
1168 posix.remove(OutDir+os.path.basename(k))
1174 # vim:set shiftwidth=3: