diff --git a/acl/acl-lib.pl b/acl/acl-lib.pl index a5781af6f..55bc99a81 100755 --- a/acl/acl-lib.pl +++ b/acl/acl-lib.pl @@ -11,8 +11,6 @@ Library for editing webmin users, passwords and access rights. =cut -# XXX make read_acl faster when we only care about one user - BEGIN { push(@INC, ".."); }; use WebminCore; &init_config(); diff --git a/acl/edit_sql.cgi b/acl/edit_sql.cgi index ef68ecde1..9dd9c85d2 100755 --- a/acl/edit_sql.cgi +++ b/acl/edit_sql.cgi @@ -74,7 +74,8 @@ push(@ldapgrid, &ui_textbox("ldap_groupclass", $proto eq "ldap" && $args->{'groupclass'} ? $args->{'groupclass'} : "webminGroup",30)); push(@ldapgrid, - &ui_submit($text{'sql_schema'}, 'schema'), ""); + &ui_button($text{'sql_schema'}, undef, 0, + "onClick='window.location=\"schema.cgi\"'"), ""); $ldapgrid = &ui_grid_table(\@ldapgrid, 2, 100); print &ui_table_row(undef, diff --git a/acl/save_sql.cgi b/acl/save_sql.cgi index 4fe7bc5e6..c51613303 100755 --- a/acl/save_sql.cgi +++ b/acl/save_sql.cgi @@ -8,12 +8,6 @@ $access{'pass'} || &error($text{'sql_ecannot'}); &error_setup($text{'sql_err'}); $p = $in{'proto'}; -if ($in{'schema'}) { - # Redirect to schema download page - &redirect("schema.cgi"); - return; - } - # Parse inputs if ($p eq 'mysql' || $p eq 'postgresql' || $p eq 'ldap') { gethostbyname($in{$p."_host"}) || diff --git a/miniserv.pl b/miniserv.pl index 21f4dec67..94e47f76c 100755 --- a/miniserv.pl +++ b/miniserv.pl @@ -3023,6 +3023,7 @@ elsif ($canmode == 1) { if ($uinfo && &password_crypt($pass, $uinfo->{'pass'})) { # Password is valid .. but check for expiry local $lc = $uinfo->{'lastchanges'}; + print DEBUG "validate_user: Password is valid lc=$lc pass_maxdays=$config{'pass_maxdays'}\n"; if ($config{'pass_maxdays'} && $lc && !$uinfo->{'nochange'}) { local $daysold = (time() - $lc)/(24*60*60); print DEBUG "maxdays=$config{'pass_maxdays'} daysold=$daysold temppass=$uinfo->{'temppass'}\n"; @@ -3042,7 +3043,12 @@ elsif ($canmode == 1) { } return ( $user, 0, 0 ); } + elsif (!$uinfo) { + print DEBUG "validate_user: User $webminuser not found\n"; + return ( undef, 0, 0 ); + } else { + print DEBUG "validate_user: User $webminuser password mismatch $pass != $uinfo->{'pass'}\n"; return ( undef, 0, 0 ); } } @@ -3536,10 +3542,12 @@ if ($header{'cookie'} !~ /testing=1/ && $vu && # check with main process for delay if ($config{'passdelay'} && $vu) { + print DEBUG "handle_login: requesting delay vu=$vu acptip=$acptip ok=$ok\n"; print $PASSINw "delay $vu $acptip $ok\n"; <$PASSOUTr> =~ /(\d+) (\d+)/; $blocked = $2; sleep($1); + print DEBUG "handle_login: delay=$1 blocked=$2\n"; } if ($ok && (!$expired || @@ -3547,6 +3555,7 @@ if ($ok && (!$expired || # Logged in OK! Tell the main process about # the new SID local $sid = &generate_random_id($pass); + print DEBUG "handle_login: sid=$sid\n"; print $PASSINw "new $sid $authuser $acptip\n"; # Run the post-login script, if any @@ -3555,6 +3564,7 @@ if ($ok && (!$expired || # Check for a redirect URL for the user local $rurl = &login_redirect($authuser, $pass, $host); + print DEBUG "handle_login: redirect URL rurl=$rurl\n"; if ($rurl) { # Got one .. go to it &write_data("HTTP/1.0 302 Moved Temporarily\r\n"); @@ -4167,7 +4177,7 @@ if ($config{'userdb'}) { } # Extract attributes - my $pass = $u->get_value('pass'); + my $pass = $u->get_value('webminPass'); $user = { 'name' => $username, 'id' => $u->dn(), 'pass' => $pass, diff --git a/web-lib-funcs.pl b/web-lib-funcs.pl index f84281fa2..d48d69eb1 100755 --- a/web-lib-funcs.pl +++ b/web-lib-funcs.pl @@ -1689,7 +1689,7 @@ $rv .= "' value=\"...\">"; return $rv; } -=head2 read_acl(&user-module-hash, &user-list-hash) +=head2 read_acl(&user-module-hash, &user-list-hash, [&only-users]) Reads the Webmin acl file into the given hash references. The first is indexed by a combined key of username,module , with the value being set to 1 when @@ -1699,9 +1699,13 @@ the value being an array ref of allowed modules. This function is deprecated in favour of foreign_available, which performs a more comprehensive check of module availability. +If the only-users array ref parameter is given, the results may be limited to +users in that list of names. + =cut sub read_acl { +my ($usermod, $userlist, $only) = @_; if (!%main::acl_hash_cache) { # Read from local files local $_; @@ -1717,52 +1721,61 @@ if (!%main::acl_hash_cache) { } } close(ACL); - - # Read from user DB - my $userdb = &get_userdb_string(); - my ($dbh, $proto, $prefix, $args) = - $userdb ? &connect_userdb($userdb) : ( ); - if (ref($dbh)) { - if ($proto eq "mysql" || $proto eq "postgresql") { - # Select usernames and modules from SQL DB - my $cmd = $dbh->prepare("select webmin_user.name,webmin_user_attr.value from webmin_user,webmin_user_attr where webmin_user.id = webmin_user_attr.id and webmin_user_attr.attr = 'modules'"); - if ($cmd && $cmd->execute()) { - while(my ($user, $mods) = $cmd->fetchrow()) { - my @mods = split(/\s+/, $mods); - foreach my $m (@mods) { - $main::acl_hash_cache{$user, - $m}++; - } - $main::acl_array_cache{$user} = \@mods; - } - } - $cmd->finish() if ($cmd); - } - elsif ($proto eq "ldap") { - # Find users in LDAP - my $rv = $dbh->search( - base => $prefix, - filter => '(objectClass='. - $args->{'userclass'}.')', - scope => 'sub', - attrs => [ 'cn', 'webminModule' ]); - if ($rv && !$rv->code) { - foreach my $u ($rv->all_entries) { - my $user = $u->get_value('cn'); - my @mods =$u->get_value('webminModule'); - foreach my $m (@mods) { - $main::acl_hash_cache{$user, - $m}++; - } - $main::acl_array_cache{$user} = \@mods; - } - } - } - &disconnect_userdb($userdb, $dbh); - } } -if ($_[0]) { %{$_[0]} = %main::acl_hash_cache; } -if ($_[1]) { %{$_[1]} = %main::acl_array_cache; } +%$usermod = %main::acl_hash_cache if ($usermod); +%$userlist = %main::acl_array_cache if ($userlist); + +# Read from user DB +my $userdb = &get_userdb_string(); +my ($dbh, $proto, $prefix, $args) = + $userdb ? &connect_userdb($userdb) : ( ); +if (ref($dbh)) { + if ($proto eq "mysql" || $proto eq "postgresql") { + # Select usernames and modules from SQL DB + my $cmd = $dbh->prepare( + "select webmin_user.name,webmin_user_attr.value ". + "from webmin_user,webmin_user_attr ". + "where webmin_user.id = webmin_user_attr.id ". + "and webmin_user_attr.attr = 'modules' ". + ($only ? " and webmin_user.name in (". + join(",", map { "'$_'" } @$only).")" : "")); + if ($cmd && $cmd->execute()) { + while(my ($user, $mods) = $cmd->fetchrow()) { + my @mods = split(/\s+/, $mods); + foreach my $m (@mods) { + $usermod->{$user,$m}++ if ($usermod); + } + $userlist->{$user} = \@mods if ($userlist); + } + } + $cmd->finish() if ($cmd); + } + elsif ($proto eq "ldap") { + # Find users in LDAP + my $filter = '(objectClass='.$args->{'userclass'}.')'; + if ($only) { + my $ufilter = + "(|".join("", map { "(cn=$_)" } @$only).")"; + $filter = "(&".$filter.$ufilter.")"; + } + my $rv = $dbh->search( + base => $prefix, + filter => $filter, + scope => 'sub', + attrs => [ 'cn', 'webminModule' ]); + if ($rv && !$rv->code) { + foreach my $u ($rv->all_entries) { + my $user = $u->get_value('cn'); + my @mods =$u->get_value('webminModule'); + foreach my $m (@mods) { + $usermod->{$user,$m}++ if ($usermod); + } + $userlist->{$user} = \@mods if ($userlist); + } + } + } + &disconnect_userdb($userdb, $dbh); + } } =head2 acl_filename @@ -2952,7 +2965,7 @@ my %foreign_module_info = &get_module_info($_[0]); # Check list of allowed modules my %acl; -&read_acl(\%acl, undef); +&read_acl(\%acl, undef, [ $base_remote_user ]); return 0 if (!$acl{$base_remote_user,$_[0]} && !$acl{$base_remote_user,'*'}); @@ -6013,7 +6026,7 @@ if ($serv->{'fast'} || !$sn) { if ($base_remote_user ne 'root' && $base_remote_user ne 'admin') { # Need to fake up a login for the CGI! - &read_acl(undef, \%acl); + &read_acl(undef, \%acl, [ 'root' ]); $ENV{'BASE_REMOTE_USER'} = $ENV{'REMOTE_USER'} = $acl{'root'} ? 'root' : 'admin'; @@ -7152,7 +7165,7 @@ returned by get_module_info. sub get_available_module_infos { my (%acl, %uacl); -&read_acl(\%acl, \%uacl); +&read_acl(\%acl, \%uacl, [ $base_remote_user ]); my $risk = $gconfig{'risk_'.$base_remote_user}; my @rv; foreach my $minfo (&get_all_module_infos($_[0])) {