#!/usr/bin/perl -w use Getopt::Long; use Unix::PasswdFile; use Authen::PAM; use POSIX qw(ttyname); ### SETTINGS my $pathid = "/usr/bin/id"; my $pathpasswd = "/etc/passwd"; my @allowed = (qr/^mail_/, qr/^web_/); ### SCRIPT BEGIN my ($match, $exp); my ($user, $pass, $newpass, $help); # Turn off warnings $SIG{} = sub { $help = 1; }; # Read Options my $args = GetOptions( "user=s"=>\$user, "pass=s"=>\$pass, "newpass=s"=>\$newpass, "help"=>\$help ); # Turn warning on again $SIG{} = sub { warn $_[0] }; # Show Help if ($help or not $args) { &showHelp(); } if (not @ARGV or not $ARGV[0] =~ /^(check|change)$/i) { &showHelp(); } # Check ID, stop if not root if (not isRoot()) { openErr("Please run this script as root."); } # Check Strings: User/Pass if (not checkUser($user)) { openErr("The Username is not valid or not allowed."); } if (not checkStr($pass)) { openErr("Please enter a valid User/Password"); } # Validate User/Pass (from ex. cpan) ref($pamh = new Authen::PAM("passwd", $user, \&convFunc)) or openErr("Error code $pamh during PAM init!"); $res = $pamh->pam_set_item(PAM_TTY(),ttyname(fileno(STDIN))); $res = $pamh->pam_authenticate; &openErr($pamh->pam_strerror($res)) unless $res == PAM_SUCCESS(); # Mode CHANGE if ($ARGV[0] =~ /^change$/i) { if (not checkStr($newpass)) { openErr("The new password is invalid."); } $pw = new Unix::PasswdFile $pathpasswd; $pw->passwd($user,$pw->encpass($newpass)); $pw->commit(); undef $pw; # Password changed print "SUCCESS: Password changed\n"; exit 0; } # Mode CHECK elsif ($ARGV[0] =~ /^check$/i) { print "SUCCESS: Password correct!\n"; exit 0; } # Mode HELP else { &showHelp(); } ### FUNCTIONS sub showHelp { print "Usage:\n"; print " pc.pl [options] check\n"; print " pc.pl [options] change\n"; print "\n"; print "Options:\n"; print " --user=s Unix username (required)\n"; print " --pass=s Current password (required)\n"; print " --newpass=s New password (only for mode change)\n"; print "\n"; exit 0; } sub openErr { print "ERROR: $_[0]\n"; exit 1; } sub checkStr { return ($_[0] and $_[0] =~ /^[0-9a-z_]+$/i)?1:0; } sub checkUser { my @allow = grep($_[0] =~ /$_/,@allowed); return (checkStr($_[0]) and @allow)?1:0; } sub isRoot { return `$pathid` =~ /^uid=0\(root\)/ and $ENV{USER} eq "root"; } sub convFunc { my @res; while ( @_ ) { my $code = shift; my $msg = shift; my $ans = ""; $ans = $user if ($code == PAM_PROMPT_ECHO_ON() ); $ans = $pass if ($code == PAM_PROMPT_ECHO_OFF() ); push @res, (PAM_SUCCESS(),$ans); } push @res, PAM_SUCCESS(); return @res; }