1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
|
10
|
|
11
|
|
12
|
|
13
|
import time, sys
|
14
|
import traceback
|
15
|
from shutil import rmtree
|
16
|
from os import system, makedirs, symlink, chown, fchmod
|
17
|
from os.path import join, islink, isfile, isdir, getmtime, exists
|
18
|
from datetime import datetime
|
19
|
import ldap
|
20
|
import MySQLdb
|
21
|
|
22
|
from scribe.ldapconf import ROOT_DN, ldap_server, ldap_passwd, SUFFIX, \
|
23
|
HOME_PATH, USER_FILTER, GROUP_FILTER, SHARE_FILTER
|
24
|
|
25
|
sys.path.append('/usr/share/eole/controlevnc/')
|
26
|
from config import mysql_host, mysql_password
|
27
|
|
28
|
PATH_SCRIPTS = '/home/netlogon/scripts'
|
29
|
SCRIPTS_EXT = '.txt'
|
30
|
|
31
|
class Ldap():
|
32
|
def __init__(self):
|
33
|
self.ldap_conn = ldap.open(ldap_server)
|
34
|
self.ldap_conn.simple_bind_s(ROOT_DN, ldap_passwd)
|
35
|
|
36
|
def ldap_search(self, ldap_filter, attrib=None, one=False):
|
37
|
result = self.ldap_conn.search_s(SUFFIX, ldap.SCOPE_SUBTREE,
|
38
|
ldap_filter, attrib)
|
39
|
if len(result) > 0 and len(result[0]) == 2:
|
40
|
if one:
|
41
|
return result[0][1]
|
42
|
else:
|
43
|
return result
|
44
|
else:
|
45
|
return {}
|
46
|
def get_user_attributs(self, user):
|
47
|
return self.ldap_search("(&%s(uid=%s))" % (USER_FILTER, user),
|
48
|
['objectClass', 'homeDirectory', 'sambaHomeDrive', 'uidNumber',
|
49
|
'gidNumber', 'displayName', 'sambaSID'], True)
|
50
|
|
51
|
def get_groups(self, user):
|
52
|
return self.ldap_search("(&%s(memberUid=%s))" % (GROUP_FILTER, user),
|
53
|
attrib=['cn', 'gidNumber'])
|
54
|
|
55
|
def get_group_name(self, gidnumber):
|
56
|
return self.ldap_search("(&%s(gidNumber=%s))" % (GROUP_FILTER,
|
57
|
gidnumber), ['displayName'], True)['displayName'][0]
|
58
|
|
59
|
def get_shares_filtred(self, group_filter):
|
60
|
return self.ldap_search('(&%s(|%s))' % (SHARE_FILTER, group_filter),
|
61
|
['sambaShareName', 'sambaFilePath', 'sambaShareURI',
|
62
|
'sambaShareDrive'])
|
63
|
|
64
|
def __del__(self):
|
65
|
self.ldap_conn.unbind()
|
66
|
del(self)
|
67
|
|
68
|
def logon(user, ostype, machine, adresse_ip, pid):
|
69
|
|
70
|
ldap_conn = Ldap()
|
71
|
user_attrib = ldap_conn.get_user_attributs(user)
|
72
|
userclass = get_userclass_name(user_attrib.get('objectClass', None))
|
73
|
|
74
|
|
75
|
if not userclass:
|
76
|
raise Exception("utilisateur %s inconnu" % user)
|
77
|
|
78
|
if userclass not in ['administratif', 'eleve', 'enseignant']:
|
79
|
raise Exception("l'utilisateur %s n'est pas autorisé à se connecter" % user)
|
80
|
|
81
|
|
82
|
|
83
|
netlogon = '/home/netlogon/%s%s.txt' % (user, ostype)
|
84
|
if isfile(netlogon):
|
85
|
diff = time.time() - getmtime(netlogon)
|
86
|
else:
|
87
|
diff = 600
|
88
|
prim_group = None
|
89
|
gidnumber = user_attrib['gidNumber'][0].strip()
|
90
|
display_name = user_attrib['displayName'][0].strip()
|
91
|
sid = user_attrib['sambaSID'][0].strip()
|
92
|
groups = []
|
93
|
if diff > 2:
|
94
|
""" construction des scripts de connexion windows
|
95
|
le fichier est du format .bat pour Win95 et .txt pour le reste
|
96
|
"""
|
97
|
homedir = user_attrib['homeDirectory'][0].strip()
|
98
|
homedrive = user_attrib['sambaHomeDrive'][0].strip()
|
99
|
uid = int(user_attrib['uidNumber'][0].strip())
|
100
|
|
101
|
group_filter = ''
|
102
|
for dn, grp in ldap_conn.get_groups(user):
|
103
|
name = grp['cn'][0]
|
104
|
if grp['gidNumber'][0] == gidnumber:
|
105
|
prim_group = name
|
106
|
groups.append(name)
|
107
|
group_filter += '(sambaShareGroup=%s)' % name
|
108
|
|
109
|
shares = []
|
110
|
for share in ldap_conn.get_shares_filtred(group_filter):
|
111
|
if share[1].has_key('sambaShareDrive'):
|
112
|
drive = share[1]['sambaShareDrive'][0]
|
113
|
else:
|
114
|
drive = ''
|
115
|
shares.append({'name': share[1]['sambaShareName'][0],
|
116
|
'path': share[1]['sambaFilePath'][0],
|
117
|
'uri': share[1]['sambaShareURI'][0],
|
118
|
'drive': drive})
|
119
|
|
120
|
|
121
|
gen_fich(user, groups, shares, machine, ostype, homedrive, userclass,
|
122
|
netlogon)
|
123
|
|
124
|
gen_ftpdir(uid, homedir, shares)
|
125
|
|
126
|
gen_groupedir(uid, homedir, shares)
|
127
|
|
128
|
gen_devdir(user, uid, homedir, userclass)
|
129
|
|
130
|
log_connexion_db(user, sid, display_name, prim_group, groups, machine,
|
131
|
ostype, adresse_ip)
|
132
|
|
133
|
if not prim_group:
|
134
|
prim_group = ldap_conn.get_group_name(gidnumber)
|
135
|
|
136
|
del(ldap_conn)
|
137
|
|
138
|
|
139
|
|
140
|
log_connexion(user, prim_group, machine, ostype, adresse_ip, pid)
|
141
|
|
142
|
def get_userclass_name(objectClass):
|
143
|
"""
|
144
|
Renvoie le nom du module gérant les objets de classe : objectClass
|
145
|
"""
|
146
|
if objectClass == None:
|
147
|
return None
|
148
|
users_objectClass = {
|
149
|
'Eleves': 'eleve',
|
150
|
'administrateur': 'enseignant',
|
151
|
'responsable': 'responsable',
|
152
|
'administratif': 'administratif',
|
153
|
'autre': 'autre',
|
154
|
}
|
155
|
for objectclass, module in users_objectClass.items():
|
156
|
if objectclass in objectClass:
|
157
|
return module
|
158
|
return None
|
159
|
|
160
|
def gen_devdir(login, uid, homedir, userclass):
|
161
|
"""
|
162
|
Partie commune pour _gen_devoirdir
|
163
|
"""
|
164
|
if userclass not in ['eleve', 'enseignant']:
|
165
|
return
|
166
|
perso = join(homedir, 'perso')
|
167
|
|
168
|
dev_part = join(homedir, 'devoirs')
|
169
|
|
170
|
dev_perso = join(perso, 'devoirs')
|
171
|
cmd = ""
|
172
|
for rep in [dev_part, dev_perso]:
|
173
|
if not isdir(rep):
|
174
|
makedirs(rep, 0750)
|
175
|
cmd += '/bin/chown -PR %s %s;' % (login, rep)
|
176
|
cmd += '/usr/bin/setfacl -PRm u:%s:rwx %s;'%(uid, rep)
|
177
|
cmd += '/usr/bin/setfacl -dPRm u:%s:rwx %s;'%(uid, rep)
|
178
|
|
179
|
if userclass == 'enseignant':
|
180
|
|
181
|
|
182
|
dev_dist_dir = join(HOME_PATH, 'workgroups/devoirs', login)
|
183
|
if not isdir(dev_dist_dir):
|
184
|
makedirs(dev_dist_dir, 0755)
|
185
|
cmd += '/usr/bin/setfacl -PRbk %s;' % dev_dist_dir
|
186
|
cmd += '/usr/bin/setfacl -PRm u:%s:rwx %s;' % (uid, dev_dist_dir)
|
187
|
cmd += '/usr/bin/setfacl -dPRm u:%s:rwx %s;' % (uid, dev_dist_dir)
|
188
|
for rep in [dev_part, dev_perso]:
|
189
|
link = join(rep, '.distribues')
|
190
|
if not islink(link):
|
191
|
symlink(dev_dist_dir, link)
|
192
|
if cmd != '':
|
193
|
system(cmd)
|
194
|
|
195
|
def gen_ftpdir(uid, homedir, shares):
|
196
|
"""
|
197
|
Gestion du répertoire ".ftp"
|
198
|
"""
|
199
|
ftpdir = join(homedir, '.ftp')
|
200
|
ftpperso = join(ftpdir, 'perso')
|
201
|
homedir = join(HOME_PATH, homedir[6:])
|
202
|
homeperso = join(homedir, 'perso')
|
203
|
def create_ftpsymlink():
|
204
|
if not islink(ftpperso):
|
205
|
symlink(homeperso, ftpperso)
|
206
|
for share in shares:
|
207
|
if share['name'] not in ['icones$', 'groupes']:
|
208
|
if HOME_PATH != '/home':
|
209
|
share['path'] = share['path'].replace('/home', HOME_PATH)
|
210
|
if not exists(join(ftpdir, share['name'])):
|
211
|
symlink(share['path'], join(ftpdir, share['name']))
|
212
|
if not isdir(ftpdir):
|
213
|
makedirs(ftpdir, 0500)
|
214
|
chown(ftpdir, uid, -1)
|
215
|
elif not islink(ftpperso) and exists(ftpperso):
|
216
|
rmtree(ftpperso)
|
217
|
create_ftpsymlink()
|
218
|
|
219
|
def gen_groupedir(uid, homedir, shares):
|
220
|
"""
|
221
|
Gestion du répertoire "groupes"
|
222
|
"""
|
223
|
groupedir = join(homedir, 'groupes')
|
224
|
if isdir(groupedir):
|
225
|
rmtree(groupedir)
|
226
|
makedirs(groupedir, 0500)
|
227
|
chown(groupedir, uid, -1)
|
228
|
|
229
|
|
230
|
for share in shares:
|
231
|
|
232
|
if share['drive'] == "":
|
233
|
|
234
|
symlink(share['path'], join(groupedir, share['name']))
|
235
|
|
236
|
def log_connexion_db(user, sid, display_name, primgrp, groups, netbios,
|
237
|
ostype, ip):
|
238
|
db = MySQLdb.connect(host=mysql_host, user='controlevnc',
|
239
|
passwd=mysql_password, db='controlevnc')
|
240
|
try:
|
241
|
c = db.cursor()
|
242
|
|
243
|
c.execute("SELECT ip FROM log WHERE ip=%s", ip)
|
244
|
rows = c.fetchall()
|
245
|
if len(rows) > 1:
|
246
|
|
247
|
c.execute("DELETE FROM `log` WHERE ip=%s", ip)
|
248
|
c.execute("SELECT ip FROM log WHERE netbios=%s", netbios)
|
249
|
rows = c.fetchall()
|
250
|
if len(rows) > 1:
|
251
|
|
252
|
c.execute("DELETE FROM `log` WHERE netbios=%s", netbios)
|
253
|
|
254
|
c.execute("SELECT ip FROM log WHERE ip=%s", ip)
|
255
|
if c.fetchone():
|
256
|
c.execute("SELECT ip FROM log WHERE netbios=%s", netbios)
|
257
|
row = c.fetchone()
|
258
|
if row and row[0] != ip:
|
259
|
c.execute("DELETE FROM `log` WHERE netbios=%s AND ip=%s", (netbios, row[0]))
|
260
|
|
261
|
c.execute("UPDATE log SET netbios=%s, user=%s, sid=%s, display_name=%s, prim_group=%s, os=%s WHERE ip=%s", (netbios, user, sid, display_name, primgrp, ostype, ip))
|
262
|
else:
|
263
|
c.execute("SELECT ip FROM log WHERE netbios=%s", netbios)
|
264
|
if c.fetchone():
|
265
|
c.execute("UPDATE log SET ip=%s, user=%s, sid=%s, display_name=%s, prim_group=%s, os=%s WHERE netbios=%s", (ip, user, sid, display_name, primgrp, ostype, netbios))
|
266
|
else:
|
267
|
c.execute("INSERT INTO log (netbios, ip, user, sid, display_name, prim_group, os) VALUES (%s, %s, %s, %s, %s, %s, %s)", (netbios, ip, user, sid, display_name, primgrp, ostype))
|
268
|
c.execute("DELETE FROM `group` WHERE ip=%s", ip)
|
269
|
|
270
|
for group in groups:
|
271
|
c.execute("INSERT INTO `group` (ip, groupname) VALUES (%s, %s)",
|
272
|
(ip, group))
|
273
|
db.commit()
|
274
|
except Exception, e:
|
275
|
db.rollback()
|
276
|
raise Exception('erreur de la base de donnée : %s %s' % (str(e), traceback.format_exc()))
|
277
|
finally:
|
278
|
db.close()
|
279
|
|
280
|
def log_connexion(user, primgrp, machine, ostype, adresse_ip, pid):
|
281
|
"""
|
282
|
Enregistrement de la connexion
|
283
|
"""
|
284
|
try:
|
285
|
sdate = datetime.now().strftime("%a %d %b %Y %H:%M").capitalize()
|
286
|
cmd = 'echo CONNECTION %s %s %s %s %s %s %s' % (sdate, user,
|
287
|
primgrp, machine, ostype, adresse_ip, pid)
|
288
|
system('%s >> /var/log/samba/%s.log' % (cmd, machine))
|
289
|
system('%s >> /var/log/samba/connexions.log' % (cmd))
|
290
|
except:
|
291
|
pass
|
292
|
|
293
|
|
294
|
|
295
|
|
296
|
|
297
|
def gen_fich(user, groups, shares, machine, ostype, homedrive, userclass,
|
298
|
netlogon):
|
299
|
"""
|
300
|
Génération du fichier lu par le client
|
301
|
"""
|
302
|
script = ""
|
303
|
|
304
|
for share in shares:
|
305
|
|
306
|
if share['drive'] != "":
|
307
|
|
308
|
script += gen_lecteur_bloc(share['drive'], share['uri'])
|
309
|
|
310
|
|
311
|
debut, fin = get_scripts(user, machine, ostype, groups)
|
312
|
|
313
|
write_fich(netlogon, debut + script + fin)
|
314
|
|
315
|
def gen_letter_share(lettre, share):
|
316
|
"""lettre : supprime les ":", juste la lettre
|
317
|
share : le partage sans \ à la fin
|
318
|
"""
|
319
|
while share[-1] == '\\':
|
320
|
share = share[:-1]
|
321
|
return lettre[:1], share
|
322
|
|
323
|
def gen_lecteur_bloc(lettre, share):
|
324
|
"""Génère un bloc de ligne pour le montage
|
325
|
d'un lecteur réseau "share" sur la lettre "lettre"
|
326
|
ou sur * sinon (sauf pour win95)
|
327
|
"""
|
328
|
lettre, share = gen_letter_share(lettre, share)
|
329
|
return 'lecteur,%s:,%s\r\n' % (lettre, share)
|
330
|
|
331
|
def gen_cmd_line(line, hide=False, nowait=False):
|
332
|
"""génère une ligne DOS (avec le bon retour chariot) (pas win95)
|
333
|
"""
|
334
|
chaine = 'cmd,%s' % line
|
335
|
if hide:
|
336
|
chaine += ',HIDDEN'
|
337
|
if nowait:
|
338
|
chaine += ',NOWAIT'
|
339
|
return chaine + '\r\n'
|
340
|
|
341
|
def get_scripts(user, machine, ostype, user_groups):
|
342
|
"""Gestion des scripts externes
|
343
|
"""
|
344
|
|
345
|
|
346
|
motif_include = [ "%%NetUse%%", "%NetUse%" ]
|
347
|
|
348
|
buffer_debut, buffer_fin = '', ''
|
349
|
|
350
|
for chemin in get_scripts_list(user, machine, ostype, user_groups):
|
351
|
if isfile(chemin):
|
352
|
debut = 1
|
353
|
for line in file(chemin,"r"):
|
354
|
line = line.strip()
|
355
|
if line in motif_include:
|
356
|
debut = 0
|
357
|
else:
|
358
|
if debut == 1:
|
359
|
buffer_debut += parse_line(ostype, line)
|
360
|
else:
|
361
|
buffer_fin += parse_line(ostype, line)
|
362
|
return (buffer_debut, buffer_fin)
|
363
|
|
364
|
def get_scripts_list(user, machine, ostype, user_groups):
|
365
|
"""On créé la liste des fichiers possibles
|
366
|
+--PATH_SCRIPTS/users/<user>.txt
|
367
|
+--PATH_SCRIPTS/groups/<group>.txt
|
368
|
+--PATH_SCRIPTS/machines/<machine>.txt
|
369
|
+--PATH_SCRIPTS/os/<os>.txt
|
370
|
+--PATH_SCRIPTS/os/<os>/<group>.txt
|
371
|
+--PATH_SCRIPTS/os/<os>/<user>.txt
|
372
|
"""
|
373
|
chemins = [join(PATH_SCRIPTS, 'users', '%s%s' % (user, SCRIPTS_EXT))]
|
374
|
chemins.append(join(PATH_SCRIPTS, 'machines', '%s%s' %
|
375
|
(machine, SCRIPTS_EXT)))
|
376
|
for group in user_groups:
|
377
|
chemins.append(join(PATH_SCRIPTS, 'groups', '%s%s' %
|
378
|
(group, SCRIPTS_EXT)))
|
379
|
chemins.append(join(PATH_SCRIPTS, 'os', '%s' % ostype, '%s%s' %
|
380
|
(group, SCRIPTS_EXT)))
|
381
|
chemins.append(join(PATH_SCRIPTS, 'os', '%s%s' % (ostype, SCRIPTS_EXT)))
|
382
|
chemins.append(join(PATH_SCRIPTS, 'os', ostype, '%s%s' %
|
383
|
(user, SCRIPTS_EXT)))
|
384
|
return chemins
|
385
|
|
386
|
def parse_line(ostype, line):
|
387
|
items = [ i.strip() for i in line.split(',') ]
|
388
|
script_type = items[0].upper()
|
389
|
options = [opt.upper() for opt in items[2:]]
|
390
|
if script_type == 'CMD':
|
391
|
|
392
|
|
393
|
|
394
|
hide = 'HIDDEN' in options
|
395
|
nowait = 'NOWAIT' in options
|
396
|
return gen_cmd_line(items[1], hide, nowait)
|
397
|
elif script_type == 'LECTEUR':
|
398
|
|
399
|
lettre, partage = items[1], items[2]
|
400
|
return gen_lecteur_bloc(lettre, partage)
|
401
|
return ''
|
402
|
|
403
|
def write_fich(netlogon, lines):
|
404
|
"""Ecrit le fichier
|
405
|
"""
|
406
|
fic = file(netlogon, 'w')
|
407
|
fchmod(fic.fileno(), 0644)
|
408
|
|
409
|
|
410
|
lines = lines.decode('utf8').encode('cp437')
|
411
|
fic.write(lines)
|
412
|
fic.close()
|