4a21dafd64f6e6d516b133cad829315514d6046a
[mirror/userdir-ldap.git] / ud-userimport
1 #!/usr/bin/env python
2 # -*- mode: python -*-
3
4 #   Copyright (c) 1999       Jason Gunthorpe <jgg@debian.org>
5 #   Copyright (c) 2003       James Troup <troup@debian.org>
6 #   Copyright (c) 2004       Joey Schulze <joey@debian.org>
7 #
8 #   This program is free software; you can redistribute it and/or modify
9 #   it under the terms of the GNU General Public License as published by
10 #   the Free Software Foundation; either version 2 of the License, or
11 #   (at your option) any later version.
12 #
13 #   This program is distributed in the hope that it will be useful,
14 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #   GNU General Public License for more details.
17 #
18 #   You should have received a copy of the GNU General Public License
19 #   along with this program; if not, write to the Free Software
20 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 # Imports passwd, shadow and group files into the directory.
23 # You should cleanse the files of anything you do not want to add to the
24 # directory.
25 #
26 # The first step is to call this script to import the passwd file and
27 # create all the new entries. This should be done on an empty freshly 
28 # initialized directory with the rootdn/password set in the server.
29 # The command to execute is
30 #   ldapimport -a -p ~/passwd
31 # The -a tells the script to add all the entries it finds, it should be
32 # used only once.
33 #
34 # The next step is to import the shadow file and group, no clensing need be 
35 # done for 
36 # this as any entries that do not exist will be ignored (silently)
37 #  ldapimport -s /etc/shadow -g /etc/group
38
39
40 import string, re, time, ldap, getopt, sys;
41 from userdir_ldap import *;
42
43 DoAdd = 0;
44 WritePasses = 1;
45 Passwd = "";
46 Shadow = "";
47 Group = "";
48
49 # This parses a gecos field and returns a tuple containing the new normalized
50 # field and the first, middle and last name of the user. Gecos is formed
51 # in the standard debian manner with 5 feilds seperated by commas
52 def ParseGecos(Field):
53    Gecos = re.split("[,:]",Field);
54    cn = "";
55    mn = "";
56    sn = "";
57    if (len(Gecos) >= 1):
58       (cn,mn,sn) = NameSplit(Gecos[0]);
59
60       # Normalize the gecos field
61       if (len(Gecos) > 5):
62          Gecos = Gecos[0:4];
63       else:
64          while (len(Gecos) < 5):
65             Gecos.append("");
66    else:
67       Gecos = ["","","","",""];
68
69    # Reconstruct the gecos after mauling it
70    Field = Gecos[0] + "," + Gecos[1] + "," + Gecos[2] + "," + \
71            Gecos[3] + "," + Gecos[4];
72    return (Field,cn,mn,sn);
73
74 # Check if a number string is really a number
75 def CheckNumber(Num):
76    for x in Num:
77       string.index(string.digits,x);
78
79 # Read the passwd file into the database
80 def DoPasswd(l,Passwd):
81    # Read the passwd file and import it
82    Passwd = open(Passwd,"r");
83    Outstanding = 0;
84    while(1):
85       Line = Passwd.readline();
86       if Line == "":
87          break;
88
89       Split = re.split("[:\n]",Line);
90       (Split[4],cn,mn,sn) = ParseGecos(Split[4]);
91       CheckNumber(Split[2]);
92       CheckNumber(Split[3]);
93       Rec = [("uid",Split[0]),
94              ("uidNumber",Split[2]),
95              ("gidNumber",Split[3]),
96              ("gecos",Split[4]),
97              ("homeDirectory",Split[5]),
98              ("loginShell",Split[6]),
99              ("cn",cn),
100              ("sn",sn)];
101
102       # Avoid schema check complaints when mn is empty
103       if (mn):
104           Rec.append(("mn",mn))
105
106       Dn = "uid=" + Split[0] + "," + BaseDn;
107       print "Importing", Dn
108       sys.stdout.flush();
109
110       DoModify = True
111
112       if (DoAdd == 1):
113          try:
114             AddRec = Rec
115             Rec.append(("objectClass", UserObjectClasses))
116             l.add_s(Dn,AddRec)
117             DoModify = False
118
119          except ldap.ALREADY_EXISTS:
120             print "exists",;
121
122       if (DoModify):
123           # Send the modify request
124           ModRec = [(ldap.MOD_REPLACE, k[0], k[1]) for k in Rec]
125           l.modify(Dn,ModRec);
126           Outstanding = Outstanding + 1;
127           Outstanding = FlushOutstanding(l,Outstanding,1);
128           print "done";
129
130    FlushOutstanding(l,Outstanding);
131
132 # Read the shadow file into the database
133 def DoShadow(l,Shadow):
134    # Read the passwd file and import it
135    Shadow = open(Shadow,"r");
136    Outstanding = 0;
137    while(1):
138       Line = Shadow.readline();
139       if Line == "":
140          break;
141
142       Split = re.split("[:\n]",Line);
143       
144       # Ignore system accounts with no password, they do not belong in the
145       # directory.
146       if (Split[1] == 'x' or Split[1] == '*'):
147          print "Ignoring system account,",Split[0];
148          continue;
149
150       for x in range(2,8):
151          CheckNumber(Split[x]);
152
153       Rec = [(ldap.MOD_REPLACE,"shadowLastChange",Split[2]),
154              (ldap.MOD_REPLACE,"shadowMin",Split[3]),
155              (ldap.MOD_REPLACE,"shadowMax",Split[4]),
156              (ldap.MOD_REPLACE,"shadowWarning",Split[5])]
157
158       # Avoid schema violations
159       if (Split[6]):
160          Rec.append((ldap.MOD_REPLACE,"shadowInactive",Split[6]))
161
162       if (Split[7]):
163          Rec.append((ldap.MOD_REPLACE,"shadowExpire",Split[7]))
164
165       if (WritePasses == 1):
166          Rec.append((ldap.MOD_REPLACE,"userPassword","{crypt}"+Split[1]));
167
168       Dn = "uid=" + Split[0] + "," + BaseDn;
169       print "Importing",Dn,
170       sys.stdout.flush();
171
172       # Send the modify request
173       l.modify(Dn,Rec);
174       Outstanding = Outstanding + 1;
175       print "done";
176       Outstanding = FlushOutstanding(l,Outstanding,1);
177    FlushOutstanding(l,Outstanding);
178
179 # Read the group file into the database
180 def DoGroup(l,Group):
181    # Read the passwd file and import it
182    Group = open(Group,"r");
183    Outstanding = 0;
184    while(1):
185       Line = Group.readline();
186       if Line == "":
187          break;
188
189       # Split up the group information
190       Split = re.split("[:\n]",Line);
191       Members = re.split("[, ]*",Split[3]);
192       CheckNumber(Split[2]);
193
194       # Iterate over the membership list and add the membership information
195       # To the directory
196       Rec = [(ldap.MOD_ADD,"supplementaryGid",Split[0])];
197       Counter = 0;
198       for x in Members:
199          if x == "":
200             continue;
201             
202          Dn = "uid=" + x + "," + BaseDn;
203          print "Adding",Dn,"to group",Split[0];
204          Counter = Counter+1;
205
206          # Send the modify request
207          l.modify(Dn,Rec);
208          Outstanding = Outstanding + 1;
209          Outstanding = FlushOutstanding(l,Outstanding,1);
210          
211       if Counter == 0:
212          continue;
213
214       Rec = [(ldap.MOD_REPLACE,"gid",Split[0]),
215              (ldap.MOD_REPLACE,"gidNumber",Split[2])];
216
217       Dn = "gid=" + Split[0] + "," + BaseDn;
218       print "Importing",Dn,
219       sys.stdout.flush();
220
221       # Unfortunately add_s does not take the same args as modify :|
222       if (DoAdd == 1):
223          try:
224             l.add_s(Dn,[("gid",Split[0]),
225                         ("objectClass", GroupObjectClasses)])
226          except ldap.ALREADY_EXISTS:
227             print "exists",;
228
229       # Send the modify request
230       l.modify(Dn,Rec);
231       Outstanding = Outstanding + 1;
232       print ".";
233
234    FlushOutstanding(l,Outstanding);
235
236 # Process options
237 (options, arguments) = getopt.getopt(sys.argv[1:], "ap:s:g:xu:")
238 for (switch, val) in options:
239    if (switch == '-a'):
240       DoAdd = 1;
241    if (switch == '-x'):
242       WritePasses = 0;
243    elif (switch == '-p'):
244       Passwd = val
245    elif (switch == '-s'):
246       Shadow = val
247    elif (switch == '-g'):
248       Group = val
249    elif (switch == '-u'):
250       AdminUser = val
251
252 # Main program starts here
253
254 # Connect to the ldap server
255 l = passwdAccessLDAP(LDAPServer, BaseDn, AdminUser)
256
257 if (Passwd != ""):
258    DoPasswd(l,Passwd);
259
260 if (Shadow != ""):
261    DoShadow(l,Shadow);
262
263 if (Group != ""):
264    DoGroup(l,Group);