#!/opt/imh-python/bin/python3
from rads.color import red, green
# Set the lock path to /tmp as a placeholder
lock_file = Path("/tmp/modsec_disable.lock")
platformI = Path("/etc/ansible/wordpress-ultrastack")
# Ensure that only one instance of the script runs at a time.
print(red("Another instance of the script is currently running. Exiting."))
lock_file.touch() # Create a lock file to indicate the script is running
# Release the lock after the script has completed.
lock_file.unlink(missing_ok=True)
nginx_dir = Path("/var/log/nginx/")
return nginx_dir.exists()
def get_apache_version():
result = subprocess.run(["apachectl", "-v"], capture_output=True, text=True, check=True)
except FileNotFoundError:
print(red("apachectl not found. Please ensure Apache is installed."))
except subprocess.CalledProcessError:
print(red("Failed to get Apache version."))
if "Server version" in result.stdout:
version_line = result.stdout.split('\n')[0]
version = version_line.split()[2]
return version.split('/')[1]
print(red("Unable to parse Apache version."))
# Update modsec.conf file based on provided arguments.
def update_modsec_configuration(modsec_file, rule_ids=None, disable_all=False, reset=False, remove_rule_id=None):
modsec_file.parent.mkdir(parents=True, exist_ok=True) # Ensure the directory exists
# Ensure the modsec.conf file exists before modifying it
if not modsec_file.exists() or reset:
modsec_file.write_text("") # Create or reset the file if necessary
modsec_file.write_text("SecRuleEngine Off\n")
disable_rule(modsec_file, rule_id)
for rule_id in remove_rule_id:
remove_rule(modsec_file, rule_id)
# Add rules to modsec.conf, checks if the rule exists and skips it if it does
def disable_rule(modsec_file, rule_id):
rule_text = f"SecRuleRemoveById {rule_id}"
with modsec_file.open("r+") as file:
if rule_text in contents:
print(red(f"Rule {rule_id} already disabled, not adding."))
with modsec_file.open("a") as file:
file.write(f"{rule_text}\n")
print(green(f"Rule {rule_id} added to file: {modsec_file}"))
# Remove a rule from the modsec file.
def remove_rule(modsec_file, rule_id):
rule_text = f"SecRuleRemoveById {rule_id}"
with modsec_file.open("r+") as file:
contents = file.readlines()
if rule_text not in line:
print(green(f"Rule {rule_id} removed from file: {modsec_file}"))
# Remove all SecRuleRemoveById and SecRuleEngine entries from the modsec file.
def reset_modsec_configuration(modsec_file):
with modsec_file.open("r+") as file:
contents = file.readlines()
if not (line.startswith("SecRuleRemoveById") or line.startswith("SecRuleEngine Off")):
print(green(f"All SecRuleRemoveById and SecRuleEngine entries removed from file: {modsec_file}"))
# Rebuild and restart Apache.
def cpanel_restart_apache():
subprocess.run(["/scripts/rebuildhttpdconf"])
subprocess.run(["/sbin/apachectl", "graceful"])
print(green("Apache configuration rebuilt and service restarted gracefully."))
def platformI_restart_apache():
subprocess.run(["apachectl", "-t"])
except subprocess.CalledProcessError:
print(red("Syntax failed apache check"))
subprocess.run(["systemctl", "restart", "httpd"])
print(green("Apache restarted correctly."))
except subprocess.CalledProcessError:
print(red("Apache failed to restart"))
# Run ngxconf if Nginx exists
def cpanel_run_ngxconf(user):
subprocess.run(["ngxconf", "-u", user, "-rd"])
# Function to handle platformI check and set the modsec file path
def platformI_modsec(args):
modsec_file_path = Path("/etc/httpd/modsecurity.d/activated_rules/z-mycustom.conf")
update_modsec_configuration(
modsec_file=modsec_file_path,
rule_ids=args.rule if args.rule else None,
reset_modsec_configuration(modsec_file_path)
platformI_restart_apache()
# Cpanel function that sets the modsec.conf file based on the flags/args passed to the script
print(red("The --user (-u) flag is required for CPanel operations."))
apache_version = get_apache_version()
if apache_version.startswith("2.4"):
std_apache_dir = Path("/usr/local/apache/conf/userdata/std/2_4")
ssl_apache_dir = Path("/usr/local/apache/conf/userdata/ssl/2_4")
elif apache_version.startswith("2."):
std_apache_dir = Path("/usr/local/apache/conf/userdata/std/2")
ssl_apache_dir = Path("/usr/local/apache/conf/userdata/ssl/2")
print(red(f"Unsupported Apache version {apache_version}."))
# Determine the correct modsec_file path based on the presence of the domain flag
modsec_file_std = std_apache_dir / args.user / args.domain / "modsec.conf"
modsec_file_ssl = ssl_apache_dir / args.user / args.domain / "modsec.conf"
modsec_file_std = std_apache_dir / args.user / "modsec.conf"
modsec_file_ssl = ssl_apache_dir / args.user / "modsec.conf"
# Ensure the directory and files exist
modsec_file_std.parent.mkdir(parents=True, exist_ok=True)
modsec_file_ssl.parent.mkdir(parents=True, exist_ok=True)
modsec_file_std.touch(exist_ok=True)
modsec_file_ssl.touch(exist_ok=True)
for rule_id in args.rule:
disable_rule(modsec_file_std, rule_id)
disable_rule(modsec_file_ssl, rule_id)
for rule_id in args.drop:
remove_rule(modsec_file_std, rule_id)
remove_rule(modsec_file_ssl, rule_id)
reset_modsec_configuration(modsec_file_std)
reset_modsec_configuration(modsec_file_ssl)
reset_modsec_configuration(std_apache_dir / args.user / "modsec.conf")
reset_modsec_configuration(ssl_apache_dir / args.user / "modsec.conf")
disable_all_rules(modsec_file_std)
disable_all_rules(modsec_file_ssl)
print(green("Nginx detected."))
cpanel_run_ngxconf(args.user)
# Function to disable all rules in modsec.conf
def disable_all_rules(modsec_file):
with modsec_file.open("a") as file:
file.write("SecRuleEngine Off\n")
print(green(f"All rules disabled in file: {modsec_file}"))
# Main function to parse arguments and run needed functions based on server type
get_lock() # Get the lock before proceeding
parser = argparse.ArgumentParser(description="Disable modsec rules for Cpanel or PlatformI users and domains.")
parser.add_argument("-r", "--rule", type=int, nargs='+', help="Specific rule IDs to disable")
parser.add_argument("-o", "--off", action="store_true", help="Disable all rules")
parser.add_argument("-R", "--reset", action="store_true", help="Reset the modsec configuration")
parser.add_argument("-D", "--drop", nargs='+', type=int, help="Drop/Remove a specific rule ID from the modsec configuration")
parser.add_argument("-u", "--user", type=str, required=True, help="CPanel user this is for")
parser.add_argument("-d", "--domain", type=str, help="The domain to modify rules for")
parser.add_argument("-r", "--rule", type=int, nargs='+', help="Specific rule IDs to disable")
parser.add_argument("-o", "--off", action="store_true", help="Disable all rules for the domain")
parser.add_argument("-R", "--reset", action="store_true", help="Reset the modsec configuration")
parser.add_argument("-a", "--all", action="store_true", help="Apply changes to all domains for the user")
parser.add_argument("-D", "--drop", nargs='+', type=int, help="Drop/Remove a specific rule ID from the modsec configuration")
args = parser.parse_args()
release_lock() # Release the lock after the script completes
if __name__ == "__main__":