summaryrefslogtreecommitdiffstats
path: root/bin/drakguard
diff options
context:
space:
mode:
Diffstat (limited to 'bin/drakguard')
-rwxr-xr-xbin/drakguard782
1 files changed, 782 insertions, 0 deletions
diff --git a/bin/drakguard b/bin/drakguard
new file mode 100755
index 0000000..dfa7c3c
--- /dev/null
+++ b/bin/drakguard
@@ -0,0 +1,782 @@
+#!/usr/bin/perl
+
+use lib qw(/usr/lib/libDrakX);
+# i18n: IMPORTANT: to get correct namespace (drakguard instead of libDrakX)
+BEGIN { unshift @::textdomains, 'drakguard' }
+use strict;
+use diagnostics;
+use common;
+use standalone;
+use mygtk2;
+use ugtk2 qw(:create :helpers :wrappers);
+use Gtk2::SimpleList;
+use interactive;
+use network::shorewall;
+use network::squid;
+use services;
+use Encode;
+
+my $dansguardian_main_file = "/etc/dansguardian/dansguardian.conf";
+my $dansguardian_filter_file = "/etc/dansguardian/dansguardianf1.conf";
+my $time_control_file = "/etc/shorewall/time_control";
+my $dansguardian_bannedsitelist = "/etc/dansguardian/lists/bannedsitelist";
+my $dansguardian_exceptionsitelist = "/etc/dansguardian/lists/exceptionsitelist";
+my $dansguardian_protected_program_list = "/etc/dansguardian/lists/blacklists/drakguard/protected_list";
+my $msec_conf = "/etc/security/msec/perms.conf";
+my $perms_orig = "/etc/security/msec/perms.orig";
+my $fstab_file = "/etc/fstab";
+my %dansguardian_levels = (
+ 160 => N_("Low"),
+ 100 => N_("Normal"),
+ 50 => N_("High"),
+);
+my %dansguardian_langs = (
+ arspanish => 'es_AR',
+ bulgarian => 'bg',
+ chinesebig5 => 'zh_TW',
+ chinesegb2312 => 'zh_CN',
+ czech => 'cs',
+ danish => 'da',
+ dutch => 'nl',
+ french => 'fr',
+ german => 'de',
+ hebrew => 'he',
+ hungarian => 'hu',
+ indonesian => 'id',
+ italian => 'it',
+ japanese => 'ja',
+ lithuanian => 'lt',
+ malay => 'ms',
+ mxspanish => 'es_MX',
+ polish => 'pl',
+ portuguese => 'pt',
+ ptbrazilian => 'pt_BR',
+ #russian-1251
+ 'russian-koi8-r' => 'ru',
+ slovak => 'sk',
+ spanish => 'es',
+ swedish => 'sv',
+ turkish => 'tr',
+ ukenglish => 'en',
+);
+
+my $blacklist_url_file = "/etc/dansguardian/lists/blacklists/drakguard/urls";
+my $whitelist_url_file = "/etc/dansguardian/lists/whitelists/drakguard/urls";
+my ($enable, $level, $time_control, $time_start_h, $time_start_m, $time_stop_h, $time_stop_m, $allow_time_change, $net_control, $not_net_control, $program_control, $net_control_state, $program_control_state, $acl_state);
+my ($acl_active);
+my $shorewall = network::shorewall::read();
+my $proxy_port = 3128;
+my $proxy_user = 'squid';
+my $guardian_port = 8080;
+my $guardian_user = 'dansguardian';
+load();
+
+
+my $toolname = 'drakguard';
+my $title = N("Parental Control");
+my $icon = 'drakguard';
+
+$ugtk2::wm_icon = $icon;
+my $w = ugtk2->new($title);
+#- so that transient_for is defined, for wait messages and popups to be centered
+$::main_window = $w->{real_window};
+my $in = interactive->vnew('su');
+
+my $allusers_list = Gtk2::SimpleList->new(N("All users") => 'text');
+$allusers_list->get_selection->set_mode('multiple');
+@{$allusers_list->{data}} = sort(list_users());
+
+my $allusers_program_list;
+my $users_program_list;
+
+my $users_list = Gtk2::SimpleList->new(N("Allowed users") => 'text');
+$users_list->get_selection->set_mode('multiple');
+@{$users_list->{data}} = difference2($shorewall->{accept_local_users}{http}, [ $proxy_user ]);
+
+my @url_lists = (
+ {
+ tab_title => N("Blacklist"),
+ list_title => N("Forbidden addresses"),
+ remove_text => N("Remove from blacklist"),
+ file => $blacklist_url_file,
+ apply => \&apply_blacklist,
+ },
+ {
+ tab_title => N("Whitelist"),
+ list_title => N("Allowed addresses"),
+ remove_text => N("Remove from whitelist"),
+ file => $whitelist_url_file,
+ apply => \&apply_whitelist,
+ },
+ {
+ tab_title => N("Block programs"),
+ list_title => N("Programs with blocked execution"),
+ remove_text => N("Remove from blocked execution list"),
+ file => $dansguardian_protected_program_list,
+ apply => \&apply_block_program,
+ }
+);
+
+sub update_time_change() {
+ gtkval_modify(\$allow_time_change, $enable && $time_control);
+ gtkval_modify(\$net_control_state, $enable && $net_control);
+ gtkval_modify(\$not_net_control, $enable && !$net_control);
+ gtkval_modify(\$program_control_state, $enable && $program_control);
+ gtkval_modify(\$acl_state, $enable && $acl_active);
+}
+
+sub update_network_change() {
+ gtkval_modify(\$not_net_control, $enable && !$net_control);
+ gtkval_modify(\$net_control_state, $enable && $net_control);
+}
+
+sub update_program_state() {
+ gtkval_modify(\$program_control_state, $enable && $program_control);
+}
+
+$w->{ok_clicked} = \&save;
+$w->{cancel_clicked} = \&quit_gui;
+
+gtkadd($w->{window},
+ gtknew('VBox', spacing => 5, children => [
+ $::isEmbedded ? () : (0, Gtk2::Banner->new($icon, $title)),
+ 1, gtknew('Notebook', children => [
+ gtknew('Label', text => N("Configuration")),
+ gtknew('VBox', spacing => 5, border_width => 5, children => [
+ 0, gtknew('Label', text => N("This tool allows to configure parental control.\nIt can block access to web sites and restrict connection during a specified timeframe.")),
+ 0, gtknew('CheckButton', text => N("Enable parental control"),
+ active_ref => \$enable, toggled => \&update_time_change),
+ 1, gtknew('Label'),
+ 0, gtknew('Title2', label => N("Main options")),
+ 0, gtknew('HBox', children_tight => [
+ gtknew('CheckButton', text => N("Block all network traffic"),
+ sensitive_ref => \$enable, active_ref => \$net_control, toggled => \&update_network_change),
+ ]),
+ 0, gtknew('HBox', children_tight => [
+ gtknew('Label', sensitive_ref => \$enable, text_markup => N("Obscenity sensibility"), #Sensitivity to bad words
+ alignment => [ 0, 0.5 ]),
+ gtknew('ComboBox',
+ list => [ keys %dansguardian_levels ],
+ text_ref => \$level,
+ sensitive_ref => \$enable,
+ format => sub { translate($dansguardian_levels{$_[0]}) }),
+ ]),
+ 1, gtknew('Label'),
+ 0, gtknew('Title2', label => N("User access")),
+ 0, gtknew('HBox', spacing => 5, children_tight => [
+ gtknew('ScrolledWindow', width => 220, height => 120, child => $allusers_list),
+ gtknew('VBox', spacing => 5, children_tight => [
+ gtknew('Button', stock => "gtk-add", clicked => \&add_user),
+ gtknew('Button', stock => "gtk-remove", clicked => \&remove_user),
+ ]),
+ gtknew('ScrolledWindow', width => 220, height => 120, child => $users_list),
+ ]),
+ 1, gtknew('Label'),
+ 0, gtknew('Title2', label => N("Time control")),
+ 0, gtknew('CheckButton', text => N("Allow connections only between these times:"),
+ active_ref => \$time_control, sensitive_ref => \$enable,
+ toggled => \&update_time_change),
+ 0, gtknew('HBox', sensitive_ref => \$allow_time_change, spacing => 20, children_tight => [
+ gtknew('Label', text => N("Start:")),
+ gtknew('HBox', spacing => 2, children_tight => [
+ gtknew('SpinButton', lower => 0, upper => 23, step_increment => 1, value => $time_start_h,
+ value_changed => sub { $time_start_h = $_[0]->get_value } ),
+ gtknew('Label', text => ':'),
+ gtknew('SpinButton', lower => 0, upper => 59, step_increment => 1, value => $time_start_m,
+ value_changed => sub { $time_start_m = $_[0]->get_value } ),
+ ]),
+ gtknew('Label'),
+ gtknew('Label', text => N("End:")),
+ gtknew('HBox', spacing => 2, children_tight => [
+ gtknew('SpinButton', lower => 0, upper => 23, step_increment => 1, value => $time_stop_h,
+ value_changed => sub { $time_stop_h = $_[0]->get_value } ),
+ gtknew('Label', text => ':'),
+ gtknew('SpinButton', lower => 0, upper => 59, step_increment => 1, value => $time_stop_m,
+ value_changed => sub { $time_stop_m = $_[0]->get_value } ),
+ ]),
+ ]),
+ ]),
+ (map {
+ my $url_list = $_;
+ $url_list->{list} = Gtk2::SimpleList->new($url_list->{list_title} => 'text');
+ $url_list->{list}->get_selection->set_mode('multiple');
+ if ($url_list->{tab_title} eq N("Block programs")){@{$url_list->{list}{data}} = read_program_list($url_list->{file}); }
+ else{@{$url_list->{list}{data}} = read_url_list($url_list->{file});}
+
+ $allusers_program_list = Gtk2::SimpleList->new(N("Blocked users") => 'text');
+ $allusers_program_list->get_selection->set_mode('multiple');
+ @{$allusers_program_list->{data}} = sort(list_users());
+
+ $users_program_list = Gtk2::SimpleList->new(N("Allowed users") => 'text');
+ $users_program_list->get_selection->set_mode('multiple');
+ @{$users_program_list->{data}} = sort (read_program_user_list($url_list->{file}));
+ my $entry;
+ my $original_entry;
+
+ (
+ gtknew('Label', if_($url_list->{tab_title} eq N("Whitelist"), sensitive_ref => \$net_control_state),
+ if_($url_list->{tab_title} eq N("Blacklist"), sensitive_ref => \$not_net_control),
+ if_($url_list->{tab_title} eq N("Block programs"), sensitive_ref => \$acl_state), text => $url_list->{tab_title}),
+ gtknew('VBox', if_($url_list->{tab_title} eq N("Whitelist"), sensitive_ref => \$net_control_state),
+ if_($url_list->{tab_title} eq N("Blacklist"), sensitive_ref => \$not_net_control), spacing => 5, children => [
+ 0, gtknew('HBox', children_tight => [
+ if_($url_list->{tab_title} eq N("Block programs"),gtknew('CheckButton', text => N("Block defined applications"),
+ sensitive_ref => \$acl_state, active_ref => \$program_control, toggled => \&update_program_state)),
+ ]),
+ 0, gtknew('HBox', if_($url_list->{tab_title} eq N("Block programs"), sensitive_ref => \$program_control_state), border_width => 5, spacing => 5, children_loose => [
+ $entry = gtknew('Entry'),
+ if_($url_list->{tab_title} eq N("Block programs"), gtknew('Button', text => N("..."), clicked => sub {
+ $entry->set_text($in->ask_file(N("Please select the program you want to control"), "/usr/bin"));
+ })),
+ 0, gtknew('Button', text => N("Add"), clicked => sub {
+ my $text = $entry->get_text;
+ my $exec;
+ my $args;
+ $text =~ s,^[^:]+://,,g; #- strip protocol
+ if ($url_list->{tab_title} eq N("Block programs")) {
+ $text =~ s,(\W?)$,,g; #- remove unknown caracters
+ $original_entry = "";
+ $text = resolve_symlinks($text);
+ if ( (grep { $_ && m/^\[Desktop Entry\]\s*/g} chomp_(cat_($text))) || $text =~ m/\.desktop/g) {# make this only for application block
+ my @exec_line = grep { $_ && m/^Exec=(.*)\s*/g} chomp_(cat_($text));
+ require lang;
+ my $locale = lang::read();
+ $locale = lc($locale->{country});
+ my @system_name = grep { $_ && m/^GenericName(\[$locale\])?=(.*)\s*/g} chomp_(cat_($text));
+ foreach (@exec_line){
+ ($exec, $text, $args) = /(^Exec=)(\w+)\s*(.*)/;
+ if ($text eq ""){
+ ($exec, $text, $args) = /(^Exec=)(.*+)\s*(.*)/;}
+ }
+ foreach my $b (@system_name){
+ $original_entry = $b;
+ $original_entry =~ s/^GenericName(\[$locale\])?=//g;
+ $original_entry = Encode::decode("utf8", $original_entry);
+ }
+ }
+ $text = `which $text 2> /dev/null` if $text ne "";
+ $text =~ s/\n//g;
+ }
+ if ( $text eq "" && $url_list->{tab_title} eq N("Block programs")) { $in->ask_warn(N("Error"), N("Invalid Binary Name")) and return; }
+ else { if ($url_list->{tab_title} eq N("Block programs")) {
+ list_add_entry_program($url_list->{list}, $text. " ( $original_entry )") if $original_entry ne "";
+ list_add_entry_program($url_list->{list}, $text) if $original_entry eq "";
+ }
+ else { list_add_entry($url_list->{list}, $text); }
+ }
+ $entry->set_text("");
+ }),
+ ]),
+ 1, gtknew('ScrolledWindow', if_($url_list->{tab_title} eq N("Block programs"), sensitive_ref => \$program_control_state), width => 500, height => 150, child => $url_list->{list}),
+ 0, gtknew('HButtonBox', if_($url_list->{tab_title} eq N("Block programs"), sensitive_ref => \$program_control_state), border_width => 5, layout => 'edge', children_loose => [
+ gtknew('Button', text => $url_list->{remove_text}, clicked => sub {
+ list_remove_selected($url_list->{list});
+ }),
+ ]),
+ if_($url_list->{tab_title} eq N("Block programs"), 1, gtknew('Label'),
+ 0, gtknew('Title2', label => N("Unblock users")),
+ 0, gtknew('HButtonBox', sensitive_ref => \$program_control_state, spacing => 5, children_tight => [
+ gtknew('ScrolledWindow', width => 220, height => 120, child => $allusers_program_list),
+ gtknew('VBox', spacing => 5, children_tight => [
+ gtknew('Button', stock => "gtk-add", clicked => \&add_user_program),
+ gtknew('Button', stock => "gtk-remove", clicked => \&remove_user_program),
+ ]),
+ gtknew('ScrolledWindow', width => 220, height => 120, child => $users_program_list),
+ ]),
+ 0, gtknew('HBox'),
+ ),
+ ]),
+ );
+ } @url_lists),
+ ]),
+ 0, $w->create_okcancel(
+ undef, undef, undef,
+ [ N("Help"), sub { run_program::raw({ detach => 1 }, 'drakhelp', '--id', $toolname) } ]),
+ ]),
+);
+
+$w->show;
+if ( (grep {$_ && !/acl/} chomp_(cat_($fstab_file)) && grep {$_ && m/ext/} chomp_(cat_($fstab_file)))) {
+ $acl_active = 1;
+ $in->ask_yesorno(N("Warning"), N("The support for Access Control Lists must be enabled in order to use the Block programs feature.\nDo you want to enable it now?", $acl_active = 1)) or $acl_active = 0;
+ if ($acl_active) {
+ my @ext_lines = grep {$_ && m/ext/} chomp_(cat_($fstab_file));
+ foreach my $line (@ext_lines){
+ my ($id, $directory, $flag, $number) = $line=~ /^(.+)\s(.+)\s(ext(\w)\s(\w*))\s(.*)/ or next;
+ $line =~ s/ext(\w)\s(\w*)\s/$flag,acl /g;
+ subst_config_line($fstab_file,"$line\n"); #adds ,acl in the fstab file in the first run
+ # remount filesystem with acl parameter
+ }
+ $acl_active = 0;
+ $in->ask_warn(N("Warning"), N("The support for Access Control Lists was enabled.") . N("It is necessary to restart your computer to activate it."));
+ }
+}
+else {
+ my @mount = `mount`;
+ if (grep (/,acl/, @mount)) {
+ $acl_active = 1;
+ } else {
+ $in->ask_warn(N("Warning"), N("The support for Access Control Lists, required by the Block programs feature, is enabled, but not yet activated.") . N("It is necessary to restart your computer to activate it."), $acl_active = 0);}
+}
+update_time_change;
+Gtk2->main;
+
+$w->exit(0);
+
+sub list_add_entry {
+ my ($list, @addr) = @_;
+ foreach my $a (@addr) {
+ push @{$list->{data}}, $a
+ unless any { $_->[0] eq $a } @{$list->{data}};
+ }
+}
+
+sub list_add_entry_program {
+ my ($list, @addr) = @_;
+ foreach my $a (@addr) {
+ $b = $a;
+ $a =~ s/\s(.*)//g;
+ my @abc = map {$_->[0]} @{$list->{data}};
+ push @{$list->{data}}, $b
+ unless (any { $_->[0] eq $b } @{$list->{data}}) || (grep {$_ && m/$a(.*)/g} @abc);
+ }
+}
+
+sub list_remove_entry {
+ my ($list, @addr) = @_;
+ #- workaround buggy Gtk2::SimpleList array abstraction, it destroys references
+ @{$list->{data}} = map { member($_->[0], @addr) ? () : [ @$_ ] } @{$list->{data}};
+}
+
+sub list_get_selected {
+ my ($list) = @_;
+ uniq(map { $list->{data}[$_][0] } $list->get_selected_indices);
+}
+
+sub list_remove_selected {
+ my ($list) = @_;
+ list_remove_entry($list, list_get_selected($list));
+}
+
+sub list_get_entries {
+ my ($list) = @_;
+ map { $_->[0] } @{$list->{data}};
+}
+
+sub add_user() {
+ list_add_entry($users_list, list_get_selected($allusers_list));
+}
+
+sub remove_user() {
+ list_remove_selected($users_list);
+}
+
+sub add_user_program() {
+ list_add_entry($users_program_list, list_get_selected($allusers_program_list));
+}
+
+sub remove_user_program() {
+ list_remove_selected($users_program_list);
+}
+
+sub quit_gui {
+ my ($o_code) = @_;
+ $w->exit($o_code);
+}
+
+sub load() {
+ my $guardian = read_dansguardian();
+ my $levelname = { %dansguardian_levels }->{$guardian->{naughtynesslimit}};
+ $net_control = $guardian->{netblock};
+ $program_control = $guardian->{programblock};
+ gtkval_modify(\$not_net_control, $enable && !$net_control);
+ $level = { reverse %dansguardian_levels }->{$levelname} if $levelname;
+ $level ||= { reverse %dansguardian_levels }->{High};
+ $enable = services::starts_on_boot('dansguardian');
+
+ $time_control = cat_($::prefix . "/etc/shorewall/start") =~ /^INCLUDE $time_control_file$/m;
+ my @time_control_settings = grep { /\bnet2fw\b/ } cat_($::prefix . $time_control_file);
+ my ($drop_start, $drop_stop);
+ if (my ($drop_start_h, $drop_start_m) = top(@time_control_settings) =~ /\B--timestart\s(\d+):(\d+)\b/) {
+ $drop_start = $drop_start_h*60 + $drop_start_m - 1;
+ }
+ if (my ($drop_stop_h, $drop_stop_m) = first(@time_control_settings) =~ /\B--timestop\s(\d+):(\d+)\b/) {
+ $drop_stop = $drop_stop_h*60 + $drop_stop_m + 1;
+ }
+ if (defined($drop_start) && defined($drop_stop)) {
+ my $day_time = 24*60;
+ $drop_start = ($drop_start + $day_time) % $day_time;
+ $drop_stop = ($drop_stop + $day_time) % $day_time;
+
+ $time_start_h = int($drop_stop/60);
+ $time_start_m = $drop_stop%60;
+ $time_stop_h = int($drop_start/60);
+ $time_stop_m = $drop_start%60;
+ }
+
+ $time_start_h //= 18;
+ $time_start_m //= 0;
+ $time_stop_h //= 21;
+ $time_stop_m //= 0;
+}
+
+sub save() {
+ my $_wait = $in->wait_message(N("Please wait"), N("Please wait"));
+
+ network::shorewall::set_in_file('start', $enable && $time_control, "INCLUDE $time_control_file");
+ if ($enable && $time_control) {
+ my $day_time = 24*60;
+ #- start/stop dropping the minute after/before traffic is allowed
+ #- and make sure times are positive and in the 00:00 <-> 23:59 interval
+ my $drop_start = ($time_stop_h*60 + $time_stop_m + 1 + $day_time) % $day_time;
+ my $drop_stop = ($time_start_h*60 + $time_start_m - 1 + $day_time) % $day_time;
+ output_p($::prefix . $time_control_file,
+ join('', map {
+ my $chain = $_;
+ map {
+ sprintf("iptables -I $chain -j DROP -m time --timestart %02d:%02d --timestop %02d:%02d\n",
+ int($_->[0]/60), $_->[0]%60,
+ int($_->[1]/60), $_->[1]%60,
+ );
+ } ($drop_stop >= $drop_start ? [ $drop_start, $drop_stop] : ([ 0, $drop_stop ], [ $drop_start, $day_time-1 ]));
+ #- if allowing start time is before allowing stop time,
+ #- we have to use two intervals to cover the completary parts of the day
+ } qw(net2fw fw2net)),
+ );
+ #- allowing from 00:00 to 23:59 is a special case that does not need rules
+ $time_control = 0 if $drop_stop == $day_time - 1 && $drop_start == 0;
+ }
+ network::shorewall::set_in_file('start', $enable && $time_control, "INCLUDE $time_control_file");
+
+ if ($enable) {
+ $in->do_pkgs->ensure_are_installed([ qw(shorewall squid dansguardian) ])
+ or quit_gui(1);
+
+ $_->{apply}(list_get_entries($_->{list})) foreach @url_lists;
+ write_dansguardian();
+ enable_transparent_proxy($proxy_port);
+ #- reload shorewall config if it has just been installed
+ $shorewall ||= network::shorewall::read();
+ }
+ else {
+ $program_control = 0;
+ @url_lists[2]->{apply}(list_get_entries(@url_lists[2]->{list}));
+ }
+ services::set_status($_, $enable) foreach qw(squid dansguardian);
+
+ if ($shorewall) {
+ $shorewall->{disabled} = 0 if $enable;
+ @{$shorewall->{accept_local_users}{http}} = if_($enable, uniq($proxy_user, list_get_entries($users_list)));
+ @{$shorewall->{accept_local_users}{$proxy_port}} = if_($enable, $guardian_user);
+ network::shorewall::set_redirected_ports($shorewall, 'tcp', $guardian_port, if_($enable, 'http', $proxy_port));
+ network::shorewall::write($shorewall, $in);
+ }
+
+ quit_gui();
+}
+
+sub resolve_symlinks {
+
+ # Check if a given file (either the pure filename or in a SANE device
+ # string as "<prefix>:<file>") is a symlink, if so expand the link.
+ # If the new file name is a link, expand again, until finding the
+ # physical file.
+ my ($file) = @_;
+ my $prefix = "";
+ if ($file =~ m!^([^/]*)(/.*)$!) {
+ $prefix = $1;
+ $file = $2;
+ } else {
+ return $file;
+ }
+ while (1) {
+ #my $ls = `ls -l $file 2> /dev/null`;
+ my $ls = readlink $file;
+ if ($ls =~ m!\s($file)\s*\->\s*(\S+)\s*$!) {
+ my $target = $2;
+ if ($target !~ m!^/! && $file =~ m!^(.*)/[^/]+$!) {
+ $target = "$1/$target";
+ }
+ $file = $target;
+ } else {
+ last;
+ }
+ }
+ return $prefix . $file;
+}
+
+sub remove_acl {
+ my ($file, $binary) = @_;
+ `setfacl -b $binary`;
+ clean_config_line($file, "$binary");
+}
+
+sub set_permissions {
+ my ($line, $line_info) = @_;
+ #`protect $line --add`;
+ chmod 0700, $line;
+ chown "root","root", $line;
+ #remove msec lines
+ #clean_config_line($msec_conf,"$line");
+ subst_config_line($dansguardian_protected_program_list,"$line_info \n"); #adds the file to dansguardian_protected_program_list
+ subst_config_line($msec_conf,"$line\troot.root\t700\tforce\t\n"); #adds the file to msec
+ #`protect $line $_` foreach list_get_entries($users_program_list);
+ #add msec line or lines...
+ foreach my $user_msec (list_get_entries($users_program_list)) {
+ my @msec_line = grep { $_ && m/$line/g} chomp_(cat_($msec_conf));
+ my @program_list_line = grep { $_ && m/^$line/g} chomp_(cat_($dansguardian_protected_program_list));
+ `setfacl -m u:$user_msec:r-x $line`;
+ subst_config_line($dansguardian_protected_program_list,"$_$user_msec,\n") foreach @program_list_line; #adds the users to the programs blocked in msec
+ subst_config_line($msec_conf,"$_$user_msec:r-x,\n") foreach @msec_line; #adds the users to the programs blocked in msec
+ }
+}
+
+sub restore_permissions {
+ my ($line) = @_;
+ foreach ($line){
+ my ($fich, $usrname, $grpname, $mode) = /^(.*)\t(\w+)\.(\w+)\t(\d+)\s*/ or next;
+ $mode = sprintf "%04d", $mode;#make number with 4 digits
+ my $guid = getgrnam($grpname);
+ my $uid = getpwnam($usrname);
+ chown $uid, $guid, $fich;
+ chmod oct($mode), $fich;
+ }
+}
+
+sub subst_config_line {
+ my ($file, $line) = @_;
+ my $key = first(split(' ', $line));
+ my $done;
+ substInFile {
+ $done = 1 if s|^\s*$key\b.*\n|$line|;
+ $_ .= $line if eof && !$done;
+ } $file;
+}
+
+sub clean_config_line {
+ my ($file, $line) = @_;
+ my $key = first(split(' ', $line));
+ my $done;
+ substInFile {
+ $done = 1 if s|^\s*$key.*\n||;
+ } $file;
+}
+
+sub block_internet_dansguardian {
+ my ($file, $line) = @_;
+ my $key = "#";
+ substInFile {
+ s|^$key\*\*\s|**\n|;
+ } $file;
+}
+
+sub unblock_internet_dansguardian {
+ my ($file) = @_;
+ my $key = "#";
+ substInFile {
+ s|^\*\*\s|$key**\n|;
+ } $file;
+}
+
+sub enable_transparent_proxy {
+ my ($port) = @_;
+ #- FIXME: use network::squid once it is rewritten to be more gentle with the config file
+ subst_config_line($network::squid::squid_conf_file, "http_port $port transparent\n");
+}
+
+#- mostly duplicated for MDK::Common::System::getVarsFromSh
+sub read_dansguardian() {
+ my $guardian = {};
+ foreach (cat_($dansguardian_filter_file)) {
+ s/#.*//;
+ s/^\s*//;
+ my ($v, $val) = /^(\w+)\s*=\s*(.*)/ or next;
+ $val = $1 if $val =~ /^"(.*)"$/ || $val =~ /^'(.*)'$/;
+ $guardian->{$v} = $val;
+ }
+ $guardian;
+}
+
+sub write_dansguardian() {
+ require lang;
+ my $locale = lang::read();
+ my $locale_lang = lang::getlocale_for_lang($locale->{lang}, $locale->{country});
+ my %lang_to_dansguardian = reverse %dansguardian_langs;
+ my $dansguardian_lang = $lang_to_dansguardian{$locale_lang} || $lang_to_dansguardian{$locale->{lang}};
+
+ subst_config_line($dansguardian_main_file, "language = '$dansguardian_lang'\n") if $dansguardian_lang;
+ subst_config_line($dansguardian_filter_file, "naughtynesslimit = '$level'\n");
+ subst_config_line($dansguardian_filter_file, "netblock = '$net_control'\n");
+ subst_config_line($dansguardian_filter_file, "programblock = '$program_control'\n");
+ if ($net_control) {
+
+ block_internet_dansguardian($dansguardian_bannedsitelist);
+
+ }
+ else {
+
+ unblock_internet_dansguardian($dansguardian_bannedsitelist);
+ }
+}
+
+sub include_guardian_file {
+ my ($guardian_file, $external_file) = @_;
+ my $to_add = ".Include<$external_file>\n";
+ clean_config_line($guardian_file, "$to_add" );
+ my @all = cat_($guardian_file);
+ if ((($dansguardian_bannedsitelist eq $guardian_file) && !$net_control) || (($dansguardian_exceptionsitelist eq $guardian_file) && $net_control)) {
+ if (!member($to_add, @all)) {
+ output_p($guardian_file, @all, $to_add);
+ }
+ }
+}
+
+sub read_url_list {
+ my ($file) = @_;
+ grep { $_ && !/^\s*#/ } chomp_(cat_($file));
+}
+
+sub read_program_list {
+ my ($file) = @_;
+ grep { $_ && s/(\s*(\w+),)*//g } chomp_(cat_($file));
+}
+
+sub read_program_user_list {
+ my ($file) = @_;
+ my @user_list = grep { $_ && s/(.*?)\s//g } chomp_(cat_($file));
+ uniq(map{ my $user = $_;
+ $user =~ m/(\w+),/g;} @user_list);
+}
+
+sub apply_blacklist {
+ my @addr = @_;
+ my $blacklist_top = "/etc/dansguardian/lists/bannedsitelist";
+ my $blacklist_category = "blocked by Mageia parental control tool";
+ output_p($blacklist_url_file, map { $_ . "\n" }
+ qq(#listcategory: "$blacklist_category"), @addr);
+ include_guardian_file($blacklist_top, $blacklist_url_file);
+}
+
+sub apply_whitelist {
+ my @addr = @_;
+ my $whitelist_top = "/etc/dansguardian/lists/exceptionsitelist";
+ output_p($whitelist_url_file, map { $_ . "\n" } @addr);
+ include_guardian_file($whitelist_top, $whitelist_url_file);
+}
+
+sub apply_block_program {
+ #my @addr = @_;
+ #output_p($acl_file, map { $_ . "\n" } @addr);
+ if ($program_control) {
+ my @original_list = read_program_list(@url_lists[2]->{file});
+ my @orig_list = read_program_list(@url_lists[2]->{file});
+ for (@original_list){
+ s/\s(.*)//;
+ }
+ my @actual_list = list_get_entries(@url_lists[2]->{list});
+ my @act_list = list_get_entries(@url_lists[2]->{list});
+ for (@actual_list){
+ s/\s(.*)//;
+ }
+ #code to make diff bettween vectors
+ my (@union, @intersection, @difference);
+ my $element;
+ @union = @intersection = @difference = ();
+ my %count = ();
+ foreach $element (@original_list, @actual_list) { $count{$element}++ };
+ foreach $element (keys %count) {
+ # push @union, $element;
+ push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element;
+ }
+ if (scalar(@difference)) {
+ #keep the permissons save, make the way to do that
+ my $diff;
+ foreach $diff (@difference) {
+ my @orig_file = cat_($perms_orig);
+ my @progs_orig_file = grep { $_ && m/$diff/g } chomp_(cat_($perms_orig));
+ #test if program is in msec
+ my @msec_program = grep { $_ && m/$diff/g } chomp_(cat_($msec_conf));
+ if (scalar(@progs_orig_file)) {#test if is to remove or to add acl
+ #clean config file of the removed programs
+ foreach $element (@progs_orig_file){
+ my $val = $element;
+ substInFile {
+ s|$element.*\n||;
+ } $perms_orig;
+ $val =~ s/\t(.*)\s*//;
+ $element =~ s/^(\d+)\t//;
+ if ($val) {
+ #write back in the msec file and set original file permissions
+ #`unprotect $diff --remove`;
+ remove_acl($dansguardian_protected_program_list, $diff);
+ subst_config_line($msec_conf,"$element\n");
+ restore_permissions($element);
+ }
+ else {
+ #only make the permissions wright
+ #`unprotect $diff --remove`;
+ remove_acl($dansguardian_protected_program_list, $diff);
+ clean_config_line($msec_conf,"$diff");
+ restore_permissions($element);
+ }
+ }
+ }
+ else {
+ if (scalar(@msec_program)){
+ output_p($perms_orig, @orig_file, "1\t".$_."\n") foreach @msec_program;
+ #add file to msec and set acls
+ }
+ else {
+ my $mode = (stat($diff))[2] & 07777;
+ #"%04o" important to make 0755 to chmod ou chown
+ $mode = sprintf "%lo", $mode;
+ my $uid = (stat($diff))[4];
+ my $gid = (stat($diff))[5];
+ my $usrname = getpwuid($uid);
+ my $gname = getgrgid($gid);
+ my $to_add = "0\t$diff\t$usrname.$gname\t$mode\n";
+ #keep the permissons safe make the way to do that
+ output_p($perms_orig, @orig_file, $to_add);
+ }
+ set_permissions($diff, grep {$_ && m/$diff/g} @act_list);
+ }
+ }
+ }
+ #this is just the case to reactivate the parental control
+ #`unprotect $_ --remove` foreach @intersection;
+ remove_acl($dansguardian_protected_program_list, $_) foreach @intersection;
+ foreach my $intersec (@intersection){
+ set_permissions($intersec, grep {$_ && m/$intersec/g} @orig_list);
+ }
+ }
+ else {
+ my @original_list = list_get_entries(@url_lists[2]->{list});
+ for (@original_list){
+ s/\s(.*)//;
+ }
+ #restore the original file permissions
+ `setfacl -b $_` foreach @original_list;
+ foreach my $list (@original_list) {
+ my @progs_orig_file = grep { $_ && m/$list/g } chomp_(cat_($perms_orig));
+ #test if program is in msec
+ if (scalar(@progs_orig_file)) {
+ #clean config file of the removed programs
+ foreach my $element (@progs_orig_file){
+ my $val = $element;
+ $val =~ s/\t(.*)\s*//;
+ $element =~ s/^(\d+)\t//;
+ if ($val) {
+ #write back in the msec file and set original file permissions
+ subst_config_line($msec_conf,"$element\n");
+ restore_permissions($element);
+ }
+ else {
+ #only make the permissions wright
+ clean_config_line($msec_conf,"$list");
+ restore_permissions($element);
+ }
+ }
+ }
+ }
+ }
+}