source: n4d-ldap/trunk/fuentes/install/usr/share/n4d/python-plugins/SlapdManager.py @ 149

Last change on this file since 149 was 149, checked in by hectorgh, 4 years ago

adding project files

File size: 34.7 KB
Line 
1import ldap
2import ldap.sasl
3import ldap.modlist
4import os
5import os.path
6import ast
7from jinja2 import Environment
8from jinja2.loaders import FileSystemLoader
9from jinja2 import Template
10import base64
11import random
12import string
13import hashlib
14import subprocess
15import tempfile
16import shutil
17
18def try_connect(f):
19        def wrap(*args,**kw):
20                if not args[0].test_ldapi_connection():
21                        if not args[0].connection_ldapi():
22                                return {"status":False,"msg":"Connection with ldapi is not created"}
23                return f(*args)
24        return wrap
25#def __try_connect__
26
27
28class SlapdManager:
29       
30        predepends = ['VariablesManager']
31       
32        def __init__(self):
33                # Vars
34                self.LDAP_SECRET1 = '/etc/lliurex-cap-secrets/ldap-master/ldap'
35                self.LDAP_SECRET2 = '/etc/lliurex-secrets/passgen/ldap.secret'
36                self.log_path = '/var/log/n4d/sldap'
37                self.enable_acl_path = '/var/lib/n4d-ldap/enable_acl'
38                self.tpl_env = Environment(loader=FileSystemLoader('/usr/share/n4d/templates/slapd'))
39        #def __init__
40       
41        def apt(self):
42                '''
43                options={}
44                options["groups"] = ["adm","admins"]
45                options["visibility"] = True
46                esto es un comentario que funciona de la siguiente forma
47                        asi
48                '''
49                pass
50        #def apt
51       
52        def startup(self,options):
53                if objects['VariablesManager'].get_variable('LDAP_BASE_DN') is None:
54                        objects['VariablesManager'].init_variable('LDAP_BASE_DN')
55                self.connection_ldapi()
56                self.connection_ldap()
57        #def startup
58       
59        def test(self):
60                pass
61        #def test
62       
63        def backup(self, folder_path="/backup/"):
64                try:
65                        if not folder_path.endswith("/"):
66                                folder_path+="/"
67                        file_path = folder_path + get_backup_name("Slapd")
68                        os.system("llx-slapd-backup dump " + file_path)
69                        objects["Golem"].ldap.restore_connection=True
70                        objects["Golem"].ldap.connect()
71                        return [True,file_path]
72                       
73                except Exception as e:
74                        return [False,str(e)]
75               
76        #def backup
77       
78        def restore(self,file_path=None):
79                if file_path==None:
80                        for f in sorted(os.listdir("/backup"),reverse=True):
81                                if "Slapd" in f:
82                                        file_path="/backup/"+f
83                                        break
84
85                try:
86
87                        if os.path.exists(file_path):
88                               
89                                os.system("llx-slapd-backup restore " + file_path)
90                                               
91                                return [True,""]
92                               
93                except Exception as e:
94                               
95                        return [False,str(e)]
96        #def restore
97       
98        def reset_slapd(self):
99                proc = subprocess.Popen(['/usr/sbin/reset-slapd'],stdout=subprocess.PIPE,stdin=subprocess.PIPE).communicate()
100                return {"status":True,"msg":"Server is reset"}
101        #def reset_slapd
102
103        @try_connect
104        def load_acl(self):
105                """
106                To be supplied
107                """
108               
109                # Get files from enable acl path ordered by number. If file name not start by number,
110                # it's putting in the end ordered by letter.
111                list_files_acl = os.listdir(self.enable_acl_path)
112                list_files_acl.sort(lambda x,y:self.__becmp__(self.__beint__(x),self.__beint__(y)))
113               
114                # Prepare environment
115                environment_vars = objects["VariablesManager"].get_variable_list(['LDAP_BASE_DN'])
116                list_acl = []
117               
118                # Number for ACL
119                i = 0
120                for x in list_files_acl:
121                        aux_file = open(os.path.join(self.enable_acl_path,x))
122                        lines = aux_file.readlines()
123                        aux_acl = ""
124                        for y in lines:
125                                aux_acl += y.strip() + " "
126                        # Render acl to replace vars
127                        acl_template = Template(aux_acl)
128                        aux_acl = acl_template.render(environment_vars).encode('utf-8')
129                        aux_acl = "{"+str(i)+"}" + aux_acl
130                        i+=1
131                        list_acl.append(aux_acl)
132               
133                remove_acl = [(ldap.MOD_DELETE,'olcAccess',None)]
134                modify_list = [(ldap.MOD_ADD,'olcAccess',list_acl)]
135
136                try:
137                        self.connect_ldapi.modify_s('olcDatabase={1}hdb,cn=config',remove_acl)
138                except:         
139                        pass
140                try:
141                        self.connect_ldapi.modify_s('olcDatabase={1}hdb,cn=config',modify_list)
142                except Exception as e:
143                        return {"status":False,"msg":str(e)}
144                return {"status":True,"msg":"Acl updated"}
145        #def load_acl
146       
147        @try_connect   
148        def load_schema(self,cn,schema,update=False):
149               
150                all_schemas = self.connect_ldapi.search_s('cn=schema,cn=config',ldap.SCOPE_SUBTREE)
151                old_config = None
152                for i in all_schemas:
153                        if cn[3:] in i[0]:
154                                old_cn = i[0]
155                                old_config = i[1]
156                                break
157                if not old_config == None:
158                        if not update:
159                                return {"status":False,"msg":"Schema " + str(cn) + " already exist. You can update with update option on True"}
160                        old_config['cn'] = schema['cn']
161                        old_config['objectClass'] = schema['objectClass']
162                        changes = ldap.modlist.modifyModlist(old_config,schema)
163                        try:
164                                self.connect_ldapi.modify_s(old_cn,changes)
165                                return {"status":True,"msg":"Schema " + str(cn) +"is updated"}
166                        except Exception as e:
167                                return {"status":False,"msg":str(e)}
168                else:
169                        changes = ldap.modlist.addModlist(schema)
170                        try:
171                                self.connect_ldapi.add_s(cn,changes)
172                                return {"status":True,"msg":"Loaded schema" + str(cn)}
173                        except Exception as e:
174                                return {"status":False,"msg":str(e)}
175        #def load_schema
176       
177        @try_connect   
178        def update_index(self,index,add_index=True):
179               
180                searching_backend = self.connect_ldapi.search_s('cn=config',ldap.SCOPE_SUBTREE,filterstr='(objectClass=olcBackendConfig)',attrlist=['olcBackend'])
181                if len(searching_backend) > 0 :
182                        backend = searching_backend[0][1]['olcBackend'][0]
183                else:
184                        return {"status":False,"msg":"not found backend for OpenLdap"}
185               
186                searching_database = self.connect_ldapi.search_s('cn=config',ldap.SCOPE_SUBTREE,filterstr='(olcDatabase~='+backend+')',attrlist=['olcDbIndex'])
187                if len(searching_database) > 0 :
188                        cn,aux_index = searching_database[0]
189                else:
190                        return {"status":False,"msg":"not found database config on OpenLdap"}
191                if aux_index.has_key('olcDbIndex'):
192                        old_Index = aux_index['olcDbIndex']
193                else:
194                        old_Index = []
195                list_index = old_Index[:]
196                if type(index) == type([]):
197                        for x in index:
198                                if add_index:
199                                        list_index.append(x)
200                                else:
201                                        if x in list_index:
202                                                list_index.remove(x)
203                elif type(index) == type(''):
204                        if add_index:
205                                list_index.append(index)
206                        else:
207                                if index in list_index:
208                                        list_index.remove(index)
209                list_index = list(set(list_index))
210                remove_acl = [(ldap.MOD_DELETE,'olcDbIndex',None)]
211                modify_list = [(ldap.MOD_ADD,'olcDbIndex',list_index)]
212
213                try:
214                        self.connect_ldapi.modify_s(cn,remove_acl)
215                except:         
216                        pass
217                try:
218                        self.connect_ldapi.modify_s(cn,modify_list)
219                except Exception as e:
220                        self.connect_ldapi.modify_s(cn,[(ldap.MOD_ADD,'olcDbIndex',old_Index)])
221                        return {"status":False,"msg":str(e)}
222                return {"status":True,"msg":"Index added"}
223        #def load_index
224       
225        def load_lliurex_schema(self):
226                #Load template
227                template = self.tpl_env.get_template("configure/lliurex_schema")
228               
229                #render template with config and turn string into dictionary for get modify ldif
230                string_template = template.render().encode('UTF-8')
231                aux_dic = ast.literal_eval(string_template)
232                # Update changes in ldap
233                for x in aux_dic.keys():
234                        result = self.load_schema(x,aux_dic[x],True)
235                        if not result['status']:
236                                return result
237                return {"status":True,"msg":"Loaded Lliurex schema"}   
238               
239        #def load_lliurex_schema
240
241        def load_basic_struture(self):
242                """
243                        Load on ldap database root dn and other basics things
244                """
245                if not self.test_ldap_connection():
246                        if not self.connection_ldap():
247                                return {"status":False,"msg":"Connection with ldap is not created"}
248               
249                #Prepare environment
250                template = self.tpl_env.get_template('struct/base')
251                environment_vars = objects["VariablesManager"].get_variable_list(['LDAP_BASE_DN'])
252               
253                #render template with config and turn string into dictionary for get modify ldif
254                string_template = template.render(environment_vars).encode("UTF-8")
255                aux_dic = ast.literal_eval(string_template)
256               
257                #Load basic strucutre
258                result = self.insert_dictionary(aux_dic)
259                if result['status']:
260                        return {"status":True,"msg":"Root structure created"} 
261                else:
262                        return {"status":True,"msg":"Root structure already exists"}
263        #def load_basic_structure
264       
265       
266        def insert_dictionary(self,dictionary,i_existing=False,f_update=False):
267                """
268                """
269                if not self.test_ldap_connection():
270                        if not self.connection_ldap():
271                                return {"status":False,"msg":"Connection with ldap is not created"}
272       
273                if not type(dictionary) == type({}):
274                        return {"status":False,"msg":"argument isn't python dictionary "}
275                dictionary_keys = dictionary.keys()
276                dictionary_keys.sort(lambda a,b: self.__dncmp__(a,b))
277                aux_msg = ""
278                for x in dictionary_keys:
279                        try:
280                                add_entry = ldap.modlist.addModlist(dictionary[x])
281                                self.connect_ldap.add_s(x,add_entry)
282                        except ldap.ALREADY_EXISTS as e:
283                                if i_existing:
284                                        aux_msg += "\nEntry " + str(x) + " has been omited because already exists"
285                                else:                                   
286                                        return {"status":False ,"msg":"Entry " + str(x) + " already exists"}
287                        except Exception as e:
288                                return {"status":False ,"msg":"Entry " + str(x) + " isn't possible create because "+ str(e)}
289                return {"status":True,"msg":"All entry added" + aux_msg}
290        #def insert_dictionary
291       
292       
293        def delete_dn(self, dn):
294                if not self.test_ldap_connection():
295                        if not self.connection_ldap():
296                                return {"status":False,"msg":"Connection with ldap is not created"}
297                try:
298                        self.connection_ldap.delete_s(dn)
299                except Exception as e:
300                        return {"status":False,"msg":str(e)}
301                return {"status":True,"msg":"Deleted dn"}
302        #def delete_dn
303       
304        def recursive_delete(self,dn):
305                try:
306                        result = self.connect_ldap.search_s(dn,ldap.SCOPE_ONELEVEL)
307                except ldap.NO_SUCH_OBJECT as e:
308                        return
309                if len(result) > 0 :
310                        for x in result:
311                                self.recursive_delete(x[0])
312                self.connect_ldap.delete_s(dn)
313                return {"status":True, "msg":"Deleted " + str(dn)}
314        #def recursive_delete
315
316        @try_connect   
317        def enable_tls_communication(self,cert_path,key_path):
318                """
319                        Enable ssl for connection
320                """
321               
322                # Remove old password and add new password . 1 = delete, 0 = add
323                remove_tls = [(ldap.MOD_DELETE,'olcTLSCertificateFile',None),(ldap.MOD_DELETE,'olcTLSCertificateKeyFile',None),(ldap.MOD_DELETE,'olcTLSVerifyClient',None)]
324                modify_list = [(ldap.MOD_ADD,'olcTLSCertificateFile',str(cert_path)),(ldap.MOD_ADD,'olcTLSCertificateKeyFile',str(key_path)),(ldap.MOD_ADD,'olcTLSVerifyClient','never')]
325
326                try:
327                        self.connect_ldapi.modify_s('cn=config',remove_tls)
328                except:         
329                        pass
330                try:
331                        self.connect_ldapi.modify_s('cn=config',modify_list)
332                except Exception as e:
333                        return {"status":False,"msg":str(e)}
334               
335                self.connection_ldap()
336                return {"status":True,"msg":"SSL is Enabled"}
337        #def enable_tls_communication
338
339        @try_connect   
340        def change_admin_passwd(self,password):
341                """
342                        Update ldap admin password and write this inside LDAP_SECRET2
343                """
344               
345                ssha_password = self.generate_ssha_password(password)
346                # Remove old password and add new password . 1 = delete, 0 = add
347                modify_list = [(ldap.MOD_DELETE, 'olcRootPW', None), (ldap.MOD_ADD, 'olcRootPW', ssha_password)]
348                try:
349                        self.connect_ldapi.modify_s('olcDatabase={1}hdb,cn=config',modify_list)
350                except Exception as e:
351                        return {"status":False,"msg":e[0]["desc"]}
352               
353                #reconnect
354                try:
355                        environment_vars = objects["VariablesManager"].get_variable_list(['LDAP_BASE_DN'])
356                        self.connect_ldap.bind_s("cn=admin,"+environment_vars['LDAP_BASE_DN'],password)
357                except:
358                        self.connect_ldap = None
359               
360                #Only write password file success case
361                password_file = open(self.LDAP_SECRET2,'w')
362                password_file.write(password+"\n")
363                password_file.close()
364                os.chmod(self.LDAP_SECRET2,0600)
365                return {"status":True,"msg":"Ldap admin password updated"}
366        #def change_admin_passwd
367
368        @try_connect   
369        def configure_simple_slapd(self,admin_password=None):
370                """
371                        This function configure openldap as simple ldap. If admin_password isn't defined
372                        it's generated by generate_random_ssha_password, with 10 characters.
373                """
374               
375                # get config template and vars
376                template = self.tpl_env.get_template("configure/basic")
377                environment_vars = objects["VariablesManager"].get_variable_list(['LDAP_BASE_DN'])
378               
379                # generate ssha password
380                if admin_password is None:
381                        ssha_password,admin_password = self.generate_random_ssha_password()
382                else:
383                        ssha_password = self.generate_ssha_password(admin_password)
384                environment_vars['PASSWORD_CRYPTED'] = ssha_password.strip()
385               
386                #render template with config and turn string into dictionary for get modify ldif
387                string_template = template.render(environment_vars).encode('UTF-8')
388                aux_dic = ast.literal_eval(string_template)
389               
390                # Update changes in ldap
391                for x in aux_dic.keys():
392                        old_config = self.connect_ldapi.search_s(x,ldap.SCOPE_SUBTREE)
393                        if len(old_config) > 0:
394                                old_config = old_config[0][1]
395                        changes = ldap.modlist.modifyModlist(old_config,aux_dic[x])
396                        try:
397                                self.connect_ldapi.modify_s(x,changes)
398                        except Exception as e:
399                                return {"status":False,"msg":e[0]["desc"]}
400               
401               
402                modify_list = [(ldap.MOD_ADD, 'olcSizeLimit', 'unlimited')]
403                try:
404                        self.connect_ldapi.modify_s('cn=config',modify_list)
405                except Exception as e:
406                        return {"status":False,"msg":e[0]["desc"]}
407
408                #Delete file password because this is a simple server
409                if os.path.exists(self.LDAP_SECRET1):
410                        os.remove(self.LDAP_SECRET1)
411               
412                #reconnect
413                try:
414                        self.connect_ldap.bind_s("cn=admin,"+environment_vars['LDAP_BASE_DN'],admin_password)
415                except:
416                        self.connect_ldap = None
417               
418                # If update config success then update file with new password
419                password_file = open(self.LDAP_SECRET2,'w')
420                password_file.write(admin_password+"\n")
421                password_file.close()
422                os.chmod(self.LDAP_SECRET2,0600)
423                return {"status":True,"msg":"OpenLdap is configured as simple ldap. Admin password is inside " + self.LDAP_SECRET2}
424
425        #def configure_simple_slapd
426       
427        def configure_master_slapd(self):
428                pass
429        #def configure_master_slapd
430       
431        def configure_client_slapd(self):
432                pass
433        #def configure_client_slapd
434       
435        def open_ports_slapd(self,server_ip):
436               
437                CLIENT_LDAP_URI = 'ldaps://'+ str(server_ip)
438                CLIENT_LDAP_URI_NOSSL = 'ldap://'+ str(server_ip)
439               
440                open_ports = 'ldap://:389/ ldapi:///'
441                connection_ok = True
442                if not self.test_ldapi_connection():
443                        if self.connection_ldapi:
444                                connection_ok = False
445                if connection_ok:
446                        try:
447                                ok_token = True
448                                result = self.connect_ldapi.search_s('cn=config',ldap.SCOPE_BASE,attrlist=['olcTLSCertificateKeyFile','olcTLSCertificateFile'])[0][1]
449                                if result.has_key('olcTLSCertificateKeyFile'):
450                                        if not os.path.exists(result['olcTLSCertificateKeyFile'][0]):
451                                                ok_token = False
452                                if ok_token and result.has_key('olcTLSCertificateFile'):
453                                        if not os.path.exists(result['olcTLSCertificateFile'][0]):
454                                                ok_token = False
455                                if ok_token:
456                                        open_ports += " ldaps:///"
457                        except:
458                                pass
459                slapd_file = open('/etc/default/slapd','r')
460                list_lines = slapd_file.readlines()
461                slapd_file.close()
462               
463                fd, tmpfilepath = tempfile.mkstemp()
464                new_slapd_file = open(tmpfilepath,'w')
465                for line in list_lines:
466                        if line.startswith('SLAPD_SERVICES='):
467                                new_slapd_file.write('SLAPD_SERVICES="'+open_ports+'"\n')
468                        else:
469                                new_slapd_file.write(line)
470                new_slapd_file.close()
471                os.close(fd)
472               
473                n4d_mv(tmpfilepath,'/etc/default/slapd')
474                if 'ldaps:' in open_ports:
475                        environment_vars = objects["VariablesManager"].init_variable('CLIENT_LDAP_URI',{'uri':CLIENT_LDAP_URI})
476                environment_vars = objects["VariablesManager"].init_variable('CLIENT_LDAP_URI_NOSSL',{'uri':CLIENT_LDAP_URI_NOSSL})
477                return {"status":True,"msg":"Open ports " + open_ports}
478        #def open_ports_slapd
479       
480        def reboot_slapd(self):
481               
482                proc = subprocess.Popen(['/etc/init.d/slapd','restart'],stdout=subprocess.PIPE,stdin=subprocess.PIPE).communicate()
483               
484                return {"status":True,"msg":"Server is reboot"}
485        #def reboot_slapd
486       
487        def generate_ssl_certificates(self):
488               
489                proc = subprocess.Popen(['/usr/sbin/n4d-ldap-generator-ssl'],stdout=subprocess.PIPE,stdin=subprocess.PIPE).communicate()
490               
491                return {"status":True,"msg":"Certificates ssl has been generated"}
492        #def generate_ssl_certificates
493       
494        def enable_folders(self):
495                shutil.copy('/usr/share/n4d/templates/folder/share','/var/lib/lliurex-folders/local/share')
496                shutil.copy('/usr/share/n4d/templates/folder/teachers_share','/var/lib/lliurex-folders/local/teachers_share')
497                shutil.copy('/usr/share/n4d/templates/folder/students','/var/lib/lliurex-folders/local/students')
498                shutil.copy('/usr/share/n4d/templates/folder/teachers','/var/lib/lliurex-folders/local/teachers')
499                shutil.copy('/usr/share/n4d/templates/folder/admins','/var/lib/lliurex-folders/local/admins')
500                shutil.copy('/usr/share/n4d/templates/folder/netadmin','/var/lib/lliurex-folders/local/netadmin')
501                return {"status":True,"msg":"Folders are enabled."}
502        #def enable_folders
503       
504        def disable_folders(self):
505                os.remove('/var/lib/lliurex-folders/local/share')
506                os.remove('/var/lib/lliurex-folders/local/teachers_share')
507                os.remove('/var/lib/lliurex-folders/local/students')
508                os.remove('/var/lib/lliurex-folders/local/teachers')
509                return {"status":True,"msg":"Folders are disabled."}
510        #def disable_folders
511       
512       
513        def set_replicate_interface(self, interface ):
514                objects['VariablesManager'].init_variable("INTERFACE_REPLICATION",{"INTERFACE_REPLICATION":interface})
515                return {"status":True,"msg":"Interface " + str(interface) + " is replication interface now"}
516        #def set_replicate_interface
517
518        @try_connect   
519        def set_serverid(self, id_server,ip=None):
520                list_ip = id_server
521                if ip != None:
522                        list_ip += " ldap://" + ip + "/"
523                remove_olcserver = [(ldap.MOD_DELETE,'olcServerID',None)]
524                modify_olcserver = [(ldap.MOD_ADD,'olcServerID',list_ip)]
525                objects['VariablesManager'].init_variable('LDAP_SID',{"SID":id_server})
526                try:
527                        self.connect_ldapi.modify_s('cn=config',remove_olcserver)
528                except:         
529                        pass
530                try:
531                        self.connect_ldapi.modify_s('cn=config',modify_olcserver)
532                except Exception as e:
533                        return {"status":False,"msg":str(e)}
534                return {"status": True, "msg":"This server now has ServerID " + str(id_server) + " on ldap"}
535               
536        #def set_serverid
537       
538        @try_connect   
539        def get_serverid(self):
540                try:
541                        result = self.connect_ldapi.search_s("cn=config",ldap.SCOPE_BASE)[0][1]['olcServerID']
542                except Exception as e:
543                        return {"status":False,"msg":"ServerID isn't defined"}
544                return {"status":True,"msg":result}
545               
546        #def get_serverid
547       
548        @try_connect   
549        def append_serverid(self, id_server, ip):
550                result = self.get_serverid()
551                if result['status']:
552                        #EXIST OTHER ID SERVER
553                        for i in result['msg']:
554                                if i.startswith(id_server+" ") or i == id_server:
555                                        return{"status":False,"msg":"This id has been registered"}
556                               
557                        if len(result['msg']) == 1:
558                                aux_ip = get_ip(objects['VariablesManager'].get_variable('INTERFACE_REPLICATION'))
559                                if aux_ip == None :
560                                        return {"status":False,"msg":"Replication interface has a problem with ip. Check it"}
561                                aux_sid = result['msg'][0].split(' ')[0]
562                                self.set_serverid(aux_sid,str(aux_ip))
563
564                list_ip = str(id_server) + " ldap://"+str(ip) + "/"
565                modify_olcserver = [(ldap.MOD_ADD,'olcServerID',list_ip)]
566
567                try:
568                        self.connect_ldapi.modify_s('cn=config',modify_olcserver)
569                except Exception as e:
570                        return {"status":False,"msg":str(e)}
571                return {"status":True,"msg":ip + " has been appended"}
572        #def append_serverid
573
574        @try_connect
575        def delete_serverid(self, ip):
576                result = self.get_serverid()
577                if result['status']:
578                        for i in result['msg']:
579                                if i.rstrip('/').endswith(ip):
580                                        result['msg'].remove(i)
581                        modify_olcserver = [(ldap.MOD_REPLACE,'olcServerID',result['msg'])]
582                else:
583                        return {"status":False,"msg":"server hasn't server ID key"}
584                try:
585                        self.connect_ldapi.modify_s('cn=config',modify_olcserver)
586                except Exception as e:
587                        return {"status":False,"msg":str(e)}
588                return {"status":True,"msg":"Server with ip " + ip + " has been delete"}
589        #def delete_server
590       
591        @try_connect
592        def set_serverid_batch(self, list_serverid):
593                result = self.get_serverid()
594                modify_olcserver = []
595                if result['status']:
596                        modify_olcserver.append((ldap.MOD_REPLACE,'olcServerID',list_serverid))
597                else:
598                        modify_olcserver.append((ldap.MOD_ADD,'olcServerID',list_serverid))
599                try:
600                        self.connect_ldapi.modify_s('cn=config',modify_olcserver)
601                except Exception as e:
602                        return {"status":False,"msg":str(e)}
603                return {"status":True,"msg":"OlcServerId is updated"}
604       
605
606
607        @try_connect
608        def enable_module(self, name):
609                try:
610                        self.connect_ldapi.modify_s('cn=module{0},cn=config',[(ldap.MOD_ADD,'olcModuleLoad',name)])
611                except Exception as e:
612                        return {'status':False,'msg':str(e)}
613                return {'status':True,'msg': 'module' + str(name) + ' has been enabled' }
614               
615        #def enable_module
616
617        def enable_replication_module(self):
618                result = self.enable_module('syncprov.la')
619                return result
620        #def enable_replication_module
621
622
623        @try_connect
624        def get_password_config(self):
625                try:
626                        password = self.connect_ldapi.search_s('olcDatabase={0}config,cn=config',ldap.SCOPE_BASE)[0][1]['olcRootPW'][0]
627                except Exception as e:
628                        return {"status":False,"msg":"Password is not defined"}
629                return {"status":True,"msg":password}
630        #def get_password_config
631       
632        @try_connect
633        def set_password_config(self, password):
634                try:
635                        if len(self.connect_ldapi.search_s('olcDatabase={0}config,cn=config',ldap.SCOPE_BASE,attrlist=['olcRootPW'])[0][1]) == 0:
636                                changes = [(ldap.MOD_ADD,'olcRootPW',password)]
637                        else:
638                                changes = [(ldap.MOD_REPLACE,'olcRootPW',password)]
639                        self.connect_ldapi.modify_s('olcDatabase={0}config,cn=config',changes)
640                except Exception as e:
641                        return {"status":False,"msg" : str(e)}
642                return {"status": True, "msg" : "Password is set"}
643        #def set_password_config
644       
645        @try_connect
646        def delete_password_config(self):
647                try:
648                        changes = [(ldap.MOD_DELETE,'olcRootPW')]
649                        password = self.connect_ldapi.modify_s('olcDatabase={0}config,cn=config',changes)
650                except Exception as e:
651                        return {"status":False,"msg":"Password is not defined"}
652                return {"status":True,"msg":"Removed password from database config"}
653        #def delete_password_config
654       
655
656        @try_connect
657        def enable_overlay_config(self):
658                x = {'objectClass': ['olcOverlayConfig', 'olcSyncProvConfig'], 'olcOverlay': 'syncprov'}
659                dn = 'olcDatabase={0}config,cn=config'
660                try:
661                        result = self.connect_ldapi.search_s(dn,ldap.SCOPE_ONELEVEL)
662                        for x in result:
663                                if 'syncprov' in x[0]:
664                                        return {"status":True,"msg":"Overlay has been enabled on the past"}
665                       
666                except ldap.NO_SUCH_OBJECT as e:
667                        pass
668                except Exception as e:
669                        return {"status":False,"msg":str(e)}
670
671                add_entry = ldap.modlist.addModlist(x)
672                self.connect_ldapi.add_s('olcOverlay=syncprov,' + dn,add_entry)
673
674                return {"status":True,"msg":"Overlay is enabled"}
675        #def enable_overlay_config
676       
677        @try_connect
678        def enable_overlay_data(self):
679                x = {'objectClass': ['olcOverlayConfig', 'olcSyncProvConfig'], 'olcOverlay': 'syncprov'}
680                dn = 'olcDatabase={1}hdb,cn=config'
681                try:
682                        result = self.connect_ldapi.search_s(dn,ldap.SCOPE_ONELEVEL)
683                        for x in result:
684                                if 'syncprov' in x[0]:
685                                        return {"status":True,"msg":"Overlay has been enabled on the past"}     
686                except ldap.NO_SUCH_OBJECT as e:
687                        pass
688                except Exception as e:
689                        return {"status":False,"msg":str(e)}
690
691                add_entry = ldap.modlist.addModlist(x)
692                self.connect_ldapi.add_s('olcOverlay=syncprov,' + dn,add_entry)
693                return {"status":True,"msg":"Overlay is enabled"}
694        #def enable_overlay_data
695       
696        @try_connect
697        def add_rid_config(self, rid, ip, password):
698                dn = 'olcDatabase={0}config,cn=config'
699                template = 'rid=%(rid)03d provider=ldap://%(ip)s/ binddn="cn=config" bindmethod=simple credentials=%(password)s searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 schemachecking=off tls_reqcert=never'
700                try:
701                        result = self.connect_ldapi.search_s('olcDatabase={0}config,cn=config',ldap.SCOPE_BASE)[0][1]
702                        changes = []
703                        if (not result.has_key('olcSyncrepl')):
704                                server_id = objects['VariablesManager'].get_variable('LDAP_SID')
705                                aux_ip = get_ip(objects['VariablesManager'].get_variable('INTERFACE_REPLICATION'))
706                                if aux_ip == None:
707                                        return {"status":False,"msg":"Replication interface has a problem with ip. Check it"}
708                                aux_result = self.get_password_config()
709                                if not aux_result['status']:
710                                        return {"status":False,"msg":"Error on password config"}
711                                changes.append((ldap.MOD_ADD,'olcSyncrepl',template%{'rid':int(server_id),'ip':aux_ip,'password':str(aux_result['msg'])}))
712                                changes.append((ldap.MOD_ADD,'olcMirrorMode','TRUE'))
713                               
714                        changes.insert(0,(ldap.MOD_ADD,'olcSyncrepl',template%{'rid':int(rid),'ip':str(ip),'password':str(password)}))
715                       
716                        try:
717                                self.connect_ldapi.modify_s(dn,changes)
718                        except Exception as e:
719                                return {"status":False,"msg":str(e)}
720
721                except Exception as e:
722                        return {"status":False,"msg":str(e)}
723                return {"status":True,"msg":"Server is join"}
724        #def add_rid_config
725
726        @try_connect
727        def remove_rid_config(self, ip):
728                pass
729        #def remove_rid_config
730       
731        @try_connect
732        def set_rid_config(self, list_rid):
733                dn = 'olcDatabase={0}config,cn=config'
734               
735                delete_chages = [(ldap.MOD_DELETE,'olcSyncrepl')]
736                new_changes = [(ldap.MOD_ADD,'olcSyncrepl',list_rid)]
737                try:
738                        self.connect_ldapi.modify_s(dn,delete_chages)
739                except Exception as e:
740                        pass
741                try:
742                        self.connect_ldapi.modify_s(dn,new_changes)
743                except Exception as e:
744                        return {"status":False,"msg":str(e)}
745                return {"status":True,"msg":"set news rids"}
746        #def set_rid_config
747       
748        @try_connect
749        def get_rid_config(self):
750                try:
751                        result = self.connect_ldapi.search_s('olcDatabase={0}config,cn=config',ldap.SCOPE_BASE)[0][1]['olcSyncrepl']
752                except Exception as e:
753                        return {"status":False,"msg":"ServerID isn't defined"}
754                return {"status":True,"msg":result}
755        #def get_rid_config
756       
757       
758        def backup_config(self, path):
759                os.system("slapcat -n 0 >> " + str(path))
760                prevmask = os.umask(0)
761                os.chmod(path,0600)
762                os.umask(prevmask)
763                return {"status":True,"msg":"Backup created on " + str(path)}
764        #def backup_config
765       
766        def restore_backup_config(self, path):
767                os.system("/etc/init.d/slapd stop")
768                os.system("rm -fr /etc/ldap/slapd.d/*")
769                os.system("slapadd -n 0 -l "+path+" -F /etc/ldap/slapd.d/")
770                os.system("chown -R openldap:openldap /etc/ldap/slapd.d/")
771                os.system("/etc/init.d/slapd start")
772                return {"status":True,"msg":"Config backup restored"}
773       
774       
775       
776        @try_connect
777        def add_rid_data(self, rid, ip, password, rootdn, basedn):
778                dn = 'olcDatabase={1}hdb,cn=config'
779                '''
780                        rid
781                        ip
782                        rootdn
783                        password
784                        basedn
785                '''
786                template = 'rid=%(rid)03d provider=ldap://%(ip)s/ binddn="%(rootdn)s" bindmethod=simple credentials=%(password)s searchbase="%(basedn)s" type=refreshOnly interval=00:00:00:10 retry="5 5 300 5" timeout=1 schemachecking=off tls_reqcert=never'
787                try:
788                        result = self.connect_ldapi.search_s(dn,ldap.SCOPE_BASE)[0][1]
789                        changes = []
790                       
791                        if (not result.has_key('olcSyncrepl')):
792                                aux_base_dn = objects['VariablesManager'].get_variable('LDAP_BASE_DN')
793                                if result.has_key('olcRootDN') and len(result['olcRootDN']) > 0 :
794                                        aux_rootdn = result['olcRootDN'][0]
795                                else:
796                                        return {"status":False,"msg":"Error on LDAP database. There isn't rootdn"}
797                               
798                                server_id = objects['VariablesManager'].get_variable('LDAP_SID')
799                                aux_ip = get_ip(objects['VariablesManager'].get_variable('INTERFACE_REPLICATION'))
800                                if aux_ip == None:
801                                        return {"status":False,"msg":"Replication interface has a problem with ip. Check it"}
802                                aux_file = open(self.LDAP_SECRET2,'r')
803                                aux_password = aux_file.readline().strip()
804                                aux_file.close()
805                                changes.append((ldap.MOD_ADD,'olcLimits','dn.exact="%s" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited'%str(aux_rootdn)))
806                                changes.append((ldap.MOD_ADD,'olcSyncrepl',template%{'rid':int(server_id),'ip':aux_ip,'password':str(aux_password),'rootdn':str(aux_rootdn),'basedn':str(aux_base_dn)}))
807                                changes.append((ldap.MOD_ADD,'olcDbIndex','entryUUID  eq'))
808                                changes.append((ldap.MOD_ADD,'olcDbIndex','entryCSN  eq'))
809                        else:
810                                changes.append((ldap.MOD_ADD,'olcSyncrepl',template%{'rid':int(rid),'ip':str(ip),'password':str(password),'rootdn':str(rootdn),'basedn':str(basedn)}))
811                                if not result.has_key('olcMirrorMode'):
812                                        changes.append((ldap.MOD_ADD,'olcMirrorMode','TRUE'))
813
814                        try:
815                                        self.connect_ldapi.modify_s(dn,changes)
816                        except Exception as e:
817                                        return {"status":False,"msg":str(e)}
818
819                except Exception as e:
820                        return {"status":False,"msg":str(e)}
821                return {"status":True,"msg":"Server is join"}
822        #def add_rid_data
823       
824        @try_connect
825        def remove_rid_data(self, ip):
826                pass
827        #def remove_rid_data
828       
829       
830        def block_replication(self):
831                template = 'iptables -A INPUT -p tcp --dport %(port)s -s %(ip)s -j ACCEPT'
832                negate = 'iptables -A INPUT -p tcp --dport %(port)s -j DROP'
833                ip = get_ip(objects['VariablesManager'].get_variable('INTERFACE_REPLICATION'))
834                iptables_rules = [template%{'ip':'127.0.0.1','port':'389'},template%{'ip':'127.0.0.1','port':'636'},template%{'port':'389','ip':str(ip)},template%{'port':'636','ip':str(ip)},negate%{'port':'389'},negate%{'port':'636'}]
835                for x in iptables_rules:
836                        os.system(x)
837                return {"status":True,"msg":"Replication is block"}
838        #def block_replication
839       
840        def unblock_replication(self):
841                p=subprocess.Popen(["iptables-save"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
842                output=p.communicate()[0].split("\n")
843                ret=[]
844                for item in output:
845                        if "--dport 389" in item or "--dport 636" in item:
846                                ret.append("iptables " + item.replace("-A","-D"))
847
848                for item in ret:
849                        os.system(item)
850                return {"status":True,"msg":"replication blockec is removed"}
851        #def unblock_replication
852       
853        @try_connect
854        def get_csn_config(self):
855                try:
856                        csn = self.connect_ldapi.search_s('cn=config',ldap.SCOPE_BASE,attrlist=['contextCSN'])
857                except Exception as e:
858                        return {"status":False,"msg":None}
859                return {"status":True,"msg":csn}
860        #def get_csn_config
861       
862        @try_connect
863        def get_csn_data(self):
864                aux_base_dn = objects['VariablesManager'].get_variable('LDAP_BASE_DN')
865                if aux_base_dn == None:
866                        return {"status":False,"msg":"LDAP_BASE_DN is not defined"}
867                try:
868                        csn = self.connect_ldapi.search_s(aux_base_dn,ldap.SCOPE_BASE,attrlist=['contextCSN'])[0][1]['contextCSN']
869                except Exception as e:
870                        return {"status":False,"msg":None}
871                return {"status":True,"msg":csn}
872        #def get_csn_data
873       
874       
875        def get_ldap_password(self):
876                password = None
877                if os.path.exists(self.LDAP_SECRET1):
878                        f=open(self.LDAP_SECRET1)
879                        lines=f.readlines()
880                        f.close()
881                        password=lines[0].replace("\n","")
882                elif os.path.exists(self.LDAP_SECRET2):
883                        f=open(self.LDAP_SECRET2)
884                        lines=f.readlines()
885                        f.close()
886                        password=lines[0].replace("\n","")
887                else:
888                        return {'status':False,'msg':'Password is not set'}
889                return {'status':True,'msg':password}
890        #def get_ldap_password
891       
892        def active_data_replication(self):
893                temp_dn = "".join(random.sample(string.letters,10))
894                base_dn = objects["VariablesManager"].get_variable("LDAP_BASE_DN")
895                if base_dn == None:
896                        return {"status":False,"msg":"LDAP_BASE_DN is not defined"}
897                aux_dic = {"ou="+temp_dn+","+base_dn: { "objectClass":["organizationalUnit"], "ou":temp_dn }}
898                self.insert_dictionary(aux_dic)
899                self.delete_dn(temp_dn)
900                return {"status":True,"msg":"Activated replication"}
901        #def active_data_replication
902
903        @try_connect
904        def enable_syncprov_checkpoint(self,num_changes,minutes):
905                dn = 'olcOverlay={0}syncprov,olcDatabase={1}hdb,cn=config'
906               
907                delete_chages = [(ldap.MOD_DELETE,'olcSpCheckpoint')]
908                new_changes = [(ldap.MOD_ADD,'olcSpCheckpoint',str(num_changes)+ " " + str(minutes))]
909                try:
910                        self.connect_ldapi.modify_s(dn,delete_chages)
911                except Exception as e:
912                        pass
913                try:
914                        self.connect_ldapi.modify_s(dn,new_changes)
915                except Exception as e:
916                        return {"status":False,"msg":str(e)}
917                return {"status":True,"msg":"set checkpoint"}
918        #def enable_syncprov_checkpoint
919
920        @try_connect
921        def add_rid_data_simple_sync(self, rid, ip, password, rootdn, basedn):
922                dn = 'olcDatabase={1}hdb,cn=config'
923                '''
924                        rid
925                        ip
926                        rootdn
927                        password
928                        basedn
929                '''
930                template = 'rid=%(rid)03d provider=ldap://%(ip)s/ binddn="%(rootdn)s" bindmethod=simple credentials=%(password)s searchbase="%(basedn)s" type=refreshAndPersist retry="60 +" schemachecking=off tls_reqcert=never'
931                try:
932                        changes = []
933                        changes.append((ldap.MOD_ADD,'olcSyncrepl',template%{'rid':int(rid),'ip':str(ip),'password':str(password),'rootdn':str(rootdn),'basedn':str(basedn)}))
934                        try:
935                                self.connect_ldapi.modify_s(dn,changes)
936                        except Exception as e:
937                                return {"status":False,"msg":str(e)}
938                except Exception as e:
939                        return {"status":False,"msg":str(e)}
940                return {"status":True,"msg":"Server is join"}
941        #def add_rid_data_simple_sync
942
943        @try_connect
944        def add_updateref_data(self,ip):
945                dn = 'olcDatabase={1}hdb,cn=config'
946                try:
947                        changes = []
948                        changes.append((ldap.MOD_ADD,'olcUpdateRef','ldaps://'+str(ip)))
949                        try:
950                                self.connect_ldapi.modify_s(dn,changes)
951                        except Exception as e:
952                                return {"status":False,"msg":str(e)}
953                except Exception as e:
954                        return {"status":False,"msg":str(e)}
955                return {"status":True,"msg":"Added updateRef to " + str(ip)}
956
957        def set_master_server_ip(self,ip):
958                objects['VariablesManager'].init_variable('MASTER_SERVER_IP',{'ip':ip})
959                return {"status":True,"msg":"Variable MASTER_SERVER_IP is set to " + str(ip)}
960        #def set_master_server_ip
961        '''
962        Internal methods
963        '''
964       
965        @staticmethod
966        def __beint__(integer):
967                """
968                        return integer from string as far as possible
969                        examples:
970                                54foo = 54
971                                foo54 = None
972                                54 = 54
973                """
974                ret = ""
975                for x in integer:
976                        try:
977                                int(x)
978                                ret += x
979                        except:
980                                break
981                return int(ret) if ret != "" else None
982        #def __beint__ 
983
984        @staticmethod
985        def __becmp__(x,y):
986                """
987                       
988                """
989                if (x == y):
990                        return 0
991                if (x is None ):
992                        return 1
993                if (y is None):
994                        return -1
995                if (int(x) < int(y) ):
996                        return -1
997                if (int(x) > int(y)):
998                        return 1
999        #def __becmp
1000       
1001        @staticmethod
1002        def __dncmp__(x,y):
1003                aux_x = x.split(',')
1004                aux_y = y.split(',')
1005                return cmp(len(aux_x),len(aux_y))
1006        #def __dncmp__
1007       
1008        def test_ldapi_connection(self):
1009                try:
1010                        self.connect_ldapi.search_s('cn=config',ldap.SCOPE_BASE)
1011                        return True
1012                except:
1013                        return False
1014        #def test_ldapi_connection
1015       
1016        def connection_ldapi(self):
1017                self.auth=ldap.sasl.sasl('','EXTERNAL')
1018                try:
1019                        self.connect_ldapi=ldap.initialize('ldapi:///',trace_level=0)
1020                        self.connect_ldapi.protocol_version=3
1021                        self.connect_ldapi.sasl_interactive_bind_s("",self.auth)
1022                        return True
1023                except:
1024                        self.connect_ldapi = None
1025                        return False
1026                       
1027        #def connection_ldapi
1028
1029        def test_ldap_connection(self):
1030                try:
1031                        self.connection_ldap.search_s('',ldap.SCOPE_BASE)
1032                        return True
1033                except:
1034                        return False
1035        #def test_ldap_connection
1036
1037        def connection_ldap(self):
1038                try:
1039                        self.connect_ldap=ldap.initialize('ldap://localhost:389',trace_level=0)
1040                        self.connect_ldap.protocol_version=3
1041                        if os.path.exists(self.LDAP_SECRET1):
1042                                f=open(self.LDAP_SECRET1)
1043                                lines=f.readlines()
1044                                f.close()
1045                                password=lines[0].replace("\n","")
1046                        elif os.path.exists(self.LDAP_SECRET2):
1047                                f=open(self.LDAP_SECRET2)
1048                                lines=f.readlines()
1049                                f.close()
1050                                password=lines[0].replace("\n","")
1051                        else:
1052                                self.connect_ldap = None
1053                                return False
1054                        environment_vars = objects["VariablesManager"].get_variable_list(['LDAP_BASE_DN'])
1055                        self.connect_ldap.bind_s("cn=admin,"+environment_vars['LDAP_BASE_DN'],password)
1056                        return True
1057                except Exception as e:
1058                        print "\n\nError" + str(e) + "\n\n"
1059                        self.connect_ldap = None
1060                        return False
1061
1062       
1063        def getsalt(self,chars = string.letters + string.digits,length=16):
1064                salt = ""
1065                for i in range(int(length)):
1066                        salt += random.choice(chars)
1067                return salt
1068        #def getsalt
1069
1070        def generate_random_ssha_password(self):
1071                password="".join(random.sample(string.letters+string.digits, 10))
1072                return self.generate_ssha_password(password),password
1073        #def generate_random_ssha_password
1074
1075        def generate_ssha_password(self,password):
1076                salt=self.getsalt()
1077                return "{SSHA}" + base64.encodestring(hashlib.sha1(str(password) + salt).digest() + salt)
1078        #def generate_ssha_password     
1079
1080
1081if __name__ == '__main__':
1082        a = Slapd()
Note: See TracBrowser for help on using the repository browser.