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 test type: my password

Logs in just fine!

  • Can you provide the link to that tutorial as I don't see any -m option for that command unless I am missing something? – George Udosen Dec 3 '17 at 18:26
  • @George Do you have whois package installed ? Check with apt-cache policy whois. The option is there. – Sergiy Kolodyazhnyy Dec 3 '17 at 18:36
  • whois: Installed: 5.2.11 Candidate: 5.2.11 Version table: *** 5.2.11 500 500 http://ng.archive.ubuntu.com/ubuntu xenial/main amd64 Packages 100 /var/lib/dpkg/status I still don't get, excuse my inexperience – George Udosen Dec 3 '17 at 18:38
  • @Neurax can you provide the exact steps you did ? How did you combine the two commands ? Both commands appear correct, so there must be something you did incorrectly – Sergiy Kolodyazhnyy Dec 3 '17 at 19:24
  • I added my steps. – Neurax Dec 3 '17 at 20:45

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


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

  • 2
    My system was playing tricks on me, and you could always do mkpasswd -m sha-512 "my password" | sed 's/\$/\\$/g' > out.txt to save yourself the replacement of $ with \$ :-) – George Udosen Dec 4 '17 at 2:38

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 */]) = 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 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
+++ 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:

  1. Command substitution:

    $ sudo -p ">" useradd -m -s /bin/bash -p $(mkpasswd --hash=SHA-512 "123" ) newusr        
    $ su newusr
  2. 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
  3. Take output from mkpasswd's stdout stream and pass it via xargs with -I flag:

    $ mkpasswd -m sha-512 'password1' | sudo -p '>' xargs -I % useradd -p % newuser1 
  4. Append \ 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
  • Haha, we were both working on this solution simultaneously. I snuck an answer in 5 minutes ahead. Good find brother, you can have the answer credit! You should definitely edit your solution to include the easy fix of escaping the $ with \$ for thoroughness. – Neurax Dec 3 '17 at 23:32
  • Looking through your solution, I can't really tell what you're doing with strace, and further, executing sudo -p ">" is confusing to anyone looking at this question. It doesn't have anything to do with the reason why the manual setting of the hash wasn't working. I'd remove that also. – Neurax Dec 3 '17 at 23:39
  • @Neurax I'll add explanation on strace and \$. As for sudo -p ">" it's just to hide my actual username ( although granted - it's already all across the internet anyway). – Sergiy Kolodyazhnyy Dec 4 '17 at 0:06
  • @Neurax and there we go - edit done – Sergiy Kolodyazhnyy Dec 4 '17 at 0:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.