Mini Shell
Direktori : /usr/share/cagefs/ |
|
Current File : //usr/share/cagefs/sanity_check.py |
# -*- coding: utf-8 -*-
# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from future import standard_library
standard_library.install_aliases()
from builtins import *
import os
import pwd
import grp
import glob
import subprocess
import re
from clcommon import clconfpars
from itertools import chain
from collections import namedtuple
from cagefsctl import (
MountpointConfig,
DISABLE_ETCFS,
get_cagefs_users,
enabled_dir,
disabled_dir,
build_wrappers_dicts,
)
from cagefslib import CageFSException
from clcagefslib.selector.configure import is_ea4_enabled, read_cpanel_ea4_php_conf
cldiaglib_found = True
try:
from cldiaglib import (
runner,
ChkResult,
OK, FAILED, SKIPPED,
)
except ImportError:
cldiaglib_found = False
# Possible result types
OK = 'OK'
FAILED = 'FAILED'
SKIPPED = 'SKIPPED'
INTERNAL_TEST_ERROR = 'INTERNAL_TEST_ERROR'
ChkResult = namedtuple('ChkResult', [
'res', # One of predefined checker result types
'msg', # Resulting msg from this checker
])
def check_cagefs_mount_points_exists():
# We don't check personal mounts because they could be virtual
# and don't use read_only_mounts list because it's already in "mounts"
mp_config = MountpointConfig(skip_errors=True, ignore_cache=True)
missing = []
for p in chain(mp_config.common_mounts,
mp_config.splitted_by_username_mounts,
mp_config.splitted_by_uid_mounts):
t = p.strip()
if not os.path.isdir(t):
missing.append(t)
if missing:
return ChkResult(FAILED, 'There are missing mount points: {}'.format(missing))
return ChkResult(OK, 'No missing mount points found')
check_cagefs_mount_points_exists.pretty_name = 'Check cagefs mount points exists'
def check_cagefs_enabled_users_isdir():
if os.path.exists(enabled_dir) and not os.path.isdir(enabled_dir):
return ChkResult(FAILED, "{} is not a directory".format(enabled_dir))
return ChkResult(OK, '{} is fine'.format(enabled_dir))
check_cagefs_enabled_users_isdir.pretty_name = 'Check cagefs users.enabled is directory'
def check_cagefs_disabled_users_isdir():
if os.path.exists(disabled_dir) and not os.path.isdir(disabled_dir):
return ChkResult(FAILED, "{} is not a directory".format(disabled_dir))
return ChkResult(OK, '{} is fine'.format(disabled_dir))
check_cagefs_disabled_users_isdir.pretty_name = 'Check cagefs users.disabled is directory'
def check_cagefs_disabled_etcfs_exists():
if not os.path.exists(DISABLE_ETCFS):
return ChkResult(FAILED, "{} doesn't exists".format(DISABLE_ETCFS))
return ChkResult(OK, '{} exists'.format(DISABLE_ETCFS))
check_cagefs_disabled_etcfs_exists.pretty_name = 'Check cagefs disable.etcfs exists'
def get_cagefs_user_for_test(groups, all_enabled_users):
"""
Filter out users that are in super groups and
return username and uid of cagefs user for test
:param groups: list of super groups
:type groups: list of str
:param all_enabled_users: list of cagefs users to filter
:type all_enabled_users: list of str
:rtype tuple (user, uid) or (None, None) when user not found
"""
super_gids = set() # set of gids of super groups from pam_lve config
super_uids = set() # set of uids of members of super groups
re_pattern = re.compile('^cldiaguser_[a-f0-9]{21}$')
for group in groups:
try:
g = grp.getgrnam(group)
except KeyError:
continue
super_gids.add(g.gr_gid)
for user in g.gr_mem:
try:
p = pwd.getpwnam(user)
except KeyError:
continue
super_uids.add(p.pw_uid)
for user in all_enabled_users:
# LU-1893: skip cldiag test user
if re_pattern.match(user):
continue
try:
p = pwd.getpwnam(user)
except KeyError:
continue
uid = p.pw_uid
gid = p.pw_gid
if gid in super_gids or uid in super_uids:
continue
return user, uid
return None, None
def check_users_can_enter_cagefs():
try:
all_enabled_users = get_cagefs_users(raise_exception=True)
except CageFSException:
return ChkResult(SKIPPED, 'No users with cagefs enabled')
if not all_enabled_users:
return ChkResult(SKIPPED, 'No users with cagefs enabled')
try:
cfg = clconfpars.parse_pam_lve_config('/etc/pam.d/su')
except (IOError, ValueError) as e:
return ChkResult(FAILED, 'Error parsing /etc/pam.d/su config file {}'.format(e))
if cfg is None:
return ChkResult(FAILED, 'pam_lve configuration is not found in /etc/pam.d/su config file')
user, uid = get_cagefs_user_for_test(cfg.groups, all_enabled_users)
if user is None:
return ChkResult(SKIPPED, 'No users with cagefs enabled (all enabled users are in super group)')
inner = ('echo -n "Logged in as: $(whoami) - $(id -u) "; '
'[ "$(id -u)" == "{0}" ] && ls /var/.cagefs').format(uid)
cmd = """unset BASH_ENV; su '{0}' -s /bin/bash -c '{1}'""".format(user, inner)
try:
subprocess.check_output(cmd, stderr=subprocess.STDOUT,
shell=True, executable='/bin/bash', text=True).strip()
except subprocess.CalledProcessError as e:
return ChkResult(FAILED, '{}; Output was: "{}"'.format(e, e.output.strip()))
return ChkResult(OK, 'Several tested users really can enter cagefs')
check_users_can_enter_cagefs.pretty_name = 'Check cagefs users can enter cagefs'
def check_proxy_commands_configs_are_parsable():
try:
# This will load all "*.proxy.commands" under the hood.
# Currently we just try to parse them and expect that some exception
# will be raised if syntax is invalid or files can't be loaded for
# any reason.
# More strict validation should be implemented in cagefsctl itself
build_wrappers_dicts(raise_exception=True)
except Exception as e:
return ChkResult(
FAILED,
'Proxy commands config parsing error: "{}"'.format(repr(e))
)
return ChkResult(OK, 'Syntax looks fine. Files are parsable')
check_proxy_commands_configs_are_parsable.pretty_name = 'Check cagefs proxy commands configs are parsable'
def check_all_virt_mp_files_syntax():
wrong = []
files = glob.glob('/var/cagefs/*/*/virt.mp')
if not files:
return ChkResult(SKIPPED, 'No virt.mp files found')
for virt_mp in files:
with open(virt_mp, 'rt') as f:
conf = f.read()
# virt.mp files shouldn't be empty if exists
if len(conf) == 0:
wrong.append(virt_mp)
continue
# files shouldn't start with sub-directory definitions,
# at least one parent should be first, so:
if conf[0] == '@':
wrong.append(virt_mp)
if wrong:
return ChkResult(FAILED, wrong)
return ChkResult(OK, 'virt.mp files syntax is fine')
check_all_virt_mp_files_syntax.pretty_name = 'Check cagefs virt.mp files syntax'
def check_multiphp_system_default():
def php_selector_is_disabled():
try:
f = open('/var/cpanel/cpanel.config', 'r')
result = 'lve_hide_selector=1\n' in f
f.close()
except IOError:
return False
return result
if is_ea4_enabled() and not php_selector_is_disabled():
conf = read_cpanel_ea4_php_conf()
if conf:
try:
# get default system php version selected via MultiPHP Manager in cPanel WHM
default_php = conf['default']
# LVEMAN-1170
if not default_php.startswith('ea-php'):
return ChkResult(FAILED, 'Choose one of ea-php versions instead of alt-php in cPanel MultiPHP Manager for PHP Selector to start working.')
except KeyError:
return ChkResult(FAILED, 'Cannot get MultiPHP system default version')
return ChkResult(OK, 'MultiPHP system default PHP version is NOT alt-php. PHP Selector should work normally.')
check_multiphp_system_default.pretty_name = 'Check MultiPHP system default php version'
CAGEFS_CHECKERS = (
check_cagefs_mount_points_exists,
check_cagefs_enabled_users_isdir,
check_cagefs_disabled_users_isdir,
check_cagefs_disabled_etcfs_exists,
check_users_can_enter_cagefs,
check_proxy_commands_configs_are_parsable,
check_all_virt_mp_files_syntax,
check_multiphp_system_default,
)
def run_tests():
errors = []
output = []
for f in CAGEFS_CHECKERS:
try:
chk_res = f()
res, details = chk_res.res, chk_res.msg
except Exception as e:
res, details = INTERNAL_TEST_ERROR, repr(e)
if res == OK:
output.append("{}...\n{}\n".format(f.__name__, res))
else:
if res not in (SKIPPED,):
errors.append(res)
output.append("{}...\n{}: {}\n".format(f.__name__, res, details))
return errors, output
def check():
if os.geteuid() != 0:
print('This script should be run by root user')
exit(1)
if cldiaglib_found:
runner(CAGEFS_CHECKERS)
else:
print('*** Starting sanity check ***\n')
errors, out = run_tests()
print('\n'.join(out))
print('*** There are {} errors ***'.format(len(errors)))
if errors:
exit(2)
Zerion Mini Shell 1.0