1 | import os |
---|
2 | import os.path |
---|
3 | import shutil |
---|
4 | import json |
---|
5 | import re |
---|
6 | import subprocess |
---|
7 | import stat |
---|
8 | import grp |
---|
9 | import pwd |
---|
10 | import imp |
---|
11 | import threading |
---|
12 | sambaparser=imp.load_source("SambaParser","/usr/share/n4d/python-plugins/support/sambaparser.py") |
---|
13 | |
---|
14 | |
---|
15 | class NetFoldersManager: |
---|
16 | |
---|
17 | |
---|
18 | LOCAL_CONF_FOLDER="/var/lib/lliurex-folders/local/" |
---|
19 | SMB_CONF_FOLDER="/var/lib/lliurex-folders/smb/" |
---|
20 | BASE_DIR="/net/server-sync/" |
---|
21 | |
---|
22 | def __init__(self): |
---|
23 | |
---|
24 | self.debug=False |
---|
25 | |
---|
26 | self.acl_thread=threading.Thread() |
---|
27 | |
---|
28 | if not os.path.exists(self.LOCAL_CONF_FOLDER): |
---|
29 | os.makedirs(self.LOCAL_CONF_FOLDER) |
---|
30 | if not os.path.exists(self.SMB_CONF_FOLDER): |
---|
31 | os.makedirs(self.SMB_CONF_FOLDER) |
---|
32 | |
---|
33 | #def __init__ |
---|
34 | |
---|
35 | |
---|
36 | def startup(self,options): |
---|
37 | self.mount_gluster_volumes() |
---|
38 | self.check_local_folders() |
---|
39 | self.get_shared_folders() |
---|
40 | |
---|
41 | #def startup |
---|
42 | |
---|
43 | def backup(self,backup_target=None,backup_dest="/backup"): |
---|
44 | if not backup_dest.endswith("/"): |
---|
45 | backup_dest+="/" |
---|
46 | file_path=backup_dest+get_backup_name("NetFoldersManager") |
---|
47 | if backup_target is None: |
---|
48 | backup_target = [os.path.join(self.BASE_DIR,x) for x in os.listdir(self.BASE_DIR)] |
---|
49 | return objects['FileUtils'].backup(backup_target,file_path) |
---|
50 | |
---|
51 | #def backup |
---|
52 | |
---|
53 | def restore(self,backup_file=None): |
---|
54 | if backup_file==None: |
---|
55 | for f in sorted(os.listdir("/backup"),reverse=True): |
---|
56 | if "NetFoldersManager" in f: |
---|
57 | backup_file="/backup/"+f |
---|
58 | break |
---|
59 | return objects['FileUtils'].restore(backup_file,'/') |
---|
60 | |
---|
61 | #def restore |
---|
62 | |
---|
63 | def mount_gluster_volumes(self): |
---|
64 | try: |
---|
65 | list_mount = [] |
---|
66 | if not os.path.exists('/var/lib/n4d-glusterfs/volumes'): |
---|
67 | return True |
---|
68 | f = open('/var/lib/n4d-glusterfs/volumes') |
---|
69 | lines = f.readlines() |
---|
70 | to_mount = [ x[:x.find('#') - 1] for x in lines ] |
---|
71 | for x in range(1,10): |
---|
72 | mounted=objects['MountManager'].mount_list().keys() |
---|
73 | to_mount_b=[] |
---|
74 | for item in to_mount: |
---|
75 | #to_mount_b.append(" ".join(item.split(" ")[0])) |
---|
76 | to_mount_b.append(item.split(" ")[0]) |
---|
77 | to_process=[] |
---|
78 | for item in to_mount_b: |
---|
79 | if item not in mounted: |
---|
80 | to_process.append(item) |
---|
81 | if len(to_process)==0: |
---|
82 | break |
---|
83 | for item in to_mount: |
---|
84 | for item2 in to_process: |
---|
85 | if item.find(item2)!=-1: |
---|
86 | os.system("mount -t glusterfs -o acl " + item ) |
---|
87 | continue |
---|
88 | except Exception, e: |
---|
89 | pass |
---|
90 | return True |
---|
91 | |
---|
92 | #def mount_gluster_volumes |
---|
93 | |
---|
94 | |
---|
95 | def get_acl_info(self,path): |
---|
96 | |
---|
97 | info={} |
---|
98 | regex="(\w+:|\A)(user|group|mask|other):([a-zA-Z0-9\-]*):([r|w|x|\-]{1,3})\s*[#]*(\S+)*\Z" |
---|
99 | os.environ["LANG"]="C" |
---|
100 | p=subprocess.Popen(["getfacl","-n",path],stdout=subprocess.PIPE,stderr=subprocess.PIPE) |
---|
101 | out=p.communicate()[0] |
---|
102 | |
---|
103 | info["acl"]=[] |
---|
104 | info["perm"]=int(str(oct(stat.S_IMODE(os.lstat(path).st_mode))).lstrip("0")) |
---|
105 | info["path"]=path |
---|
106 | |
---|
107 | for item in out.split("\n"): |
---|
108 | |
---|
109 | #item=item.strip("\n") |
---|
110 | x=re.match(regex,item) |
---|
111 | |
---|
112 | if x!=None: |
---|
113 | |
---|
114 | special=x.group(1) |
---|
115 | type_=x.group(2) |
---|
116 | custom_group=x.group(3) |
---|
117 | acl=x.group(4) |
---|
118 | extra=x.group(5) |
---|
119 | |
---|
120 | if special.find("default")!=-1: |
---|
121 | mode="-d -m" |
---|
122 | else: |
---|
123 | mode="-m" |
---|
124 | |
---|
125 | if type_=="group": |
---|
126 | type_="g:" |
---|
127 | elif type_=="user": |
---|
128 | type_="u:" |
---|
129 | elif type_=="mask": |
---|
130 | type_="m:" |
---|
131 | elif type_=="other": |
---|
132 | type_="o:" |
---|
133 | |
---|
134 | |
---|
135 | info["acl"].append([mode,type_+custom_group+":"+acl]) |
---|
136 | |
---|
137 | |
---|
138 | |
---|
139 | return info |
---|
140 | |
---|
141 | #def get_acl_info |
---|
142 | |
---|
143 | def get_missing_acl_conf(self,info): |
---|
144 | |
---|
145 | ret=[] |
---|
146 | ret_={} |
---|
147 | for f in os.listdir(NetFoldersManager.LOCAL_CONF_FOLDER): |
---|
148 | try: |
---|
149 | ff=open(NetFoldersManager.LOCAL_CONF_FOLDER+f) |
---|
150 | txt="".join(ff.readlines()) |
---|
151 | ff.close() |
---|
152 | orig_info=eval(txt) |
---|
153 | for item in orig_info: |
---|
154 | found=False |
---|
155 | if orig_info[item]["path"]==info["path"]: |
---|
156 | for acl in orig_info[item]["acl"]: |
---|
157 | if not acl in info["acl"]: |
---|
158 | ret.append(acl) |
---|
159 | found=True |
---|
160 | |
---|
161 | if found: |
---|
162 | |
---|
163 | ret_[info["path"]]={} |
---|
164 | ret_[info["path"]]["path"]=info["path"] |
---|
165 | ret_[info["path"]]["perm"]=orig_info[item]["perm"] |
---|
166 | ret_[info["path"]]["acl"]=ret |
---|
167 | |
---|
168 | return(ret_) |
---|
169 | |
---|
170 | |
---|
171 | |
---|
172 | except Exception as e: |
---|
173 | print e |
---|
174 | |
---|
175 | |
---|
176 | return None |
---|
177 | |
---|
178 | |
---|
179 | #def get_diferences |
---|
180 | |
---|
181 | def parse_local_folders_conf(self): |
---|
182 | |
---|
183 | for f in sorted(os.listdir(self.LOCAL_CONF_FOLDER)): |
---|
184 | try: |
---|
185 | #execfile(self.LOCAL_CONF_FOLDER+f) |
---|
186 | #self.local_dirs=dict(self.local_dirs.items()+locals()["folder"].items()) |
---|
187 | |
---|
188 | f_=open(self.LOCAL_CONF_FOLDER+f,"r") |
---|
189 | data=json.load(f_) |
---|
190 | f_.close() |
---|
191 | self.local_dirs=dict(self.local_dirs.items()+data.items()) |
---|
192 | |
---|
193 | except Exception as e: |
---|
194 | print("!!",e,"File: " + f) |
---|
195 | |
---|
196 | |
---|
197 | |
---|
198 | |
---|
199 | def check_local_folders(self,recursive=False): |
---|
200 | |
---|
201 | self.local_dirs={} |
---|
202 | #sorted!!! |
---|
203 | |
---|
204 | self.parse_local_folders_conf() |
---|
205 | |
---|
206 | #path,perm,acl |
---|
207 | |
---|
208 | for item in sorted(self.local_dirs.keys()): |
---|
209 | |
---|
210 | self.dprint("Checking %s configuration..."%item) |
---|
211 | path=self.local_dirs[item]["path"] |
---|
212 | try: |
---|
213 | user = int(self.local_dirs[item]["owner"]) |
---|
214 | except: |
---|
215 | user = int(pwd.getpwnam(self.local_dirs[item]["owner"]).pw_uid) |
---|
216 | try: |
---|
217 | group = int(self.local_dirs[item]["group"]) |
---|
218 | except: |
---|
219 | group = int(grp.getgrnam(self.local_dirs[item]["group"]).gr_gid) |
---|
220 | if not os.path.exists(path): |
---|
221 | print("\t* Creating path %s ..."%path) |
---|
222 | try: |
---|
223 | os.makedirs(path) |
---|
224 | prevmask=os.umask(0) |
---|
225 | os.chmod(path,int(str(self.local_dirs[item]["perm"]),8)) |
---|
226 | os.lchown(path,user,group) |
---|
227 | os.umask(prevmask) |
---|
228 | except Exception as e: |
---|
229 | print("!!",e,path) |
---|
230 | |
---|
231 | |
---|
232 | |
---|
233 | try: |
---|
234 | info=self.get_acl_info(path) |
---|
235 | info=self.get_missing_acl_conf(info) |
---|
236 | |
---|
237 | if ( os.lstat(path).st_uid != user ) or (os.lstat(path).st_gid != group): |
---|
238 | os.lchown(path,user,group) |
---|
239 | if int(str(oct(stat.S_IMODE(os.lstat(path).st_mode))).lstrip("0"))!=info[path]["perm"]: |
---|
240 | prevmask=os.umask(0) |
---|
241 | os.chmod(path,int(str(info[path]["perm"]),8)) |
---|
242 | os.umask(prevmask) |
---|
243 | |
---|
244 | |
---|
245 | for acl in info[path]["acl"]: |
---|
246 | print("\t* Setting acls to " + path + " ...") |
---|
247 | options,value=acl |
---|
248 | self.set_acl(path,options,value,recursive) |
---|
249 | except Exception as e: |
---|
250 | print e |
---|
251 | |
---|
252 | #def check_local_folders |
---|
253 | |
---|
254 | def set_acl(self,path,options,value,recursive=False): |
---|
255 | |
---|
256 | if recursive: |
---|
257 | recursive="-R" |
---|
258 | else: |
---|
259 | recursive="" |
---|
260 | |
---|
261 | if type(path)==type(""): |
---|
262 | path=path.decode("utf-8") |
---|
263 | |
---|
264 | cmd_str="setfacl %s %s %s '%s'"%(recursive,options,value,path) |
---|
265 | |
---|
266 | self.dprint(cmd_str) |
---|
267 | |
---|
268 | os.system(cmd_str.encode("utf-8")) |
---|
269 | #here goes executing command |
---|
270 | |
---|
271 | #def set_acl |
---|
272 | |
---|
273 | def get_shared_folders(self): |
---|
274 | |
---|
275 | self.remote_dirs={} |
---|
276 | |
---|
277 | try: |
---|
278 | srv_ip=objects["VariablesManager"].get_variable("SRV_IP") |
---|
279 | except: |
---|
280 | pass |
---|
281 | |
---|
282 | if srv_ip!=None: |
---|
283 | sp=sambaparser.SambaParser() |
---|
284 | for item in os.listdir(self.SMB_CONF_FOLDER): |
---|
285 | f=self.SMB_CONF_FOLDER+item |
---|
286 | sp.read(f) |
---|
287 | for key in sp.conf: |
---|
288 | if key!=None: |
---|
289 | try: |
---|
290 | line="//"+srv_ip+"/"+key |
---|
291 | self.remote_dirs[line]={} |
---|
292 | self.remote_dirs[line]["dst"]=sp.conf[key]["mount_point"] |
---|
293 | self.remote_dirs[line]["fstype"]="cifs" |
---|
294 | except Exception as e: |
---|
295 | #print e |
---|
296 | pass |
---|
297 | |
---|
298 | return self.remote_dirs |
---|
299 | |
---|
300 | #def check_shared_folders |
---|
301 | |
---|
302 | |
---|
303 | def dprint(self,item): |
---|
304 | |
---|
305 | if self.debug: |
---|
306 | |
---|
307 | try: |
---|
308 | print("[NetFoldersManager] " + str(item) ) |
---|
309 | except: |
---|
310 | pass |
---|
311 | |
---|
312 | #def dprint |
---|
313 | |
---|
314 | def get_acl_group_filtered(self,group): |
---|
315 | result = [] |
---|
316 | path = self.LOCAL_CONF_FOLDER + os.path.sep + group.lower() |
---|
317 | if os.path.exists(path): |
---|
318 | aux_file = open(path) |
---|
319 | list_acl = json.load(aux_file) |
---|
320 | |
---|
321 | for items in list_acl.values(): |
---|
322 | for x in items['acl']: |
---|
323 | if '-d' in x[0]: |
---|
324 | x[0] = u'-m' |
---|
325 | result.append(x) |
---|
326 | aux_file.close() |
---|
327 | return result |
---|
328 | |
---|
329 | |
---|
330 | def is_dir_workable(self,current_dir,banned_list): |
---|
331 | |
---|
332 | for dir in banned_list: |
---|
333 | |
---|
334 | if dir in current_dir: |
---|
335 | |
---|
336 | return False |
---|
337 | |
---|
338 | |
---|
339 | return True |
---|
340 | |
---|
341 | #def is_dir_workable |
---|
342 | |
---|
343 | |
---|
344 | def restore_acls(self): |
---|
345 | |
---|
346 | try: |
---|
347 | |
---|
348 | self.local_folders={} |
---|
349 | self.local_dirs={} |
---|
350 | self.parse_local_folders_conf() |
---|
351 | |
---|
352 | dirs_to_process={} |
---|
353 | |
---|
354 | for item in self.local_dirs: |
---|
355 | dirs_to_process[self.local_dirs[item]["path"]]="" |
---|
356 | |
---|
357 | |
---|
358 | |
---|
359 | for item in self.local_dirs: |
---|
360 | |
---|
361 | |
---|
362 | owner=self.local_dirs[item]["owner"] |
---|
363 | group=self.local_dirs[item]["group"] |
---|
364 | path=self.local_dirs[item]["path"] |
---|
365 | perm=self.local_dirs[item]["perm"] |
---|
366 | acls=self.local_dirs[item]["acl"] |
---|
367 | file_acls=[] |
---|
368 | |
---|
369 | dirs_to_process.pop(path) |
---|
370 | |
---|
371 | for acl in acls: |
---|
372 | options,value=acl |
---|
373 | if "-d" not in options: |
---|
374 | file_acls.append(acl) |
---|
375 | |
---|
376 | ''' |
---|
377 | print item |
---|
378 | print "\t",owner,group,path,perm |
---|
379 | print "\t",file_acls |
---|
380 | ''' |
---|
381 | |
---|
382 | for walk_item in os.walk(path): |
---|
383 | dir,subdirs,files=walk_item |
---|
384 | |
---|
385 | if self.is_dir_workable(dir,dirs_to_process): |
---|
386 | #print dir |
---|
387 | #print "\t",files |
---|
388 | dir=dir.encode("utf-8") |
---|
389 | cmd="setfacl -k -b '" + dir + "'" |
---|
390 | os.system(cmd) |
---|
391 | |
---|
392 | prevmask=os.umask(0) |
---|
393 | os.chmod(path,int(str(perm),8)) |
---|
394 | |
---|
395 | for f in files: |
---|
396 | for acl in file_acls: |
---|
397 | options,value=acl |
---|
398 | if type(f)==type(u""): |
---|
399 | f=f.encode("utf-8") |
---|
400 | |
---|
401 | self.set_acl(dir+"/"+f,options,value) |
---|
402 | self.set_acl(dir+"/"+f,"-m","m:rw") |
---|
403 | |
---|
404 | for acl in acls: |
---|
405 | options,value=acl |
---|
406 | self.set_acl(dir,options,value) |
---|
407 | |
---|
408 | os.umask(prevmask) |
---|
409 | |
---|
410 | |
---|
411 | return [True,""] |
---|
412 | |
---|
413 | |
---|
414 | except Exception as e: |
---|
415 | |
---|
416 | return [False,str(e)] |
---|
417 | |
---|
418 | |
---|
419 | #def restore_acls |
---|
420 | |
---|
421 | def restore_acls_via_thread(self): |
---|
422 | |
---|
423 | if not self.acl_thread.is_alive(): |
---|
424 | |
---|
425 | self.acl_thread=threading.Thread(target=self.restore_acls) |
---|
426 | self.daemon=True |
---|
427 | self.acl_thread.start() |
---|
428 | |
---|
429 | |
---|
430 | return True |
---|
431 | |
---|
432 | |
---|
433 | #def restore_acls_via_thread |
---|
434 | |
---|
435 | def is_acl_thread_alive(self): |
---|
436 | |
---|
437 | return self.acl_thread.is_alive() |
---|
438 | |
---|
439 | #def is_acl_thread_alive |
---|
440 | |
---|
441 | def restore_teacher_access(self,student): |
---|
442 | |
---|
443 | folders=["/net/server-sync/home/students/%s/Desktop","/net/server-sync/home/students/%s/Documents"] |
---|
444 | if pwd.getpwnam(student).pw_uid > 20000: |
---|
445 | |
---|
446 | print "Fixing %s ..."%student |
---|
447 | |
---|
448 | for folder in folders: |
---|
449 | |
---|
450 | os.system("chown %s:nogroup '%s'"%(student,folder%student)) |
---|
451 | os.system("chmod 770 -R '%s'"%(folder%student)) |
---|
452 | |
---|
453 | return True |
---|
454 | |
---|
455 | else: |
---|
456 | return False |
---|
457 | |
---|
458 | |
---|
459 | #def restore_teacher_access |
---|
460 | |
---|
461 | |
---|
462 | #class NetFoldersManager |
---|
463 | |
---|
464 | if __name__=="__main__": |
---|
465 | |
---|
466 | nfm=NetFoldersManager() |
---|
467 | #nfm.restore_acls() |
---|