I want to check, from the linux command line, if a given cleartext password is the same of a crypted password on a /etc/shadow

(I need this to authenticate web users. I'm running an embedded linux.)

I have access to the /etc/shadow file itself.

  • Log in as the user with the password? – Kusalananda Sep 29 '11 at 14:39
  • The test must be done automatically, I can't manually type the password from the web server – michelemarcon Sep 29 '11 at 14:43

You can easily extract the encrypted password with awk. You then need to extract the prefix $algorithm$salt$ (assuming that this system isn't using the traditional DES, which is strongly deprecated because it can be brute-forced these days).

correct=$(</etc/shadow awk -v user=bob -F : 'user == $1 {print $2}')

For password checking, the underlying C function is crypt, but there's no standard shell command to access it.

On the command line, you can use a Perl one-liner to invoke crypt on the password.

supplied=$(echo "$password" |
           perl -e '$_ = <STDIN>; chomp; print crypt($_, $ARGV[0])' "$prefix")
if [ "$supplied" = "$correct" ]; then …

Since this can't be done in pure shell tools, if you have Perl available, you might as well do it all in Perl. (Or Python, Ruby, … whatever you have available that can call the crypt function.) Warning, untested code.

#!/usr/bin/env perl
use warnings;
use strict;
my @pwent = getpwnam($ARGV[0]);
if (!@pwent) {die "Invalid username: $ARGV[0]\n";}
my $supplied = <STDIN>;
if (crypt($supplied, $pwent[1]) eq $pwent[1]) {
} else {
    print STDERR "Invalid password for $ARGV[0]\n";

On an embedded system without Perl, I'd use a small, dedicated C program. Warning, typed directly into the browser, I haven't even tried to compile. This is meant to illustrate the necessary steps, not as a robust implementation!

/* Usage: echo password | check_password username */
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <shadow.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
    char password[100];
    struct spwd shadow_entry;
    char *p, *correct, *supplied, *salt;
    if (argc < 2) return 2;
    /* Read the password from stdin */
    p = fgets(password, sizeof(password), stdin);
    if (p == NULL) return 2;
    *p = 0;
    /* Read the correct hash from the shadow entry */
    shadow_entry = getspnam(username);
    if (shadow_entry == NULL) return 1;
    correct = shadow_entry->sp_pwdp;
    /* Extract the salt. Remember to free the memory. */
    salt = strdup(correct);
    if (salt == NULL) return 2;
    p = strchr(salt + 1, '$');
    if (p == NULL) return 2;
    p = strchr(p + 1, '$');
    if (p == NULL) return 2;
    p[1] = 0;
    /*Encrypt the supplied password with the salt and compare the results*/
    supplied = crypt(password, salt);
    if (supplied == NULL) return 2;
    return !!strcmp(supplied, correct);

A different approach is to use an existing program such as su or login. In fact, if you can, it would be ideal to arrange for the web application to perform whatever it needs via su -c somecommand username. The difficulty here is to feed the password to su; this requires a terminal. The usual tool to emulate a terminal is expect, but it's a big dependency for an embedded system. Also, while su is in BusyBox, it's often omitted because many of its uses require the BusyBox binary to be setuid root. Still, if you can do it, this is the most robust approach from a security point of view.

| improve this answer | |
  • 1
    I like the su approach. – Benjohn Aug 1 '17 at 17:11

Have a look at man 5 shadow and man 3 crypt. From the latter, you can learn that password hashes in /etc/shadow have the following form:


where id defines the type of encryption and, reading further, can be one of

          ID  | Method
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

Depending on the type of hash, you need to use the appropriate function/tool for generating and verifying the password "by hand". If the system contains mkpasswd program, you can use it as suggested here. (You take the salt from the shadow file, if that wasn't obvious.) For example, with md5 passwords :

 mkpasswd -5 <the_salt> <the_password>

will generate the string that should match /etc/shadow entry.

| improve this answer | |
  • 1
    On my Debian wheezy I had a completely different syntax for the command mkpasswd, which I had to install using apt-get install whois. The command line for the shadow line <user>:$6$<salt>$<pwd>: was mkpasswd -msha-512 <password> <salt> – Daniel Alder Jul 9 '14 at 9:34

There was a similar question asked on Stack Overflow. cluelessCoder provided a script using expect, which you may or may not have on your embedded system.


#this script doesn't work if it is run as root, since then we don't have to specify a pw for 'su'
if [ $(id -u) -eq 0 ]; then
        echo "This script can't be run as root." 1>&2
        exit 1

if [ ! $# -eq 2 ]; then
        echo "Wrong Number of Arguments (expected 2, got $#)" 1>&2
        exit 1


#since we use expect inside a bash-script, we have to escape tcl-$.
expect << EOF
spawn su $USERNAME -c "exit" 
expect "Password:"
send "$PASSWORD\r"
#expect eof

set wait_result  [wait]

# check if it is an OS error or a return code from our command
#   index 2 should be -1 for OS erro, 0 for command return code
if {[lindex \$wait_result 2] == 0} {
        exit [lindex \$wait_result 3]
else {
        exit 1 
| improve this answer | |

Bear in mind that, assuming the system is properly configured, the program will need to be run as root.

A better solution than reading the shadow file directly and writing your own code around crypt would be to just use the pam bindings.

The squid tarball used to come with a simple CLI tool for verifying usernames/passwords using stdio - so simple to adapt to using arguments - although the version I hacked previously was hardly a pin-up poster for structured programming. A quick google and it looks like the more recent versions have been cleaned up significantly but still a few 'goto's in there.

| improve this answer | |
#! /bin/bash
#  (GPL3+) Alberto Salvia Novella (es20490446e)

passwordHash () {

    hashes=$(echo ${password} | openssl passwd -${encryption} -salt ${salt} -stdin)
    echo $(substring ${hashes} "$" "3")

passwordIsValid () {

    encryption=$(secret "encryption" ${user})
    salt=$(secret "salt" ${user})
    salted=$(secret "salted" ${user})
    hash=$(passwordHash ${password} ${salt} ${encryption})

    [ ${salted} = ${hash} ] && echo "true" || echo "false"

secret () {
    shadow=$(shadow ${user})

    if [ ${secret} = "encryption" ]; then
    elif [ ${secret} = "salt" ]; then
    elif [ ${secret} = "salted" ]; then

    echo $(substring ${shadow} "$" ${position})

shadow () {
    shadow=$(cat /etc/shadow | grep ${user})
    shadow=$(substring ${shadow} ":" "1")
    echo ${shadow}

substring () {

    IFS=$'\2' read -a substring <<< "${substring}"
    echo ${substring[${position}]}

passwordIsValid ${@}
| improve this answer | |
  • Spews an error line 61: :: syntax error: operand expected (error token is ":") – hoefling May 10 '19 at 21:55
  • The terminal emulator should be Bash 5, and you have to indicate both username and password as arguments. I have tested it works. – Alberto Salvia Novella May 12 '19 at 2:04

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.