Add new password restriction for min days before a change is allowed

This commit is contained in:
Jamie Cameron
2012-03-29 22:37:37 -07:00
parent c4fd066374
commit 74ea1f9da8
8 changed files with 54 additions and 18 deletions

View File

@@ -246,7 +246,7 @@ else {
# Password is blank
if (!$mconfig{'empty_mode'}) {
local $err = &useradmin::check_password_restrictions(
"", $user);
"", $user, $in{'new'} ? 'none' : \%ouser);
&error($err) if ($err);
}
$pass = "";
@@ -263,7 +263,8 @@ else {
elsif ($in{'passmode'} == 3) {
# Normal password entered - check restrictions
local $err = &useradmin::check_password_restrictions(
$in{'pass'}, $user);
$in{'pass'}, $user,
$in{'new'} ? 'none' : \%ouser);
&error($err) if ($err);
$pass = $pfx.&encrypt_password($in{'pass'});
$plainpass = $in{'pass'};

View File

@@ -46,7 +46,7 @@ $again =~ s/\r|\n//g;
$pass eq $again || &errordie("Passwords don't match");
# Check password sanity
$err = &useradmin::check_password_restrictions($pass, $ARGV[0]);
$err = &useradmin::check_password_restrictions($pass, $ARGV[0], $user);
&errordie($err) if ($err);
# Do the change!

View File

@@ -68,7 +68,7 @@ else {
$in{'new'} eq $in{'repeat'} || &error($text{'passwd_erepeat'});
}
$err = &useradmin::check_password_restrictions(
$in{'new'}, $in{'user'});
$in{'new'}, $in{'user'}, $user);
&error($err) if ($err);
&can_edit_passwd([ $user->{'user'}, $user->{'pass'},

View File

@@ -69,3 +69,5 @@ Fixed an XSS vulnerability that can be triggered if an attacker has the ability
---- Changes since 1.550 ----
Updated all links to users and groups to be by name instead of by index, to avoid incorrect links if the passwd or group files are changed manually or by another Webmin session.
The faster lastlog command is now used to get the most recent login time on Linux, for display in the user list.
---- Changes since 1.580 ----
Added a new password restriction for the minimum number of days before a password can be changed.

View File

@@ -54,6 +54,7 @@ passwd_re=Perl regexp to check password against,3,None
passwd_same=Prevent passwords containing username?,1,1-Yes,0-No
passwd_prog=External password-checking program,3,None
passwd_progmode=Pass username and password to program,1,1-As input,0-As parameters
passwd_mindays=Number of days before password change is allowed,3,None
line0=Before and after commands,11
pre_command=Command to run before making changes,0

View File

@@ -176,6 +176,7 @@ usave_epasswd_min=Password must be at least $1 letters long
usave_epasswd_re=Password does not match regexp $1
usave_epasswd_dict=Password is a dictionary word
usave_epasswd_same=Password contains or is the same as username
usave_epasswd_mindays=Password was changed less than $1 days ago
usave_eothers=The user was successfully saved, but an error occured in another module : $1
gedit_title=Edit Group

View File

@@ -282,7 +282,8 @@ if ($access{'ugroups'} ne "*") {
if ($in{'passmode'} == 0) {
# Password is blank
if (!$config{'empty_mode'}) {
local $err = &check_password_restrictions("", $user{'user'});
local $err = &check_password_restrictions("", $user{'user'},
$in{'old'} eq '' ? 'none' : \%ouser);
&error($err) if ($err);
}
$user{'pass'} = "";
@@ -297,7 +298,8 @@ elsif ($in{'passmode'} == 2) {
}
elsif ($in{'passmode'} == 3) {
# Normal password entered - check restrictions
local $err = &check_password_restrictions($in{'pass'}, $user{'user'});
local $err = &check_password_restrictions($in{'pass'}, $user{'user'},
$in{'old'} eq '' ? 'none' : \%ouser);
&error($err) if ($err);
$user{'pass'} = &encrypt_password($in{'pass'});
}

View File

@@ -1502,7 +1502,7 @@ foreach my $k (keys %group_properties_map) {
}
}
=head2 check_password_restrictions(pass, username)
=head2 check_password_restrictions(pass, username, [&user-hash|"none"])
Returns an error message if the given password fails length and other
checks, or undef if it is OK.
@@ -1510,20 +1510,21 @@ checks, or undef if it is OK.
=cut
sub check_password_restrictions
{
local ($pass, $username, $uinfo) = @_;
return &text('usave_epasswd_min', $config{'passwd_min'})
if (length($_[0]) < $config{'passwd_min'});
if (length($pass) < $config{'passwd_min'});
local $re = $config{'passwd_re'};
return &text('usave_epasswd_re', $re)
if ($re && !eval { $_[0] =~ /^$re$/ });
if ($re && !eval { $pass =~ /^$re$/ });
if ($config{'passwd_same'}) {
return &text('usave_epasswd_same') if ($_[0] =~ /\Q$_[1]\E/i);
return &text('usave_epasswd_same') if ($pass =~ /\Q$username\E/i);
}
if ($config{'passwd_dict'} && $_[0] =~ /^[A-Za-z\'\-]+$/ &&
if ($config{'passwd_dict'} && $pass =~ /^[A-Za-z\'\-]+$/ &&
(&has_command("ispell") || &has_command("spell"))) {
# Call spell or ispell to check for dictionary words
local $temp = &transname();
open(TEMP, ">$temp");
print TEMP $_[0],"\n";
print TEMP $pass,"\n";
close(TEMP);
if (&has_command("ispell")) {
open(SPELL, "ispell -a <$temp |");
@@ -1547,8 +1548,8 @@ if ($config{'passwd_prog'}) {
local $out;
if ($config{'passwd_progmode'} == 0) {
# Run external validation program with user and password as args
local $qu = quotemeta($_[1]);
local $qp = quotemeta($_[0]);
local $qu = quotemeta($username);
local $qp = quotemeta($pass);
$out = &backquote_command(
"$config{'passwd_prog'} $qu $qp 2>&1 </dev/null");
}
@@ -1556,8 +1557,8 @@ if ($config{'passwd_prog'}) {
# Run program with password as input on stdin
local $temp = &transname();
&open_tempfile(TEMP, ">$temp", 0, 1);
&print_tempfile(TEMP, $_[1],"\n");
&print_tempfile(TEMP, $_[0],"\n");
&print_tempfile(TEMP, $username,"\n");
&print_tempfile(TEMP, $pass,"\n");
&close_tempfile(TEMP);
$out = &backquote_command("$config{'passwd_prog'} <$temp 2>&1");
}
@@ -1565,6 +1566,33 @@ if ($config{'passwd_prog'}) {
return $out;
}
}
if ($config{'passwd_mindays'} && $uinfo ne "none") {
# Check if password was changed too recently
if (!$uinfo) {
($uinfo) = grep { $_->{'user'} eq $username } &list_users();
}
if ($uinfo) {
local $pft = &passfiles_type();
local $when;
if ($pft == 1 || $pft == 6) {
# BSD (unix time)
$when = $uinfo->{'change'};
}
elsif ($pft == 2 || $pft == 5) {
# Linux (number of days)
$when = $uinfo->{'change'} * 24*60*60;
}
elsif ($pft == 4) {
# AIX (unix time)
$when = $uinfo->{'change'};
}
if ($when && time() - $when <
$config{'passwd_mindays'}*24*60*60) {
return &text('usave_epasswd_mindays',
$config{'passwd_mindays'});
}
}
}
return undef;
}
@@ -1576,12 +1604,13 @@ it is OK.
=cut
sub check_username_restrictions
{
if ($config{'max_length'} && length($_[0]) > $config{'max_length'}) {
local ($username) = @_;
if ($config{'max_length'} && length($username) > $config{'max_length'}) {
return &text('usave_elength', $config{'max_length'});
}
local $re = $config{'username_re'};
return &text('usave_ere', $re)
if ($re && !eval { $_[0] =~ /^$re$/ });
if ($re && !eval { $username =~ /^$re$/ });
return undef;
}