PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /opt/sharedrads/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //opt/sharedrads/cmspass.py |
#!/opt/imh-python/bin/python3 """Scans a cPanel account for WordPress and Joomla! configuration files, then uses whmapi1 to reset database passwords to match what was found in them. This script logs to /var/log/messages""" import subprocess import re import sys from argparse import ArgumentParser from pathlib import Path from typing import Union import rads import logging from logging.handlers import SysLogHandler from cpapis import whmapi1, CpAPIError WP_CONF = re.compile(r"DB_(USER|PASSWORD).*['\"](.+)['\"]") JM_CONF = re.compile(r"\b(user|password) = '(.+)'") def setup_logging() -> logging.Logger: logger = logging.getLogger('cmspass.py') logger.setLevel(logging.DEBUG) out_fmt = logging.Formatter(fmt='%(levelname)s: %(message)s') log_fmt = logging.Formatter(fmt='cmspass.py: %(levelname)s: %(message)s') stdout = logging.StreamHandler(stream=sys.stdout) stdout.setFormatter(out_fmt) stdout.setLevel(logging.DEBUG) logger.addHandler(stdout) syslog = SysLogHandler(address='/dev/log') syslog.setFormatter(log_fmt) syslog.setLevel(logging.WARNING) logger.addHandler(syslog) return logger def conf_parse( regex: re.Pattern, path: Path ) -> tuple[Union[str, None], Union[str, None]]: """Will parse db conf variables""" db_user, db_pass = None, None with open(path, encoding='utf-8') as file: for line in file: if match := regex.search(line): key, val = match.groups() key: str val: str if key.lower() == 'user': db_user = val elif key.lower() == 'password': db_pass = val return db_user, db_pass def set_pass(logger: logging.Logger, cpuser: str, db_user: str, db_pass: str): """Will pass the reset variables to the cPanel API""" if db_user is None or db_pass is None: return try: whmapi1( 'set_mysql_password', args={'cpuser': cpuser, 'user': db_user, 'password': db_pass}, check=True, ) except CpAPIError as exc: logger.error("Failed to reset password for %s: %s", db_user, exc) else: logger.warning("Reset password for %s", db_user) def parse_args() -> str: """Will parse input for user and ensure the user exists""" parser = ArgumentParser(description=__doc__) parser.add_argument('-u', '--user', required=True, help='cPanel username') user = parser.parse_args().user if not rads.cpuser_safe(user): sys.exit(f"{user} does not exist or is restricted") return user def find_files(homedir: str) -> list[Path]: """Find all config files""" # fmt: off cmd = [ 'find', homedir, '-not', '(', '-path', f"{homedir}/mail", '-prune', ')', '(', '-name', 'wp-config.php', '-o', '-name', 'configuration.php', ')', '-type', 'f', '-print0', ] # fmt: on ret = subprocess.run( cmd, stdout=subprocess.PIPE, encoding='utf-8', check=False ) return [Path(x) for x in ret.stdout.split('\0') if x] def conf_is_joomla(path: Path): if path.name != 'configuration.php': return False with open(path, encoding='utf-8') as conf: for line in conf: if 'class JConfig' in line: return True return False def main(): user = parse_args() logger = setup_logging() try: homedir = rads.get_homedir(user) except rads.CpuserError as exc: sys.exit(exc) for path in find_files(homedir): db_user, db_pass = None, None if path.name == 'wp-config.php': logger.debug('Scanning %s', path) db_user, db_pass = conf_parse(WP_CONF, path) elif conf_is_joomla(path): logger.debug('Scanning %s', path) db_user, db_pass = conf_parse(JM_CONF, path) if db_user and db_pass: set_pass(logger, user, db_user, db_pass) if __name__ == "__main__": main()