source: hwdetector/trunk/fuentes/hwdetector.install/hwdetector/modules/llxhelpers.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: 13.7 KB
Line 
1#!/usr/bin/env python
2import hwdetector.Detector as Detector
3import hwdetector.utils.log as log
4import re
5import urllib2 as urllib
6import os.path
7import grp,pwd
8import subprocess,time
9import base64,zlib
10
11log.debug("File "+__name__+" loaded")
12
13class LlxHelpers(Detector):
14    _PROVIDES = ['HELPER_EXECUTE','HELPER_UNCOMMENT',"HELPER_GET_FILE_FROM_NET",'HELPER_FILE_FIND_LINE','HELPER_DEMOTE','HELPER_SET_ROOT_IDS','HELPER_CHECK_ROOT','HELPER_WHO_I_AM','HELPER_USERS_LOGGED','ROOT_MODE','HELPER_COMPRESS_FILE','HELPER_LIST_FILES','HELPER_COMPACT_FILES']
15    _NEEDS = []
16
17    # def _close_stderr(self):
18    #     self.errfile=os.fdopen(2,'w',0)
19    #     sys.stderr.close()
20    #     sys.stderr = open(os.devnull, 'w')
21    #
22    #
23    # def _open_stderr(self):
24    #     sys.stderr.flush()
25    #     sys.stderr.close()
26    #     sys.stderr = self.errfile
27    #
28    # def ctl_stderr(self,*args,**kwargs):
29    #     keys=[k.lower() for k in kwargs.keys()]
30    #     if 'close' in keys:
31    #         self._close_stderr()
32    #     if 'open' in keys:
33    #         self._open_stderr()
34
35    def uncomment(self,*args,**kwargs):
36        r = ''
37        comments=kwargs.get('comments',['#'])
38        creg=[]
39        for c in comments:
40            creg.append(c+'.*')
41        creg='|'.join(creg)
42        try:
43            is_file = os.path.isfile(args[0])
44        except:
45            is_file = False
46        if is_file:
47            reg=re.compile(r'^(\s*|{})*$'.format(creg))
48            try:
49                with open(args[0],'r') as f:
50                    for line in f.readlines():
51                        m=re.match(reg,line)
52                        if not m:
53                            r += line
54            except:
55                log.warning('Trying to read unreadable file {}'.format(args[0]))
56                r += 'NOT_READABLE'
57
58        else:
59            if isinstance(args[0],list):
60                string = ''.join(str(args[0]))
61            else:
62                string=str(args[0])
63
64            reg=re.compile(r'^(\s*|#.*)*$')
65            for line in string.split("\n"):
66                m=re.match(reg,line)
67                if not m:
68                    r += line + "\n"
69        try:
70            r=r.decode('utf-8')
71        except UnicodeDecodeError:
72            r=r.encode('utf-8')
73        return r.strip()
74
75    def get_file_from_net(self,*args,**kwargs):
76        if not args[0]:
77            return None
78        if kwargs.get('proxy',None):
79        #if 'proxy' in kwargs and kwargs['proxy'] == True:
80            proxy = urllib.ProxyHandler() #use autodetected proxies
81            proxydata={}
82            if kwargs.get('proxy_http',None):
83                proxydata.setdefault('http',kwargs.get(kwargs.get('proxy_http')))
84            if kwargs.get('proxy_https',None):
85                proxydata.setdefault('https',kwargs.get(kwargs.get('proxy_https')))
86
87            if proxydata:
88                proxy = urllib.ProxyHandler(proxydata)
89
90            opener = urllib.build_opener(proxy)
91            urllib.install_opener(opener)
92
93        proto=args[0].split(':')
94        if proto[0]:
95            proto=proto[0].lower()
96        else:
97            return None
98        if 'http' != proto and 'https' != proto:
99            return None
100        try:
101            content = urllib.urlopen(args[0])
102            data = content.read()
103            try:
104                data=data.decode('utf-8')
105            except UnicodeDecodeError:
106                data=data.encode('utf-8')
107            return data
108        except Exception as e:
109            return None
110
111    def file_find_line(self, content, *args, **kwargs):
112
113        if not (isinstance(content,str) or isinstance(content,list) or isinstance(content,unicode)):
114            return None
115
116        is_file=os.path.isfile(content)
117
118        multimatch = isinstance(args[0],list)
119
120        if not multimatch:
121            keys = [k.strip() for k in args if k]
122        else:
123            keys = []
124            for k_item in args[0]:
125                if isinstance(k_item,list):
126                    keys.append([k.strip() for k in k_item if k])
127
128        if not is_file:
129            if not isinstance(content,list):
130                s = content.split("\n")
131            else:
132                s = content
133        else:
134            with open(content,'r') as f:
135                s=f.readlines()
136
137        if not multimatch:
138            r=re.compile('\s*'.join(keys),re.IGNORECASE | re.UNICODE)
139        else:
140            r=[]
141            for k in keys:
142                r.append(re.compile('\s*'.join(k),re.IGNORECASE | re.UNICODE))
143        i=0
144        output = []
145        for line in s:
146            if not multimatch:
147                m=re.findall(r,line)
148                if m:
149                    if kwargs.get('multiple_result',False):
150                        output.append(m)
151                    else:
152                        return m
153            else:
154                m=[ test for test in [ re.findall(regexp,line) for regexp in r ] if test ]
155                if m:
156                    i = i+1
157                    output.append(m[0])
158                if i == len(r):
159                    if kwargs.get('multiple_result',False):
160                        output.append(m[0])
161                    else:
162                        return output
163
164        return output
165
166    def demote(self,*args,**kwargs):
167        try:
168            info=pwd.getpwnam('nobody')
169            id=info.pw_uid
170            gid=info.pw_gid
171            os.setuid(id)
172            os.setgid(gid)
173        except Exception as e:
174            return False
175        return True
176    def set_root_ids(self,*args,**kwargs):
177        try:
178            os.seteuid(0)
179            os.setegid(0)
180        except Exception as e:
181            return False
182        return True
183    def check_root(self,*args,**kwargs):
184        if os.geteuid() == 0:
185            return True
186        else:
187            return False
188
189    def who_i_am(self,*args,**kwargs):
190        euid=os.geteuid()
191        user_info=pwd.getpwuid(euid)
192        user_name=user_info[0]
193        groups = [group[0] for group in grp.getgrall() if user_name in group[3]]
194        return {'id':euid,'user_info':user_info,'name':user_name,'groups':groups}
195
196    def users_logged(self,*args,**kwargs):
197        l=[]
198        regexp=re.compile(r'^(?P<username>\S+)\s+(?P<terminal>\S+)\s+\S+\s+\S+\s+(?P<display>\S+)?$')
199        for line in self.execute(run='who').split('\n'):
200            m = re.match(regexp,line)
201            if m:
202                d=m.groupdict()
203                if d['display'] != None and d['username'] not in l:
204                    l.append(d['username'])
205        return l
206
207    def execute(self,timeout=3.0,shell=False,*args,**kwargs):
208        params={}
209        if 'run' not in kwargs:
210            log.error('Execute called without \'run\' key parameter')
211            return None
212        else:
213            if not isinstance(kwargs['run'],list):
214                runlist=kwargs['run'].split(' ')
215            else:
216                runlist=kwargs['run']
217        timeout_remaning=float(timeout)
218        #Ready for python3
219        #params.setdefault('timeout',int(timeout))
220        #Python 2 code
221        delay=0.1
222        if 'stderr' in kwargs:
223            if kwargs['stderr'] == 'stdout':
224                params.setdefault('stderr',subprocess.STDOUT)
225            if kwargs['stderr'] == None or kwargs['stderr'] == 'no':
226                params.setdefault('stderr',open(os.devnull,'w'))
227            else:
228                params.setdefault('stderr',subprocess.PIPE)
229        else:
230            params.setdefault('stderr',subprocess.PIPE)
231        params.setdefault('stdout',subprocess.PIPE)
232        with_uncomment=False
233        if 'nocomment' in kwargs:
234            if kwargs['nocomment'] == True or kwargs['nocomment'] == 'yes':
235                with_uncomment=True
236
237        myinfo=pwd.getpwuid(os.geteuid())
238        user = myinfo.pw_name
239        group = grp.getgrgid(myinfo.pw_gid).gr_name
240        root_mode = False
241        if self.check_root():
242            if 'asroot' in kwargs:
243                if kwargs['asroot'] == True or kwargs['asroot'] == 'yes':
244                    root_mode=True
245            if not root_mode:
246                params.setdefault('preexec_fn', self.demote)
247                user = 'nobody'
248                group = 'nogroup'
249            else:
250                params.setdefault('preexec_fn', self.set_root_ids)
251
252        params.setdefault('shell',shell)
253        stdout=None
254        stderr=None
255        log.info('Executing command \'{}\' as {}:{}'.format(' '.join(runlist),user,group))
256        try:
257            start=time.time()
258            p=subprocess.Popen(runlist,**params)
259            ret=p.poll()
260            while ret is None and timeout_remaning > 0:
261                time.sleep(delay)
262                timeout_remaning -= delay
263                stdout,stderr = p.communicate()
264                ret = p.poll()
265            if stdout is None:
266                stdout,stderr = p.communicate()
267            if timeout_remaning <= 0:
268                raise Exception('timeout({}) exceded while executing {}'.format(timeout,kwargs['run']))
269            if ret != 0:
270                if stderr != '':
271                    stderr = 'stderr={}'.format(stderr)
272                log.warning('Execution with exit code {} (possible error) {}'.format(ret,stderr))
273        except Exception as e:
274            log.error('Error executing: {}'.format(e))
275            return None
276        if stdout != None:
277            if with_uncomment:
278                out=self.uncomment(stdout.strip())
279            else:
280                out=stdout.strip()
281            try:
282                out=out.decode('utf-8')
283            except UnicodeDecodeError:
284                out=out.encode('utf-8')
285            return out
286        else:
287            log.error("Execution of {} hasn't produced any result, returning None".format(kwargs['run']))
288            return None
289
290    def compress_file(self,*args,**kwargs):
291        file=kwargs.get('file')
292        string=kwargs.get('string')
293        if not ('file' in kwargs or  'string' in kwargs):
294            log.error('Compressing called without \'file\' or \'string\' keyparam')
295        if file:
296            if os.path.exists(file):
297                try:
298                    with open(file,'r') as f:
299                        try:
300                            content=f.read()
301                        except:
302                            return None
303                        try:
304                            return ('__gz__',base64.b64encode(zlib.compress(content.encode('utf-8').strip())))
305                        except:
306                            return ('__gz__',base64.b64encode(zlib.compress(content.strip())))
307                except Exception as e:
308                    log.warning('Fail compressing file {} : {}'.format(file,e))
309                    return None
310        if string:
311            try:
312                try:
313                    return ('__gz__',base64.b64encode(zlib.compress(string.encode('utf-8').strip())))
314                except:
315                    return ('__gz__',base64.b64encode(zlib.compress(string.strip())))
316            except Exception as e:
317                log.warning('Fail compressing string {} : {}'.format(string,e))
318                return None
319
320
321    def list_files(self,*args,**kwargs):
322        path=kwargs.get('path',None)
323        filter=kwargs.get('filter',None)
324        regexp=kwargs.get('regexp',None)
325
326        if not path:
327            log.error('List files called without \'path\' keyparameter')
328            return None
329
330        paths=[]
331        if isinstance(path,str) or isinstance(path,unicode):
332            paths.append(path)
333        elif isinstance(path,list):
334            for x in [ x for x in path if isinstance(x,str) or isinstance(x,unicode) ]:
335                paths.append(x)
336        else:
337            return None
338
339        paths=[x for x in paths if os.path.exists(x)]
340
341        if regexp:
342            if isinstance(regexp,re._pattern_type):
343                reg=regexp
344            else:
345                reg=re.compile(regexp,re.UNICODE)
346
347            filter=lambda x: [ f for f in x if re.match(reg,f)]
348
349        files=[]
350
351        for p in paths:
352            if os.path.isdir(p):
353                for root,dirnames,filenames in os.walk(p):
354                    if filter:
355                        for filename in filter(filenames):
356                            files.append(os.path.join(root,filename))
357                    else:
358                        for filename in filenames:
359                            files.append(os.path.join(root,filename))
360            else:
361                files.append(p)
362        return files
363
364    def compact_files(self,*args,**kwargs):
365        files=self.list_files(*args,**kwargs)
366        if not (files and isinstance(files,list)):
367            return None
368        content=''
369        for file in files:
370            try:
371                with open(file,'r') as f:
372                    content+=f.read()
373            except Exception as e:
374                pass
375
376        return self.uncomment(content)
377
378    def run(self,*args,**kwargs):
379        return {
380            'ROOT_MODE': self.check_root(),
381            'HELPER_UNCOMMENT':{'code':self.uncomment,'glob':globals()},
382            'HELPER_GET_FILE_FROM_NET': {'code': self.get_file_from_net, 'glob': globals()},
383            'HELPER_FILE_FIND_LINE':{'code': self.file_find_line, 'glob': globals()},
384            'HELPER_DEMOTE':{'code':self.demote,'glob':globals()},
385            'HELPER_SET_ROOT_IDS':{'code':self.set_root_ids,'glob':globals()},
386            'HELPER_CHECK_ROOT':{'code':self.check_root,'glob':globals()},
387            'HELPER_WHO_I_AM':{'code':self.who_i_am,'glob':globals()},
388            'HELPER_EXECUTE':{'code':self.execute,'glob':globals()},
389            'HELPER_USERS_LOGGED':{'code':self.users_logged,'glob':globals()},
390            'HELPER_COMPRESS_FILE':{'code':self.compress_file,'glob':globals()},
391            'HELPER_COMPACT_FILES':{'code':self.compact_files,'glob':globals()},
392            'HELPER_LIST_FILES':{'code':self.list_files,'glob':globals()}
393                }
Note: See TracBrowser for help on using the repository browser.