#!/bin/bash ### Copyright 1999-2025. WebPros International GmbH. All rights reserved. export LC_ALL="C" PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin unset GREP_OPTIONS umask 022 prog="`basename $0`" action="$1" # Communication protocol with repaird is: # * emit output to stdout as plaintext; # * stderr is not shown to user, but may be logged by 'repaird -v 3'; # * last line of output is JSON with any remaining output (see result() below); # * exit code is 0. info() { echo "INFO: $*" } warn() { echo "WARNING: $*" } err() { echo "ERROR: $*" } die() { err "$@" | result "failed" exit 0 } success() { echo -n | result "ok" exit 0 } usage() { echo "Usage: $prog { --check | --repair }" >&2 exit 1 } result() { local status="$1" python3 -c 'import sys, json message = sys.stdin.read() status = sys.argv[1] if message.strip() else "ok" print(json.dumps({"status": status, "message": message})) ' "$status" } is_remote_db_feature_enabled() { [ -s "/etc/psa/private/dsn.ini" ] } get_mysql_option_value() { local section="$1" local name="$2" local default="$3" local value="`/usr/bin/my_print_defaults "$section" | sed -n "s/^--$name=//p" | tail -n 1`" echo "${value:-$default}" } get_mysql_datadir() { get_mysql_option_value mysqld datadir "/var/lib/mysql" } find_psa_shadow() { find /etc/psa/.psa.shadow /etc/psa/private/secret_key "$@" } find_mysql_datadir() { find "$MYSQL_DATADIR" -maxdepth 0 "$@" } find_mysql_dirs() { find "$MYSQL_DATADIR" -mindepth 1 -type d ! \( -name 'lost+found' -o -name 'lost@002bfound' \) "$@" } find_mysql_files() { find "$MYSQL_DATADIR" -mindepth 1 -type f \ ! \( -name 'debian-*.flag' -o -name 'mysql_upgrade_info' -o -name 'mariadb_upgrade_info' \) "$@" } declare -A PERMS=( [find_psa_shadow]=" " # Use permissions fsmng knows about # Ideally permission changes on MySQL files should be done with stopped MySQL, but we don't # want the procedure to require downtime, so sacrifice some degree of correctness by skipping this. [find_mysql_dirs]=" --perms 0700 --owner mysql --group mysql --filetype directory" [find_mysql_files]=" --perms 0660,0600 --owner mysql --group mysql --filetype file" [find_mysql_datadir]=" --perms 0755 --owner mysql --group mysql --filetype directory" ) permissions() { local operation="$1" [ "$operation" = "--check-ac" -o "$operation" = "--set-ac" ] || die "Unknown operation: $operation" local restorecon_opts=(-iv) [ "$operation" = "--set-ac" ] || restorecon_opts+=(-n) local rc=0 for finder in "${!PERMS[@]}"; do local perms="${PERMS[$finder]}" $finder | "$PRODUCT_ROOT_D/admin/sbin/fsmng" "$operation" - $perms 2>&1 || rc="$?" done if command -v restorecon >/dev/null 2>&1 && should_check_selinux "$operation"; then for finder in "${!PERMS[@]}"; do $finder done | restorecon -f - "${restorecon_opts[@]}" || rc="$?" fi return "$rc" } should_check_selinux() { local operation="$1" local mode="`get_selinux_mode`" if [ "$operation" = "--check-ac" -a "$mode" = "Enforcing" ]; then # Check only in Enforcing mode return 0 elif [ "$operation" = "--set-ac" -a "$mode" != "Disabled" ]; then # Repair in Enforcing or Permissive mode return 0 fi return 1 } get_selinux_mode() { if ! command -v selinuxenabled >/dev/null 2>&1 || ! selinuxenabled; then echo "Disabled" elif ! command -v getenforce >/dev/null 2>&1; then echo "Disabled" else getenforce || echo "Disabled" fi } check() { ! is_remote_db_feature_enabled || die "Cannot check permissions of MySQL-related files with a remote database." permissions --check-ac | result "corrupted" exit 0 } repair() { ! is_remote_db_feature_enabled || die "Cannot repair permissions of MySQL-related files with a remote database." permissions --set-ac || die "Failed to repair some permissions of MySQL-related files." success } PRODUCT_ROOT_D="/opt/psa" MYSQL_DATADIR="`get_mysql_datadir`" case "$action" in --check) check ;; --repair) repair ;; *) usage ;; esac # vim:ft=sh