source: hwdetector/trunk/fuentes/hwdetector.install/hwdetector/modules/llxldap.py @ 6420

Last change on this file since 6420 was 6420, checked in by mabarracus, 2 years ago

Fix type checks with unicode vars

File size: 10.2 KB
Line 
1#!/usr/bin/env python
2import hwdetector.Detector as Detector
3import hwdetector.utils.log as log
4import re
5import base64
6import hashlib
7import os
8
9log.debug("File "+__name__+" loaded")
10
11class LlxLdap(Detector):
12    _NEEDS = ['HELPER_EXECUTE','HELPER_FILE_FIND_LINE','HELPER_UNCOMMENT','HELPER_CHECK_OPEN_PORT','LLIUREX_RELEASE','HELPER_CHECK_ROOT','NETINFO','N4D_VARS','HELPER_CHECK_NS','HELPER_COMPRESS_FILE']
13    _PROVIDES = ['SERVER_LDAP','LDAP_INFO','LDAP_MODE','LDAP_MASTER_IP','LOCAL_LDAP']
14
15    def check_files(self,*args,**kwargs):
16        release=args[0]
17        mode=args[1]
18        server=args[2]
19
20        if not server:
21            log.error('Unable to locate ldap server')
22
23        if mode and mode.lower() == 'independent':
24            servername = server
25        else:
26            servername = 'localhost'
27
28        output={}
29        content_ldap_conf=self.uncomment("/etc/ldap.conf")
30        ldap_conf_ok = self.file_find_line(content_ldap_conf,
31        [
32            ['^base','dc=ma5,dc=lliurex,dc=net'],
33            ['^uri','ldap://'+servername],
34            ['^nss_base_group','ou=Groups,dc=ma5,dc=lliurex,dc=net'],
35            ['^nss_map_attribute','gecos','description']
36        ])
37        content_etc_ldap_ldap_conf=self.uncomment("/etc/ldap/ldap.conf")
38        etc_ldap_ldap_conf_ok = self.file_find_line(content_etc_ldap_ldap_conf,
39        [
40            ['^BASE','dc=ma5,dc=lliurex,dc=net'],
41            ['^URI','ldaps://'+servername]
42        ])
43        if ldap_conf_ok:
44            output['etc_ldap_conf']={'syntax':'OK','content':content_ldap_conf}
45        else:
46            output['etc_ldap_conf'] = {'syntax': 'NOK', 'content': content_ldap_conf}
47
48        if etc_ldap_ldap_conf_ok:
49            output['etc_ldap_ldap_conf']={'syntax':'OK','content':content_etc_ldap_ldap_conf}
50        else:
51            output['etc_ldap_ldap_conf'] = {'syntax': 'NOK', 'content': content_etc_ldap_ldap_conf}
52
53        nsswitch_content = self.uncomment('/etc/nsswitch.conf')
54        nsswitch_ok = self.file_find_line(nsswitch_content,
55        [
56            ['passwd:','files','ldap'],
57            ['group:','files','ldap'],
58            ['shadow:','files','ldap']
59        ])
60        if nsswitch_ok:
61            output['nsswitch_conf']={'syntax':'OK','content':nsswitch_content}
62        else:
63            output['nsswitch_conf'] = {'syntax': 'NOK', 'content': nsswitch_content}
64        return output
65
66    def check_ports(self,*args,**kwargs):
67        ports=['389','636']
68        server=args[0]
69        #localldap=args[1]
70        # split uri
71        #server=re.findall(r'(?:[^/]+/+)?(.*)$',server)[0]
72        #if not localldap:
73        #    # is dnsname?
74        #    is_ip=re.findall(r'(\d+(?:\.\d+){3})',server)[0]
75        #    if is_ip:
76        #        server=is_ip[0]
77        out = {}
78        for p in ports:
79            out[p]=self.check_open_port(server,p)
80        try:
81            self.file_find_line(self.execute(run='netstat -nx'),'/var/run/slapd/ldapi')
82            out['LDAPI']=True
83        except Exception as e:
84            out['LDAPI']=False
85        return out
86
87    def parse_tree(self,*args,**kwargs):
88        if not (isinstance(args[0],str) or isinstance(args[0],unicode)):
89            return None
90        output = {}
91        lines = args[0].split("\n")
92
93        path = output
94        atrib=''
95        value=''
96        for line in lines:
97            if line=='':
98                path=output
99            else:
100                if line.startswith('dn: '):
101                    hierarchy=line[4:].split(',')
102                    hierarchy.reverse()
103                    for level in hierarchy:
104                        if level not in path:
105                            path[level]={}
106                        path = path[level]
107                elif line.startswith(' '):
108                    value=value+line[1:]
109                    path[atrib][-1]=value
110                else:
111                    parts=line.split(' ')
112                    atrib=parts[0][:-1]
113                    value=' '.join(parts[1:])
114                    if atrib in path:
115                        path[atrib].append(value)
116                    else:
117                        path.update({atrib:[value]})
118
119        output=self.make_alias(output)
120        return output
121
122    def make_alias(self,*args,**kwargs):
123        d=args[0]
124        if len(args) == 1:
125            out={}
126        else:
127            out = args[1]
128        for k in d.keys():
129            if isinstance(d[k],dict):
130                split = k.split('=')
131                if len(split) > 1:
132                    aliaslevel = split[1]
133                    out[aliaslevel] = self.make_alias(d[k])
134            else:
135                out.update({k:d[k]})
136        return out
137
138    def read_pass(self):
139        self.pwd=None
140        sfile='/etc/ldap.secret'
141        try:
142            if not os.path.exists(sfile):
143                sfile=None
144            else:
145                with open(sfile,'r') as f:
146                    self.pwd=f.read().strip()
147        except:
148            if sfile:
149                log.warning('Running as user, secret file verification is not possible')
150            pass
151
152    def checkpass(self,*args,**kwargs):
153        p=args[0]
154        if self.pwd:
155            hash_digest_with_salt=base64.b64decode(base64.b64decode(p)[6:]).strip()
156            salt=hash_digest_with_salt[hashlib.sha1().digest_size:]
157            compare=base64.b64encode("{SSHA}" + base64.encodestring(hashlib.sha1(str(self.pwd) + salt).digest() + salt))
158            return p == compare
159        return None
160
161    def get_ldap_config(self,*args,**kwargs):
162        release=str(args[0]).lower()
163        server=str(args[1])
164        root_mode=self.check_root()
165        kw={'stderr':None}
166
167        if root_mode:
168            kw.setdefault('asroot',True)
169        auth="-Y EXTERNAL"
170        uri="ldapi:///"
171
172        if release=='client' and self.pwd:
173            auth="-D cn=admin,dc=ma5,dc=lliurex,dc=net -w "+self.pwd
174            uri="ldaps://"+server+":636"
175
176        try:
177            db=self.execute(run='ldapsearch {} -H {} -LLL'.format(auth,uri),**kw)
178            tree_db=self.parse_tree(db)
179        except:
180            db=None
181            tree_db=None
182        try:
183            config=self.execute(run='ldapsearch {} -H {} -b cn=config -LLL'.format(auth,uri),**kw)
184            tree_config=self.parse_tree(config)
185        except:
186            config=None
187            tree_config=None
188
189        try:
190            tree_db['net']['lliurex']['ma5']['o']
191            init_done=True
192        except:
193            init_done=False
194
195        if tree_config:
196            good_pass=False
197            if tree_config['config']['{1}mdb']['olcRootPW:'] and 'cn=admin,dc=ma5,dc=lliurex,dc=net' in tree_config['config']['{1}mdb']['olcRootDN']:
198                good_pass=self.checkpass(tree_config['config']['{1}mdb']['olcRootPW:'][0])
199        else:
200            good_pass=None
201        return {'CONFIG':tree_config,'DB':tree_db,'RAW_CONFIG':self.compress_file(string=config),'RAW_DB':self.compress_file(string=db),'INITIALIZED':init_done,'SECRET_STATUS':good_pass}
202
203    def run(self,*args,**kwargs):
204        out = {'LDAP_MASTER_IP':None}
205        output = {}
206        release=kwargs['LLIUREX_RELEASE']
207        vars=kwargs['N4D_VARS']
208        mapping={'CLIENT_LDAP_URI':'SERVER_LDAP'}
209        server=None
210        localldap=None
211
212        # Guess server ldap uri
213        for search_var in mapping:
214            if search_var in vars and 'value' in vars[search_var]:
215                out.update({mapping[search_var]:vars[search_var]['value']})
216                server=vars[search_var]['value']
217                out.setdefault('LOCAL_LDAP',True)
218                localldap=True
219        if not server:
220            ip_server=self.check_ns('server')
221            try:
222                ip_server2=kwargs['NETINFO']['gw']['via']
223            except:
224                ip_server2=None
225
226            if not ip_server:
227                log.error("'server' not resolvable")
228                if ip_server2:
229                    server=ip_server2
230                else:
231                    log.error('not detected any gateway')
232            else:
233                server=ip_server
234                if ip_server != ip_server2:
235                    log.warning("'server' is not my gateway")
236            if server:
237                out.update({'SERVER_LDAP':server})
238                out.update({'LOCAL_LDAP':False})
239                localldap=False
240            else:
241                out.update({'SERVER_LDAP':None})
242                out.update({'LOCAL_LDAP':None})
243                localldap=None
244
245        self.read_pass()
246
247        output['PORTS'] = self.check_ports(server,localldap)
248        mode=None
249
250        if output['PORTS']['636']:
251            output['CONFIG']=self.get_ldap_config(release,server)
252            mode='UNKNOWN'
253            try:
254                test=output['CONFIG']['INITIALIZED']
255            except:
256                mode='UNNINITIALIZED'
257            try:
258                test=output['CONFIG']['CONFIG']['config']['{1}mdb']['olcSyncrepl']
259                test=output['CONFIG']['CONFIG']['config']['{1}mdb']['olcUpdateRef']
260                mode='SLAVE'
261                if output['CONFIG']['CONFIG']['config']['{1}mdb']['olcSyncrepl'][0]:
262                    m=re.search(r'provider=ldapi?://(?P<LDAP_MASTER_IP>\d+\.\d+\.\d+\.\d+)',output['CONFIG']['CONFIG']['config']['{1}mdb']['olcSyncrepl'][0])
263                    if m:
264                        out.update(m.groupdict())
265            except:# indep or (master/slave(running without permissions))
266                mode='INDEPENDENT'
267                netinfo=kwargs['NETINFO']
268                if netinfo:
269                    aliased_interfaces = [ k for k in netinfo if isinstance(netinfo[k],dict) and 'nalias' in netinfo[k] and netinfo[k]['nalias'] > 0 ]
270                    for i in aliased_interfaces:
271                        for n in range(netinfo[i]['nalias']):
272                            if 'alias'+str(n+1)+'_ifaddr' in netinfo[i]:
273                                ip_alias=netinfo[i]['alias'+str(n+1)+'_ifaddr'].split('.')[3].split('/')[0]
274                                if ip_alias=='1':
275                                    mode='SLAVE'
276                                elif ip_alias=='254':
277                                    mode='MASTER'
278
279        output['FILES'] = self.check_files(release,mode,server)
280        out.update( {'LDAP_INFO':output,'LDAP_MODE':mode})
281
282        return out
Note: See TracBrowser for help on using the repository browser.