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