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
$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
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 */]) = 0
In 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
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
+++ 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 */]) = 0
What 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:
$ sudo -p ">" useradd -m -s /bin/bash -p $(mkpasswd --hash=SHA-512 "123" ) newusr
$ su newusr
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"
$ sudo -p ">" useradd -m -s /bin/sh -p 'GVhvDY$vhw89D2X0bd2REQWE' newusr2
$ su newusr2
$ echo $USER
Take output from
stdout stream and pass it via
$ mkpasswd -m sha-512 'password1' | sudo -p '>' xargs -I % useradd -p % newuser1
\ 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