Support for temporary passwords which must be changed at the next login

This commit is contained in:
Jamie Cameron
2008-03-20 17:51:05 +00:00
parent 3eb6a234bd
commit ee997485ff
8 changed files with 62 additions and 32 deletions

View File

@@ -46,3 +46,4 @@ Updated the user interface to use the Webmin UI library.
Fixed the display of modules granted to groups.
Added a per-user option to opt out of forced password changes after a certain number of days.
A human-readable description of the password restrictions regular expression can be entered, for use in error messages.
Webmin users can now be given temporary passwords, which they are forced to change at the next login.

View File

@@ -43,6 +43,7 @@ while(<PWFILE>) {
$user{'olds'} = [ split(/\s+/, $user[7]) ];
$user{'minsize'} = $user[8];
$user{'nochange'} = int($user[9]);
$user{'temppass'} = int($user[10]);
$user{'modules'} = $acl{$user[0]};
$user{'lang'} = $gconfig{"lang_$user[0]"};
$user{'notabs'} = $gconfig{"notabs_$user[0]"};
@@ -135,7 +136,8 @@ push(@times, "hours", $user{'hoursfrom'}."-".$user{'hoursto'})
$user{'lastchange'},":",
join(" ", @{$user{'olds'}}),":",
$user{'minsize'},":",
$user{'nochange'},
$user{'nochange'},":",
$user{'temppass'},
"\n");
&close_tempfile(PWFILE);
&unlock_file($miniserv{'userfile'});
@@ -238,7 +240,8 @@ foreach (@pwfile) {
$user{'lastchange'},":",
join(" ", @{$user{'olds'}}),":",
$user{'minsize'},":",
$user{'nochange'},
$user{'nochange'},":",
$user{'temppass'},
"\n");
}
else {

View File

@@ -114,6 +114,10 @@ if ($passmode == 1) {
$lockbox = &ui_checkbox("lock", 1, $text{'edit_templock'},
$user{'pass'} =~ /^\!/ ? 1 : 0);
}
if ($passmode != 3 && $passmode != 4) {
$tempbox = &ui_checkbox("temp", 1, $text{'edit_temppass'},
$user{'temppass'});
}
if ($user{'lastchange'} && $miniserv{'pass_maxdays'}) {
$daysold = int((time() - $user{'lastchange'})/(24*60*60));
if ($miniserv{'pass_lockdays'} &&
@@ -134,7 +138,8 @@ if ($user{'lastchange'} && $miniserv{'pass_maxdays'}) {
}
print &ui_table_row($text{'edit_pass'},
&ui_select("pass_def", $passmode, \@opts)." ".
&ui_password("pass", undef, 25).$lockbox.$expmsg);
&ui_password("pass", undef, 25).
($lockbox || $tempbox ? "<br>" : "").$lockbox.$tempbox.$expmsg);
# Real name
print &ui_table_row($text{'edit_real'},

View File

@@ -83,6 +83,7 @@ edit_rbacdeny0=RBAC only controls selected module ACLs
edit_rbacdeny1=RBAC controls all modules and ACLs
edit_special=Special
edit_templock=Temporarily locked
edit_temppass=Force change at next login
edit_days=Allowed days of the week
edit_alldays=Every day
edit_seldays=Only selected days ..

View File

@@ -232,8 +232,11 @@ if ($in{'pass_def'} == 0) {
$in{'pass'} =~ /:/ && &error($text{'save_ecolon'});
$user{'pass'} = &encrypt_password($in{'pass'});
$user{'sync'} = 0;
$perr = &check_password_restrictions($in{'name'}, $in{'pass'});
$perr && &error(&text('save_epass', $perr));
if (!$in{'temp'}) {
# Check password quality, unless this is a temp password
$perr = &check_password_restrictions($in{'name'}, $in{'pass'});
$perr && &error(&text('save_epass', $perr));
}
}
elsif ($in{'pass_def'} == 1) {
# No change in password
@@ -304,6 +307,9 @@ elsif ($in{'lock'} && $user{'pass'} !~ /^\!/ && $in{'pass_def'} <= 1) {
$user{'pass'} = "!".$user{'pass'};
}
# Check for force change
$user{'temppass'} = $in{'temp'};
if ($in{'old'}) {
# update user and all ACLs
&modify_user($in{'old'}, \%user);

View File

@@ -2944,7 +2944,7 @@ sub urlize {
# validate_user(username, password, host)
# Checks if some username and password are valid. Returns the modified username,
# the expired flag, and the non-existence flag
# the expired / temp pass flag, and the non-existence flag
sub validate_user
{
local ($user, $pass, $host) = @_;
@@ -2978,6 +2978,10 @@ elsif ($canmode == 1) {
# Password has expired
return ( $user, 1, 0 );
}
elsif ($temppass{$user}) {
# Temporary password - force change now
return ( $user, 2, 0 );
}
}
return ( $user, 0, 0 );
}
@@ -3522,13 +3526,14 @@ if ($ok && (!$expired ||
return 0;
}
elsif ($ok && $expired &&
$config{'passwd_mode'} == 2) {
# Login was ok, but password has expired. Need
($config{'passwd_mode'} == 2 || $expired == 2)) {
# Login was ok, but password has expired or was temporary. Need
# to force display of password change form.
$validated = 1;
$authuser = undef;
$querystring = "&user=".&urlize($vu).
"&pam=".$use_pam;
"&pam=".$use_pam.
"&expired=".$expired;
$method = "GET";
$queryargs = "";
$page = $config{'password_form'};
@@ -3928,6 +3933,7 @@ undef(%allowdays);
undef(%allowhours);
undef(%lastchanges);
undef(%nochange);
undef(%temppass);
if ($config{'userfile'}) {
open(USERS, $config{'userfile'});
while(<USERS>) {
@@ -3953,6 +3959,7 @@ if ($config{'userfile'}) {
}
$lastchanges{$user[0]} = $user[6];
$nochange{$user[0]} = $user[9];
$temppass{$user[0]} = $user[10];
}
close(USERS);
}

View File

@@ -39,6 +39,7 @@ if ($wuser) {
$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();
}

View File

@@ -5,39 +5,45 @@
$ENV{'MINISERV_INTERNAL'} || die "Can only be called by miniserv.pl";
require './web-lib.pl';
&init_config();
require './ui-lib.pl';
&ReadParse();
&header(undef, undef, undef, undef, 1, 1);
print "<center>\n";
print "<h3>$text{'password_expired'}</h3><p>\n";
if ($in{'expired'} == 2) {
print &ui_subheading($text{'password_temp'});
}
else {
print &ui_subheading($text{'password_expired'});
}
# Start of the form
print "$text{'password_prefix'}\n";
print "<form action=$gconfig{'webprefix'}/password_change.cgi method=post>\n";
print "<input type=hidden name=user value='",&html_escape($in{'user'}),"'>\n";
print "<input type=hidden name=pam value='",&html_escape($in{'pam'}),"'>\n";
print &ui_form_start("$gconfig{'webprefix'}/password_change.cgi", "post");
print &ui_hidden("user", $in{'user'});
print &ui_hidden("pam", $in{'pam'});
print &ui_hidden("expired", $in{'expired'});
print &ui_table_start($text{'password_header'}, "width=50% style='width:50%'", 2);
print "<table border width=40%>\n";
print "<tr $tb> <td><b>$text{'password_header'}</b></td> </tr>\n";
print "<tr $cb> <td align=center><table cellpadding=3>\n";
# Current username
print &ui_table_row($text{'password_user'},
&html_escape($in{'user'}));
print "<tr> <td><b>$text{'password_user'}</b></td>\n";
print "<td><tt>",&html_escape($in{'user'}),"</tt></td> </tr>\n";
# Old password
print &ui_table_row($text{'password_old'},
&ui_password("old", undef, 20));
print "<tr> <td><b>$text{'password_old'}</b></td>\n";
print "<td><input name=old size=20 type=password></td> </tr>\n";
# New password, twice
print &ui_table_row($text{'password_new1'},
&ui_password("new1", undef, 20));
print &ui_table_row($text{'password_new2'},
&ui_password("new2", undef, 20));
print "<tr> <td><b>$text{'password_new1'}</b></td>\n";
print "<td><input name=new1 size=20 type=password></td> </tr>\n";
print "<tr> <td><b>$text{'password_new2'}</b></td>\n";
print "<td><input name=new2 size=20 type=password></td> </tr>\n";
print "<tr> <td colspan=2 align=center><input type=submit ",
"value='$text{'password_ok'}'>\n";
print "<input type=reset value='$text{'password_clear'}'><br>\n";
print "</td> </tr>\n";
print "</table></td></tr></table><p>\n";
print "<hr>\n";
print "</form></center>\n";
# End of form
print &ui_table_end();
print &ui_form_end([ [ undef, $text{'password_ok'} ] ]);
print "</center>\n";
print "$text{'password_postfix'}\n";
&footer();