3 # Actually update a user's password by directly modifying /etc/shadow
5 $ENV{'MINISERV_INTERNAL'} || die "Can only be called by miniserv.pl";
6 require './web-lib.pl';
9 &get_miniserv_config(\%miniserv);
10 $miniserv{'passwd_mode'} == 2 || die "Password changing is not enabled!";
12 $miniserv{'passwd_cindex'} ne '' && $miniserv{'passwd_mindex'} ne '' ||
13 die "Missing password file configuration";
17 $in{'new1'} ne '' || &pass_error($text{'password_enew1'});
18 $in{'new1'} eq $in{'new2'} || &pass_error($text{'password_enew2'});
21 # Use PAM to make the change..
22 eval "use Authen::PAM;";
24 &pass_error(&text('password_emodpam', $@));
27 # Check if the old password is correct
28 $service = $miniserv{'pam'} ? $miniserv{'pam'} : "webmin";
29 $pamh = new Authen::PAM($service, $in{'user'}, \&pam_check_func);
30 $rv = $pamh->pam_authenticate();
31 $rv == PAM_SUCCESS() ||
32 &pass_error($text{'password_eold'});
35 # Change the password with PAM, in a sub-process. This is needed because
36 # the UID must be changed to properly signal to the PAM libraries that
37 # the password change is not being done by the root user.
40 @uinfo = getpwnam($in{'user'});
42 ($>, $<) = (0, $uinfo[2]);
43 $pamh = new Authen::PAM("passwd", $in{'user'}, \&pam_change_func);
44 $rv = $pamh->pam_chauthtok();
47 print TEMP ($messages || $pamh->pam_strerror($rv)),"\n";
54 chop($messages = <TEMP>);
57 $rv == PAM_SUCCESS || &pass_error(&text('password_epam', $messages));
61 # Directly update password file
63 # Read shadow file and find user
64 &lock_file($miniserv{'passwd_file'});
65 $lref = &read_file_lines($miniserv{'passwd_file'});
66 for($i=0; $i<@$lref; $i++) {
67 @line = split(/:/, $lref->[$i], -1);
68 local $u = $line[$miniserv{'passwd_uindex'}];
69 if ($u eq $in{'user'}) {
74 defined($idx) || &pass_error($text{'password_euser'});
76 # Validate old password
77 &unix_crypt($in{'old'}, $line[$miniserv{'passwd_pindex'}]) eq
78 $line[$miniserv{'passwd_pindex'}] ||
79 &pass_error($text{'password_eold'});
81 # Make sure new password meets restrictions
82 if (&foreign_check("changepass")) {
83 &foreign_require("changepass", "changepass-lib.pl");
84 $err = &changepass::check_password($in{'new1'}, $in{'user'});
85 &pass_error($err) if ($err);
87 elsif (&foreign_check("useradmin")) {
88 &foreign_require("useradmin", "user-lib.pl");
89 $err = &useradmin::check_password_restrictions(
90 $in{'new1'}, $in{'user'});
91 &pass_error($err) if ($err);
94 # Set new password and save file
95 $salt = chr(int(rand(26))+65) . chr(int(rand(26))+65);
96 $line[$miniserv{'passwd_pindex'}] = &unix_crypt($in{'new1'}, $salt);
97 $days = int(time()/(24*60*60));
98 $line[$miniserv{'passwd_cindex'}] = $days;
99 $lref->[$idx] = join(":", @line);
101 &unlock_file($miniserv{'passwd_file'});
105 &header(undef, undef, undef, undef, 1, 1);
107 print "<center><h3>",&text('password_done', "/"),"</h3></center>\n";
113 &header(undef, undef, undef, undef, 1, 1);
116 print "<center><h3>",$text{'password_err'}," : ",@_,"</h3></center>\n";
131 $ans = $in{'user'} if ($code == PAM_PROMPT_ECHO_ON());
132 $ans = $in{'old'} if ($code == PAM_PROMPT_ECHO_OFF());
134 push @res, PAM_SUCCESS();
137 push @res, PAM_SUCCESS();
150 if ($code == PAM_PROMPT_ECHO_ON()) {
151 # Assume asking for username
152 push @res, PAM_SUCCESS();
153 push @res, $in{'user'};
155 elsif ($code == PAM_PROMPT_ECHO_OFF()) {
156 # Assume asking for a password (old first, then new)
157 push @res, PAM_SUCCESS();
158 if ($msg =~ /old|current/i) {
159 push @res, $in{'old'};
162 push @res, $in{'new1'};
166 # Some message .. ignore it
167 push @res, PAM_SUCCESS();
171 push @res, PAM_SUCCESS();