#!/bin/bash
# info: change database server password
# options: TYPE HOST USER PASSWORD
#
# example: v-change-database-host-password mysql localhost wp_user pA$$w@rD
#
# This function changes database server password.

#----------------------------------------------------------#
#                Variables & Functions                     #
#----------------------------------------------------------#

# Argument definition
type=$1
host=$2
dbuser=$3
password=$4
HIDE=4

# Includes
# shellcheck source=/etc/tuliocp/tulio.conf
source /etc/tuliocp/tulio.conf
# shellcheck source=/usr/local/tulio/func/main.sh
source $TULIO/func/main.sh
# shellcheck source=/usr/local/tulio/func/db.sh
source $TULIO/func/db.sh
# load config file
source_conf "$TULIO/conf/tulio.conf"

#----------------------------------------------------------#
#                    Verifications                         #
#----------------------------------------------------------#

args_usage='TYPE HOST DBUSER DBPASS'
check_args '4' "$#" "$args_usage"
is_format_valid 'host' 'dbuser'
is_object_valid "../../../conf/$type" 'HOST' "$host"
is_password_valid
dbpass="$password"

# Tulio stores the password in its KEY='value' config format (mysql.conf),
# which has NO escaping mechanism. Reject characters that would corrupt that
# format or /root/.my.cnf: single quote, double quote and backslash.
if printf '%s' "$dbpass" | LC_ALL=C grep -q "['\"\\]"; then
	echo "Error: password contains forbidden characters ( ' \" \\ )"
	log_event "$E_INVALID" "$ARGUMENTS"
	exit "$E_INVALID"
fi

# Perform verification if read-only mode is enabled
check_tulio_demo_mode

#----------------------------------------------------------#
#                       Action                             #
#----------------------------------------------------------#

# Define email
email=$(grep CONTACT "$TULIO/data/users/$ROOT_USER/user.conf" | cut -f2 -d \')
subj="v-change-database-host-password $*"

case $type in
	mysql)
		mysql_connect "$host"

		# Account names and passwords are SQL string literals here.
		dbuser_esc=$(mysql_sql_escape "$dbuser")
		dbpass_esc=$(mysql_sql_escape "$dbpass")

		# Preserve the previous "UPDATE mysql.user ... WHERE User = ..."
		# semantics: change the password for every existing account of this
		# username, regardless of its Host (localhost, %, custom hosts, ...).
		query="SELECT Host FROM mysql.user WHERE User='$dbuser_esc'"
		account_hosts=$(mysql_query_raw "$query")
		check_result $? "Unable to get MySQL account hosts for $dbuser"

		if [ -z "$account_hosts" ]; then
			echo "Error: MySQL user $dbuser does not exist"
			log_event "$E_NOTEXIST" "$ARGUMENTS"
			exit "$E_NOTEXIST"
		fi

		while IFS= read -r account_host; do
			[ -n "$account_host" ] || continue

			account_host_esc=$(mysql_sql_escape "$account_host")
			query="ALTER USER '$dbuser_esc'@'$account_host_esc' IDENTIFIED BY '$dbpass_esc'"

			mysql_query "$query"
			check_result $? "Unable to change password for MySQL account $dbuser@$account_host"
		done << EOF
$account_hosts
EOF

		if [ "$dbuser" = "root" ]; then
			# /root/.my.cnf is an option file, NOT SQL. Within quotes MySQL/MariaDB
			# processes backslash escapes and the closing quote, so escape backslashes
			# and single quotes for the option-file format (different from SQL escaping).
			mycnf_pass=$(printf '%s' "$dbpass" | sed -e 's/\\/\\\\/g' -e "s/'/\\'/g")
			umask 077
			printf "[client]\npassword='%s'\n" "$mycnf_pass" > /root/.my.cnf
			chmod 600 /root/.my.cnf
		fi
		;;
	pgsql)
		echo "TBD" > /dev/null
		;;
esac

update_object_value "../../../conf/$type" 'HOST' "$host" '$USER' "$dbuser"
update_object_value "../../../conf/$type" 'HOST' "$host" '$PASSWORD' "$dbpass"

#----------------------------------------------------------#
#                       Tulio                             #
#----------------------------------------------------------#

# Logging
$BIN/v-log-action "system" "Warning" "Database" "Password changed for remote database host (Host: $host)."
log_event "$OK" "$ARGUMENTS"

exit
