master
py 89 lines 3.19 KB
Raw
1 # -*- coding: utf-8 -*-
2 # Description:
3 # SPDX-License-Identifier: GPL-3.0-or-later
4
5 import os
6
7 from subprocess import Popen, PIPE
8
9 from bases.FrameworkServices.SimpleService import SimpleService
10 from bases.collection import find_binary
11
12
13 class ExecutableService(SimpleService):
14 def __init__(self, configuration=None, name=None):
15 SimpleService.__init__(self, configuration=configuration, name=name)
16 self.command = None
17
18 def _get_raw_data(self, stderr=False, command=None):
19 """
20 Get raw data from executed command
21 :return: <list>
22 """
23 command = command or self.command
24 self.debug("Executing command '{0}'".format(' '.join(command)))
25 try:
26 p = Popen(command, stdout=PIPE, stderr=PIPE)
27 except Exception as error:
28 self.error('Executing command {0} resulted in error: {1}'.format(command, error))
29 return None
30
31 data = list()
32 std = p.stderr if stderr else p.stdout
33 for line in std:
34 try:
35 data.append(line.decode('utf-8'))
36 except (TypeError, UnicodeDecodeError):
37 continue
38
39 return data
40
41 def check(self):
42 """
43 Parse basic configuration, check if command is whitelisted and is returning values
44 :return: <boolean>
45 """
46 # Preference: 1. "command" from configuration file 2. "command" from plugin (if specified)
47 if 'command' in self.configuration:
48 self.command = self.configuration['command']
49
50 # "command" must be: 1.not None 2. type <str>
51 if not (self.command and isinstance(self.command, str)):
52 self.error('Command is not defined or command type is not <str>')
53 return False
54
55 # Split "command" into: 1. command <str> 2. options <list>
56 command, opts = self.command.split()[0], self.command.split()[1:]
57
58 # Check for "bad" symbols in options. No pipes, redirects etc.
59 opts_list = ['&', '|', ';', '>', '<']
60 bad_opts = set(''.join(opts)) & set(opts_list)
61 if bad_opts:
62 self.error("Bad command argument(s): {opts}".format(opts=bad_opts))
63 return False
64
65 # Find absolute path ('echo' => '/bin/echo')
66 if '/' not in command:
67 command = find_binary(command)
68 if not command:
69 self.error('Can\'t locate "{command}" binary'.format(command=self.command))
70 return False
71 # Check if binary exist and executable
72 else:
73 if not os.access(command, os.X_OK):
74 self.error('"{binary}" is not executable'.format(binary=command))
75 return False
76
77 self.command = [command] + opts if opts else [command]
78
79 try:
80 data = self._get_data()
81 except Exception as error:
82 self.error('_get_data() failed. Command: {command}. Error: {error}'.format(command=self.command,
83 error=error))
84 return False
85
86 if isinstance(data, dict) and data:
87 return True
88 self.error('Command "{command}" returned no data'.format(command=self.command))
89 return False