Skip to content

Commit

Permalink
Completed password change lockout function
Browse files Browse the repository at this point in the history
  • Loading branch information
jcameron committed Sep 13, 2007
1 parent aaaef03 commit 446c733
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 7 deletions.
5 changes: 5 additions & 0 deletions acl/edit_pass.cgi
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ print &ui_table_row($text{'pass_maxdays'},
&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'}));
Expand Down
2 changes: 2 additions & 0 deletions acl/lang/en
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ pass_minsize=Minimum password length
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?
Expand All @@ -348,6 +349,7 @@ pass_pass=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
Expand Down
7 changes: 7 additions & 0 deletions acl/save_pass.cgi
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ else {
$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'}) {
Expand Down
25 changes: 23 additions & 2 deletions miniserv.pl
Original file line number Diff line number Diff line change
Expand Up @@ -2899,8 +2899,27 @@ sub validate_user
}
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
Expand Down Expand Up @@ -3842,6 +3861,7 @@ sub read_users_file
undef(%deny);
undef(%allowdays);
undef(%allowhours);
undef(%lastchanges);
if ($config{'userfile'}) {
open(USERS, $config{'userfile'});
while(<USERS>) {
Expand All @@ -3865,6 +3885,7 @@ sub read_users_file
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);
}
Expand Down
35 changes: 30 additions & 5 deletions password_change.cgi
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,41 @@ require './web-lib.pl';
&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 ($@) {
Expand Down

0 comments on commit 446c733

Please sign in to comment.