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