#!/usr/bin/perl
## no critic (ProhibitParensWithBuiltins)
use strict;
use warnings;
use English qw(-no_match_vars);

# Read root's hash from /etc/shadow
open(my $fh, '<', '/etc/shadow') or die "Cannot open /etc/shadow: $ERRNO\n";
my $hash;
while (my $line = <$fh>) {
    if ($line =~ /\A root: ([^:]+) : /xms) {
        $hash = $1;
        last;
    }
}
close($fh) or die "Cannot close /etc/shadow: $ERRNO\n";

if (!$hash) {
    die "Could not find root entry in /etc/shadow\n";
}
die "Root account has no password set\n" if $hash =~ /\A [!*] /xms;

# Prompt for password without echoing
system('stty', '-echo');
print 'Enter root password: ';
my $password = <STDIN>; ## no critic (ProhibitExplicitStdin)
system('stty', 'echo');
print "\n";
chomp $password;

if (crypt($password, $hash) eq $hash) {
    print "Password is correct.\n";
    exit 0;
} else {
    print "Password is incorrect.\n";
    exit 1;
}

__END__

##############################################################################
# Documentation
##############################################################################

=head1 NAME

check-root-password - Verify the root password against /etc/shadow

=head1 SYNOPSIS

B<check-root-password>

=head1 DESCRIPTION

B<check-root-password> reads the root password hash from F</etc/shadow>,
prompts the user for a password without echoing it, and checks whether
the entered password matches the stored hash using B<crypt>(3).

If the root account has no password set (the hash field is C<!> or C<*>),
the program exits with an error.

The exit status is 0 if the password is correct and 1 if it is incorrect.

=head1 FILES

=over 4

=item F</etc/shadow>

Read to obtain the root password hash.  The program must be run as root
or as a user with permission to read this file.

=back

=head1 AUTHOR

Adam Lewenberg <adamhl@stanford.edu>

=head1 SEE ALSO

crypt(3), shadow(5), passwd(1)

=cut
