Пример #1
0
 def make(self, log):
     output_dir = settings.get('install_path') + 'etc/modsec/'
     output_file = output_dir + 'rules.conf'
     # if os.path.exists(output_dir):
     #     shutil.rmtree(output_dir)
     filelist = glob.glob(os.path.join(output_dir, "*.data"))
     filelist.extend(glob.glob(os.path.join(output_dir, "*.mapping")))
     filelist.extend(glob.glob(os.path.join(output_dir, "*.conf")))
     for f in filelist:
         os.remove(f)
     if not os.path.exists(output_dir):
         os.makedirs(output_dir)
     with open(output_file, 'w+') as output:
         with open(self.build_dir + 'ModSecurity/modsecurity.conf-recommended') as base_config:
             for line in base_config:
                 if line.startswith('SecRuleEngine '):
                     output.write('SecRuleEngine On\n')
                 elif line.startswith('SecAuditLog '):
                     output.write('SecAuditLog ' + settings.get('install_path') + 'var/log/modsec_audit.log\n')
                 else:
                     output.write(line)
         for builder in get_enabled_ruleset_builders():
             input_file = builder.rule_output_file()
             input_dir = builder.rule_output_dir()
             with open(input_file) as input:
                 for line in input:
                     output.write(line)
             for data_file in glob.glob(input_dir + '*.data'):
                 shutil.copy(data_file, output_dir)
     source_map = self.build_dir + 'ModSecurity/unicode.mapping'
     target_map = output_dir + 'unicode.mapping'
     shutil.copy(source_map, target_map)
     return 0 # 0 = successful bash command
Пример #2
0
 def get_config_arg_file(self):
     """
     Returns the name of the file that lists arguments that are passed to
     the configure command. When overridden, this method can return an array
     of filenames instead.
     """
     return settings.get('install_path') + 'etc/build-config/' + self.slug
Пример #3
0
def write_primary_logrotate():
    """
    Write out a configuration file for logrotated to rotate the global php log
    files. Also add an include directive that will include all website
    logrotated files.

    Args:
        domain - The domain name
    """
    install_path = settings.get('install_path')
    filename = primary_logrotate_file()
    version_list = get_versions()
    if len(version_list) == 0:
        if os.path.exists(filename):
            os.remove(filename)
    else:
        with open(filename, 'w+') as output:
            output.write('include ' + install_path +
                         'etc/logrotate.d/php-sites/*\n\n')
            for version in version_list:
                output.write(
                    '/opt/php-' + version + '/var/log/*.log {\n\
  weekly\n\
  rotate 52\n\
  dateext\n\
  compress\n\
  copytruncate\n\
  missingok\n\
  postrotate\n\
    /bin/kill -USR1 `cat /opt/php-' + version +
                    '/var/run/php-fpm.pid 2>/dev/null` 2>/dev/null || true\n\
  endscript\n\
}\n\n')
Пример #4
0
def list_frozen():
    frozen_list = []
    freeze_file = settings.get('install_path') + 'etc/build-freeze'
    with open(freeze_file) as frozen:
        for line in frozen:
            frozen_list.append(line.strip())
    return frozen_list
Пример #5
0
def unfreeze(slug):
    """
    Allow a builder to update it's source code to a newer version. This
    will not start a build.
    """
    freeze_file = settings.get('install_path') + 'etc/build-freeze'
    return file_filter.RemoveExact(freeze_file, slug).run()
Пример #6
0
def freeze(slug):
    """
    Prevent a builder from updating it's source code to a newer version.
    The software will still be re-built if it's dependants are upated.
    """
    freeze_file = settings.get('install_path') + 'etc/build-freeze'
    return file_filter.AppendUnique(freeze_file, slug).run()
Пример #7
0
def create_one_time_login(domain):
    """
    Create a PHP file to give a one-time login into a WordPress site without a
    password. There is no safty measure to remove this link if it is not used.

    Args:
        domain - The domain that needs a one-time login
    """
    sys_user = nginx.user_from_domain(domain)
    passcode = input_util.random_string(40, False)
    passname = input_util.random_string(40, False)
    docroot = nginx.docroot_from_domain(domain)
    target_file = docroot + 'wp-admin/wp-autologin-' + passname + '.php'
    site_url = get_site_url(sys_user, docroot)

    # Set environment
    whoami = os.geteuid()
    os.seteuid(getpwnam(sys_user).pw_uid)

    with open(settings.get('install_path') + 'etc/wp-autologin.php',
              'r') as template:
        with open(target_file, 'w') as php_file:
            for line in template:
                line = line.replace('PASSWORDD', passcode, 10000)
                php_file.write(line)

    # Reset environment
    os.seteuid(whoami)
    print('Go to: ' + site_url + 'wp-admin/wp-autologin-' + passname +
          '.php?pass=' + passcode)
