I'm running into trouble trying to set passwords for my new users.
I found a tutorial indicating that mkpasswd -m sha-512 "my password here" would produce a salted and hashed password that can be used in combination with useradd -m -p "hashed and salted passwd" -s /bin/bash username, however when I tried this on a test user, I keep receiving Incorrect Login.
I am running Ubuntu 16.04 and using mkpasswd from the whois package.
What am I doing wrong here?
Exact Steps
1) apt update
2) apt install whois
3) mkpasswd -m sha-512 "my password here"
produces: $6$1FuuSdKgVke$bc8doOVGZhzomoeafvcQnpYhAxfR4aWdAuYvbxSHw6ZCFZ4NC5j9C762kmvs4Pc66bv4.LYTfrlknm5cWx65g.
4) useradd -m -p $6$1FuuSdKgVke$bc8doOVGZhzomoeafvcQnpYhAxfR4aWdAuYvbxSHw6ZCFZ4NC5j9C762kmvs4Pc66bv4.LYTfrlknm5cWx65g. -s /bin/bash testuser
5) login testuser
Prompts for password:
6) type my password here
Says: Login incorrect
Would like to add that I tried the same thing with a password that has no spaces, and omitted the quotes from the mkpasswd command. Neither seemed to make a difference.
I also tried to make the user without the -p flag (meaning don't add a password) and manually copied the salted/hashed password into /etc/shadow which produces the same results as above, Login incorrect.
Even more interesting, if I use a subshell to put the value in, everything seems to work fine.
useradd -m -p $(mkpasswd -m sha-512 "my password") -s /bin/bash test
login testtype: my password
Logs in just fine!
132 Answers
Okay, I locked down the issue. Since the output of mkpassword will result in $id$salt$hash, when you copy and paste this into a useradd command, bash will try and do variable replacement on the $. As such, those need to be escaped using \$id\$salt\$hash so that bash will not do variable replacement before adding the string to /etc/shadow.
mkpasswd -m sha-512 "my password"results in
$6$5AfGzrQ9u$r6Q7Vt6h8f2rr4TuW4ZA22m6/eoQh9ciwUuMDtVBX31tR3Tb0o9EB1eBdZ2L9mvT.pX3dIEfxipMoQ0LtTR3V1
which can be copied and pasted into useradd making sure to replace each $ with \$.
useradd -m -s /bin/bash -p \$6\$5AfGzrQ9u\$r6Q7Vt6h8f2rr4TuW4ZA22m6/eoQh9ciwUuMDtVBX31tR3Tb0o9EB1eBdZ2L9mvT.pX3dIEfxipMoQ0LtTR3V1
Why does this happen ?
The reason why it fails is because items with leading $ are treated as variable and are unquoted when you pass it to useradd.
The $6...,$1..., and $b... portions from your hash are treated as variable. Of course, the fault is with the shell - shells perform variable expansion (unless they're single-quoted ) before anything runs. And because those 3 variables don't exist in your environment they disappear from the string you pass to useradd.
Practical example:
Let's see what actual command runs after the shell finished performing all necessary expansions and substitutions and passed that to execve() system call. Compare:
$ strace -e execve useradd -p $abra$cadabra newuser
execve("/usr/sbin/useradd", ["useradd", "-p", "newuser"], [/* 82 vars */]) = 0
$ strace -e trace=execve useradd -p '$abra$cadabra' newuser
execve("/usr/sbin/useradd", ["useradd", "-p", "$abra$cadabra", "newuser"], [/* 82 vars */]) = 0In the first example $abra$cadabra ( which is where your hash would go) disappears from the command that actually gets to run by the system. In contrast, the single quoted $abra$cadabra in the second example appears on the list of arguments that do get passed to execve().
In other words, you generated correct hash, but shell passes completely different thing to useradd as argument, which ultimately is the command that system runs. In fact, let's just take your hash for instance and compare two cases of quoting and non-quoting:
$ strace -e execve echo $6$1FuuSdKgVke$bc8doOVGZhzomoeafvcQnpYhAxfR4aWdAuYvbxSHw6ZCFZ4NC5j9C762kmvs4Pc66bv4.LYTfrlknm5cWx65g
execve("/bin/echo", ["echo", "FuuSdKgVke.LYTfrlknm5cWx65g"], [/* 82 vars */]) = 0
FuuSdKgVke.LYTfrlknm5cWx65g
+++ exited with 0 +++Notice that what system actually sees after the shell is done processing the variables is FuuSdKgVke.LYTfrlknm5cWx65g. But it will see the correct hash if you quote it:
$ strace -e execve echo '$6$1FuuSdKgVke$bc8doOVGZhzomoeafvcQnpYhAxfR4aWdAuYvbxSHw6ZCFZ4NC5j9C762kmvs4Pc66bv4.LYTfrlknm5cWx65g'
execve("/bin/echo", ["echo", "$6$1FuuSdKgVke$bc8doOVGZhzomoeaf"...], [/* 82 vars */]) = 0What can be done ? What works ?
However, subshell works because there is no replacement occurring - there's no variables. And quoting also works for the same reason.
Here are a few methods:
Command substitution:
$ sudo -p ">" useradd -m -s /bin/bash -p $(mkpasswd --hash=SHA-512 "123" ) newusr > $ su newusr Password: newusr@ubuntu1604:/home/admin$Single-quoting(note that I've trimmed actual hash because it's too long and doesn't fit into formatting):
$ sudo -p ">" mkpasswd --hash=SHA-512 "112" > GVhvDY$vhw89D2X0bd2REQWE $ sudo -p ">" useradd -m -s /bin/sh -p 'GVhvDY$vhw89D2X0bd2REQWE' newusr2 > $ su newusr2 Password: $ echo $USER newusr2Take output from
mkpasswd'sstdoutstream and pass it viaxargswith-Iflag:$ mkpasswd -m sha-512 'password1' | sudo -p '>' xargs -I % useradd -p % newuser1Append
\to every$(which OP figured out themselves in their answer). Scriptable, too, as per George's comment.$ useradd -m -s /bin/bash -p \$6\$5AfGzrQ9u\$r6Q7Vt6h8f2rr4TuW4ZA22m6/eoQh9ciwUuMDtVBX31tR3Tb0o9EB1eBdZ2L9mvT.pX3dIEfxipMoQ0LtTR3V1 newuser