Added host ACL
[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 import string, re, time, ldap, getopt, sys, os, posix, pwd;
6 from userdir_ldap import *;
7
8 PasswdAttrs = None;
9 GroupIDMap = {};
10 Allowed = None;
11 CurrentHost = "";
12
13 # See if this user is in the group list
14 def IsInGroup(DnRecord):
15   global Allowed,CurrentHost;
16   if Allowed == None:
17      return 1;
18
19   # See if the primary group is in the list
20   if Allowed.has_key(GetAttr(DnRecord,"gidnumber")) != 0:
21      return 1;
22
23   # Check the host based ACL
24   if DnRecord[1].has_key("allowedhosts") != 0:
25      for I in DnRecord[1]["allowedhosts"]:
26         if CurrentHost == I:
27            return 1;
28
29   # See if there are supplementary groups
30   if DnRecord[1].has_key("supplementarygid") == 0:
31      return 0;
32
33   # Check the supplementary groups
34   for I in DnRecord[1]["supplementarygid"]:
35      if Allowed.has_key(I):
36         return 1;
37   return 0;
38
39 def Die(F,Fdb):
40    if F != None:
41       F.close();
42    if Fdb != None:
43       Fdb.close();
44    try: os.remove(File + ".tmp");
45    except: pass;
46    try: os.remove(File + ".tdb.tmp");
47    except: pass;
48
49 def Done(File,F,Fdb):
50   if F != None:
51     F.close();
52     os.rename(File + ".tmp",File);
53   if Fdb != None:
54     Fdb.close();
55     os.rename(File + ".tdb.tmp",File+".tdb");
56   
57 # Generate the password list
58 def GenPasswd(l,File,HomePrefix):
59   F = None;
60   Fdb = None;
61   try:
62    F = open(File + ".tmp","w");
63    Fdb = open(File + ".tdb.tmp","w");
64
65    # Fetch all the users
66    global PasswdAttrs;
67    if PasswdAttrs == None:
68       raise "No Users";
69
70    I = 0;
71    for x in PasswdAttrs:
72       if x[1].has_key("uidnumber") == 0 or IsInGroup(x) == 0:
73          continue;
74             
75       Line = "%s:x:%s:%s:%s:%s%s:%s\n" % (GetAttr(x,"uid"),\
76               GetAttr(x,"uidnumber"),GetAttr(x,"gidnumber"),\
77               GetAttr(x,"gecos"),HomePrefix,GetAttr(x,"uid"),\
78               GetAttr(x,"loginshell"));
79       F.write(Line);
80       Fdb.write("0%u %s" % (I,Line));
81       Fdb.write(".%s %s" % (GetAttr(x,"uid"),Line));
82       Fdb.write("=%s %s" % (GetAttr(x,"uidnumber"),Line));
83       I = I + 1;
84
85   # Oops, something unspeakable happened.
86   except:
87    Die(F,Fdb);
88    raise;
89   Done(File,F,Fdb);
90
91 # Generate the shadow list
92 def GenShadow(l,File):
93   F = None;
94   Fdb = None;
95   try:
96    OldMask = os.umask(0077);
97    F = open(File + ".tmp","w",0600);
98    Fdb = open(File + ".tdb.tmp","w",0600);
99    os.umask(OldMask);
100
101    # Fetch all the users
102    global PasswdAttrs;
103    if PasswdAttrs == None:
104       raise "No Users";
105
106    I = 0;
107    for x in PasswdAttrs:
108       if x[1].has_key("uidnumber") == 0 or IsInGroup(x) == 0:
109          continue;
110          
111       Pass = GetAttr(x,"userpassword");
112       if Pass[0:7] != "{crypt}":
113          Pass = '*';
114       else:
115          Pass = Pass[7:];
116       Line = "%s:%s:%s:%s:%s:%s:%s:%s:\n" % (GetAttr(x,"uid"),\
117               Pass,GetAttr(x,"shadowlastchange"),\
118               GetAttr(x,"shadowmin"),GetAttr(x,"shadowmax"),\
119               GetAttr(x,"shadowwarning"),GetAttr(x,"shadowinactive"),\
120               GetAttr(x,"shadowexpire"));
121       F.write(Line);
122       Fdb.write("0%u %s" % (I,Line));
123       Fdb.write(".%s %s" % (GetAttr(x,"uid"),Line));
124       I = I + 1;
125
126   # Oops, something unspeakable happened.
127   except:
128    Die(F,Fdb);
129    raise;
130   Done(File,F,Fdb);
131
132 # Generate the group list
133 def GenGroup(l,File):
134   F = None;
135   Fdb = None;
136   try:
137    F = open(File + ".tmp","w");
138    Fdb = open(File + ".tdb.tmp","w");
139
140    # Generate the GroupMap
141    GroupMap = {};
142    for x in GroupIDMap.keys():
143       GroupMap[x] = [];
144       
145    # Fetch all the users
146    global PasswdAttrs;
147    if PasswdAttrs == None:
148       raise "No Users";
149
150    # Sort them into a list of groups having a set of users
151    for x in PasswdAttrs:
152       if x[1].has_key("uidnumber") == 0 or IsInGroup(x) == 0:
153          continue;
154       if x[1].has_key("supplementarygid") == 0:
155          continue;
156          
157       for I in x[1]["supplementarygid"]:
158          if GroupMap.has_key(I):
159             GroupMap[I].append(GetAttr(x,"uid"));
160          else:
161             print "Group does not exist ",I,"but",GetAttr(x,"uid"),"is in it";
162             
163    # Output the group file.
164    Counter = 0; 
165    for x in GroupMap.keys():
166       Line = "%s:x:%u:" % (x,GroupIDMap[x]);
167       Comma = '';
168       for I in GroupMap[x]:
169         Line = Line + ("%s%s" % (Comma,I));
170         Comma = ',';
171       Line = Line + '\n';
172       F.write(Line);
173       Fdb.write("0%u %s" % (Counter,Line));
174       Fdb.write(".%s %s" % (x,Line));
175       Fdb.write("=%u %s" % (GroupIDMap[x],Line));
176       Counter = Counter + 1;
177       
178   # Oops, something unspeakable happened.
179   except:
180    Die(F,Fdb);
181    raise;
182   Done(File,F,Fdb);
183
184 # Generate the email forwarding list
185 def GenForward(l,File):
186   F = None;
187   Fdb = None;
188   try:
189    OldMask = os.umask(0022);
190    F = open(File + ".tmp","w",0644);
191    Fdb = None;
192    os.umask(OldMask);
193
194    # Fetch all the users
195    global PasswdAttrs;
196    if PasswdAttrs == None:
197       raise "No Users";
198
199    # Write out the email address for each user
200    for x in PasswdAttrs:
201       if x[1].has_key("emailforward") == 0 or IsInGroup(x) == 0:
202          continue;
203       Line = "%s: %s\n" % (GetAttr(x,"uid"),GetAttr(x,"emailforward"));
204       F.write(Line);
205       
206   # Oops, something unspeakable happened.
207   except:
208    Die(F,Fdb);
209    raise;
210   Done(File,F,Fdb);
211
212 # Generate the anon XEarth marker file 
213 def GenMarkers(l,File):
214   F = None;
215   Fdb = None;
216   try:
217    F = open(File + ".tmp","w");
218    Fdb = None;
219
220    # Fetch all the users
221    global PasswdAttrs;
222    if PasswdAttrs == None:
223       raise "No Users";
224
225    # Write out the email address for each user
226    for x in PasswdAttrs:
227       if x[1].has_key("latitude") == 0 or x[1].has_key("longitude") == 0:
228          continue;       
229       try:
230          F.write("%8s %8s \"\"\n"%(DecDegree(x,"latitude",1),DecDegree(x,"longitude",1)));
231       except:
232          pass;
233       
234   # Oops, something unspeakable happened.
235   except:
236    Die(F,Fdb);
237    raise;
238   Done(File,F,Fdb);
239   
240 # Connect to the ldap server
241 l = ldap.open(LDAPServer);
242 F = open(PassDir+"/pass-"+pwd.getpwuid(posix.getuid())[0],"r");
243 Pass = string.split(string.strip(F.readline())," ");
244 F.close();
245 l.simple_bind_s("uid="+Pass[0]+","+BaseDn,Pass[1]);
246
247 # Fetch all the groups
248 GroupIDMap = {};
249 Attrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"gid=*",\
250                   ["gid","gidnumber"]);
251
252 # Generate the GroupMap and GroupIDMap
253 for x in Attrs:
254    if x[1].has_key("gidnumber") == 0:
255       continue;
256    GroupIDMap[x[1]["gid"][0]] = int(x[1]["gidnumber"][0]);
257
258 # Fetch all the users
259 PasswdAttrs = l.search_s(BaseDn,ldap.SCOPE_ONELEVEL,"uid=*",\
260                 ["uid","uidnumber","gidnumber","supplementarygid",\
261                  "gecos","loginshell","userpassword","shadowlastchange",\
262                  "shadowmin","shadowmax","shadowwarning","shadowinactive",
263                  "shadowexpire","emailforward","latitude","longitude",\
264                  "allowedhosts"]);
265
266 # Open the control file
267 if len(sys.argv) == 1:
268    F = open(GenerateConf,"r");
269 else:
270    F = open(sys.argv[1],"r")
271 while(1):
272    Line = F.readline();
273    if Line == "":
274       break;
275    Line = string.strip(Line);
276    if Line == "":
277       continue;
278    if Line[0] == '#':
279       continue;
280
281    Split = string.split(Line," ");
282    OutDir = GenerateDir + '/' + Split[0] + '/';
283    try: os.mkdir(OutDir);
284    except: pass;
285
286    # Get the group list and convert any named groups to numerics
287    GroupList = {};
288    for I in Split[2:]:
289       GroupList[I] = None;
290       if GroupIDMap.has_key(I):
291          GroupList[str(GroupIDMap[I])] = None;
292
293    global Allowed,CurrentHost;
294    Allowed = GroupList;
295    CurrentHost = Split[0];
296
297    GenPasswd(l,OutDir+"passwd",Split[1]);
298    GenGroup(l,OutDir+"group");
299    GenShadow(l,OutDir+"shadow");
300    GenForward(l,OutDir+"forward-alias");
301    GenMarkers(l,OutDir+"markers");
302