Пример #8
0
def create_and_install_dkim(domain):
    """
    Create a new DKIM key pair and apply them to the DNS and mail system
    configuration for a domain.

    Args:
        domain - The domain to update with a new DKIM key pair
    """
    if domain and not os.path.exists(bind.zone_folder + domain + '.db'):
        print('No zone file for ' + domain + ' found.')
        domain = False
    if not domain:
        domain = bind.select_main_domain('Select site to add DKIM to: ')[:-3]
    dkim_folder = settings.get('dkim_folder')
    if not os.path.exists(dkim_folder + domain + '.pub'):
        if not os.path.exists(dkim_folder):
            os.makedirs(dkim_folder)
        make_dkim_pair(domain)
    dkim = make_dkim_dns_value(domain)
    print('TXT Encoded DKIM: ' + dkim)

    DkimZoneUpdater(domain, dkim).run()
    bind.increment_soa(domain)

    print('Reloading nameserver to apply changes...')
    bind.reload()
    print('Done.')
Пример #9
0
def logrotate_file(domain):
    """
    Get the logrotate configuration filename associated with a domain.

    Args:
        domain - The domain name
    """
    return settings.get('install_path') + 'etc/logrotate.d/php-sites/' + domain
Пример #10
0
def template_path(name):
    """
    Get the full path for a given nginx vhost template name.

    Args:
        name - The name (slug) of the template
    """
    return settings.get('install_path') + 'etc/nginx-templates/' + name
Пример #11
0
 def populate_config_args(self, log, command=False):
     if command == False:
         command = ['./configure']
     command.append('--prefix=/opt/php-' + self.versions['sub'])
     command.append('--with-mysql-sock=' + settings.get('mysql_socket'))
     for pecl_builder in get_registered_pecl_builders():
         command.append(pecl_builder.get_php_build_arg())
     return super().populate_config_args(log, command)
Пример #12
0
 def log_name(self):
     if not self.source_version:
         self.source_version = self.get_updated_version()
     name = settings.get('install_path') + 'var/log/build/' + self.slug
     if self.source_version and len(self.source_version) > 0:
         name += '-' + self.source_version
     name += '.log'
     return name
Пример #13
0
def get_updated_versions(force_refresh=False):
    """
    Get the full version numbers of versions avaliable at php.net.

    Args:
        force_refresh - (optional) When set to True, do not use cached values
    """
    vers = []
    cache_dir = settings.get('install_path') + 'var/cache/'
    cache_file = cache_dir + 'php-versions'
    use_cache = force_refresh == False

    if os.path.exists(cache_file):
        max_age = settings.get_num('build_cache_age')
        mod_time = os.stat(cache_file).st_mtime
        age = time.time() - mod_time
        if age > max_age:
            use_cache = False
    else:
        if not os.path.exists(cache_dir):
            os.makedirs(cache_dir)
        use_cache = False

    if use_cache:
        return file_filter.get_trimmed_file_as_array(cache_file)
    else:
        request = requests.get('https://www.php.net/downloads.php')
        regex = re.compile(r'.*/distributions/php-([0-9\.]*)\.tar\.bz2.*')
        for line in request.text.splitlines():
            match = regex.match(line)
            if match == None:
                continue
            match = match.group(1)
            if len(match) > 0:
                vers.append(match)
        if settings.get_bool('enable_php_legacy_versions'):
            vers.append(php71version)
            vers.append(php70version)
            vers.append(php56version)
        if settings.get_bool('enable_php_super_legacy_versions'):
            vers.append(php55version)
            vers.append(php54version)
            vers.append(php53version)
            vers.append(php52version)
            vers.append(php51version)
            vers.append(php50version)
            vers.append(php44version)
            vers.append(php43version)
            vers.append(php42version)
            vers.append(php41version)
            vers.append(php40version)
            vers.append(php30version)
        if settings.get_bool('enable_php_prerelease_version'):
            vers.extend(get_prerelease_version(vers))
        with open(cache_file, 'w+') as cache_write:
            for v in vers:
                cache_write.write(v + "\n")
        return vers
