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

Last change on this file since 331 was 331, checked in by hectorgh, 5 years ago

supporting mdbconfig instead of hdbconfig. ldap has changed its default config

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