Fix to clarify Unix authentication mapping behavior

https://github.com/webmin/webmin/issues/2791
This commit is contained in:
Ilia Ross
2026-07-14 12:46:15 +02:00
parent ed3cd51e40
commit 18a4d6a6df
4 changed files with 61 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
#!/usr/local/bin/perl
# edit_unix.cgi
# Choose a user whose permissions will be used for logins that don't
# match any webmin user, but have unix accounts
# Map Unix users that do not have Webmin accounts to a Webmin user whose
# access rights and authentication method will be used for their logins.
use strict;
use warnings;
@@ -20,7 +20,7 @@ my %miniserv;
print &ui_form_start("save_unix.cgi", "post");
print &ui_table_start($text{'unix_header'}, undef, 2);
# Enable Unix auth
# Configure Unix login mappings
my @unixauth = &get_unixauth(\%miniserv);
my $utable = "";
$utable .= &ui_radio("unix_def", @unixauth ? 0 : 1,
@@ -28,8 +28,13 @@ $utable .= &ui_radio("unix_def", @unixauth ? 0 : 1,
$utable .= &ui_columns_start([ $text{'unix_mode'}, $text{'unix_who'},
$text{'unix_to'} ]);
my $i = 0;
my @webmins = map { [ $_->{'name'} ] }
sort { $a->{'name'} cmp $b->{'name'} } &list_users();
my @webmins = map {
my $auth = $_->{'pass'} eq 'x' ? $text{'edit_unix'} :
$_->{'pass'} eq 'e' ? $text{'edit_extauth'} :
$_->{'pass'} eq '*LK*' || $_->{'pass'} =~ /^!/ ?
$text{'edit_lock'} : $text{'unix_webminpass'};
[ $_->{'name'}, "$_->{'name'} ($auth)" ]
} sort { $a->{'name'} cmp $b->{'name'} } &list_users();
foreach my $ua (@unixauth, [ ], [ ]) {
$utable .= &ui_columns_row([
&ui_select("mode_$i", !defined($ua->[0]) ? 0 :
@@ -47,6 +52,7 @@ foreach my $ua (@unixauth, [ ], [ ]) {
$i++;
}
$utable .= &ui_columns_end();
$utable .= "<p>".&ui_note($text{'unix_mapdesc'}, 0)."</p>\n";
print &ui_table_row($text{'unix_utable'}, $utable);
# Allow users who can sudo to root?
@@ -88,4 +94,3 @@ print &ui_table_end();
print &ui_form_end([ [ undef, $text{'save'} ] ]);
&ui_print_footer("", $text{'index_return'});

View File

@@ -316,15 +316,17 @@ sync_ecannot=You are not allowed to configure user synchronization.
unix_title=Unix User Authentication
unix_err=Failed to save Unix authentication
unix_desc=This page allows you to configure Webmin to validate login attempts against the system user list and PAM. This can be useful if you have a large number of existing Unix users who you want to give access to Webmin.
unix_def=Only allow Webmin users to login
unix_sel=Allow Unix users listed below to login ..
unix_desc=This page allows Unix and directory-backed users, as well as PAM-only users, to log in without creating a separate Webmin account for each user. Each login receives the access rights and uses the authentication method of the mapped Webmin user.
unix_def=Only allow Webmin users to log in
unix_sel=Allow the users and groups mapped below to log in
unix_mode=Allow
unix_mall=All users
unix_group=Members of group..
unix_user=Unix user ..
unix_group=Members of group
unix_user=Unix user
unix_who=User or Group
unix_to=As Webmin user
unix_to=Webmin user access and authentication
unix_mapdesc=The selected Webmin user supplies both access rights and the authentication method. To authenticate the original username through PAM, SSSD, or the system password database, select a Webmin user configured for <b>Unix authentication</b>. If the selected user has a Webmin password, every matching login uses that shared password instead.
unix_webminpass=Webmin password
unix_ecannot=You are not allowed to configure Unix user authentication
unix_epam=Unix authentication is not available as the <tt>Authen::PAM</tt> Perl module is not installed or not working properly.
unix_all=Allow all Unix users
@@ -345,7 +347,7 @@ unix_pamany=Treat logins that only pass PAM validation as $1
unix_esudo=The $1 command is not installed
unix_esudomod=The Perl module $1 needed for <tt>sudo</tt> authentication is not installed
unix_header=Unix user authentication settings
unix_utable=Allowed Unix users
unix_utable=Login mappings
sessions_title=Current Login Sessions
sessions_id=Session ID

View File

@@ -1179,6 +1179,34 @@ is(group_line({ name => 'empty' }),
# writing <confdir>/acl/<user>.acl, seeds whatever miniserv-user state the CGI
# needs, runs the CGI as a subprocess, and asserts on what the caller sees.
# edit_unix.cgi should make the authentication method inherited from each
# mapped Webmin user visible without changing the submitted username value.
subtest 'edit_unix.cgi authentication labels' => sub {
_reset_fixture();
_seed_user_acl('admin', { unix => 1, create => 1, delete => 1 });
create_user({ name => 'external-user', pass => 'e', modules => ['acl'] });
create_user({ name => 'locked-user', pass => '*LK*', modules => ['acl'] });
create_user({ name => 'pam-user', pass => 'x', modules => ['acl'] });
create_user({ name => 'webmin-user', pass => 'fixed', modules => ['acl'] });
my $r = run_cgi('edit_unix.cgi', {});
is($r->{status}, 0, 'mapping page renders successfully');
like($r->{out},
qr/value="pam-user"[^>]*>pam-user \(Unix authentication\)/,
'Unix authentication target is labeled');
like($r->{out},
qr/value="external-user"[^>]*>external-user \(External authentication program\)/,
'external authentication target is labeled');
like($r->{out},
qr/value="locked-user"[^>]*>locked-user \(No password accepted\)/,
'locked target is labeled');
like($r->{out},
qr/value="webmin-user"[^>]*>webmin-user \(Webmin password\)/,
'fixed Webmin password target is labeled');
like($r->{out}, qr/every matching login uses that shared password/,
'mapping authentication behavior is explained');
};
# Harness sanity: a CGI with no privileges should reject any action and
# print an HTML error (not a redirect). switch.cgi is the smallest victim.
subtest 'CGI harness smoke' => sub {

View File

@@ -2581,7 +2581,8 @@ elsif ($canmode == 0) {
return ( $canuser, 0, 0, $webminuser );
}
elsif ($canmode == 1) {
# Attempt Webmin authentication
# Attempt Webmin authentication. For a unixauth mapping, this checks
# the fixed password of the mapped Webmin user.
my $uinfo = &get_user_details($webminuser, $canuser);
if ($uinfo &&
&password_crypt($pass, $uinfo->{'pass'}) eq $uinfo->{'pass'}) {
@@ -2774,14 +2775,17 @@ return $resp =~ /^OK/i ? 1 : 0;
# Second is 0 if cannot login, 1 if using Webmin pass, 2 if PAM, 3 if password
# file, 4 if external.
# Third is 1 if the user does not exist at all, 0 if he does.
# Fourth is the Webmin username whose permissions apply, based on unixauth.
# Fourth is the Webmin username whose permissions apply. For a unixauth
# mapping, its password setting also selects the authentication method.
# Fifth is a flag indicating if a sudo check is needed.
sub can_user_login
{
local $uinfo = &get_user_details($_[0]);
if (!$uinfo) {
# See if this user exists in Unix and can be validated by the same
# method as the unixauth webmin user
# See if this user exists in Unix and can use the authentication method
# configured for the mapped Webmin user. The original username is passed
# to PAM, the password file, or the external authentication program; the
# mapped Webmin user supplies the access rights.
local $realuser = $unixauth{$_[0]};
local @uinfo;
local $sudo = 0;
@@ -2821,6 +2825,8 @@ if (!$uinfo) {
return (undef, 0, 1, undef) if (!$realuser);
local $uinfo = &get_user_details($realuser);
return (undef, 0, 1, undef) if (!$uinfo);
# The mapped user's password setting selects how the original username
# will be authenticated.
local $up = $uinfo->{'pass'};
# Work out possible domain names from the hostname
@@ -2920,17 +2926,17 @@ if (!$uinfo) {
}
if ($up eq 'x') {
# PAM or passwd file authentication
# Authenticate the original username through PAM or the password file
print DEBUG "can_user_login: Validate with PAM\n";
return ( $_[0], $use_pam ? 2 : 3, 0, $realuser, $sudo );
}
elsif ($up eq 'e') {
# External authentication
# Authenticate the original username externally
print DEBUG "can_user_login: Validate externally\n";
return ( $_[0], 4, 0, $realuser, $sudo );
}
else {
# Fixed Webmin password
# Authenticate against the fixed password of the mapped Webmin user
print DEBUG "can_user_login: Validate by Webmin\n";
return ( $_[0], 1, 0, $realuser, $sudo );
}