### Copyright 1999-2014. Parallels IP Holdings GmbH. All Rights Reserved.

import urllib2, tempfile, subprocess, sys, os, shutil, StringIO
import os.path
from plesk_atomic import create_include_conf, pack_archive, comment_plesk_managed_directives, TORTIX_WAF_FILENAME
from contextlib import closing

aum_plesk_installer_name = "aum-plesk-installer"
aum_plesk_installer_url = "http://www.atomicorp.com/installers/" + aum_plesk_installer_name
aum_plesk_installer_signature_url = aum_plesk_installer_url + ".asc"
bin_aum = "/var/asl/bin/aum"
asl_config = "/etc/asl/config"
asl_license = "/etc/asl/license.key"
unpaid_asl_license = "/var/lib/plesk/modsec/tortix-unpaid-license.key"
atomicorp_gpg_public_key_path = "/var/lib/plesk/modsec/atomicorp.gpg.key"
gpghomedir = "/var/lib/plesk/modsec/.gnupg"
yum_conf_path = "/etc/yum.conf"
yum_conf_backup = yum_conf_path + ".saved_by_plesk_modsecurity"

aum_exit_no_error = 0
aum_exit_no_args = 1
aum_exit_handled = 2
aum_exit_fatal = 3

atomic_mod_security_conf = "/etc/httpd/conf.d/00_mod_security.conf"

def check_asl_license():
    if os.path.isfile(asl_license):
        return
    if not os.path.isdir("/etc/asl"):
        os.makedirs("/etc/asl", 0755)
    shutil.copyfile(unpaid_asl_license, asl_license)

def verify_gpg_signature(path, signature_url, public_key):
    signature_path = path + ".asc"
    with open(signature_path, "w") as fout:
        with closing(urllib2.urlopen(signature_url)) as fin:
            for line in fin:
                fout.write(line)
    subprocess.check_call(["gpg", "--homedir", gpghomedir, "--import", public_key])
    subprocess.check_call(["gpg", "--homedir", gpghomedir, "--verify", signature_path])

def run_aum_plesk_installer():
    try:
        installer_dir = tempfile.mkdtemp()
        installer_path = os.path.join(installer_dir, aum_plesk_installer_name)
        with open(installer_path, "w") as fout:
            with closing(urllib2.urlopen(aum_plesk_installer_url)) as fin:
                for line in fin:
                    fout.write(line)
        verify_gpg_signature(installer_path, aum_plesk_installer_signature_url, atomicorp_gpg_public_key_path)
        subprocess.check_call("/bin/bash < %s" % installer_path, shell=True)
    finally:
        shutil.rmtree(installer_dir, ignore_errors=True)

def yum_hold_modsecurity_package():
    modsec_package = "mod_security"
    if not os.path.isfile(yum_conf_path):
        return
    shutil.copyfile(yum_conf_path, yum_conf_backup)
    with open(yum_conf_path, "a") as f:
        f.write("\n\n[main]\nexclude=%s\n" % modsec_package)

def yum_unhold_modsecurity_package():
    if os.path.isfile(yum_conf_backup):
        shutil.move(yum_conf_backup, yum_conf_path)

def fix_asl_config(configs_dir):
    subprocess.check_call(["sed", "-i",
        "-e", "s#^MODSEC_RULES_PATH\s*=.*#MODSEC_RULES_PATH=\"%s\"#g" % configs_dir,
        "-e", "s#^RESTART_APACHE\s*=.*#RESTART_APACHE=\"no\"#g",
        "-e", "s#^AUTOMATIC_UPDATES\s*=.*#AUTOMATIC_UPDATES=\"no\"#g",
        asl_config])

def prepare_ruleset_layout(base_dir):
    modsec_d = os.path.join(base_dir, "modsec")
    if not os.path.isdir(modsec_d):
        os.makedirs(modsec_d)
    open(os.path.join(base_dir, "plesk_init.conf"), "w").close() # file for aum not to create 00_modsecurity.conf
    create_include_conf(os.path.join(base_dir, "plesk_init.conf.tpl"))

def run_aum():
    p = subprocess.Popen([bin_aum, "-uf"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (out, err) = p.communicate()
    if p.returncode == aum_exit_no_error:
        return
    # handle errors
    if p.returncode == aum_exit_handled:
        sys.stderr.write("Non-fatal error during aum execution.\nstdout: %s\nstderr: %s\nContinue execution." % (out, err))
    else:
        raise Exception("aum failed with exitcode %d.\nstdout: %s\nstderr: %s" % (p.returncode, out, err))

def remove_00_mod_security_conf():
    try:
        os.unlink(atomic_mod_security_conf)
    except OSError:
        pass

def main():
    try:
        target_archive_path = sys.argv[1]
        ruleset_dir = sys.argv[2]

        yum_hold_modsecurity_package() # tempfix for PPP-11007
        check_asl_license()
        run_aum_plesk_installer()
        prepare_ruleset_layout(ruleset_dir)
        fix_asl_config(os.path.join(ruleset_dir, "modsec"))
        run_aum()
        comment_plesk_managed_directives(os.path.join(ruleset_dir, "modsec", TORTIX_WAF_FILENAME))

        remove_00_mod_security_conf()
    except Exception as ex:
        sys.stderr.write("%s\n" % ex)
        sys.exit(1)
    finally:
        yum_unhold_modsecurity_package() # tempfix for PPP-11007

if __name__ == "__main__":
    main()

# vim: ts=4 sts=4 sw=4 et :
