ec62981b607dabd4dbd137519f7ff9d61402d1a9
[mirror/userdir-ldap.git] / ud-generate
1 #!/usr/bin/env python
2 # -*- mode: python -*-
3 # Generates passwd, shadow and group files from the ldap directory.
4
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 #
10 #   This program is free software; you can redistribute it and/or modify
11 #   it under the terms of the GNU General Public License as published by
12 #   the Free Software Foundation; either version 2 of the License, or
13 #   (at your option) any later version.
14 #
15 #   This program is distributed in the hope that it will be useful,
16 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 #   GNU General Public License for more details.
19 #
20 #   You should have received a copy of the GNU General Public License
21 #   along with this program; if not, write to the Free Software
22 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 import string, re, time, ldap, getopt, sys, os, pwd, posix, socket, base64, sha, shutil
25 from userdir_ldap import *;
26
27 global Allowed;
28 global CurrentHost;
29
30 PasswdAttrs = None;
31 GroupIDMap = {};
32 Allowed = None;
33 CurrentHost = "";
34
35 EmailCheck = re.compile("^([^ <>@]+@[^ ,<>@]+)?$");
36 BSMTPCheck = re.compile(".*mx 0 (gluck)\.debian\.org\..*",re.DOTALL);
37 DNSZone = ".debian.net"
38 Keyrings = [ "/org/keyring.debian.org/keyrings/debian-keyring.gpg",
39              "/org/keyring.debian.org/keyrings/debian-keyring.pgp" ]
40
41 def Sanitize(Str):
42   return Str.translate(string.maketrans("\n\r\t","$$$"))
43
44 def DoLink(From,To,File):
45    try: posix.remove(To+File);
46    except: pass;
47    posix.link(From+File,To+File);
48
49 # See if this user is in the group list
50 def IsInGroup(DnRecord):
51   if Allowed == None:
52      return 1;
53
54   # See if the primary group is in the list
55   if Allowed.has_key(GetAttr(DnRecord,"gidNumber")) != 0:
56      return 1;
57
58   # Check the host based ACL
59   if DnRecord[1].has_key("allowedHost") != 0:
60      for I in DnRecord[1]["allowedHost"]:
61         if CurrentHost == I:
62            return 1;
63
64   # See if there are supplementary groups
65   if DnRecord[1].has_key("supplementaryGid") == 0:
66      return 0;
67
68   # Check the supplementary groups
69   for I in DnRecord[1]["supplementaryGid"]:
70      if Allowed.has_key(I):
71         return 1;
72   return 0;
73
74 def Die(File,F,Fdb):
75    if F != None:
76       F.close();
77    if Fdb != None:
78       Fdb.close();
79    try: os.remove(File + ".tmp");
80    except: pass;
81    try: os.remove(File + ".tdb.tmp");
82    except: pass;
83
84 def Done(File,F,Fdb):
85   if F != None:
86     F.close();
87     os.rename(File + ".tmp",File);
88   if Fdb != None:
89     Fdb.close();
90     os.rename(File + ".tdb.tmp",File+".tdb");
91   
92 # Generate the password list
93 def GenPasswd(l,File,HomePrefix,PwdMarker):
94   F = None;
95   try:
96    F = open(File + ".tdb.tmp","w");
97
98    # Fetch all the users
99    global PasswdAttrs;
100    if PasswdAttrs == None:
101       raise "No Users";
102
103    I = 0;
104    for x in PasswdAttrs:
105       if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
106          continue;
107
108       # Do not let people try to buffer overflow some busted passwd parser.
109       if len(GetAttr(x,"gecos")) > 100 or len(GetAttr(x,"loginShell")) > 50:
110          continue;
111
112       Line = "%s:%s:%s:%s:%s:%s%s:%s" % (GetAttr(x,"uid"),\
113               PwdMarker,\
114               GetAttr(x,"uidNumber"),GetAttr(x,"gidNumber"),\
115               GetAttr(x,"gecos"),HomePrefix,GetAttr(x,"uid"),\
116               GetAttr(x,"loginShell"));
117
118       Line = Sanitize(Line) + "\n";
119       F.write("0%u %s" % (I,Line));
120       F.write(".%s %s" % (GetAttr(x,"uid"),Line));
121       F.write("=%s %s" % (GetAttr(x,"uidNumber"),Line));
122       I = I + 1;
123
124   # Oops, something unspeakable happened.
125   except:
126    Die(File,None,F);
127    raise;
128   Done(File,None,F);
129
130 # Generate the shadow list
131 def GenShadow(l,File):
132   F = None;
133   try:
134    OldMask = os.umask(0077);
135    F = open(File + ".tdb.tmp","w",0600);
136    os.umask(OldMask);
137
138    # Fetch all the users
139    global PasswdAttrs;
140    if PasswdAttrs == None:
141       raise "No Users";
142
143    I = 0;
144    for x in PasswdAttrs:
145       if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
146          continue;
147          
148       Pass = GetAttr(x,"userPassword");
149       if Pass[0:7] != "{crypt}" or len(Pass) > 50:
150          Pass = '*';
151       else:
152          Pass = Pass[7:];
153
154       # If the account is locked, mark it as such in shadow
155       # See Debian Bug #308229 for why we set it to 1 instead of 0
156       if (GetAttr(x,"userPassword").find("*LK*") != -1) \
157           or GetAttr(x,"userPassword").startswith("!"):
158          ShadowExpire = '1'
159       else:
160          ShadowExpire = GetAttr(x,"shadowexpire")
161
162       Line = "%s:%s:%s:%s:%s:%s:%s:%s:" % (GetAttr(x,"uid"),\
163               Pass,GetAttr(x,"shadowLastChange"),\
164               GetAttr(x,"shadowMin"),GetAttr(x,"shadowMax"),\
165               GetAttr(x,"shadowWarning"),GetAttr(x,"shadowinactive"),\
166               ShadowExpire);
167       Line = Sanitize(Line) + "\n";
168       F.write("0%u %s" % (I,Line));
169       F.write(".%s %s" % (GetAttr(x,"uid"),Line));
170       I = I + 1;
171
172   # Oops, something unspeakable happened.
173   except:
174    Die(File,None,F);
175    raise;
176   Done(File,None,F);
177
178 # Generate the shadow list
179 def GenSSHShadow(l,File):
180   F = None;
181   try:
182    OldMask = os.umask(0077);
183    F = open(File + ".tmp","w",0600);
184    os.umask(OldMask);
185
186    # Fetch all the users
187    global PasswdAttrs;
188    if PasswdAttrs == None:
189       raise "No Users";
190
191    for x in PasswdAttrs:
192       # If the account is locked, do not write it.
193       # This is a partial stop-gap. The ssh also needs to change this
194       # to ignore ~/.ssh/authorized* files.
195       if (GetAttr(x,"userPassword").find("*LK*") != -1) \
196              or GetAttr(x,"userPassword").startswith("!"):
197          continue;
198
199       if x[1].has_key("uidNumber") == 0 or \
200          x[1].has_key("sshRSAAuthKey") == 0:
201          continue;
202       for I in x[1]["sshRSAAuthKey"]:
203          User = GetAttr(x,"uid");
204          Line = "%s: %s" %(User,I);
205          Line = Sanitize(Line) + "\n";
206          F.write(Line);
207   # Oops, something unspeakable happened.
208   except:
209    Die(File,F,None);
210    raise;
211   Done(File,F,None);
212
213 # Generate the group list
214 def GenGroup(l,File):
215   F = None;
216   try:
217    F = open(File + ".tdb.tmp","w");
218
219    # Generate the GroupMap
220    GroupMap = {};
221    for x in GroupIDMap.keys():
222       GroupMap[x] = [];
223       
224    # Fetch all the users
225    global PasswdAttrs;
226    if PasswdAttrs == None:
227       raise "No Users";
228
229    # Sort them into a list of groups having a set of users
230    for x in PasswdAttrs:
231       if x[1].has_key("uidNumber") == 0 or IsInGroup(x) == 0:
232          continue;
233       if x[1].has_key("supplementaryGid") == 0:
234          continue;
235          
236       for I in x[1]["supplementaryGid"]:
237          if GroupMap.has_key(I):
238             GroupMap[I].append(GetAttr(x,"uid"));
239          else:
240             print "Group does not exist ",I,"but",GetAttr(x,"uid"),"is in it";
241             
242    # Output the group file.
243    J = 0;
244    for x in GroupMap.keys():
245       if GroupIDMap.has_key(x) == 0:
246          continue;
247       Line = "%s:x:%u:" % (x,GroupIDMap[x]);
248       Comma = '';
249       for I in GroupMap[x]:
250         Line = Line + ("%s%s" % (Comma,I));
251         Comma = ',';
252       Line = Sanitize(Line) + "\n";
253       F.write("0%u %s" % (J,Line));
254       F.write(".%s %s" % (x,Line));
255       F.write("=%u %s" % (GroupIDMap[x],Line));
256       J = J + 1;
257       
258   # Oops, something unspeakable happened.
259   except:
260    Die(File,None,F);
261    raise;
262   Done(File,None,F);
263
264 # Generate the email forwarding list
265 def GenForward(l,File):
266   F = None;
267   try:
268    OldMask = os.umask(0022);
269    F = open(File + ".tmp","w",0644);
270    os.umask(OldMask);
271
272    # Fetch all the users
273    global PasswdAttrs;
274    if PasswdAttrs == None:
275       raise "No Users";
276
277    # Write out the email address for each user
278    for x in PasswdAttrs:
279       if x[1].has_key("emailForward") == 0 or IsInGroup(x) == 0:
280          continue;
281       
282       # Do not allow people to try to buffer overflow busted parsers
283       if len(GetAttr(x,"emailForward")) > 200:
284          continue;
285
286       # Check the forwarding address
287       if EmailCheck.match(GetAttr(x,"emailForward")) == None:
288          continue;
289       Line = "%s: %s" % (GetAttr(x,"uid"),GetAttr(x,"emailForward"));
290       Line = Sanitize(Line) + "\n";
291       F.write(Line);
292       
293   # Oops, something unspeakable happened.
294   except:
295    Die(File,F,None);
296    raise;
297   Done(File,F,None);
298
299 def GenAllForward(l,File):
300   Fdb = None;
301   try:
302    OldMask = os.umask(0022);
303    Fdb = os.popen("cdbmake %s %s.tmp"%(File,File),"w");
304    os.umask(OldMask);
305
306    # Fetch all the users
307    global PasswdAttrs;
308    if PasswdAttrs == None:
309       raise "No Users";
310
311    # Write out the email address for each user
312    for x in PasswdAttrs:
313       if x[1].has_key("emailForward") == 0:
314          continue;
315       
316       # Do not allow people to try to buffer overflow busted parsers
317       Forward = GetAttr(x,"emailForward");
318       if len(Forward) > 200:
319          continue;
320
321       # Check the forwarding address
322       if EmailCheck.match(Forward) == None:
323          continue;
324          
325       User = GetAttr(x,"uid");
326       Fdb.write("+%d,%d:%s->%s\n"%(len(User),len(Forward),User,Forward));
327    Fdb.write("\n");
328   # Oops, something unspeakable happened.
329   except:
330     Fdb.close();
331     raise;
332   if Fdb.close() != None:
333     raise "cdbmake gave an error";
334
335 # Generate the anon XEarth marker file 
336 def GenMarkers(l,File):
337   F = None;
338   try:
339    F = open(File + ".tmp","w");
340
341    # Fetch all the users
342    global PasswdAttrs;
343    if PasswdAttrs == None:
344       raise "No Users";
345
346    # Write out the position for each user
347    for x in PasswdAttrs:
348       if x[1].has_key("latitude") == 0 or x[1].has_key("longitude") == 0:
349          continue;       
350       try:
351          Line = "%8s %8s \"\""%(DecDegree(GetAttr(x,"latitude"),1),DecDegree(GetAttr(x,"longitude"),1));
352          Line = Sanitize(Line) + "\n";
353          F.write(Line);
354       except:
355          pass;
356       
357   # Oops, something unspeakable happened.
358   except:
359    Die(File,F,None);
360    raise;
361   Done(File,F,None);
362
363 # Generate the debian-private subscription list
364 def GenPrivate(l,File):
365   F = None;
366   try:
367    F = open(File + ".tmp","w");
368
369    # Fetch all the users
370    global PasswdAttrs;
371    if PasswdAttrs == None:
372       raise "No Users";
373
374    # Write out the position for each user
375    for x in PasswdAttrs:
376       if x[1].has_key("privateSub") == 0:
377          continue;
378
379       # If the account is locked, do not write it
380       if (GetAttr(x,"userPassword").find("*LK*") != -1) \
381              or GetAttr(x,"userPassword").startswith("!"):
382          continue;
383
384       # If the account has no PGP key, do not write it
385       if x[1].has_key("keyFingerPrint") == 0:
386          continue;
387
388       # Must be in the Debian group (yuk, hard coded for now)
389       if GetAttr(x,"gidNumber") != "800":
390          continue;
391
392       try:
393          Line = "%s"%(GetAttr(x,"privateSub"));
394          Line = Sanitize(Line) + "\n";
395          F.write(Line);
396       except:
397          pass;
398       
399   # Oops, something unspeakable happened.
400   except:
401    Die(File,F,None);
402    raise;
403   Done(File,F,None);
404
405 # Generate a list of locked accounts
406 def GenDisabledAccounts(l,File):
407   F = None;
408   try:
409    F = open(File + ".tmp","w");
410
411    # Fetch all the users
412    global PasswdAttrs;
413    if PasswdAttrs == None:
414       raise "No Users";
415
416    I = 0;
417    for x in PasswdAttrs:
418       if x[1].has_key("uidNumber") == 0:
419          continue;
420          
421       Pass = GetAttr(x,"userPassword");
422       Line = ""
423       # *LK* is the reference value for a locked account
424       # password starting with ! is also a locked account
425       if Pass.find("*LK*") != -1 or Pass.startswith("!"):
426          # Format is <login>:<reason>
427          Line = "%s:%s" % (GetAttr(x,"uid"), "Account is locked")
428
429       if Line != "":
430          F.write(Sanitize(Line) + "\n")
431
432   # Oops, something unspeakable happened.
433   except:
434    Die(File,F,None);
435    raise;
436   Done(File,F,None);
437
438 # Generate the list of local addresses that refuse all mail
439 def GenMailDisable(l,File):
440   F = None;
441   try:
442    F = open(File + ".tmp","w");
443
444    # Fetch all the users
445    global PasswdAttrs;
446    if PasswdAttrs == None:
447       raise "No Users";
448
449    for x in PasswdAttrs:
450       Reason = None
451       
452       # If the account is locked, disable incoming mail
453       if (GetAttr(x,"userPassword").find("*LK*") != -1):
454          if GetAttr(x,"uid") == "luther":
455             continue
456          else:
457             Reason = "user account locked"
458       else:
459          if x[1].has_key("mailDisableMessage"):
460             Reason = GetAttr(x,"mailDisableMessage")
461          else:
462             continue
463
464       # Must be in the Debian group (yuk, hard coded for now)
465       if GetAttr(x,"gidNumber") != "800":
466          continue;
467
468       try:
469          Line = "%s: %s"%(GetAttr(x,"uid"),Reason);
470          Line = Sanitize(Line) + "\n";
471          F.write(Line);
472       except:
473          pass;
474       
475   # Oops, something unspeakable happened.
476   except:
477    Die(File,F,None);
478    raise;
479   Done(File,F,None);
480
481 # Generate a list of uids that should have boolean affects applied
482 def GenMailBool(l,File,Key):
483   F = None;
484   try:
485    F = open(File + ".tmp","w");
486
487    # Fetch all the users
488    global PasswdAttrs;
489    if PasswdAttrs == None:
490       raise "No Users";
491
492    for x in PasswdAttrs:
493       Reason = None
494       
495       if x[1].has_key(Key) == 0:
496          continue
497
498       # Must be in the Debian group (yuk, hard coded for now)
499       if GetAttr(x,"gidNumber") != "800":
500          continue
501
502       if GetAttr(x,Key) != "TRUE":
503          continue
504
505       try:
506          Line = "%s"%(GetAttr(x,"uid"));
507          Line = Sanitize(Line) + "\n";
508          F.write(Line);
509       except:
510          pass;
511       
512   # Oops, something unspeakable happened.
513   except:
514    Die(File,F,None);
515    raise;
516   Done(File,F,None);
517
518 # Generate a list of hosts for RBL or whitelist purposes.
519 def GenMailList(l,File,Key):
520   F = None;
521   try:
522    F = open(File + ".tmp","w");
523
524    # Fetch all the users
525    global PasswdAttrs;
526    if PasswdAttrs == None:
527       raise "No Users";
528
529    for x in PasswdAttrs:
530       Reason = None
531       
532       if x[1].has_key(Key) == 0:
533          continue
534
535       # Must be in the Debian group (yuk, hard coded for now)
536       if GetAttr(x,"gidNumber") != "800":
537          continue
538
539       try:
540          found = 0
541          Line = None
542          for z in x[1][Key]:
543              if Key == "mailWhitelist":
544                  if re.match('^[-\w.]+(/[\d]+)?$',z) == None:
545                      continue
546              else:
547                  if re.match('^[-\w.]+$',z) == None:
548                      continue
549              if found == 0:
550                  found = 1
551                  Line = GetAttr(x,"uid")
552              else:
553                  Line += " "
554              Line += ": " + z
555              if Key == "mailRHSBL":
556                  Line += "/$sender_address_domain"
557
558          if Line != None:
559              Line = Sanitize(Line) + "\n";
560              F.write(Line);
561       except:
562          pass;
563       
564   # Oops, something unspeakable happened.
565   except:
566    Die(File,F,None);
567    raise;
568   Done(File,F,None);
569
570 # Generate the DNS Zone file
571 def GenDNS(l,File,HomePrefix):
572   F = None;
573   try:
574    F = open(File + ".tmp","w");
575    
576    # Fetch all the users
577    global PasswdAttrs;
578    if PasswdAttrs == None:
579       raise "No Users";
580
581    # Write out the zone file entry for each user
582    for x in PasswdAttrs:
583       if x[1].has_key("dnsZoneEntry") == 0:
584          continue;
585
586       # If the account has no PGP key, do not write it
587       if x[1].has_key("keyFingerPrint") == 0:
588          continue;
589       try:
590          F.write("; %s\n"%(EmailAddress(x)));
591          for z in x[1]["dnsZoneEntry"]:
592             Split = z.lower().split()
593             if Split[1].lower() == 'in':
594                for y in range(0,len(Split)):
595                   if Split[y] == "$":
596                      Split[y] = "\n\t";
597                Line = " ".join(Split) + "\n";
598                F.write(Line);
599                
600                Host = Split[0] + DNSZone;
601                if BSMTPCheck.match(Line) != None:
602                    F.write("; Has BSMTP\n");
603                                
604                # Write some identification information
605                if Split[2].lower() == "a":
606                   Line = "%s IN TXT \"%s\"\n"%(Split[0],EmailAddress(x));
607                   for y in x[1]["keyFingerPrint"]:
608                      Line = Line + "%s IN TXT \"PGP %s\"\n"%(Split[0],FormatPGPKey(y));
609                   F.write(Line);
610             else:
611                Line = "; Err %s"%(str(Split));
612                F.write(Line);
613
614          F.write("\n");
615       except:
616          F.write("; Errors\n");
617          pass;
618       
619   # Oops, something unspeakable happened.
620   except:
621    Die(File,F,None);
622    raise;
623   Done(File,F,None);
624
625 # Generate the DNS SSHFP records
626 def GenSSHFP(l,File,HomePrefix):
627   F = None
628   try:
629    F = open(File + ".tmp","w")
630    
631    # Fetch all the hosts
632    global HostAttrs
633    if HostAttrs == None:
634       raise "No Hosts"
635
636    for x in HostAttrs:
637       if x[1].has_key("hostname") == 0 or \
638          x[1].has_key("sshRSAHostKey") == 0:
639          continue
640       Host = GetAttr(x,"hostname");
641       Algorithm = None
642       for I in x[1]["sshRSAHostKey"]:
643          Split = I.split()
644          if Split[0] == 'ssh-rsa':
645             Algorithm = 1
646          if Split[0] == 'ssh-dss':
647             Algorithm = 2
648          if Algorithm == None:
649             continue
650          Fingerprint = sha.new(base64.decodestring(Split[1])).hexdigest()
651          Line = "%s. IN SSHFP %u 1 %s" % (Host,Algorithm,Fingerprint)
652          Line = Sanitize(Line) + "\n"
653          F.write(Line)
654   # Oops, something unspeakable happened.
655   except:
656    Die(File,F,None)
657    raise;
658   Done(File,F,None)
659
660 # Generate the BSMTP file
661 def GenBSMTP(l,File,HomePrefix):
662   F = None;
663   try:
664    F = open(File + ".tmp","w");
665    
666    # Fetch all the users
667    global PasswdAttrs;
668    if PasswdAttrs == None:
669       raise "No Users";
670
671    # Write out the zone file entry for each user
672    for x in PasswdAttrs:
673       if x[1].has_key("dnsZoneEntry") == 0:
674          continue;
675
676       # If the account has no PGP key, do not write it
677       if x[1].has_key("keyFingerPrint") == 0:
678          continue;
679       try:
680          for z in x[1]["dnsZoneEntry"]:
681             Split = z.lower().split()
682             if Split[1].lower() == 'in':
683                for y in range(0,len(Split)):
684                   if Split[y] == "$":
685                      Split[y] = "\n\t";
686                Line = " ".join(Split) + "\n";
687                
688                Host = Split[0] + DNSZone;
689                if BSMTPCheck.match(Line) != None:
690                    F.write("%s: user=%s group=Debian file=%s%s/bsmtp/%s\n"%(Host,
691                                GetAttr(x,"uid"),HomePrefix,GetAttr(x,"uid"),Host));
692                                
693       except:
694          F.write("; Errors\n");
695          pass;
696       
697   # Oops, something unspeakable happened.
698   except:
699    Die(File,F,None);
700    raise;
701   Done(File,F,None);
702
703 # Generate the ssh known hosts file
704 def GenSSHKnown(l,File):
705   F = None;
706   try:
707    OldMask = os.umask(0022);
708    F = open(File + ".tmp","w",0644);
709    os.umask(OldMask);
710
711    global HostAttrs
712    if HostAttrs == None:
713       raise "No Hosts";
714    
715    for x in HostAttrs:
716       if x[1].has_key("hostname") == 0 or \
717          x[1].has_key("sshRSAHostKey") == 0:
718          continue;
719       Host = GetAttr(x,"hostname");
720       SHost = Host.find(".")
721       for I in x[1]["sshRSAHostKey"]:
722          if SHost == None:
723             Line = "%s,%s %s" %(Host,socket.gethostbyname(Host),I);
724          else:
725             Line = "%s,%s,%s %s" %(Host,Host[0:SHost],socket.gethostbyname(Host),I);
726          Line = Sanitize(Line) + "\n";
727          F.write(Line);
728   # Oops, something unspeakable happened.
729   except:
730    Die(File,F,None);
731    raise;
732   Done(File,F,None);
733
734 # Generate the debianhosts file (list of all IP addresses)
735 def GenHosts(l,File):
736   F = None;
737   try:
738    OldMask = os.umask(0022);
739    F = open(File + ".tmp","w",0644);
740    os.umask(OldMask);
741
742    # Fetch all the hosts
743    HostNames = l.search_s(HostBaseDn,ldap.SCOPE_ONELEVEL,"hostname=*",\
744                 ["hostname"]);
745    
746    if HostNames == None:
747       raise "No Hosts";
748
749    for x in HostNames:
750       if x[1].has_key("hostname") == 0:
751          continue;
752       Host = GetAttr(x,"hostname");
753       try:
754         Addr = socket.gethostbyname(Host);
755         F.write(Addr + "\n");
756       except:
757         pass
758   # Oops, something unspeakable happened.
759   except:
760    Die(File,F,None);
761    raise;
762   Done(File,F,None);
763
764 def GenKeyrings(l,OutDir):
765   for k in Keyrings:
766     shutil.copy(k, OutDir)
767
768 # Connect to the ldap server
769 l = ldap.open(LDAPServer);
770 F = open(PassDir+"/pass-"+pwd.getpwuid(os.getuid())[0],"r");
771 Pass = F.readline().strip().split(" ")
772 F.close();
773 l.simple_bind_s("uid="+Pass[0]+","+BaseDn,Pass[1]);
774
775 # Fetch all the groups
776 GroupIDMap = {};
777 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"gid=*",\
778                   ["gid","gidNumber"]);
779
780 # Generate the GroupMap and GroupIDMap
781 for x in Attrs:
782    if x[1].has_key("gidNumber") == 0:
783       continue;
784    GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidNumber"][0]);
785
786 # Fetch all the users
787 PasswdAttrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=*",\
788                 ["uid","uidNumber","gidNumber","supplementaryGid",\
789                  "gecos","loginShell","userPassword","shadowLastChange",\
790                  "shadowMin","shadowMax","shadowWarning","shadowinactive",
791                  "shadowexpire","emailForward","latitude","longitude",\
792                  "allowedHost","sshRSAAuthKey","dnsZoneEntry","cn","sn",\
793                  "keyFingerPrint","privateSub","mailDisableMessage",\
794                  "mailGreylisting","mailCallout","mailRBL","mailRHSBL",\
795                  "mailWhitelist"]);
796 # Fetch all the hosts
797 HostAttrs    = l.search_s(HostBaseDn,ldap.SCOPE_ONELEVEL,"sshRSAHostKey=*",\
798                 ["hostname","sshRSAHostKey"]);
799
800 # Open the control file
801 if len(sys.argv) == 1:
802    F = open(GenerateConf,"r");
803 else:
804    F = open(sys.argv[1],"r")
805
806 # Generate global things
807 GlobalDir = GenerateDir+"/";
808 GenSSHShadow(l,GlobalDir+"ssh-rsa-shadow");
809 GenAllForward(l,GlobalDir+"mail-forward.cdb");
810 GenMarkers(l,GlobalDir+"markers");
811 GenPrivate(l,GlobalDir+"debian-private");
812 GenDisabledAccounts(l,GlobalDir+"disabled-accounts");
813 GenSSHKnown(l,GlobalDir+"ssh_known_hosts");
814 GenHosts(l,GlobalDir+"debianhosts");
815 GenMailDisable(l,GlobalDir+"mail-disable");
816 GenMailBool(l,GlobalDir+"mail-greylist","mailGreylisting");
817 GenMailBool(l,GlobalDir+"mail-callout","mailCallout");
818 GenMailList(l,GlobalDir+"mail-rbl","mailRBL");
819 GenMailList(l,GlobalDir+"mail-rhsbl","mailRHSBL");
820 GenMailList(l,GlobalDir+"mail-whitelist","mailWhitelist");
821 GenKeyrings(l,GlobalDir);
822
823 # Compatibility.
824 GenForward(l,GlobalDir+"forward-alias");
825
826 while(1):
827    Line = F.readline();
828    if Line == "":
829       break;
830    Line = Line.strip()
831    if Line == "":
832       continue;
833    if Line[0] == '#':
834       continue;
835
836    Split = Line.split(" ")
837    OutDir = GenerateDir + '/' + Split[0] + '/';
838    try: os.mkdir(OutDir);
839    except: pass;
840
841    # Get the group list and convert any named groups to numerics
842    GroupList = {};
843    ExtraList = {};
844    for I in Split[2:]:
845       if I[0] == '[':
846          ExtraList[I] = None;
847          continue;
848       GroupList[I] = None;
849       if GroupIDMap.has_key(I):
850          GroupList[str(GroupIDMap[I])] = None;
851
852    Allowed = GroupList;
853    if Allowed == {}:
854      Allowed = None
855    CurrentHost = Split[0];
856
857    DoLink(GlobalDir,OutDir,"ssh-rsa-shadow");
858    DoLink(GlobalDir,OutDir,"debianhosts");
859    DoLink(GlobalDir,OutDir,"ssh_known_hosts");
860    DoLink(GlobalDir,OutDir,"disabled-accounts")
861
862    sys.stdout.flush();
863    if ExtraList.has_key("[NOPASSWD]"):
864       GenPasswd(l,OutDir+"passwd",Split[1], "*");
865    else:
866       GenPasswd(l,OutDir+"passwd",Split[1], "x");
867    sys.stdout.flush();
868    GenGroup(l,OutDir+"group");
869    if ExtraList.has_key("[UNTRUSTED]"):
870         continue;
871    if not ExtraList.has_key("[NOPASSWD]"):
872      GenShadow(l,OutDir+"shadow");
873         
874    # Link in global things   
875    DoLink(GlobalDir,OutDir,"markers");
876    DoLink(GlobalDir,OutDir,"mail-forward.cdb");
877    DoLink(GlobalDir,OutDir,"mail-disable");
878    DoLink(GlobalDir,OutDir,"mail-greylist");
879    DoLink(GlobalDir,OutDir,"mail-callout");
880    DoLink(GlobalDir,OutDir,"mail-rbl");
881    DoLink(GlobalDir,OutDir,"mail-rhsbl");
882    DoLink(GlobalDir,OutDir,"mail-whitelist");
883
884    # Compatibility.
885    DoLink(GlobalDir,OutDir,"forward-alias");
886
887    if ExtraList.has_key("[DNS]"):
888       GenDNS(l,OutDir+"dns-zone",Split[1]);
889       GenSSHFP(l,OutDir+"dns-sshfp",Split[1])
890       
891    if ExtraList.has_key("[BSMTP]"):
892       GenBSMTP(l,OutDir+"bsmtp",Split[1])
893
894    if ExtraList.has_key("[PRIVATE]"):
895       DoLink(GlobalDir,OutDir,"debian-private")
896
897    if ExtraList.has_key("[KEYRING]"):
898       for k in Keyrings:
899         DoLink(GlobalDir,OutDir,os.path.basename(k))
900    else:
901      for k in Keyrings:
902        try: posix.remove(OutDir+os.path.basename(k));
903        except: pass;