Пример #14
0
def make_vhost(username, domain, template_name='php', template_fields=False):
    """
    Create a new vhost file for a given domain.

    Args:
        username - The system username that stores the sitesfiles
        domain - The domain associated with the new vhost file
        template_name - The name of the nginx vhost template to use
    """
    modsec = get_modsec_path(domain)
    home = user.home_dir(username)
    dash_domain = domain.replace('.', '-', 100)
    under_domain = domain.replace('.', '_', 100)
    vhost_path = get_vhost_path(domain)
    local_ip = settings.get('local_ip')
    public_ip = settings.get('public_ip')
    read_path = template_path(template_name)
    fields = get_vhost_headers(read_path)[0]
    if not template_fields:
        template_fields = []
        for key, value in fields:
            value = input_util.prompt_value(key, value)
            template_fields.append([key, value])
    if not os.path.exists(modsec_exception_dir):
        os.makedirs(modsec_exception_dir)
    if not os.path.exists(vhost_dir):
        os.makedirs(vhost_dir)
    with open(modsec, 'a+'):
        pass
    with open(read_path) as template:
        with open(vhost_path, 'w') as host:
            for line in template:
                line = line.replace('DOMAINNAMEE', domain, 10000)
                line = line.replace('USERNAMEE', username, 10000)
                line = line.replace('DASHDOMAINN', dash_domain, 10000)
                line = line.replace('UNDERDOMAINN', under_domain, 10000)
                line = line.replace('HOMEDIRR', home, 10000)
                line = line.replace('LOCALIPP', local_ip, 10000)
                line = line.replace('PUBLICIPP', public_ip, 10000)
                line = line.replace('MODSECC', modsec, 10000)
                for key, value in template_fields:
                    line = line.replace(key, value, 10000)
                host.write(line)
    print('Created ' + vhost_path)
    reload()
Пример #15
0
def make_dkim_pair(domain):
    """
    Generate a new DKIM public key and private key. Then give EXIM access to
    those files.

    Args:
        domain - generate the keys for this domain
    """
    pem_file = settings.get('dkim_folder') + domain + '.pem'
    pub_file = settings.get('dkim_folder') + domain + '.pub'
    pwd_user = pwd.getpwnam(settings.get('exim_user')).pw_uid
    grp_group = grp.getgrnam(settings.get('exim_group')).gr_gid
    subprocess.run(['openssl', 'genrsa', '-out', pem_file, '2048'])
    subprocess.run(
        ['openssl', 'rsa', '-in', pem_file, '-pubout', '-out', pub_file])
    os.chown(pem_file, pwd_user, grp_group)
    os.chown(pub_file, pwd_user, grp_group)
    os.chmod(pem_file, 0o640)
    os.chmod(pub_file, 0o640)
Пример #16
0
def get_mail_domains():
    """Get an array of all domains registered in the mail system."""
    domains = []
    with open(settings.get('mail_domain_file')) as file:
        for line in file:
            segments = line.split(':')
            domain = segments[0].strip().lower()
            if domain != '*':
                domains.append(domain)
    return sorted(domains)
Пример #17
0
 def get_distro(self):
     distro = settings.get('imap_distro')
     if distro == 'unset':
         detected_distro = detect_distro_code()
         if detected_distro:
             distro = detected_distro
             settings.set('imap_distro', distro)
     if distro == 'unset':
         distro = self.select_distro('Select your current operating system')
         settings.set('imap_distro', distro)
     return distro
Пример #18
0
def account_exists(account):
    """Check if an email address is registered in the email system."""
    account = account.lower() + ':'
    length = len(account)
    found = False
    with open(settings.get('mail_shadow_file')) as shadow:
        for line in shadow:
            if line[:length].lower() == account:
                found = True
                break
    return found
Пример #19
0
def is_frozen(slug):
    """
    Returns True if the slug is set to be restricted from updating.
    """
    freeze_file = settings.get('install_path') + 'etc/build-freeze'
    if os.path.exists(freeze_file):
        with open(freeze_file) as frozen:
            for line in frozen:
                if slug == line.strip():
                    return True
    return False
Пример #20
0
def libs_path():
    path = settings.get('openssl_libs')
    if path == 'unset':
        paths = ['/usr/local/ssl/lib', '/usr/local/lib64', '/usr/local/lib']
        at = -1
        while path == 'unset' or not os.path.exists(path + '/libssl.so.1.1'):
            at += 1
            if at >= len(paths):
                return False
            path = paths[at]
        settings.set('openssl_libs', path)
    return path
Пример #21
0
 def cleanup_old_versions(self, log):
     found = False
     found_version = False
     for logname in builder.find_old_build_elements(
             settings.get('install_path') + 'var/log/build/php-' +
             self.versions['sub'] + '.', '.log'):
         os.remove(logname)
         log.log("Removed old log file " + logname)
     for folder in builder.find_old_build_elements(
             '/usr/local/src/php-' + self.versions['sub'] + '.', '/'):
         shutil.rmtree(folder)
         log.log("Removed old source directory " + folder)
