mirror of
https://github.com/webmin/webmin.git
synced 2026-05-06 15:20:29 +01:00
Add proper ACLs to nftables module
[no-build]
This commit is contained in:
73
nftables/acl_security.pl
Normal file
73
nftables/acl_security.pl
Normal file
@@ -0,0 +1,73 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
no warnings 'redefine';
|
||||
no warnings 'uninitialized';
|
||||
|
||||
require 'nftables-lib.pl';
|
||||
our (%in, %text);
|
||||
|
||||
# acl_security_form(&options)
|
||||
# Output HTML for editing security options for the nftables module
|
||||
sub acl_security_form
|
||||
{
|
||||
my ($o) = @_;
|
||||
|
||||
my $mode = $o->{'tables'} eq '*' ? 1 :
|
||||
$o->{'tables'} =~ /^\!/ ? 2 : 0;
|
||||
my @selected = split(/\s+/, $o->{'tables'} || '');
|
||||
shift(@selected) if ($mode == 2 && @selected && $selected[0] eq '!');
|
||||
my @table_opts = acl_table_options();
|
||||
|
||||
print ui_table_row($text{'acl_tables'},
|
||||
ui_radio("tables_def", $mode,
|
||||
[ [ 1, $text{'acl_tables_all'} ],
|
||||
[ 0, $text{'acl_tables_sel'} ],
|
||||
[ 2, $text{'acl_tables_nsel'} ] ])."<br>\n".
|
||||
ui_select("tables", \@selected, \@table_opts, 6, 1),
|
||||
3);
|
||||
|
||||
foreach my $a (qw(view active create setup chains sets rules raw delete
|
||||
apply import clear quick)) {
|
||||
print ui_table_row($text{'acl_'.$a}, ui_yesno_radio($a, $o->{$a}));
|
||||
}
|
||||
}
|
||||
|
||||
# acl_security_save(&options)
|
||||
# Parse the form for security options for the nftables module
|
||||
sub acl_security_save
|
||||
{
|
||||
if ($in{'tables_def'} == 1) {
|
||||
$_[0]->{'tables'} = '*';
|
||||
}
|
||||
elsif ($in{'tables_def'} == 2) {
|
||||
$_[0]->{'tables'} = join(" ", "!", split(/\0/, $in{'tables'}));
|
||||
}
|
||||
else {
|
||||
$_[0]->{'tables'} = join(" ", split(/\0/, $in{'tables'}));
|
||||
}
|
||||
foreach my $a (qw(view active create setup chains sets rules raw delete
|
||||
apply import clear quick)) {
|
||||
$_[0]->{$a} = $in{$a} || 0;
|
||||
}
|
||||
}
|
||||
|
||||
# acl_table_options()
|
||||
# Returns saved and active table choices for the ACL editor
|
||||
sub acl_table_options
|
||||
{
|
||||
my %seen;
|
||||
my @opts;
|
||||
foreach my $t (get_nftables_save()) {
|
||||
push(@opts, [ table_acl_name($t), nft_table_spec($t) ]);
|
||||
$seen{table_acl_name($t)} = 1;
|
||||
}
|
||||
my ($active, $err) = get_active_nftables_save();
|
||||
if (!$err) {
|
||||
foreach my $t (@$active) {
|
||||
next if ($seen{table_acl_name($t)}++);
|
||||
push(@opts, [ table_acl_name($t),
|
||||
nft_table_spec($t)." ($text{'active_title'})" ]);
|
||||
}
|
||||
}
|
||||
return sort { $a->[1] cmp $b->[1] } @opts;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ require './nftables-lib.pl'; ## no critic
|
||||
use strict;
|
||||
use warnings;
|
||||
our (%text);
|
||||
assert_acl('active');
|
||||
|
||||
ui_print_header(undef, $text{'active_title'}, "", "intro", 1, 1);
|
||||
|
||||
@@ -13,10 +14,12 @@ my ($tables, $err) = get_active_nftables_save();
|
||||
if ($err) {
|
||||
print text('active_failed', $err);
|
||||
}
|
||||
elsif (!@$tables) {
|
||||
print "<b>$text{'active_none'}</b><p>\n";
|
||||
}
|
||||
else {
|
||||
@$tables = grep { check_table_acl($_) } @$tables;
|
||||
if (!@$tables) {
|
||||
print "<b>$text{'active_none'}</b><p>\n";
|
||||
}
|
||||
else {
|
||||
my @saved_tables = get_nftables_save();
|
||||
print ui_columns_start(
|
||||
[ $text{'active_table'}, $text{'active_flags'},
|
||||
@@ -40,12 +43,13 @@ else {
|
||||
push(@actions, ui_link(
|
||||
"import_table.cgi?family=".urlize($t->{'family'}).
|
||||
"&name=".urlize($t->{'name'}),
|
||||
$text{'active_import'})) if (!$is_saved);
|
||||
$text{'active_import'}))
|
||||
if (!$is_saved && check_acl('import'));
|
||||
push(@actions, ui_link(
|
||||
"clear_table.cgi?family=".urlize($t->{'family'}).
|
||||
"&name=".urlize($t->{'name'}),
|
||||
$text{'active_clear'}))
|
||||
if (!table_is_externally_managed($t));
|
||||
if (!table_is_externally_managed($t) && check_acl('clear'));
|
||||
my $actions = @actions ? join(" ", @actions) : "-";
|
||||
print ui_columns_row([
|
||||
ui_link($table_url, html_escape(nft_table_spec($t))),
|
||||
@@ -59,7 +63,8 @@ else {
|
||||
}
|
||||
print ui_columns_end();
|
||||
|
||||
my @clearable = grep { !table_is_externally_managed($_) } @$tables;
|
||||
my @clearable = grep { !table_is_externally_managed($_) &&
|
||||
check_acl('clear') } @$tables;
|
||||
if (@clearable) {
|
||||
print ui_hr();
|
||||
print ui_buttons_start();
|
||||
@@ -68,6 +73,7 @@ else {
|
||||
$text{'active_clear_alldesc'});
|
||||
print ui_buttons_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui_print_footer("index.cgi", $text{'index_return'});
|
||||
|
||||
@@ -8,6 +8,7 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'active_table_err'});
|
||||
assert_acl('active');
|
||||
|
||||
my ($tables, $err) = get_active_nftables_save();
|
||||
error(text('active_failed', $err)) if ($err);
|
||||
@@ -20,6 +21,7 @@ foreach my $t (@$tables) {
|
||||
}
|
||||
}
|
||||
$table || error($text{'active_table_notable'});
|
||||
assert_table_acl($table);
|
||||
my @saved_tables = get_nftables_save();
|
||||
my $status_key = active_table_status($table, \@saved_tables);
|
||||
my $is_saved = table_is_webmin_managed($table, \@saved_tables);
|
||||
@@ -32,7 +34,7 @@ print ui_table_row($text{'active_flags'}, html_escape($table->{'flags'} || "-"))
|
||||
print ui_table_row($text{'active_status'}, $text{'active_'.$status_key});
|
||||
print ui_table_end();
|
||||
|
||||
if (!$is_saved) {
|
||||
if (!$is_saved && check_acl('import')) {
|
||||
print ui_buttons_start();
|
||||
print ui_buttons_row(
|
||||
"import_table.cgi?family=".urlize($table->{'family'}).
|
||||
|
||||
@@ -8,6 +8,7 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'clear_err'});
|
||||
assert_acl('clear');
|
||||
|
||||
my ($tables, $err) = get_active_nftables_save();
|
||||
error(text('active_failed', $err)) if ($err);
|
||||
@@ -20,6 +21,7 @@ foreach my $t (@$tables) {
|
||||
}
|
||||
}
|
||||
$table || error($text{'active_table_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
if ($in{'confirm'}) {
|
||||
$err = delete_active_table($table);
|
||||
|
||||
@@ -8,11 +8,13 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'clear_all_err'});
|
||||
assert_acl('clear');
|
||||
|
||||
my ($tables, $err) = get_active_nftables_save();
|
||||
error(text('active_failed', $err)) if ($err);
|
||||
|
||||
my @clearable = grep { !table_is_externally_managed($_) } @$tables;
|
||||
my @clearable = grep { !table_is_externally_managed($_) &&
|
||||
check_table_acl($_) } @$tables;
|
||||
@clearable || error($text{'clear_all_enone'});
|
||||
|
||||
if ($in{'confirm'}) {
|
||||
|
||||
@@ -8,6 +8,7 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'create_err'});
|
||||
assert_acl('create');
|
||||
|
||||
my @families = qw(ip ip6 inet arp bridge netdev);
|
||||
my %family_ok = map { $_ => 1 } @families;
|
||||
@@ -40,6 +41,7 @@ if ($in{'create'}) {
|
||||
'rules' => [],
|
||||
'chains' => {},
|
||||
'sets' => {} };
|
||||
assert_table_acl($table);
|
||||
push(@tables, $table);
|
||||
my $err = create_table_configuration($table, @tables);
|
||||
error(text('create_failed', $err)) if ($err);
|
||||
|
||||
14
nftables/defaultacl
Normal file
14
nftables/defaultacl
Normal file
@@ -0,0 +1,14 @@
|
||||
view=1
|
||||
active=1
|
||||
tables=*
|
||||
create=1
|
||||
setup=1
|
||||
chains=1
|
||||
sets=1
|
||||
rules=1
|
||||
raw=1
|
||||
delete=1
|
||||
apply=1
|
||||
import=1
|
||||
clear=1
|
||||
quick=1
|
||||
@@ -8,10 +8,12 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'delete_chain_err'});
|
||||
assert_acl('delete');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'chain_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $chain = $table->{'chains'}->{$in{'chain'}};
|
||||
$chain || error($text{'chain_nochain'});
|
||||
|
||||
@@ -8,6 +8,7 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'delete_chains_err'});
|
||||
assert_acl('delete');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table_idx = $in{'table'};
|
||||
@@ -24,6 +25,7 @@ if (defined($in{'table_family'}) && defined($in{'table_name'})) {
|
||||
}
|
||||
$table ||= $tables[$table_idx];
|
||||
$table || error($text{'chain_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my @chains = split(/\0/, $in{'d'} || "");
|
||||
my %seen;
|
||||
|
||||
@@ -8,10 +8,12 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'delete_set_err'});
|
||||
assert_acl('delete');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'set_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $set = $table->{'sets'}->{$in{'set'}};
|
||||
$set || error($text{'set_noset'});
|
||||
|
||||
@@ -8,6 +8,7 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'delete_sets_err'});
|
||||
assert_acl('delete');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table_idx = $in{'table'};
|
||||
@@ -24,6 +25,7 @@ if (defined($in{'table_family'}) && defined($in{'table_name'})) {
|
||||
}
|
||||
$table ||= $tables[$table_idx];
|
||||
$table || error($text{'set_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my @sets = split(/\0/, $in{'s'} || "");
|
||||
my %seen;
|
||||
|
||||
@@ -8,6 +8,7 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'delete_err'});
|
||||
assert_acl('delete');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table_idx = $in{'table'};
|
||||
@@ -27,6 +28,7 @@ else {
|
||||
$table = $tables[$table_idx];
|
||||
}
|
||||
$table || error($text{'delete_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
if ($in{'confirm'}) {
|
||||
my $needs_apply = needs_config_restart();
|
||||
|
||||
@@ -7,10 +7,12 @@ use strict;
|
||||
use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
assert_acl('chains');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'chain_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $chain = { };
|
||||
my $chain_name = "";
|
||||
|
||||
@@ -7,8 +7,12 @@ use strict;
|
||||
use warnings;
|
||||
our (%in, %text, %config);
|
||||
ReadParse();
|
||||
assert_acl('rules');
|
||||
my $can_edit_raw = check_acl('raw');
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'move_notable'});
|
||||
assert_table_acl($table);
|
||||
my $rule;
|
||||
my $chain_def;
|
||||
my $chain_hook;
|
||||
@@ -301,10 +305,11 @@ print ui_hidden_table_end("advanced");
|
||||
print ui_table_start($text{'edit_rule'}, "width=100%", 2);
|
||||
|
||||
# Raw rule (read-only unless edit direct is checked)
|
||||
my $raw_controls = ui_checkbox("edit_direct", 1, $text{'edit_raw_rule_direct'}, 0);
|
||||
my $raw_controls = $can_edit_raw ?
|
||||
ui_checkbox("edit_direct", 1, $text{'edit_raw_rule_direct'}, 0)."<br>" : "";
|
||||
my $raw_area = ui_textarea("raw_rule", $rule->{'text'}, 4, 60, undef, undef,
|
||||
"readonly='true'");
|
||||
print ui_table_row(hlink($text{'edit_raw_rule'}, "raw_rule"), $raw_controls."<br>".$raw_area,
|
||||
print ui_table_row(hlink($text{'edit_raw_rule'}, "raw_rule"), $raw_controls.$raw_area,
|
||||
undef, undef, ["data-column-span='all' data-column-locked='1'"]);
|
||||
|
||||
print ui_table_end();
|
||||
|
||||
@@ -7,10 +7,12 @@ use strict;
|
||||
use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
assert_acl('sets');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'set_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $set = { };
|
||||
my $set_name = "";
|
||||
|
||||
@@ -9,6 +9,7 @@ use Storable qw(dclone);
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'import_err'});
|
||||
assert_acl('import');
|
||||
|
||||
my ($active, $active_err) = get_active_nftables_save();
|
||||
error(text('active_failed', $active_err)) if ($active_err);
|
||||
@@ -21,6 +22,7 @@ foreach my $t (@$active) {
|
||||
}
|
||||
}
|
||||
$source || error($text{'import_esource'});
|
||||
assert_table_acl($source);
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
if (table_is_webmin_managed($source, \@tables)) {
|
||||
@@ -45,6 +47,7 @@ if ($in{'import'}) {
|
||||
my $import = dclone($source);
|
||||
$import->{'name'} = $name;
|
||||
delete($import->{'flags'});
|
||||
assert_table_acl($import);
|
||||
push(@tables, $import);
|
||||
write_configuration(@tables);
|
||||
register_managed_table($import,
|
||||
|
||||
@@ -7,6 +7,11 @@ use strict;
|
||||
use warnings;
|
||||
our (%in, %text, %config);
|
||||
ReadParse();
|
||||
my $can_view_saved = check_acl('view');
|
||||
if (!$can_view_saved && !check_acl('active') && !check_acl('create') &&
|
||||
!check_acl('setup')) {
|
||||
error($text{'acl_ecannot'});
|
||||
}
|
||||
my $partial = $in{'partial'};
|
||||
if (!$partial) {
|
||||
ui_print_header(undef, $text{'index_title'}, "", "intro", 1, 1,
|
||||
@@ -24,16 +29,20 @@ if (!$cmd) {
|
||||
}
|
||||
|
||||
# Load tables
|
||||
my @tables = get_nftables_save();
|
||||
my @tables = $can_view_saved ? get_nftables_save() : ( );
|
||||
@tables = grep { check_table_acl($_) } @tables;
|
||||
my $rules_html = "";
|
||||
|
||||
if (!@tables) {
|
||||
$rules_html .= ui_buttons_start();
|
||||
$rules_html .= ui_buttons_row("setup.cgi", $text{'index_setup'}, $text{'index_setupdesc'});
|
||||
$rules_html .= ui_buttons_row("setup.cgi", $text{'index_setup'}, $text{'index_setupdesc'})
|
||||
if (check_acl('setup'));
|
||||
$rules_html .= ui_buttons_row("create_table.cgi", $text{'index_table_create'},
|
||||
$text{'index_table_createdesc'});
|
||||
$text{'index_table_createdesc'})
|
||||
if (check_acl('create'));
|
||||
$rules_html .= ui_buttons_row("active.cgi", $text{'index_active'},
|
||||
$text{'index_activedesc'});
|
||||
$text{'index_activedesc'})
|
||||
if (check_acl('active'));
|
||||
$rules_html .= ui_buttons_end();
|
||||
} else {
|
||||
# Select table
|
||||
@@ -66,12 +75,13 @@ if (!@tables) {
|
||||
print ui_select("table", $in{'table'}, \@table_opts, 1, 0, 1, 0,
|
||||
"onchange='this.form.querySelector(\"[name=nft_submit]\").click()'");
|
||||
print ui_submit("", "nft_submit", 0, "style='display:none'");
|
||||
print " ", ui_link_button("create_table.cgi", $text{'index_table_create'});
|
||||
print " ", ui_link_button("create_table.cgi", $text{'index_table_create'})
|
||||
if (check_acl('create'));
|
||||
print " ", ui_link_button(
|
||||
"delete_table.cgi?table=$in{'table'}&table_family=".
|
||||
urlize($tables[$in{'table'}]->{'family'}).
|
||||
"&table_name=".urlize($tables[$in{'table'}]->{'name'}),
|
||||
$text{'index_table_delete'});
|
||||
$text{'index_table_delete'}) if (check_acl('delete'));
|
||||
print "</div>\n";
|
||||
print ui_form_end();
|
||||
}
|
||||
@@ -90,14 +100,12 @@ if (!@tables) {
|
||||
my $set_form = $partial ? 1 : 2;
|
||||
my $has_sets = $curr->{'sets'} && ref($curr->{'sets'}) eq 'HASH' &&
|
||||
keys(%{$curr->{'sets'}});
|
||||
my @set_select_links = $has_sets ?
|
||||
my @set_select_links = $has_sets && check_acl('delete') ?
|
||||
( select_all_link("s", $set_form),
|
||||
select_invert_link("s", $set_form) ) : ( );
|
||||
my @set_top_links = (
|
||||
@set_select_links,
|
||||
ui_link("edit_set.cgi?table=$in{'table'}&new=1",
|
||||
$text{'index_set_create'})
|
||||
);
|
||||
my @set_top_links = @set_select_links;
|
||||
push(@set_top_links, ui_link("edit_set.cgi?table=$in{'table'}&new=1",
|
||||
$text{'index_set_create'})) if (check_acl('sets'));
|
||||
$sets_html .= ui_links_row(\@set_top_links);
|
||||
my @set_tds = ( "width=5" );
|
||||
$sets_html .= ui_columns_start(
|
||||
@@ -107,16 +115,19 @@ if (!@tables) {
|
||||
if ($has_sets) {
|
||||
foreach my $s (sort keys %{$curr->{'sets'}}) {
|
||||
my $set = $curr->{'sets'}->{$s} || { };
|
||||
my $actions_html =
|
||||
my $actions_html = check_acl('sets') ?
|
||||
ui_link("edit_set.cgi?table=$in{'table'}&set=".
|
||||
urlize($s), $text{'index_set_edit'});
|
||||
$sets_html .= ui_checked_columns_row([
|
||||
urlize($s), $text{'index_set_edit'}) : "-";
|
||||
my @cols = (
|
||||
$s,
|
||||
$set->{'type'} || "-",
|
||||
$set->{'flags'} || "-",
|
||||
set_elements_summary($set),
|
||||
$actions_html
|
||||
], \@set_tds, "s", $s);
|
||||
);
|
||||
$sets_html .= check_acl('delete') ?
|
||||
ui_checked_columns_row(\@cols, \@set_tds, "s", $s) :
|
||||
ui_columns_row([ "", @cols ]);
|
||||
}
|
||||
}
|
||||
$sets_html .= ui_columns_end();
|
||||
@@ -131,14 +142,12 @@ if (!@tables) {
|
||||
$chains_html .= ui_hidden("table_family", $curr->{'family'});
|
||||
$chains_html .= ui_hidden("table_name", $curr->{'name'});
|
||||
my $chain_form = $partial ? 0 : 1;
|
||||
my @chain_select_links = keys(%{$curr->{'chains'}}) ?
|
||||
my @chain_select_links = keys(%{$curr->{'chains'}}) && check_acl('delete') ?
|
||||
( select_all_link("d", $chain_form),
|
||||
select_invert_link("d", $chain_form) ) : ( );
|
||||
my @chain_top_links = (
|
||||
@chain_select_links,
|
||||
ui_link("edit_chain.cgi?table=$in{'table'}&new=1",
|
||||
$text{'index_chain_create'})
|
||||
);
|
||||
my @chain_top_links = @chain_select_links;
|
||||
push(@chain_top_links, ui_link("edit_chain.cgi?table=$in{'table'}&new=1",
|
||||
$text{'index_chain_create'})) if (check_acl('chains'));
|
||||
$chains_html .= ui_links_row(\@chain_top_links);
|
||||
my @chain_tds = ( "width=5" );
|
||||
$chains_html .= ui_columns_start(
|
||||
@@ -165,14 +174,14 @@ if (!@tables) {
|
||||
my $desc = describe_rule($r);
|
||||
my $rule_url = "edit_rule.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c)."&idx=$r->{'index'}";
|
||||
my $rule_link = ui_tag('a', $desc,
|
||||
{ 'href' => $rule_url });
|
||||
my $rule_link = check_acl('rules') ?
|
||||
ui_tag('a', $desc, { 'href' => $rule_url }) : $desc;
|
||||
my $imgdir = "@{[get_webprefix()]}/images";
|
||||
my $up_url = "move_rule.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c)."&idx=$r->{'index'}&dir=up";
|
||||
my $down_url = "move_rule.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c)."&idx=$r->{'index'}&dir=down";
|
||||
my $down_move = $ri < $#rules ?
|
||||
my $down_move = check_acl('rules') && $ri < $#rules ?
|
||||
ui_tag('a',
|
||||
ui_tag('img', undef,
|
||||
{ 'class' => 'ui_up_down_arrows_down',
|
||||
@@ -183,7 +192,7 @@ if (!@tables) {
|
||||
ui_tag('img', undef,
|
||||
{ 'class' => 'ui_up_down_arrows_gap',
|
||||
'src' => "$imgdir/movegap.gif" });
|
||||
my $up_move = $ri > 0 ?
|
||||
my $up_move = check_acl('rules') && $ri > 0 ?
|
||||
ui_tag('a',
|
||||
ui_tag('img', undef,
|
||||
{ 'class' => 'ui_up_down_arrows_up',
|
||||
@@ -213,14 +222,18 @@ if (!@tables) {
|
||||
$rules_html_row = ui_tag('i', $text{'index_rules_none'});
|
||||
}
|
||||
|
||||
my $actions_html =
|
||||
ui_link("edit_chain.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c), $text{'index_cedit'})." | ".
|
||||
ui_link("rename_chain.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c), $text{'index_crename'})." | ".
|
||||
ui_link("edit_rule.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c)."&new=1", $text{'index_radd'});
|
||||
$chains_html .= ui_checked_columns_row([
|
||||
my @actions;
|
||||
if (check_acl('chains')) {
|
||||
push(@actions, ui_link("edit_chain.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c), $text{'index_cedit'}));
|
||||
push(@actions, ui_link("rename_chain.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c), $text{'index_crename'}));
|
||||
}
|
||||
push(@actions, ui_link("edit_rule.cgi?table=$in{'table'}&chain=".
|
||||
urlize($c)."&new=1", $text{'index_radd'}))
|
||||
if (check_acl('rules'));
|
||||
my $actions_html = @actions ? join(" | ", @actions) : "-";
|
||||
my @cols = (
|
||||
$c,
|
||||
$chain_def->{'type'} || "-",
|
||||
$chain_def->{'hook'} || "-",
|
||||
@@ -228,29 +241,33 @@ if (!@tables) {
|
||||
$policy_label,
|
||||
$rules_html_row,
|
||||
$actions_html
|
||||
], \@chain_tds, "d", $c);
|
||||
);
|
||||
$chains_html .= check_acl('delete') ?
|
||||
ui_checked_columns_row(\@cols, \@chain_tds, "d", $c) :
|
||||
ui_columns_row([ "", @cols ]);
|
||||
}
|
||||
$chains_html .= ui_columns_end();
|
||||
$chains_html .= @chain_select_links ?
|
||||
ui_form_end([ [ undef, $text{'index_cdeletesel'} ] ]) :
|
||||
ui_form_end();
|
||||
|
||||
my @tabs = (
|
||||
[ 'chains', $text{'index_tab_chains'} ],
|
||||
[ 'sets', $text{'index_tab_sets'} ],
|
||||
);
|
||||
my $tab = $in{'view'} && $in{'view'} eq 'sets' ? 'sets' : 'chains';
|
||||
my @tabs = ( [ 'chains', $text{'index_tab_chains'} ] );
|
||||
push(@tabs, [ 'sets', $text{'index_tab_sets'} ]) if (check_acl('sets'));
|
||||
my $tab = check_acl('sets') && $in{'view'} && $in{'view'} eq 'sets' ?
|
||||
'sets' : 'chains';
|
||||
$rules_html .= ui_hr();
|
||||
$rules_html .= ui_tabs_start(\@tabs, "view", $tab, 1);
|
||||
$rules_html .= ui_tabs_start_tab("view", "chains");
|
||||
$rules_html .= $chains_html;
|
||||
$rules_html .= ui_tabs_end_tab();
|
||||
$rules_html .= ui_tabs_start_tab("view", "sets");
|
||||
$rules_html .= $sets_html;
|
||||
$rules_html .= ui_tabs_end_tab();
|
||||
if (check_acl('sets')) {
|
||||
$rules_html .= ui_tabs_start_tab("view", "sets");
|
||||
$rules_html .= $sets_html;
|
||||
$rules_html .= ui_tabs_end_tab();
|
||||
}
|
||||
$rules_html .= ui_tabs_end(1);
|
||||
|
||||
if (find_input_chain($curr)) {
|
||||
if (check_acl('quick') && find_input_chain($curr)) {
|
||||
my $ip_placeholder =
|
||||
text('quick_ip_placeholder', '1.2.3.4', '2001:db8::1/64');
|
||||
foreach my $action (
|
||||
@@ -277,12 +294,15 @@ if ($partial) {
|
||||
|
||||
print $rules_html;
|
||||
|
||||
if (@tables) {
|
||||
if (@tables && (check_acl('apply') || check_acl('active') || check_acl('setup'))) {
|
||||
print ui_hr();
|
||||
print ui_buttons_start();
|
||||
print ui_buttons_row("restart.cgi", $text{'index_apply'}, $text{'index_applydesc'});
|
||||
print ui_buttons_row("active.cgi", $text{'index_active'}, $text{'index_activedesc'});
|
||||
print ui_buttons_row("setup.cgi", $text{'index_setup'}, $text{'index_setupdesc'});
|
||||
print ui_buttons_row("restart.cgi", $text{'index_apply'}, $text{'index_applydesc'})
|
||||
if (check_acl('apply'));
|
||||
print ui_buttons_row("active.cgi", $text{'index_active'}, $text{'index_activedesc'})
|
||||
if (check_acl('active'));
|
||||
print ui_buttons_row("setup.cgi", $text{'index_setup'}, $text{'index_setupdesc'})
|
||||
if (check_acl('setup'));
|
||||
print ui_buttons_end();
|
||||
}
|
||||
|
||||
|
||||
@@ -333,3 +333,22 @@ import_flags=Source flags
|
||||
import_external_note=This active table is marked as externally managed; importing creates a separate module-managed copy and does not change the active source table
|
||||
import_new_name=New table name
|
||||
import_ok=Import Copy
|
||||
acl_ecannot=You are not allowed to perform this nftables action.
|
||||
acl_etable=You are not allowed to manage table $1.
|
||||
acl_tables=Tables this user can manage
|
||||
acl_tables_all=All tables
|
||||
acl_tables_sel=Selected tables
|
||||
acl_tables_nsel=All except selected tables
|
||||
acl_view=View managed tables and rules
|
||||
acl_active=View active ruleset
|
||||
acl_create=Create tables
|
||||
acl_setup=Create ruleset profiles
|
||||
acl_chains=Create, edit and rename chains
|
||||
acl_sets=Create and edit sets
|
||||
acl_rules=Create, edit, move and delete rules
|
||||
acl_raw=Edit raw rule text
|
||||
acl_delete=Delete tables, chains and sets
|
||||
acl_apply=Apply saved configuration
|
||||
acl_import=Import active tables
|
||||
acl_clear=Clear active tables
|
||||
acl_quick=Use quick allow/block controls
|
||||
|
||||
@@ -7,6 +7,7 @@ use strict;
|
||||
use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
assert_acl('quick');
|
||||
|
||||
my $action = $in{'allow'} ? 'allow' : $in{'block'} ? 'block' : '';
|
||||
error_setup($action eq 'allow' ? $text{'quick_allow_err'} :
|
||||
@@ -29,6 +30,7 @@ else {
|
||||
$table = $tables[$table_idx];
|
||||
}
|
||||
$table || error($text{'quick_etable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $err = add_quick_ip_rule($table, $in{'ip'}, $action);
|
||||
error($err) if ($err);
|
||||
|
||||
@@ -8,10 +8,12 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'move_err'});
|
||||
assert_acl('rules');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'move_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $chain = $in{'chain'};
|
||||
$chain || error($text{'move_nochain'});
|
||||
|
||||
@@ -5,16 +5,69 @@ BEGIN { push(@INC, ".."); }; ## no critic
|
||||
use WebminCore;
|
||||
use strict;
|
||||
use warnings;
|
||||
our (%config, $module_config_directory, $module_var_directory);
|
||||
our (%config, %access, $module_config_directory, $module_var_directory);
|
||||
our ($last_config_change_flag, $last_restart_time_flag);
|
||||
init_config();
|
||||
%access = get_module_acl();
|
||||
$last_config_change_flag = $module_var_directory."/config-flag";
|
||||
$last_restart_time_flag = $module_var_directory."/restart-flag";
|
||||
|
||||
# check_acl(action)
|
||||
# Returns true if the current Webmin user can perform an action
|
||||
sub check_acl
|
||||
{
|
||||
my ($action) = @_;
|
||||
return $access{$action} ? 1 : 0;
|
||||
}
|
||||
|
||||
# assert_acl(action)
|
||||
# Fails if the current Webmin user cannot perform an action
|
||||
sub assert_acl
|
||||
{
|
||||
my ($action) = @_;
|
||||
check_acl($action) || error(text('acl_ecannot'));
|
||||
}
|
||||
|
||||
# table_acl_name(&table)
|
||||
# Returns the ACL token for a table
|
||||
sub table_acl_name
|
||||
{
|
||||
my ($table) = @_;
|
||||
return ($table->{'family'} || '').":".($table->{'name'} || '');
|
||||
}
|
||||
|
||||
# check_table_acl(&table)
|
||||
# Returns true if the current Webmin user can manage a table
|
||||
sub check_table_acl
|
||||
{
|
||||
my ($table) = @_;
|
||||
return 0 if (!$table);
|
||||
my $tables = defined($access{'tables'}) ? $access{'tables'} : '*';
|
||||
return 1 if ($tables eq '*');
|
||||
my $name = table_acl_name($table);
|
||||
my @tokens = grep { $_ ne '' } split(/\s+/, $tables);
|
||||
if (@tokens && $tokens[0] eq '!') {
|
||||
my %deny = map { $_ => 1 } @tokens[1..$#tokens];
|
||||
return !$deny{$name};
|
||||
}
|
||||
my %allow = map { $_ => 1 } @tokens;
|
||||
return $allow{$name} ? 1 : 0;
|
||||
}
|
||||
|
||||
# assert_table_acl(&table)
|
||||
# Fails if the current Webmin user cannot manage a table
|
||||
sub assert_table_acl
|
||||
{
|
||||
my ($table) = @_;
|
||||
check_table_acl($table) ||
|
||||
error(text('acl_etable', html_escape(nft_table_spec($table))));
|
||||
}
|
||||
|
||||
# restart_button()
|
||||
# Returns HTML for the header apply button
|
||||
sub restart_button
|
||||
{
|
||||
return "" if (!check_acl('apply'));
|
||||
my @tables = get_nftables_save();
|
||||
return "" if (!@tables);
|
||||
my $args = "redir=".urlize(this_url());
|
||||
|
||||
@@ -7,10 +7,12 @@ use strict;
|
||||
use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
assert_acl('chains');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'chain_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $chain = $table->{'chains'}->{$in{'chain'}};
|
||||
$chain || error($text{'chain_nochain'});
|
||||
|
||||
@@ -8,6 +8,7 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'apply_err'});
|
||||
assert_acl('apply');
|
||||
|
||||
my $err = apply_restore();
|
||||
error($err) if ($err);
|
||||
|
||||
@@ -8,10 +8,12 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'chain_err'});
|
||||
assert_acl('chains');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'chain_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $is_new = $in{'new'} ? 1 : 0;
|
||||
my $is_rename = $in{'rename'} ? 1 : 0;
|
||||
|
||||
@@ -8,8 +8,12 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'save_err'});
|
||||
assert_acl('rules');
|
||||
assert_acl('raw') if ($in{'edit_direct'});
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'move_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
foreach my $sfield (qw(saddr_set daddr_set sport_set dport_set)) {
|
||||
if ($in{$sfield}) {
|
||||
|
||||
@@ -8,10 +8,12 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'set_err'});
|
||||
assert_acl('sets');
|
||||
|
||||
my @tables = get_nftables_save();
|
||||
my $table = $tables[$in{'table'}];
|
||||
$table || error($text{'set_notable'});
|
||||
assert_table_acl($table);
|
||||
|
||||
my $is_new = $in{'new'} ? 1 : 0;
|
||||
my $name = $in{'set_name'};
|
||||
|
||||
@@ -8,6 +8,7 @@ use warnings;
|
||||
our (%in, %text);
|
||||
ReadParse();
|
||||
error_setup($text{'setup_err'});
|
||||
assert_acl('setup');
|
||||
if ($in{'action'} eq 'create') {
|
||||
my $profile = $in{'profile'} || 'virtualmin';
|
||||
my $table_name = $in{'table_name'} || default_profile_table_name();
|
||||
@@ -31,6 +32,7 @@ if ($in{'action'} eq 'create') {
|
||||
|
||||
my @allow = grep { $_ ne '' } split(/\0/, $in{'allow'} || '');
|
||||
my $table = create_profile_ruleset($profile, $table_name, \@allow);
|
||||
assert_table_acl($table);
|
||||
push(@tables, $table);
|
||||
|
||||
my $error = save_configuration(@tables);
|
||||
|
||||
Reference in New Issue
Block a user