# password_change.cgi
# Actually update a user's password by directly modifying /etc/shadow
+BEGIN { push(@INC, ".."); };
+use WebminCore;
+
$ENV{'MINISERV_INTERNAL'} || die "Can only be called by miniserv.pl";
-require './web-lib.pl';
&init_config();
&ReadParse();
&get_miniserv_config(\%miniserv);
$miniserv{'passwd_mode'} == 2 || die "Password changing is not enabled!";
-if (!$in{'pam'}) {
- $miniserv{'passwd_cindex'} ne '' && $miniserv{'passwd_mindex'} ne '' ||
- die "Missing password file configuration";
- }
# Validate inputs
$in{'new1'} ne '' || &pass_error($text{'password_enew1'});
$in{'new1'} eq $in{'new2'} || &pass_error($text{'password_enew2'});
-if ($in{'pam'}) {
+# Is this a Webmin user?
+if (&foreign_check("acl")) {
+ &foreign_require("acl", "acl-lib.pl");
+ ($wuser) = grep { $_->{'name'} eq $in{'user'} } &acl::list_users();
+ if ($wuser->{'pass'} eq 'x') {
+ # A Webmin user, but using Unix authentication
+ $wuser = undef;
+ }
+ elsif ($wuser->{'pass'} eq '*LK*' ||
+ $wuser->{'pass'} =~ /^\!/) {
+ &pass_error("Webmin users with locked accounts cannot change ".
+ "their passwords!");
+ }
+ }
+if (!$in{'pam'} && !$wuser) {
+ $miniserv{'passwd_cindex'} ne '' && $miniserv{'passwd_mindex'} ne '' ||
+ die "Missing password file configuration";
+ }
+
+if ($wuser) {
+ # Update Webmin user's password
+ $enc = &acl::encrypt_password($in{'old'}, $wuser->{'pass'});
+ $enc eq $wuser->{'pass'} || &pass_error($text{'password_eold'});
+ $perr = &acl::check_password_restrictions($in{'user'}, $in{'new1'});
+ $perr && &pass_error(&text('password_enewpass', $perr));
+ $wuser->{'pass'} = &acl::encrypt_password($in{'new1'});
+ $wuser->{'temppass'} = 0;
+ &acl::modify_user($wuser->{'name'}, $wuser);
+ &reload_miniserv();
+ }
+elsif ($gconfig{'passwd_cmd'}) {
+ # Use some configured command
+ $passwd_cmd = &has_command($gconfig{'passwd_cmd'});
+ $passwd_cmd || &pass_error("The password change command <tt>$gconfig{'passwd_cmd'}</tt> was not found");
+
+ &foreign_require("proc", "proc-lib.pl");
+ &clean_environment();
+ $ENV{'REMOTE_USER'} = $in{'user'}; # some programs need this
+ $passwd_cmd .= " ".quotemeta($in{'user'});
+ ($fh, $fpid) = &proc::pty_process_exec($passwd_cmd, 0, 0);
+ &reset_environment();
+ while(1) {
+ local $rv = &wait_for($fh,
+ '(new|re-enter).*:',
+ '(old|current|login).*:',
+ 'pick a password',
+ 'too\s+many\s+failures',
+ 'attributes\s+changed\s+on|successfully\s+changed',
+ 'pick your passwords');
+ $out .= $wait_for_input;
+ sleep(1);
+ if ($rv == 0) {
+ # Prompt for the new password
+ syswrite($fh, $in{'new1'}."\n", length($in{'new1'})+1);
+ }
+ elsif ($rv == 1) {
+ # Prompt for the old password
+ syswrite($fh, $in{'old'}."\n", length($in{'old'})+1);
+ }
+ elsif ($rv == 2) {
+ # Request for a menu option (SCO?)
+ syswrite($fh, "1\n", 2);
+ }
+ elsif ($rv == 3) {
+ # Failed too many times
+ last;
+ }
+ elsif ($rv == 4) {
+ # All done
+ last;
+ }
+ elsif ($rv == 5) {
+ # Request for a menu option (HP/UX)
+ syswrite($fh, "p\n", 2);
+ }
+ else {
+ last;
+ }
+ last if (++$count > 10);
+ }
+ $crv = close($fh);
+ sleep(1);
+ waitpid($fpid, 1);
+ if ($? || $count > 10 ||
+ $out =~ /error|failed/i || $out =~ /bad\s+password/i) {
+ &pass_error("<tt>".&html_escape($out)."</tt>");
+ }
+ }
+elsif ($in{'pam'}) {
# Use PAM to make the change..
eval "use Authen::PAM;";
if ($@) {
&unlock_file($miniserv{'passwd_file'});
}
+# Change password in Usermin too
+if (&get_product_name() eq 'usermin' &&
+ &foreign_check("changepass")) {
+ # XXX remote user??
+ &foreign_require("changepass", "changepass-lib.pl");
+ &changepass::change_mailbox_passwords(
+ $in{'user'}, $in{'old'}, $in{'new1'});
+ }
+
# Show ok page
&header(undef, undef, undef, undef, 1, 1);
sub pass_error
{
&header(undef, undef, undef, undef, 1, 1);
-print "<hr>\n";
+print &ui_hr();
print "<center><h3>",$text{'password_err'}," : ",@_,"</h3></center>\n";
-print "<hr>\n";
+print &ui_hr();
&footer();
exit;
}