Пример #22
0
    def clean(self, log):
        """
        Clean build binaries for the software.

        Args:
            log - An open log file or null
        """
        old_pwd = os.getcwd()
        target_dir = self.source_dir()
        if os.path.exists(target_dir):
            os.chdir(target_dir)
            log.run(['make', 'clean', '-l', settings.get('max_build_load')])
        os.chdir(old_pwd)
Пример #23
0
def get_account_from_domain(domain):
    """
    Get the username of the system user that stores email for the given domain.

    Args:
        domain - The domain to check
    """
    domain = domain.lower()
    with open(settings.get('mail_domain_file')) as file:
        for line in file:
            segments = line.split(':')
            if segments[0].strip().lower() == domain:
                return segments[1].strip()
    return False
Пример #24
0
def get_local_deploy_domains():
    """
    Returns an array of domains that should have a copy of new certificates
    placed in ~/certs/ after renewal.
    """
    local_deploy = []
    local_filename = settings.get('install_path') + 'etc/local-cert-deploy'
    if os.path.exists(local_filename):
        with open(local_filename) as domain_list:
            for domain in domain_list:
                domain = domain.lower().strip()
                if not domain.startswith('#'):
                    local_deploy.append(domain.lower().strip())
    return local_deploy
Пример #25
0
def remove_local_deploy(domain):
    """
    Unregister a domain to recieve copies of new certificates in the matching
    user's ~/cert directory.

    Args:
        domain - The domain to unregister
    """
    domain = domain.strip()
    filename = settings.get('install_path') + 'etc/local-cert-deploy'
    return file_filter.RemoveExact(filename,
                                   domain,
                                   ignore_trim=True,
                                   ignore_case=True).run()
Пример #26
0
def template_list(hide_ssl=False):
    """
    Get an array containing all of the nginx vhost template file names exluding
    path.

    Args:
        hide_ssl - Only show non-SSL templates
    """
    templates = []
    folder_name = settings.get('install_path') + 'etc/nginx-templates/'
    for temp in glob.glob(folder_name + '*'):
        if not hide_ssl or not temp.endswith('-ssl'):
            templates.append(temp[len(folder_name):])
    return sorted(templates)
Пример #27
0
def get_public_dkim_key(domain):
    """
    Get the contents of a public DKIM key with no line breaks.

    Args:
        domain - Get the public key for this domain
    """
    key = ''
    with open(settings.get('dkim_folder') + domain + '.pub') as pub:
        for line in pub:
            if line.startswith('-----'):
                continue
            key += line.replace('\n', '').replace('\r', '')
    return key
Пример #28
0
def get_connection():
    """
    Cet a connected MySQL connection.
    """
    root_needs_pass = settings.get_bool('db_root_requires_password')
    socket = settings.get('mysql_socket')
    if (root_needs_pass):
        bitpass = getpass('Enter the MySQL root password: '******'root',
                                 passwd=bitpass)
    else:
        return connector.connect(unix_socket=socket, user='******')
Пример #29
0
def _setpass(address):
    from libsw import email
    from getpass import getpass
    if address != False and not email.account_exists(address):
        print(address + ' does not exist on this server.')
        address = False
    if address == False:
        address = email.select_email()
    password = email.hash_password( getpass('Email Password: '******'Password Updated.')
    else:
        from libsw import settings
        print('Error. Password Not Updated. Check ' + settings.get('mail_shadow_file') + ' for syntax errors.')
Пример #30
0
def make_zone(domain):
    """
    Create a new zone file for the given domain name. The new zone file is
    populated with values for the new domain. The index of zone files is not
    rebuilt to include the new zone and Bind is not restarted or reloaded.

    Args:
        domain - The primary domain of the zone file
    """
    if not os.path.exists(zone_folder):
        os.mkdir(zone_folder)
    template = open(settings.get('install_path') + 'etc/zone-file', 'r')
    ns1 = settings.get('nameserver_one')
    ns2 = settings.get('nameserver_two')
    dns_authority = settings.get('dns_authority')
    ip = settings.get('public_ip')
    with open(zone_filename(domain), 'w') as zone:
        for line in template:
            line = line.replace('DOMAINNAMEE', domain, 10000)
            line = line.replace('NAMESERVER_ONEE', ns1, 10000)
            line = line.replace('NAMESERVER_TWOO', ns2, 10000)
            line = line.replace('DNS_AUTHORITYY', dns_authority, 10000)
            line = line.replace('PUBLIC_IPP', ip, 10000)
            zone.write(line)