Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQL escape passwords #356

Merged
merged 1 commit into from
Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 36 additions & 19 deletions 10.2/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ docker_temp_server_start() {
# Stop the server. When using a local socket file mysqladmin will block until
# the shutdown is complete.
docker_temp_server_stop() {
if ! mysqladmin --defaults-extra-file=<( _mysql_passfile ) shutdown -uroot --socket="${SOCKET}"; then
export MYSQL_PWD=$MARIADB_ROOT_PASSWORD
if ! mysqladmin shutdown -uroot --socket="${SOCKET}"; then
mysql_error "Unable to shut down server."
fi
unset MYSQL_PWD
}

# Verify that the minimally required password settings are set for new databases.
Expand Down Expand Up @@ -216,15 +218,32 @@ docker_setup_env() {
docker_process_sql() {
passfileArgs=()
if [ '--dont-use-mysql-root-password' = "$1" ]; then
passfileArgs+=( "$1" )
shift
unset MYSQL_PWD
else
export MYSQL_PWD=$MARIADB_ROOT_PASSWORD
fi
local count=5
while [ $count -gt 0 ] && [ ! -S "${SOCKET}" ]
do
count=$(( $count - 1 ))
mysql_note "Waiting for MariaDB to start, $count more seconds"
sleep 1
done
# args sent in can override this db, since they will be later in the command
if [ -n "$MYSQL_DATABASE" ]; then
set -- --database="$MYSQL_DATABASE" "$@"
fi

mysql --defaults-extra-file=<( _mysql_passfile "${passfileArgs[@]}") --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" "$@"
mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" "$@"
unset MYSQL_PWD
}

# SQL escape the string $1 to be placed in a string literal.
# escape, \ followed by '
docker_sql_escape_string_literal() {
local escaped=${1//\\/\\\\}
echo "${escaped//\'/\\\'}"
}

# Initializes database with timezone info and root password, plus optional extra db/user
Expand Down Expand Up @@ -258,24 +277,29 @@ docker_setup_db() {
fi
# Sets root password and creates root users for non-localhost hosts
local rootCreate=
local rootPasswordEscaped=$( docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}" )

# default root to listen for connections from anywhere
if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then
# no, we don't care if read finds a terminating character in this heredoc
# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
read -r -d '' rootCreate <<-EOSQL || true
CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}' ;
CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this one also need the NO_BACKSLASH_ESCAPES you added below?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its in the same session where rootCreate is used.

GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ;
EOSQL
fi

# tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set
docker_process_sql --dont-use-mysql-root-password --database=mysql <<-EOSQL
# --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding.
docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL
-- What's done in this file shouldn't be replicated
-- or products like mysql-fabric won't work
SET @@SESSION.SQL_LOG_BIN=0;
-- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set
SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', '');

DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mariadb.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MARIADB_ROOT_PASSWORD}') ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ;
-- 10.1: https://github.com/MariaDB/server/blob/d925aec1c10cebf6c34825a7de50afe4e630aff4/scripts/mysql_secure_installation.sh#L347-L365
-- 10.5: https://github.com/MariaDB/server/blob/00c3a28820c67c37ebbca72691f4897b57f2eed5/scripts/mysql_secure_installation.sh#L351-L369
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' ;
Expand All @@ -294,7 +318,12 @@ docker_setup_db() {

if [ -n "$MARIADB_USER" ] && [ -n "$MARIADB_PASSWORD" ]; then
mysql_note "Creating user ${MARIADB_USER}"
docker_process_sql --database=mysql <<<"CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASSWORD' ;"
# SQL escape the user password, \ followed by '
local userPasswordEscaped=$( docker_sql_escape_string_literal "${MARIADB_PASSWORD}" )
docker_process_sql --database=mysql --binary-mode <<-EOSQL_USER
SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', '');
CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';
EOSQL_USER

if [ -n "$MARIADB_DATABASE" ]; then
mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}"
Expand All @@ -303,18 +332,6 @@ docker_setup_db() {
fi
}

_mysql_passfile() {
# echo the password to the "file" the client uses
# the client command will use process substitution to create a file on the fly
# ie: --defaults-extra-file=<( _mysql_passfile )
if [ '--dont-use-mysql-root-password' != "$1" ] && [ -n "$MARIADB_ROOT_PASSWORD" ]; then
cat <<-EOF
[client]
password="${MARIADB_ROOT_PASSWORD}"
EOF
fi
}

# check arguments for an option that would cause mysqld to stop
# return true if there is one
_mysql_want_help() {
Expand Down
55 changes: 36 additions & 19 deletions 10.3/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ docker_temp_server_start() {
# Stop the server. When using a local socket file mysqladmin will block until
# the shutdown is complete.
docker_temp_server_stop() {
if ! mysqladmin --defaults-extra-file=<( _mysql_passfile ) shutdown -uroot --socket="${SOCKET}"; then
export MYSQL_PWD=$MARIADB_ROOT_PASSWORD
if ! mysqladmin shutdown -uroot --socket="${SOCKET}"; then
mysql_error "Unable to shut down server."
fi
unset MYSQL_PWD
}

# Verify that the minimally required password settings are set for new databases.
Expand Down Expand Up @@ -216,15 +218,32 @@ docker_setup_env() {
docker_process_sql() {
passfileArgs=()
if [ '--dont-use-mysql-root-password' = "$1" ]; then
passfileArgs+=( "$1" )
shift
unset MYSQL_PWD
else
export MYSQL_PWD=$MARIADB_ROOT_PASSWORD
fi
local count=5
while [ $count -gt 0 ] && [ ! -S "${SOCKET}" ]
do
count=$(( $count - 1 ))
mysql_note "Waiting for MariaDB to start, $count more seconds"
sleep 1
done
# args sent in can override this db, since they will be later in the command
if [ -n "$MYSQL_DATABASE" ]; then
set -- --database="$MYSQL_DATABASE" "$@"
fi

mysql --defaults-extra-file=<( _mysql_passfile "${passfileArgs[@]}") --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" "$@"
mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" "$@"
unset MYSQL_PWD
}

# SQL escape the string $1 to be placed in a string literal.
# escape, \ followed by '
docker_sql_escape_string_literal() {
local escaped=${1//\\/\\\\}
echo "${escaped//\'/\\\'}"
}

# Initializes database with timezone info and root password, plus optional extra db/user
Expand Down Expand Up @@ -258,24 +277,29 @@ docker_setup_db() {
fi
# Sets root password and creates root users for non-localhost hosts
local rootCreate=
local rootPasswordEscaped=$( docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}" )

# default root to listen for connections from anywhere
if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then
# no, we don't care if read finds a terminating character in this heredoc
# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
read -r -d '' rootCreate <<-EOSQL || true
CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}' ;
CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ;
GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ;
EOSQL
fi

# tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set
docker_process_sql --dont-use-mysql-root-password --database=mysql <<-EOSQL
# --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding.
docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL
-- What's done in this file shouldn't be replicated
-- or products like mysql-fabric won't work
SET @@SESSION.SQL_LOG_BIN=0;
-- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set
SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', '');

DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mariadb.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MARIADB_ROOT_PASSWORD}') ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ;
-- 10.1: https://github.com/MariaDB/server/blob/d925aec1c10cebf6c34825a7de50afe4e630aff4/scripts/mysql_secure_installation.sh#L347-L365
-- 10.5: https://github.com/MariaDB/server/blob/00c3a28820c67c37ebbca72691f4897b57f2eed5/scripts/mysql_secure_installation.sh#L351-L369
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' ;
Expand All @@ -294,7 +318,12 @@ docker_setup_db() {

if [ -n "$MARIADB_USER" ] && [ -n "$MARIADB_PASSWORD" ]; then
mysql_note "Creating user ${MARIADB_USER}"
docker_process_sql --database=mysql <<<"CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASSWORD' ;"
# SQL escape the user password, \ followed by '
local userPasswordEscaped=$( docker_sql_escape_string_literal "${MARIADB_PASSWORD}" )
docker_process_sql --database=mysql --binary-mode <<-EOSQL_USER
SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', '');
CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';
EOSQL_USER

if [ -n "$MARIADB_DATABASE" ]; then
mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}"
Expand All @@ -303,18 +332,6 @@ docker_setup_db() {
fi
}

_mysql_passfile() {
# echo the password to the "file" the client uses
# the client command will use process substitution to create a file on the fly
# ie: --defaults-extra-file=<( _mysql_passfile )
if [ '--dont-use-mysql-root-password' != "$1" ] && [ -n "$MARIADB_ROOT_PASSWORD" ]; then
cat <<-EOF
[client]
password="${MARIADB_ROOT_PASSWORD}"
EOF
fi
}

# check arguments for an option that would cause mysqld to stop
# return true if there is one
_mysql_want_help() {
Expand Down
55 changes: 36 additions & 19 deletions 10.4/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,11 @@ docker_temp_server_start() {
# Stop the server. When using a local socket file mysqladmin will block until
# the shutdown is complete.
docker_temp_server_stop() {
if ! mysqladmin --defaults-extra-file=<( _mysql_passfile ) shutdown -uroot --socket="${SOCKET}"; then
export MYSQL_PWD=$MARIADB_ROOT_PASSWORD
if ! mysqladmin shutdown -uroot --socket="${SOCKET}"; then
mysql_error "Unable to shut down server."
fi
unset MYSQL_PWD
}

# Verify that the minimally required password settings are set for new databases.
Expand Down Expand Up @@ -216,15 +218,32 @@ docker_setup_env() {
docker_process_sql() {
passfileArgs=()
if [ '--dont-use-mysql-root-password' = "$1" ]; then
passfileArgs+=( "$1" )
shift
unset MYSQL_PWD
else
export MYSQL_PWD=$MARIADB_ROOT_PASSWORD
fi
local count=5
while [ $count -gt 0 ] && [ ! -S "${SOCKET}" ]
do
count=$(( $count - 1 ))
mysql_note "Waiting for MariaDB to start, $count more seconds"
sleep 1
done
# args sent in can override this db, since they will be later in the command
if [ -n "$MYSQL_DATABASE" ]; then
set -- --database="$MYSQL_DATABASE" "$@"
fi

mysql --defaults-extra-file=<( _mysql_passfile "${passfileArgs[@]}") --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" "$@"
mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" "$@"
unset MYSQL_PWD
}

# SQL escape the string $1 to be placed in a string literal.
# escape, \ followed by '
docker_sql_escape_string_literal() {
local escaped=${1//\\/\\\\}
echo "${escaped//\'/\\\'}"
}

# Initializes database with timezone info and root password, plus optional extra db/user
Expand Down Expand Up @@ -258,24 +277,29 @@ docker_setup_db() {
fi
# Sets root password and creates root users for non-localhost hosts
local rootCreate=
local rootPasswordEscaped=$( docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}" )

# default root to listen for connections from anywhere
if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then
# no, we don't care if read finds a terminating character in this heredoc
# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
read -r -d '' rootCreate <<-EOSQL || true
CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}' ;
CREATE USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ;
GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ;
EOSQL
fi

# tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set
docker_process_sql --dont-use-mysql-root-password --database=mysql <<-EOSQL
# --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding.
docker_process_sql --dont-use-mysql-root-password --database=mysql --binary-mode <<-EOSQL
-- What's done in this file shouldn't be replicated
-- or products like mysql-fabric won't work
SET @@SESSION.SQL_LOG_BIN=0;
-- we need the SQL_MODE NO_BACKSLASH_ESCAPES mode to be clear for the password to be set
SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', '');

DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mariadb.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MARIADB_ROOT_PASSWORD}') ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ;
-- 10.1: https://github.com/MariaDB/server/blob/d925aec1c10cebf6c34825a7de50afe4e630aff4/scripts/mysql_secure_installation.sh#L347-L365
-- 10.5: https://github.com/MariaDB/server/blob/00c3a28820c67c37ebbca72691f4897b57f2eed5/scripts/mysql_secure_installation.sh#L351-L369
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' ;
Expand All @@ -294,7 +318,12 @@ docker_setup_db() {

if [ -n "$MARIADB_USER" ] && [ -n "$MARIADB_PASSWORD" ]; then
mysql_note "Creating user ${MARIADB_USER}"
docker_process_sql --database=mysql <<<"CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$MARIADB_PASSWORD' ;"
# SQL escape the user password, \ followed by '
local userPasswordEscaped=$( docker_sql_escape_string_literal "${MARIADB_PASSWORD}" )
docker_process_sql --database=mysql --binary-mode <<-EOSQL_USER
SET @@SESSION.SQL_MODE=REPLACE(@@SESSION.SQL_MODE, 'NO_BACKSLASH_ESCAPES', '');
CREATE USER '$MARIADB_USER'@'%' IDENTIFIED BY '$userPasswordEscaped';
EOSQL_USER

if [ -n "$MARIADB_DATABASE" ]; then
mysql_note "Giving user ${MARIADB_USER} access to schema ${MARIADB_DATABASE}"
Expand All @@ -303,18 +332,6 @@ docker_setup_db() {
fi
}

_mysql_passfile() {
# echo the password to the "file" the client uses
# the client command will use process substitution to create a file on the fly
# ie: --defaults-extra-file=<( _mysql_passfile )
if [ '--dont-use-mysql-root-password' != "$1" ] && [ -n "$MARIADB_ROOT_PASSWORD" ]; then
cat <<-EOF
[client]
password="${MARIADB_ROOT_PASSWORD}"
EOF
fi
}

# check arguments for an option that would cause mysqld to stop
# return true if there is one
_mysql_want_help() {
Expand Down
Loading