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.
$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]"};
$user{'lastchange'},":",
join(" ", @{$user{'olds'}}),":",
$user{'minsize'},":",
- $user{'nochange'},
+ $user{'nochange'},":",
+ $user{'temppass'},
"\n");
&close_tempfile(PWFILE);
&unlock_file($miniserv{'userfile'});
$user{'lastchange'},":",
join(" ", @{$user{'olds'}}),":",
$user{'minsize'},":",
- $user{'nochange'},
+ $user{'nochange'},":",
+ $user{'temppass'},
"\n");
}
else {
$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'} &&
}
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'},
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 ..
$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
$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);
# 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) = @_;
# Password has expired
return ( $user, 1, 0 );
}
+ elsif ($temppass{$user}) {
+ # Temporary password - force change now
+ return ( $user, 2, 0 );
+ }
}
return ( $user, 0, 0 );
}
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'};
undef(%allowhours);
undef(%lastchanges);
undef(%nochange);
+undef(%temppass);
if ($config{'userfile'}) {
open(USERS, $config{'userfile'});
while(<USERS>) {
}
$lastchanges{$user[0]} = $user[6];
$nochange{$user[0]} = $user[9];
+ $temppass{$user[0]} = $user[10];
}
close(USERS);
}
$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();
}
$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 "<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";
-
-print "<tr> <td><b>$text{'password_user'}</b></td>\n";
-print "<td><tt>",&html_escape($in{'user'}),"</tt></td> </tr>\n";
-
-print "<tr> <td><b>$text{'password_old'}</b></td>\n";
-print "<td><input name=old size=20 type=password></td> </tr>\n";
-
-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";
+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);
+
+# Current username
+print &ui_table_row($text{'password_user'},
+ &html_escape($in{'user'}));
+
+# Old password
+print &ui_table_row($text{'password_old'},
+ &ui_password("old", undef, 20));
+
+# 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));
+
+# End of form
+print &ui_table_end();
+print &ui_form_end([ [ undef, $text{'password_ok'} ] ]);
+print "</center>\n";
print "$text{'password_postfix'}\n";
+
&footer();