&ui_opt_textbox("maxdays", $miniserv{'pass_maxdays'}, 5,
$text{'pass_nomaxdays'})." ".$text{'pass_days'});
+# Days before lockout
+print &ui_table_row($text{'pass_lockdays'},
+ &ui_opt_textbox("lockdays", $miniserv{'pass_lockdays'}, 5,
+ $text{'pass_nolockdays'})." ".$text{'pass_days'});
+
# Disallow use of username
print &ui_table_row($text{'pass_nouser'},
&ui_yesno_radio("nouser", $miniserv{'pass_nouser'}));
pass_nominsize=No minimum
pass_regexps=Regular expressions passwords must match
pass_maxdays=Days before password must be changed
+pass_lockdays=Days before un-changed password locks account
pass_nomaxdays=Change never required
pass_nouser=Disallow passwords containing username?
pass_nodict=Disallow dictionary word passwords?
pass_err=Failed to save password restrictions
pass_eminsize=Missing or non-numeric minimum password length
pass_emaxdays=Missing or non-numeric number of days before changing
+pass_elockdays=Missing or non-numeric number of days before account is locked
pass_eoldblock=Missing or non-numeric number of old passwords to reject
cpass_minsize=Must be at least $1 letters long
$in{'maxdays'} =~ /^\d+$/ || &error($text{'pass_emaxdays'});
$miniserv{'pass_maxdays'} = $in{'maxdays'};
}
+if ($in{'lockdays_def'}) {
+ delete($miniserv{'pass_lockdays'});
+ }
+else {
+ $in{'lockdays'} =~ /^\d+$/ || &error($text{'pass_elockdays'});
+ $miniserv{'pass_lockdays'} = $in{'lockdays'};
+ }
$miniserv{'pass_nouser'} = $in{'nouser'};
$miniserv{'pass_nodict'} = $in{'nodict'};
if ($in{'oldblock_def'}) {
}
elsif ($canmode == 1) {
# Attempt Webmin authentication
- return $users{$webminuser} eq &unix_crypt($pass, $users{$webminuser}) ?
- ( $user, 0, 0 ) : ( undef, 0, 0 );
+ if ($users{$webminuser} eq &unix_crypt($pass, $users{$webminuser})) {
+ # Password is valid .. but check for expiry
+ local $lc = $lastchanges{$user};
+ if ($config{'pass_maxdays'} && $lc) {
+ local $daysold = (time() - $lc)/(24*60*60);
+ print DEBUG "maxdays=$config{'pass_maxdays'} daysold=$daysold\n";
+ if ($config{'pass_lockdays'} &&
+ $daysold > $config{'pass_lockdays'}) {
+ # So old that the account is locked
+ return ( undef, 0, 0 );
+ }
+ elsif ($daysold > $config{'pass_maxdays'}) {
+ # Password has expired
+ return ( $user, 1, 0 );
+ }
+ }
+ return ( $user, 0, 0 );
+ }
+ else {
+ return ( undef, 0, 0 );
+ }
}
elsif ($canmode == 2 || $canmode == 3) {
# Attempt PAM or passwd file authentication
undef(%deny);
undef(%allowdays);
undef(%allowhours);
+undef(%lastchanges);
if ($config{'userfile'}) {
open(USERS, $config{'userfile'});
while(<USERS>) {
if ($user[5] =~ /hours\s+(\d+)\.(\d+)-(\d+).(\d+)/) {
$allowhours{$user[0]} = [ $1*60+$2, $3*60+$4 ];
}
+ $lastchanges{$user[0]} = $user[6];
}
close(USERS);
}
&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'});
+ &acl::modify_user($wuser->{'name'}, $wuser);
+ &reload_miniserv();
+ }
+elsif ($in{'pam'}) {
# Use PAM to make the change..
eval "use Authen::PAM;";
if ($@) {