use Authen::PAM;
use POSIX qw(ttyname);
$service = "login";
$username = "foo";
$password = "bar";
$tty_name = ttyname(fileno(STDIN));
sub my_conv_func {
my @res;
while ( @_ ) {
my $code = shift;
my $msg = shift;
my $ans = "";
$ans = $username if ($code == PAM_PROMPT_ECHO_ON() );
$ans = $password if ($code == PAM_PROMPT_ECHO_OFF() );
push @res, (PAM_SUCCESS(),$ans);
}
push @res, PAM_SUCCESS();
return @res;
}
ref($pamh = new Authen::PAM($service, $username, \&my_conv_func)) ||
die "Error code $pamh during PAM init!";
$res = $pamh->pam_set_item(PAM_TTY(), $tty_name);
$res = $pamh->pam_authenticate;
print $pamh->pam_strerror($res),"\n" unless $res == PAM_SUCCESS();
The Authen::PAM module comes with a default conversation function which you can find in the file PAM.pm.
use Authen::PAM;
$service = "passwd";
$username = "foo";
$oldpassword = "old_pass";
$newpassword = "new_pass";
sub my_conv_func {
my @res;
while ( @_ ) {
my $code = shift;
my $msg = shift;
my $ans = "";
$ans = $username if ($code == PAM_PROMPT_ECHO_ON() );
if ($code == PAM_PROMPT_ECHO_OFF() ) {
$ans = $oldpassword if ($state == 0);
$ans = $newpassword if ($state == 1);
$ans = $newpassword if ($state == 2);
$state++;
}
push @res, (PAM_SUCCESS(),$ans);
}
push @res, PAM_SUCCESS();
return @res;
}
ref($pamh = new Authen::PAM($service, $username, \&my_conv_func)) ||
die "Error code $pamh during PAM init!";
$state = 0;
$res = $pamh->pam_chauthtok;
print $pamh->pam_strerror($res),"\n" unless $res == PAM_SUCCESS();
If you are running the script as root then most likely you will not be prompted for an old password. In this case you can simply return the new password at the ECHO_OFF prompt.
The $msg variable contains the text of the input prompt which you can use for additional test or for debugging purposes, e.g.
if ($code == PAM_PROMPT_ECHO_OFF() ) {
if ($state>=1 || $msg=~/new/i) { # are we asked for a new password
$ans = $newpassword;
} else {
$ans = $oldpassword;
}
$state++;
}