7

I have a script that asks for the user's password and I want to check if the given password is wrong or not.

#A little fragment of my script

read -sp 'Your password: ' password;

if [[ $password -ne WHAT GOES HERE? ]]; then
    MORE CODE HERE
else
    MORE CODE HERE
fi

3 Answers 3

5

There's no fully portable way to check the user's password. This requires a privileged executable, so this isn't something you can whip up from scratch. PAM, which is used on most non-embedded Linux systems as well as many embedded systems and most other Unix variants, comes with a setuid binary but it doesn't have a direct shell interface, you need to go via the PAM stack.

You can use a PAM binding in Perl, Python or Ruby.

You can install one of several checkpassword implementations.

If the user is allowed to run sudo for anything, then sudo -kv will prompt for authentication (unless this has been disabled in the sudo configuration). But that doesn't work if there's no sudoers rule concerning the user.

You can run su. This works on most implementations. This is probably the best bet in your case.

if su -c true "$USER"; then
  echo "Correct password"
fi
3

You can validate that a given local password is correct for a given username using the shadow file.

On most modern distributions, the hashed passwords are stored in the shadow file /etc/shadow (which is only readable by root). As root, pull the line from the shadow file for the given user like so:

cat /etc/shadow | grep username

You will see something like this:

username:$1$TrOIigLp$PUHL00kS5UY3CMVaiC0/g0:15020:0:99999:7:::

After the username there is $1. This indicates that it is an MD5 hash. After that there is another $, then (in this case) TrOIigLp followed by another $. TrOIigLp is the salt. After that is the hashed password, which was hashed using the salt - in this case PUHL00kS5UY3CMVaiC0/g0.

Now, you can use openssl to hash the given password using the same salt, like so:

openssl passwd -1 -salt TrOIigLp

Enter the given password when prompted, the openssl command should compute the MD5 hash using the salt provided, and it should be exactly the same as the above from the shadow file. The -1 in the above command is for MD5 hashing.

3
  • 2
    This only works for local users with a local password; it won't work for, e.g., LDAP users, or a system that uses Kerberos for authentication.
    – jayhendren
    Dec 12, 2016 at 18:18
  • 1
    This only works for a script running as root. And even then parsing /etc/shadow is a bad idea for many reasons. How will you cope with an unknown algorithm? What if the account is from a different source? Don't reinvent the wheel, especially when you're making a square that's held by three half-spokes. Dec 12, 2016 at 23:13
  • 3
    This answer was copied verbatim from another user here. While all answers on Stack Overflow are licensed under a Creative Commons license and, thus, can be legally duplicated, attribution is required.
    – jmbpiano
    Dec 19, 2018 at 20:29
2

Here's a relatively robust solution that works with both local and remote users and attempts to authenticate against the full PAM stack as the user in question, rather than simply comparing password hashes.

#!/usr/bin/env ruby

require 'rpam'

username = ARGV[0]
password = ARGV[1]

if Rpam.auth(username, password, service: 'system-auth')
  puts 'authentication successful'
  exit 0
else
  puts 'authentication failure'
  exit 1
end

To run it: Save it as ./authenticate_as.rb, chmod +x ./authenticate_as.rb, and ./authenticate_as.rb $username $password. Requires Ruby and the rpam gem, in case that wasn't obvious.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .