After understanding the problem with using a password in the command line, I need to find a way of feeding a program with a password without it being a problem (without the password being recorded somewhere).
I have a bash script that automatically installs an entire LAMP server from source: Apache, FastCGI, PHP & MySQL. These installations require a password, especially MySQL.
How can I make the script fully automated without revealing the password?
Edit (9 June, 3:55 UTC):
I'm invoking mysql with a password on the command line, via root:
root@dor-desktop:/home/dor# PASS=`cat /home/dor/tmpf/pass`
root@dor-desktop:/home/dor# mysql -u root -p"$PASS"
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 6
(PASS="p4ssw0rd" in our case)
And I execute ps aux | grep mysql
via my regular user (dor), which doesn't show me the password!
(Some of) ps
output is:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 3562 0.0 0.0 34156 2864 pts/0 S+ 05:53 0:00 mysql -u root -px xxxxxx
How's that possible?
-
Also see unix.stackexchange.com/q/385339/135943, but note this does not make it safe!Wildcard– Wildcard2017年10月19日 05:00:42 +00:00Commented Oct 19, 2017 at 5:00
3 Answers 3
In regard to your update:
When a process is started it has a dedicated area of memory where arguments are stored and a int which tells how many arguments was passed.
MEMORY
argc 2
argv[0] program_name
argv[1] foo
argv[2] bar
MySQL check if password was passed on command line by -p
, and if it was copy it to a new variable that is not visible, then overwrite that region of memory with x
'es.
In simple terms e.g.:
argc 2
argv[1] -p
argv[2] p4ssw0rd
new_var = copy(argv[2]);
argv[2] = "xxxxx";
You can find it e.g. in client/mysqladmin.cc
of the source code:
case 'p':
...
opt_password=my_strdup(argument,MYF(MY_FAE));
while (*argument)
*argument++= 'x'; /* Destroy argument */
When ps
run it reads the memory region of the arguments, (argv[N]
), and thus it is xxxx
.
For a very short while the password is visible, but only for a few CPU cycles.
You can update the MySQL password using the special --init-file
option and procedure. C.5.4.1.2. Resetting the Root Password: Unix Systems
mysqld_safe --init-file=/home/me/mysql-init &
Edit:
As @Gilles say, you can echo
, printf
or use here
document from a script.
You can also add this to .my.cnf
of your home directory or in a (temporary) file and use the --defaults-extra-file
option. (Believe you have to add that option early on the command line.) optionally also include user. Also note the extra in the option name unless you want to use only that file as configuration:
[client]
user=foo
password='password!'
shell> chmod 400 my_tmp.cnf
shell> mysql --defaults-extra-file=my_tmp.conf -...
Optionally the [client]
grouping makes mysqld
skip the configuration.
One can also use MYSQL_PWD
environment variable, but that should never be used as you can list environment, in many ps
implementations by ps -e
, in the /proc/<PID>/environ
file on Linux etc.
tr '0円' '\n' < /proc/<PID>/environ
More on the topic here.
You might also want to have a look at the MySQL Configuration Utility which enables you to store password in a encrypted file in your home directory – .mylogin.cnf
.
-
Is there a way to change a token in the
mysql-init
file with the password that is stored in a bash variable? (without being revealed)Dor– Dor2013年06月09日 14:37:42 +00:00Commented Jun 9, 2013 at 14:37 -
4@Dor Something like
echo 'password=p4ssw0rd' >>mysql.cnf
is safe, becauseecho
is a built-in, so the password doesn't appear on the command line of any process. A here document is also safe.Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2013年06月09日 22:32:25 +00:00Commented Jun 9, 2013 at 22:32
The typical solution is to read the password from a file or from standard input (or from another file descriptor which would have to be passed as a parameter).
Some programs (command line ftp
for example) read passwords from /dev/tty
, the per-process special file that represents the process' controlling TTY. This lets the program not echo the password back to the screen, and to have a little more assurance about where the password comes from.
#!/bin/bash
stty -F /dev/tty -echo
read PASSWORD < /dev/tty
echo $PASSWORD