diff options
author | Nicolas Lécureuil <nlecureuil@mandriva.com> | 2011-08-30 13:16:42 +0000 |
---|---|---|
committer | Nicolas Lécureuil <nlecureuil@mandriva.com> | 2011-08-30 13:16:42 +0000 |
commit | c590a4a7c162d1a81dbf02ca2e174384af0385bb (patch) | |
tree | 7e1279550b8e48add99b7b41281d27d249d279f3 /bin | |
parent | 39d2ee13572a6dc634c0c454dfc43e0297483279 (diff) | |
download | drakx-net-c590a4a7c162d1a81dbf02ca2e174384af0385bb.tar drakx-net-c590a4a7c162d1a81dbf02ca2e174384af0385bb.tar.gz drakx-net-c590a4a7c162d1a81dbf02ca2e174384af0385bb.tar.bz2 drakx-net-c590a4a7c162d1a81dbf02ca2e174384af0385bb.tar.xz drakx-net-c590a4a7c162d1a81dbf02ca2e174384af0385bb.zip |
Create 2010.1 branch for drakx-net
Diffstat (limited to 'bin')
-rw-r--r-- | bin/.perl_checker | 1 | ||||
-rwxr-xr-x | bin/drakconnect | 58 | ||||
-rwxr-xr-x | bin/drakconnect-old | 313 | ||||
-rwxr-xr-x | bin/drakfirewall | 34 | ||||
-rwxr-xr-x | bin/drakgw | 454 | ||||
-rw-r--r-- | bin/drakhosts | 261 | ||||
-rw-r--r-- | bin/drakids | 337 | ||||
-rwxr-xr-x | bin/drakinvictus | 151 | ||||
-rwxr-xr-x | bin/draknetcenter | 28 | ||||
-rwxr-xr-x | bin/draknetprofile | 226 | ||||
-rwxr-xr-x | bin/draknfs | 629 | ||||
-rwxr-xr-x | bin/drakproxy | 38 | ||||
-rwxr-xr-x | bin/drakroam | 28 | ||||
-rwxr-xr-x | bin/draksambashare | 1474 | ||||
-rw-r--r-- | bin/drakvpn | 17 | ||||
-rwxr-xr-x | bin/net_applet | 585 | ||||
-rwxr-xr-x | bin/net_monitor | 642 |
17 files changed, 5276 insertions, 0 deletions
diff --git a/bin/.perl_checker b/bin/.perl_checker new file mode 100644 index 0000000..202e053 --- /dev/null +++ b/bin/.perl_checker @@ -0,0 +1 @@ +Basedir .. diff --git a/bin/drakconnect b/bin/drakconnect new file mode 100755 index 0000000..7a95cc1 --- /dev/null +++ b/bin/drakconnect @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +# DrakConnect $Id$ + +# Copyright (C) 1999-2006 Mandriva +# Damien "Dam's" Krotkine +# Damien "poulpy" Chaumette +# Thierry Vignaud <tvignaud@mandriva.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +use lib qw(/usr/lib/libDrakX); +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use strict; +use standalone; #- warning, standalone must be loaded very first, for 'explanations' +use interactive; +use common; +use network::network; +use modules; + +$ugtk2::wm_icon = "drakconnect"; +my $in = 'interactive'->vnew('su'); + +my $net = {}; +network::network::read_net_conf($net); +my $modules_conf = modules::any_conf->read; + +local $_ = join '', @ARGV; +if (/--skip-wizard/) { + require network::drakconnect::edit; + network::drakconnect::edit::manage($in, $net, $modules_conf); +} elsif (/--del/) { + require network::drakconnect::delete; + network::drakconnect::delete::del_intf($in, $net, $modules_conf); +} elsif (/--internet/) { + require network::drakconnect::global; + network::drakconnect::global::configure_net($in, $net, $modules_conf); +} else { + # default is to run wizard (--add) + require network::netconnect; + network::netconnect::safe_main($net, $in, $modules_conf); +} + +$modules_conf->write; +$in->exit(0); diff --git a/bin/drakconnect-old b/bin/drakconnect-old new file mode 100755 index 0000000..81ec706 --- /dev/null +++ b/bin/drakconnect-old @@ -0,0 +1,313 @@ +#!/usr/bin/perl + +# DrakConnect $Id: drakconnect 239415 2008-03-14 11:06:49Z blino $ + +# Copyright (C) 1999-2006 Mandriva +# Damien "Dam's" Krotkine +# Damien "poulpy" Chaumette +# Thierry Vignaud <tvignaud@mandriva.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +use strict; +use lib qw(/usr/lib/libDrakX); +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; #- warning, standalone must be loaded very first, for 'explanations' +use common; +use interactive; +use ugtk2 qw(:create :dialogs :helpers :wrappers); +use mygtk2 qw(gtknew); +use network::netconnect; +use network::connection::ethernet; + +$ugtk2::wm_icon = "drakconnect"; +my $in = 'interactive'->vnew('su'); + +my $net = {}; +network::network::read_net_conf($net); +my $modules_conf = modules::any_conf->read; + +my @all_cards; + +my $window1 = ugtk2->new(N("Network configuration (%d adapters)", scalar @all_cards)); +$window1->{rwindow}->signal_connect(delete_event => sub { ugtk2->exit(0) }); +unless ($::isEmbedded) { + $window1->{rwindow}->set_position('center'); + $window1->{rwindow}->set_size_request(-1, -1); +} +$window1->{rwindow}->set_border_width(10); + +my $button_apply; + + +my $hostname = chomp_(`hostname`); + +my $tree_model = Gtk2::TreeStore->new("Gtk2::Gdk::Pixbuf", map { "Glib::String" } 2..6); +my $list = Gtk2::TreeView->new_with_model($tree_model); +$list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererPixbuf->new, 'pixbuf' => 0)); +each_index { + $list->append_column(my $col = Gtk2::TreeViewColumn->new_with_attributes($_, Gtk2::CellRendererText->new, 'text' => $::i + 1)); + $col->set_sort_column_id($::i); +} (N("Interface"), N("IP address"), N("Protocol"), N("Driver"), N("State")); + +$list->signal_connect(button_press_event => sub { + my (undef, $event) = @_; + my (undef, $iter) = $list->get_selection->get_selected; + return unless $iter; + configure_lan() if $event->type eq '2button-press'; + }); + +update_list($modules_conf); + +my $label_host; +$window1->{window}->add( + gtkpack__(Gtk2::VBox->new(0,10), + gtkpack(Gtk2::HBox->new, + Gtk2::Label->new(N("Hostname: ")), + $label_host = Gtk2::Label->new($hostname), + gtksignal_connect(Gtk2::Button->new(N("Configure hostname...")), + clicked => sub { + local ($::isWizard, $::Wizard_finished) = (1, 1); + eval { # For wizcancel + network::netconnect::real_main($net, $in, $modules_conf); + $button_apply->set_sensitive(1); + update(); + }; + if ($@ =~ /wizcancel/) {} + $::WizardWindow->destroy; + undef $::WizardWindow; + } + ), + ), + gtkadd(gtkcreate_frame(N("LAN configuration")), + gtkpack_(gtkset_border_width(Gtk2::VBox->new(0,0), 5), + 0, $list, + 0, Gtk2::HBox->new(0,0), + 0, gtkpack_(Gtk2::HBox->new(0, 0), + 0, gtksignal_connect(Gtk2::Button->new(N("Configure Local Area Network...")), + clicked => \&configure_lan), + ), + ) + ), + gtkpack(Gtk2::HButtonBox->new, + gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub { + run_program::raw({ detach => 1 }, 'drakhelp', '--id', 'internet-connection') }), + $button_apply = gtksignal_connect(gtkset_sensitive(Gtk2::Button->new(N("Apply")), 0), + clicked => \&apply), + gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => \&quit_global), + gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { + if ($button_apply->get('sensitive')) { + my $dialog = _create_dialog(N("Please wait")); + gtkpack($dialog->vbox, + Gtk2::Label->new(N("Please Wait... Applying the configuration"))); + $dialog->show_all; + gtkflush(); + apply(); + $dialog->destroy; + } + update(); + quit_global(); + }), + ), + ), + ); + + + +$window1->{rwindow}->show_all; +gtkflush(); +$window1->main; +ugtk2->exit(0); + +sub quit_global() { + ugtk2->exit(0); +} + +sub get_intf_status { + my ($c) = @_; + ethisup($c) ? N("Deactivate now") : N("Activate now"); +} + +my %intf; +sub update_list { + my ($modules_conf) = @_; + @all_cards = network::connection::ethernet::get_eth_cards($modules_conf); + my %new_intf = map { @$_ } @all_cards; + my @new_intf = sort keys %new_intf; + foreach my $interface (difference2(\@new_intf, [ keys %intf ])) { + $intf{$interface} = $tree_model->append(undef); + } + foreach my $interface (@new_intf) { + my ($ip, $state) = get_intf_ip($interface); + $tree_model->set($intf{$interface}, map_index { $::i => $_ } (gtkcreate_pixbuf("eth_card_mini2"), $interface, $ip , $net->{ifcfg}{$interface}{BOOTPROTO}, $new_intf{$interface}, $state)); + } + foreach my $i (difference2([ keys %intf ], \@new_intf)) { + $tree_model->remove($intf{$i}); + delete $intf{$i}; + } +} + +sub update() { + my $h = chomp_(`hostname`); + $label_host->set_label($h); + update_list($modules_conf); + 1; +} + +sub configure_lan() { + my $window = _create_dialog(N("LAN configuration")); + my @card_tab; + + if (@all_cards < 1) { + $window->vbox->add(Gtk2::Label->new(N("You do not have any configured interface. +Configure them first by clicking on 'Configure'"))); + gtkpack(gtkset_layout($window->action_area, 'end'), + gtksignal_connect(Gtk2::Button->new(N("Ok")), + clicked => sub { Gtk2->main_quit }) + ); + $window->show_all; + $window->run; + $window->destroy; + return; + } + + $window->set_border_width(10); + gtkpack($window->vbox, + Gtk2::Label->new(N("LAN Configuration")), + my $notebook = Gtk2::Notebook->new, + ); + + foreach (0..$#all_cards) { + my @infos; + my @conf_data; + $card_tab[2*$_] = \@infos; + $card_tab[2*$_+1] = \@conf_data; + + my $vbox_local = Gtk2::VBox->new(0,0); + $vbox_local->set_border_width(10); + $vbox_local->pack_start(Gtk2::Label->new(N("Adapter %s: %s", $_+1 , $all_cards[$_][0])),1,1,0); + # Eth${_}Hostname = $netc->{HOSTNAME} + # Eth${_}HostAlias = " . do { $netc->{HOSTNAME} =~ /([^\.]*)\./; $1 } . " + # Eth${_}Driver = $all_cards[$_]->[1] + my $interface = $all_cards[$_][0]; + my ($ip, undef, $mask) = get_intf_ip($interface); + $mask ||= $net->{ifcfg}{$interface}{NETMASK}; + @conf_data = ([ N("IP address"), \$ip ], + [ N("Netmask"), \$mask ], + [ N("Boot Protocol"), \$net->{ifcg}{$interface}{BOOTPROTO}, ["static", "dhcp", "bootp"] ], + [ N("Started on boot"), \$net->{ifcg}{$interface}{ONBOOT} , ["yes", "no"] ], + [ N("DHCP client"), \$net->{ifcfg}{$interface}{DHCP_CLIENT} ] + ); + my $i = 0; + my $size_group = Gtk2::SizeGroup->new('horizontal'); + + foreach my $j (@conf_data) { + my $l = Gtk2::Label->new($j->[0]); + $l->set_justify('left'); + $infos[2*$i] = gtkpack_(Gtk2::HBox->new, + 1, $l); + $vbox_local->pack_start($infos[2*$i], 1, 1, 0); + my $c; + if (defined $j->[2]) { + $c = Gtk2::ComboBox->new_text; + $c->set_popdown_strings(@{$j->[2]}); + $infos[2*$i+1] = $c->entry; + $infos[2*$i]->pack_start($c,0,0,0); + } else { + $infos[2*$i+1] = ($c = Gtk2::Entry->new); + $infos[2*$i]->pack_start($infos[2*$i+1],0,0,0); + } + $size_group->add_widget($c); + $infos[2*$i+1]->set_text(${$j->[1]}); + $i++; + } + + my $widget_temp; + if (-e "/etc/sysconfig/network-scripts/ifcfg-$interface") { + $widget_temp = gtksignal_connect(Gtk2::Button->new(get_intf_status($interface)), + clicked => sub { + system("/sbin/if" . (ethisup($interface) ? "down" : "up") . " $interface"); + $_[0]->set_label(get_intf_status($interface)); + update(); + }); + } else { + $widget_temp = N("This interface has not been configured yet.\nRun the \"%s\" assistant from the Mandriva Linux Control Center", N("Set up a new network interface (LAN, ISDN, ADSL, ...)")); + } + $vbox_local->pack_start(gtkpack__(Gtk2::HBox->new(0,0), + $widget_temp + ),0,0,0); + # $list->append($_+1, $interface, $intf->{$interface}{IPADDR}, $intf->{$interface}{BOOTPROTO}, $all_cards[$_]->[1]); + # $list->set_selectable($_, 0); + $notebook->append_page($vbox_local, Gtk2::Label->new($interface)); + } + + my $exit_dialogsub = sub { + $window->destroy; + Gtk2->main_quit; + }; + + gtkpack($window->action_area, + gtksignal_connect(Gtk2::Button->new(N("Cancel")), + clicked => $exit_dialogsub), + gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { + foreach (0..$#all_cards) { + my @infos = @{$card_tab[2*$_]}; + each_index { ${$_->[1]} = $infos[2*$::i+1]->get_text } @{$card_tab[2*$_+1]}; + my $interface = $all_cards[$_][0]; + if ($net->{ifcfg}{$interface}{BOOTPROTO} ne "static") { + delete @{$net->{ifcfg}{$interface}}{qw(IPADDR NETWORK NETMASK BROADCAST)}; + } else { + if ($infos[1]->get_text ne N("No IP")) { + $net->{ifcfg}{$interface}{IPADDR} = $infos[1]->get_text; + $net->{ifcfg}{$interface}{NETMASK} = $infos[3]->get_text; + } + } + } + update(); + $button_apply->set_sensitive(1); + $exit_dialogsub->(); + }), + ); + + $window->show_all; + foreach (0..$#all_cards) { + my @infos = @{$card_tab[2*$_]}; + $net->{ifcfg}{$all_cards[$_][0]}{BOOTPROTO} eq "dhcp" or $infos[8]->hide; + } + $window->run; +} + +sub apply() { + network::network::configure_network($net, $in, $modules_conf); +} + +sub ethisup { `LC_ALL=C LANGUAGE=C /sbin/ifconfig $_[0]` =~ /inet/ } + +# FIXME: duplicated with drakconnect +sub get_intf_ip { + my ($interface) = @_; + my ($ip, $state, $mask); + if (-x "/sbin/ifconfig") { + local $_ = `LC_ALL=C LANGUAGE=C /sbin/ifconfig $interface`; + $ip = /inet addr:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/mso ? $1 : N("No IP"); + $mask = /Mask:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/mso ? $1 : N("No Mask"); + $state = /inet/ ? N("up") : N("down"); + } else { + $ip = $net->{ifcfg}{$interface}{IPADDR}; + $state = "n/a"; + } + ($ip, $state, $mask); +} diff --git a/bin/drakfirewall b/bin/drakfirewall new file mode 100755 index 0000000..4588047 --- /dev/null +++ b/bin/drakfirewall @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +# Copyright (C) 1999-2006 Mandriva (pixel@mandrakesoft.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; #- warning, standalone must be loaded very first, for 'explanations' + +use interactive; +use network::drakfirewall; + +$ugtk2::wm_icon = "/usr/share/mcc/themes/default/firewall-mdk.png"; + +my $in = 'interactive'->vnew('su'); + +network::drakfirewall::main($in, undef); + +$in->exit; diff --git a/bin/drakgw b/bin/drakgw new file mode 100755 index 0000000..be3f5b9 --- /dev/null +++ b/bin/drakgw @@ -0,0 +1,454 @@ +#!/usr/bin/perl + +# +# author Guillaume Cottenceau (gc@mandrakesoft.com) +# modified by Florin Grad (florin@mandrakesoft.com) +# wizardified by Olivier Blin (oblin@mandriva.com) +# +# Copyright 2000-2006 Mandriva +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +use strict; +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; #- warning, standalone must be loaded very first, for 'explanations' + +use common; +use detect_devices; +use interactive; +use network::network; +use network::connection::ethernet; +use run_program; +use log; +use c; +use network::shorewall; +use network::dhcpd; +use network::squid; +use services; + +my $sysconf_network = "/etc/sysconfig/network"; +my $masq_file = "$::prefix/etc/shorewall/masq"; +my $cups_conf = "$::prefix/etc/cups/cupsd.conf"; + +my $in = 'interactive'->vnew('su'); + +my $net = {}; +network::network::read_net_conf($net); +my $modules_conf = modules::any_conf->read; +my %eth_intf = map { $_->[0] => join(': ', $_->[0], $_->[2]) } network::connection::ethernet::get_eth_cards($modules_conf); + +my $shorewall = network::shorewall::read(); +my $choice; +my $gw_enabled; +my ($lan_interface_name, $lan_intf, $internal_domain_name); +my $use_dhcpd = 1; +my $use_caching_dns = 1; +my $use_caching_proxy = 1; + +my $resolv_conf = network::network::read_resolv_conf_raw(); +my $squid_conf = network::squid::read_squid_conf(); +my $dhcpd_conf = network::dhcpd::read_dhcpd_conf(); + +require wizards; +my $wiz = wizards->new( + { + defaultimage => "drakgw", + name => N("Internet Connection Sharing"), + pages => { + welcome => + { + name => N("You are about to configure your computer to share its Internet connection. +With that feature, other computers on your local network will be able to use this computer's Internet connection. + +Make sure you have configured your Network/Internet access using drakconnect before going any further. + +Note: you need a dedicated Network Adapter to set up a Local Area Network (LAN). Please disable Mandriva Firewall for the network adapter connected to your LAN connection before proceeding."), + post => sub { + $gw_enabled = !$shorewall->{disabled} && grep { !/^#/ } cat_($masq_file); + return $gw_enabled ? "ask_reconfigure" : "choose_net_interface"; + }, + }, + + ask_reconfigure => + { + name => sub { + $gw_enabled ? + N("The setup of Internet Connection Sharing has already been done. +It's currently enabled. + +What would you like to do?") : + N("The setup of Internet connection sharing has already been done. +It's currently disabled. + +What would you like to do?"); #- FIXME : not used for now + }, + data => sub { + [ { type => "list", val => \$choice, list => [ ($gw_enabled ? N_("Disable") : N_("Enable")), N_("Reconfigure") ], format => \&translate } ]; + }, + post => sub { + if ($choice eq "Enable") { + #- FIXME, not used for now + #- gw_enable(); + return "end_enabled"; + } elsif ($choice eq "Disable") { + gw_disable(); + return "end_disabled"; + } elsif ($choice eq "Reconfigure") { + return "choose_net_interface"; + } + }, + }, + + choose_net_interface => + { + pre => sub { + $shorewall->{masq}{net_interface} = network::tools::get_default_gateway_interface($net); + }, + name => N("Please select the network interface directly connected to the internet."), + data => [ { label => N("Net Device"), val => \$shorewall->{masq}{net_interface}, list => [ sort keys %{$net->{ifcfg}} ], format => sub { network::tools::get_interface_description($net, $_[0]) } } ], + post => sub { + network::shorewall::add_interface_to_net_zone($shorewall, $shorewall->{masq}{net_interface}); + my $locals = @{$shorewall->{loc_zone}}; + if ($locals == 0) { + return "end_no_lan_interface"; + } elsif ($locals == 1) { + $lan_interface_name = $shorewall->{loc_zone}[0]; + return "one_lan_interface"; + } else { + return "choose_lan_interface"; + } + }, + }, + + one_lan_interface => + { + name => sub { + N("There is only one network adapter on your system configured for LAN connections: + +%s + +I am about to setup your Local Area Network with that adapter. + +If you have any other adapter connected to Local Area Network, +disable the firewall protection on it using drakfirewall before +configuring Internet Connection sharing.", format_interfaces($lan_interface_name)); + }, + next => "lan_configure", + }, + + choose_lan_interface => + { + name => N("Please choose what network adapter will be connected to your Local Area Network."), + data => sub { + [ { type => "list", val => \$lan_interface_name, list => $shorewall->{loc_zone}, format => \&format_interfaces } ]; + }, + post => sub { + log::explanations("Choosing network device: $lan_interface_name"); + "lan_configure"; + }, + }, + + lan_configure => + { + pre => sub { + $lan_intf = $net->{ifcfg}{$lan_interface_name} ||= {}; + $lan_intf->{DEVICE} = $lan_interface_name; + $lan_intf->{ONBOOT} = 'yes'; + $lan_intf->{BOOTPROTO} = 'static'; + $lan_intf->{IPADDR} ||= "192.168.1.1"; + $lan_intf->{NETMASK} ||= "255.255.255.0"; + $internal_domain_name = $resolv_conf->{search}[0] ||= "homeland.net"; + }, + name => N("Local Area Network settings"), + data => sub { + [ + { label => N("Local IP address"), val => \$lan_intf->{IPADDR} }, + { label => N("Netmask"), val => \$lan_intf->{NETMASK} }, + { label => N("The internal domain name"), val => \$internal_domain_name }, + ]; + }, + complete => sub { + network::network::update_broadcast_and_network($lan_intf); + if (my $conflict = find { $_->{NETWORK} eq $lan_intf->{NETWORK} } grep { $_->{DEVICE} ne $lan_intf->{DEVICE} } values %{$net->{ifcfg}}) { + $in->ask_warn(N("Error"), N("Potential LAN address conflict found in current config of %s!\n", $conflict->{DEVICE})); + return 1; + } + 0; + }, + post => sub { + network::network::configure_network($net, $in, $modules_conf) unless $::testing; + return "dns"; + }, + }, + + dns => + { + pre => sub { + $dhcpd_conf->{domain_name_servers}[0] = $resolv_conf->{nameserver}[0] ||= $lan_intf->{IPADDR}; + }, + name => N("Domain Name Server (DNS) configuration"), + data => sub { + my @disable = (disabled => sub { $use_caching_dns }); + [ + { text => N("Use this gateway as domain name server"), val => \$use_caching_dns, type => 'bool' }, + { label => N("The DNS Server IP"), val => \$dhcpd_conf->{domain_name_servers}[0], @disable }, + ]; + }, + complete => sub { + !$use_caching_dns || $::testing and return 0; + #- install a caching name server if the specified DNS is the gateway + !$in->do_pkgs->ensure_is_installed('bind', '/usr/sbin/named'); + }, + post => sub { + services::set_status($_, $use_caching_dns) foreach qw(named); + return "dhcpd"; + }, + }, + + dhcpd => + { + pre => sub { + #- not editable + $dhcpd_conf->{option_routers}[0] = $lan_intf->{IPADDR}; + $dhcpd_conf->{subnet_mask}[0] = $lan_intf->{NETMASK}; + $dhcpd_conf->{domain_name}[0] = $internal_domain_name; + #- editable + $dhcpd_conf->{dynamic_bootp}[0] ||= "16"; + $dhcpd_conf->{dynamic_bootp}[1] ||= "253"; + $dhcpd_conf->{default_lease_time}[0] ||= "21600"; + $dhcpd_conf->{max_lease_time}[0] ||= "43200"; + }, + name => N("DHCP Server Configuration. + +Here you can select different options for the DHCP server configuration. +If you do not know the meaning of an option, simply leave it as it is."), + data => sub { + my @advanced_disable = (advanced => 1, disabled => sub { !$use_dhcpd }); + [ + { text => N("Use automatic configuration (DHCP)"), val => \$use_dhcpd, type => 'bool' }, + { label => N("The DHCP start range"), val => \$dhcpd_conf->{dynamic_bootp}[0], @advanced_disable }, + { label => N("The DHCP end range"), val => \$dhcpd_conf->{dynamic_bootp}[1], @advanced_disable }, + { label => N("The default lease (in seconds)"), val => \$dhcpd_conf->{default_lease_time}[0], @advanced_disable }, + { label => N("The maximum lease (in seconds)"), val => \$dhcpd_conf->{max_lease_time}[0], @advanced_disable } + ]; + }, + complete => sub { + !$use_dhcpd || $::testing and return 0; + $in->do_pkgs->ensure_is_installed('dhcp-server', '/usr/sbin/dhcpd') or return 1; + 0; + }, + post => sub { + network::dhcpd::write_dhcpd_conf($dhcpd_conf, $lan_intf->{DEVICE}) if $use_dhcpd; + services::set_status("dhcpd", $use_dhcpd); + return "proxy"; + } + }, + + proxy => + { + pre => sub { + $squid_conf->{http_port}[0] ||= "3128"; + $squid_conf->{cache_size}[1] ||= "100"; + $squid_conf->{admin_mail}[0] ||= 'admin@mydomain.com'; + $squid_conf->{visible_hostname}[0] ||= 'myfirewall@mydomain.com'; + }, + name => N("Proxy caching server (SQUID)"), + data => sub { + my @disable = (advanced => 1, disabled => sub { !$use_caching_proxy }); + [ + { text => N("Use this gateway as proxy caching server"), val => \$use_caching_proxy, type => 'bool' }, + { label => N("Admin mail"), val => \$squid_conf->{admin_mail}[0], @disable }, + { label => N("Visible hostname"), val => \$squid_conf->{visible_hostname}[0], @disable }, + { label => N("Proxy port"), val => \$squid_conf->{http_port}[0], advanced => 1, @disable }, + { label => N("Cache size (MB)"), val => \$squid_conf->{cache_size}[1], advanced => 1, @disable }, + ]; + }, + complete => sub { + !$use_caching_proxy || $::testing and return 0; + $in->do_pkgs->ensure_is_installed('squid', '/usr/sbin/squid') or return 1; + 0; + }, + post => sub { + network::squid::write_squid_conf($squid_conf, $lan_intf, $internal_domain_name) if $use_caching_proxy; + services::set_status("squid", $use_caching_proxy); + network::shorewall::set_redirected_ports($shorewall, 'tcp', $squid_conf->{http_port}[0], if_($use_caching_proxy, 'http')); + @{$shorewall->{accept_local_users}{http}} = if_($use_caching_proxy, 'squid'); + -f $cups_conf ? "cups" : end_step(); + }, + }, + + cups => + { + name => N("Broadcast printer information"), + type => "yesorno", + default => "yes", + post => sub { + update_cups() unless $::testing; + end_step(); + }, + }, + + end_no_lan_interface => + { + name => N("No ethernet network adapter configured for LAN has been detected on your system. + +Please run the hardware configuration tool to configure it, and ensure that the Mandriva firewall is not enabled for network adapter connected to your LAN network."), + end => 1, + }, + + end_enabled => + { + name => N("Internet Connection Sharing is now enabled."), + end => 1, + }, + + end_disabled => + { + name => N("Internet Connection Sharing is now disabled."), + end => 1, + }, + + end => + { + name => N("Everything has been configured. +You may now share Internet connection with other computers on your Local Area Network, using automatic network configuration (DHCP) and + a Transparent Proxy Cache server (SQUID)."), + end => 1, + }, + }, +}); +$wiz->safe_process($in); + + + +sub format_interfaces { + my ($interface) = @_; + $eth_intf{$interface} || $interface; +} + +sub end_step() { + gw_configure(); + log::l("[drakgw] Installation complete, exiting"); + "end"; +} + +sub gw_disable() { + my $_wait_disabl = $in->wait_message(N("Please wait"), N("Disabling servers...")); + return if $::testing; + services::set_status($_, 0) foreach qw(dhcpd squid named); + network::shorewall::set_redirected_ports($shorewall, 'tcp', $squid_conf->{http_port}[0], ()); + network::shorewall::write($shorewall); + foreach ($network::dhcpd::dhcpd_conf_file, $network::squid::squid_conf_file, $masq_file) { + if (-f $_) { rename($_, "$_.drakgwdisable") or die "Could not rename $_ to $_.drakgwdisable" } + } + services::restart("shorewall"); +} + +sub gw_configure() { + #- test for potential conflict with previous firewall config + if (network::shorewall::check_iptables()) { + $in->ask_warn(N("Firewalling configuration detected!"), + N("Warning! An existing firewalling configuration has been detected. You may need some manual fixes after installation.")); + } + + $in->do_pkgs->ensure_is_installed('shorewall', '/sbin/shorewall') or $in->exit(-1); + + my $_wait_configuring = $in->wait_message(N("Configuring..."), + N("Configuring firewall...")); + + $shorewall->{disabled} = 0; + $shorewall->{masq}{subnet} = $lan_intf->{NETWORK} . '/' . network::network::netmask_to_vlsm($lan_intf->{NETMASK}); + network::shorewall::write($shorewall); + + #- be sure that FORWARD_IPV4 is enabled in /etc/sysconfig/network + log::explanations("Enabling IPV4 forwarding"); + substInFile { s/^FORWARD_IPV4.*\n//; $_ .= "FORWARD_IPV4=true\n" if eof } $sysconf_network if !$::testing; + services::restart("network"); +} + +sub update_cups() { + #- Set up /etc/cups/cupsd.conf to make the broadcasting of the printer info + #- working correctly: + #- + #- 1. ServerName <server's IP address> # because clients do necessarily + #- # know the server's name + #- + #- 2. BrowseAddress <server's Broadcast IP> # broadcast printer info into + #- # the local network. + #- + #- 3. BrowseOrder Deny,Allow + #- BrowseDeny All + #- BrowseAllow <IP mask for local net> # Only accept broadcast signals + #- # coming from local network + #- + #- 4. <Location /> + #- Order Deny,Allow + #- Deny From All + #- Allow From <IP mask for local net> # Allow only machines of local + #- </Location> # network to access the server + #- + #- These steps are only done when the CUPS package is installed. + + #- Modify the root location block in /etc/cups/cupsd.conf + + log::explanations("Updating CUPS configuration accordingly"); + + substInFile { + s/^ServerName[^:].*\n//; $_ .= "ServerName $lan_intf->{IPADDR}\n" if eof; + s/^BrowseAddress.*\n//; $_ .= "BrowseAddress $lan_intf->{BROADCAST}\n" if eof; + s/^BrowseOrder.*\n//; $_ .= "BrowseOrder Deny,Allow\n" if eof; + s/^BrowseDeny.*\n//; $_ .= "BrowseDeny All\n" if eof; + s/^BrowseAllow.*\n//; $_ .= "BrowseAllow \@IF($lan_interface_name)\n" if eof; + } $cups_conf; + + my @cups_conf_content = cat_($cups_conf); + my @root_location; my $root_location_start; my $root_location_end; + + # Cut out the root location block so that it can be treated seperately + # without affecting the rest of the file + if (any { m|^\s*<Location\s+/\s*>| } @cups_conf_content) { + $root_location_start = -1; + $root_location_end = -1; + # Go through all the lines, bail out when start and end line found + for (my $i = 0; $i < @cups_conf_content && $root_location_end == -1; $i++) { + if ($cups_conf_content[$i] =~ m|^\s*<\s*Location\s+/\s*>|) { + $root_location_start = $i; + } elsif ($cups_conf_content[$i] =~ m|^\s*<\s*/Location\s*>| && $root_location_start != -1) { + $root_location_end = $i; + } + } + # Rip out the block and store it seperately + @root_location = splice(@cups_conf_content, $root_location_start, $root_location_end - $root_location_start + 1); + } else { + # If there is no root location block, create one + $root_location_start = @cups_conf_content; + @root_location = ("<Location />\n", "</Location>\n"); + } + + # Delete all former "Order", "Allow", and "Deny" lines from the root location block + s/^\s*Order.*//, s/^\s*Allow.*//, s/^\s*Deny.*// foreach @root_location; + + # Add the new "Order" and "Deny" lines, add an "Allow" line for the local network + splice(@root_location, -1, 0, $_) foreach "Order Deny,Allow\n", "Deny From All\n", "Allow From 127.0.0.1\n", + "Allow From \@IF($lan_interface_name)\n"; + + # Put the changed root location block back into the file + splice(@cups_conf_content, $root_location_start, 0, @root_location); + + output $cups_conf, @cups_conf_content; +} diff --git a/bin/drakhosts b/bin/drakhosts new file mode 100644 index 0000000..1b99c1b --- /dev/null +++ b/bin/drakhosts @@ -0,0 +1,261 @@ +#!/usr/bin/perl +# +# Copyright (C) 2005-2006 by Mandriva aginies _ateuh_ mandriva.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +my $version = "0.1"; + +# i18n: IMPORTANT: to get correct namespace (drakhosts instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakhosts' } + +use lib qw(/usr/lib/libDrakX); +use standalone; +use strict; +use common; +use network::network; + +$ugtk2::wm_icon = 'IC-Dhost-48'; +use mygtk2 qw(gtknew); +use ugtk2 qw(:ask :wrappers :create :dialogs); + +use constant FALSE => 0; + + +my $HOSTS = "/etc/hosts"; +my @listhosts; + +use constant COLUMN_IP => 0; +use constant COLUMN_HOSTNAME => 1; +use constant COLUMN_ALIAS => 2; +use constant NUM_COLUMNS => 3; + +require_root_capability(); + +my %size_groups = map { $_ => Gtk2::SizeGroup->new('horizontal') } qw(label widget); +my $label_and_widgets = sub { + my ($label, $widget) = @_; + gtkpack_(Gtk2::HBox->new(0,5), + 0, gtkadd_widget($size_groups{label}, gtknew('Label_Left', text => $label)), + 1, gtkadd_widget($size_groups{widget}, $widget), + ); +}; + + +sub get_host_data() { +# 127.0.0.1 localhost.localdomain localhost +# 10.0.1.253 guibpiv.guibland.com + foreach (cat_($HOSTS)) { + my ($ip, $name, $alias) = /^(\d\S*)\s+(\S*)\s+(.*)$/; + $ip and push @listhosts, { + ip => $ip, + hostname => $name, + alias => $alias, + }; + } +} + +sub write_conf_hosts() { + output($HOSTS, "# generated by drakhosts\n"); + foreach my $a (@listhosts) { + append_to_file($HOSTS, "$a->{ip} $a->{hostname} $a->{alias}\n"); + } +} + +sub add_modify_entry { + my ($treeview, $wanted, $title) = @_; + my $model = $treeview->get_model; + my $selection = $treeview->get_selection; + my $iter; + my ($i, $ip, $hostname, $alias, $oldip); + undef $i; + undef $iter; + + $_ = Gtk2::Entry->new foreach $ip, $hostname, $alias; + +# test if modify or add a host + + my $dialog = _create_dialog(); + $dialog->set_transient_for($::main_window); + $dialog->set_title($title); + $dialog->set_modal(1); + $dialog->set_resizable(1); + $dialog->set_size_request(300, -1); + + if ($wanted =~ /modify/) { + $iter = $selection->get_selected; + $iter or info_dialog(N("Error"), N("Please add an host to be able to modify it.")) and return; + my $path = $model->get_path($iter); + $i = ($path->get_indices)[0]; + $ip->set_text($listhosts[$i]{ip}); + $hostname->set_text($listhosts[$i]{hostname}); + $alias->set_text($listhosts[$i]{alias}); + $oldip = $listhosts[$i]{ip}; + } + + my $text; + $text = N("Please modify information") if $wanted =~ /modify/; + $text = N("Please delete information") if $wanted =~ /delete/; + $text = N("Please add information") if $wanted =~ /add/; + + gtkpack__($dialog->vbox, + gtknew('Title2', label => $text), + $label_and_widgets->(N("IP address:"), $ip), + $label_and_widgets->(N("Host name:"), $hostname), + $label_and_widgets->(N("Host Aliases:"), $alias), + create_okcancel({ + cancel_clicked => sub { $dialog->destroy }, + ok_clicked => sub { + is_ip($ip->get_text) or err_dialog(N("Error!"), N("Please enter a valid IP address.")) and return; + if ($wanted =~ /add/) { + $iter = $model->append; + $i = "-1"; + push @listhosts, { + ip => $ip->get_text, + hostname => $hostname->get_text, + alias => $alias->get_text, + }; + } + $listhosts[$i]{hostname} = $hostname->get_text; + $listhosts[$i]{alias} = $alias->get_text; + $listhosts[$i]{ip} = $ip->get_text; + $model->set($iter, + COLUMN_IP, $listhosts[$i]{ip}, + COLUMN_HOSTNAME, $listhosts[$i]{hostname}, + COLUMN_ALIAS, $listhosts[$i]{alias}, + ); + $dialog->destroy; +# write_conf_hosts(); + }, + }, + ), + ); + $dialog->show_all; +} + +sub remove_entry { + my ($treeview) = @_; + my $model = $treeview->get_model; + my $selection = $treeview->get_selection; + my $iter = $selection->get_selected; + if ($iter) { + my $path = $model->get_path($iter); + my $i = ($path->get_indices)[0]; + ask_okcancel("Remove entry ?", "Remove $listhosts[$i]{hostname}") or return; + $model->remove($iter); + splice @listhosts, $i, 1; + } +# write_conf_hosts(); +} + +sub create_model() { + get_host_data(); + my $model = Gtk2::ListStore->new("Glib::String", "Glib::String", "Glib::String"); + foreach my $a (@listhosts) { + my $iter = $model->append; + $model->set($iter, + COLUMN_IP, $a->{ip}, + COLUMN_HOSTNAME, $a->{hostname}, + COLUMN_ALIAS, $a->{alias}, + ); + } + return $model; +} + +# add colum to model +sub add_columns { + my $treeview = shift; + my $model = $treeview->get_model; + each_index { + my $renderer = Gtk2::CellRendererText->new; + $renderer->set(editable => 0); + $renderer->set_data(column => $::i); + $treeview->insert_column_with_attributes(-1, $_, $renderer, 'text' => $::i); + } N("IP address"), N("Host name"), N("Host Aliases"); +} + + +############### +# Main Program +############### +# create model +my $model = create_model(); + +my $window = ugtk2->new(N("Manage hosts definitions")); +$::main_window = $window->{real_window}; +$window->{rwindow}->set_size_request(500, 400) unless $::isEmbedded; +my $W = $window->{window}; +$W->signal_connect(delete_event => sub { ugtk2->exit }); + +my $treeview = Gtk2::TreeView->new_with_model($model); +$treeview->set_rules_hint(1); +$treeview->get_selection->set_mode('single'); +add_columns($treeview); + +$treeview->signal_connect(button_press_event => sub { + my (undef, $event) = @_; + my $selection = $treeview->get_selection; + my $iter = $selection->get_selected; + if ($iter) { + add_modify_entry($treeview, 'modify', N("Modify entry")) if $event->type eq '2button-press'; + } + }); + +my $okcancel = create_okcancel({ + cancel_clicked => sub { ugtk2->exit }, + ok_clicked => sub { write_conf_hosts(); ugtk2->exit }, + }, + ); + + + +# main interface +$W->add(gtkpack_(Gtk2::VBox->new(0,0), + if_(!$::isEmbedded, 0, Gtk2::Banner->new('IC-Dhost-48', N("Manage hosts definitions"))), + #if_($::isEmbedded, 0, Gtk2::Label->new("Here you can add, remove and alter hosts definition.")), + 1, gtkpack_(gtkset_border_width(Gtk2::HBox->new, 0), + 1, create_scrolled_window($treeview), + 0, gtkpack_(gtkset_border_width(create_vbox('start', 3)), + 0, gtksignal_connect(Gtk2::Button->new(N("Add")), clicked => sub { + eval { add_modify_entry($treeview, 'add', N("Add entry")) }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to add host.") . "\n\n" . $err); + } + }), + 0, gtksignal_connect(Gtk2::Button->new(N("Modify")), clicked => sub { + eval { add_modify_entry($treeview, 'modify', N("Modify entry")) }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to Modify host.") . "\n\n" . $err); + } + }), + 0, gtksignal_connect(Gtk2::Button->new(N("Remove")), clicked => sub { + eval { remove_entry($treeview) }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to remove host.") . "\n\n" . $err); + } + }), + if_($::isEmbedded, 0, gtksignal_connect(Gtk2::Button->new(N("Quit")), clicked => sub { ugtk2->exit })), + ), + ), + 0, $okcancel, + ), + ); + +$W->show_all; +Gtk2->main; diff --git a/bin/drakids b/bin/drakids new file mode 100644 index 0000000..50cc786 --- /dev/null +++ b/bin/drakids @@ -0,0 +1,337 @@ +#!/usr/bin/perl + +use strict; +use lib qw(/usr/lib/libDrakX); +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use common; +use standalone; + +use Socket; +use mygtk2 qw(gtknew); +use ugtk2 qw(:dialogs); +use POSIX qw(strftime); +use dbus_object; +use network::ifw; + +use Gtk2::SimpleList; + +use ugtk2 qw(:create :helpers :wrappers); + +my $loglist = create_attack_list(); +$loglist->get_selection->set_mode('single'); + +my $blacklist = create_attack_list(); +$blacklist->get_selection->set_mode('multiple'); + +my $whitelist = Gtk2::SimpleList->new(addr => 'hidden', + N("Allowed addresses") => 'text', + ); +$whitelist->get_selection->set_mode('multiple'); +$whitelist->set_headers_clickable(1); +$whitelist->get_column(0)->signal_connect('clicked', \&sort_by_column, $whitelist->get_model); +$whitelist->get_column(0)->set_sort_column_id(0); + +my $i_m_ifw2 = member("--ifw2", @ARGV); +my $services_log = create_service_list('status'); +my $allowed_services = create_service_list(); +my $blocked_services = create_service_list(); + +my $title = N("Interactive Firewall"); +my $icon = "drakfirewall"; + +$ugtk2::wm_icon = $icon; +my $w = ugtk2->new($title); + +my $ifw; +eval { + my $bus = dbus_object::system_bus(); + dbus_object::set_gtk2_watch_helper($bus); + network::ifw::init($bus, sub { + my ($_con, $msg) = @_; + my $member = $msg->get_member; + if ($member eq 'Attack') { + handle_log($msg->get_args_list); + } elsif ($member eq 'Blacklist') { + handle_blacklist($msg->get_args_list); + } elsif ($member eq 'Whitelist') { + handle_whitelist($msg->get_args_list); + } elsif ($member eq 'Clear') { + clear_lists(); + } elsif ($member eq 'Init') { + handle_init(); + } elsif ($member eq 'ManageRequest') { + $w->{window}->present; + } + }); + $ifw = network::ifw->new($bus); +}; + +if ($@) { + err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + $w->exit(1); +} + +init_lists(); + +gtkadd($w->{window}, + gtknew('VBox', spacing => 5, children => [ + $::isEmbedded ? () : (0, Gtk2::Banner->new($icon, $title)), + 1, gtknew('Notebook', children => [ + if_($i_m_ifw2, + gtknew('Label', text => N("Log")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $services_log), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Allow"), clicked => sub {}), + gtknew('Button', text => N("Block"), clicked => sub {}), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + gtknew('Label', text => N("Allowed services")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $allowed_services), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Remove"), clicked => sub {}), + gtknew('Button', text => N("Block"), clicked => sub {}), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + gtknew('Label', text => N("Blocked services")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $blocked_services), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Remove"), clicked => sub {}), + gtknew('Button', text => N("Allow"), clicked => sub {}), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + ), + gtknew('Label', text => N("Log")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $loglist), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Clear logs"), clicked => \&clear_log), + gtknew('Button', text => N("Blacklist"), clicked => sub { blacklist(get_selected_log_seq()) }), + gtknew('Button', text => N("Whitelist"), clicked => sub { whitelist(get_selected_log()) }), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + gtknew('Label', text => N("Blacklist")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $blacklist), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Remove from blacklist"), clicked => sub { unblacklist(get_selected_blacklist()) }), + gtknew('Button', text => N("Move to whitelist"), clicked => sub { + my @addr = get_selected_blacklist(); + unblacklist(@addr); + whitelist(@addr); + }), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + gtknew('Label', text => N("Whitelist")), + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('ScrolledWindow', width => 600, height => 260, child => $whitelist), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Remove from whitelist"), clicked => sub { unwhitelist(get_selected_whitelist()) }), + gtknew('Button', text => N("Close"), clicked => sub { Gtk2->main_quit }) + ]), + ]), + ]), + ]), +); +$w->show; +Gtk2->main; + +$w->exit(0); + +sub sort_by_column { + my ($column, $model) = @_; + my $col_id = $column->get_sort_column_id; + my ($old_id, $old_order) = $model->get_sort_column_id; + $model->set_sort_column_id($col_id, $old_id == $col_id && $old_order ne 'descending' ? 'ascending' : 'descending'); +} + +sub handle_init() { + $ifw->attach_object; + init_lists(); +} + +sub list_remove_addr { + my ($list, @addr) = @_; + #- workaround buggy Gtk2::SimpleList array abstraction, it destroys references + @$list = map { member($_->[0], @addr) ? () : [ @$_ ] } @$list; +} + +#- may throw an exception +sub init_blacklist() { + my @packets = $ifw->get_blacklist; + while (my @blacklist = splice(@packets, 0, 8)) { + handle_blacklist(@blacklist); + } +} + +sub clear_blacklist() { + @{$blacklist->{data}} = (); +} + +sub handle_blacklist { + attack_list_add($blacklist, network::ifw::attack_to_hash(\@_)); +} + +sub get_selected_blacklist() { + uniq(map { $blacklist->{data}[$_][0] } $blacklist->get_selected_indices); +} + +sub blacklist { + my @seq = @_; + eval { $ifw->set_blacklist_verdict($_, 1) foreach @seq }; + $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); +} + +sub unblacklist { + my @addr = @_; + eval { $ifw->unblacklist($_) foreach @addr }; + if (!$@) { + list_remove_addr($blacklist->{data}, @addr); + } else { + err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + } +} + +#- may throw an exception +sub init_whitelist() { + handle_whitelist($_) foreach $ifw->get_whitelist; +} + +sub clear_whitelist() { + @{$whitelist->{data}} = (); +} + +sub handle_whitelist { + my ($addr) = @_; + push @{$whitelist->{data}}, [ $addr, network::ifw::resolve_address(network::ifw::get_ip_address($addr)) ]; +} + +sub get_selected_whitelist() { + uniq(map { $whitelist->{data}[$_][0] } $whitelist->get_selected_indices); +} + +sub whitelist { + my @addr = @_; + eval { $ifw->whitelist($_) foreach @addr }; + $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); +} + +sub unwhitelist { + my @addr = @_; + eval { $ifw->unwhitelist($_) foreach @addr }; + if (!$@) { + list_remove_addr($whitelist->{data}, @addr); + } else { + err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + } +} + +sub init_lists() { + eval { + init_loglist(); + init_blacklist(); + init_whitelist(); + }; + $@ and print "$@\n", err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); +} + +sub clear_lists() { + clear_loglist(); + clear_blacklist(); + clear_whitelist(); +} + +sub create_attack_list() { + my $attacklist = Gtk2::SimpleList->new(addr => 'hidden', + seq => 'hidden', + timestamp => 'hidden', + N("Date") => 'text', + N("Remote host") => 'text', + N("Type") => 'text', + N("Service") => 'text', + N("Network interface") => 'text', + N("Protocol") => 'text', + ); + $attacklist->set_headers_clickable(1); + foreach (0, 1, 2) { + $attacklist->get_column($_)->signal_connect('clicked', \&sort_by_column, $attacklist->get_model); + #- sort on timestamp if Date column is clicked + #- sort columns include hidden columns while list columns don't + $attacklist->get_column($_)->set_sort_column_id($_ == 0 ? 1 : $_ + 2); + } + $attacklist; +} + +sub attack_list_add { + my ($attacklist, $attack) = @_; + push @{$attacklist->{data}}, [ + $attack->{addr}, + $attack->{seq}, + $attack->{timestamp}, + $attack->{date}, + $attack->{hostname}, + $attack->{type}, + $attack->{service}, + $attack->{indev}, + $attack->{protocol}, + ]; +} + +sub create_service_list { + my ($o_status) = @_; + my $service_list = Gtk2::SimpleList->new( + N("Application") => 'text', + N("Service") => 'text', + if_($o_status, N("Status") => 'text'), + ); + N_("Allowed"); + N_("Blocked"); + $service_list->set_headers_clickable(1); + foreach (0, 1, if_($o_status, 2)) { + $service_list->get_column($_)->signal_connect('clicked', \&sort_by_column, $service_list->get_model); + } + $service_list; +} + +#- may throw an exception +sub init_loglist() { + my @packets = $ifw->get_reports(1); + while (my @attack = splice(@packets, 0, 10)) { + handle_log(@attack); + } +} + +sub clear_loglist() { + @{$loglist->{data}} = (); +} + +sub handle_log { + attack_list_add($loglist, network::ifw::attack_to_hash(\@_)); +} + +sub get_selected_log_seq() { + uniq(map { $loglist->{data}[$_][1] } $loglist->get_selected_indices); +} +sub get_selected_log() { + uniq(map { $loglist->{data}[$_][0] } $loglist->get_selected_indices); +} + +sub clear_log() { + eval { + $ifw->clear_processed_reports; + $ifw->send_alert_ack; + }; + if (!$@) { + clear_loglist(); + } else { + err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + } +} diff --git a/bin/drakinvictus b/bin/drakinvictus new file mode 100755 index 0000000..ad6e142 --- /dev/null +++ b/bin/drakinvictus @@ -0,0 +1,151 @@ +#!/usr/bin/perl + +# Copyright (C) 2006 Mandriva +# Olivier Blin <blino@mandriva.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +use strict; + +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; + +use common; +use network::invictus; +use network::network; +use detect_devices; +use mygtk2 qw(gtknew); +use ugtk2 qw(:create :helpers :wrappers :dialogs); + +$ugtk2::wm_icon = 'invictus-16'; +my $title = N("Invictus Firewall"); +my $w = ugtk2->new($title); +$::main_window = $w->{real_window}; #- so that transient_for is defined for wait messages and dialogs + +my $net = {}; +network::network::read_net_conf($net); +my @interfaces = detect_devices::get_lan_interfaces; + +my $invictus = {}; +network::invictus::read_config($invictus); + +my %interface_addresses = map { $_ => { + real_address => gtknew('Entry', text => $invictus->{ucarp}{$_}{SRCIP}), + virtual_address => gtknew('Entry', text => $invictus->{ucarp}{$_}{VIRTIP}), + vid => do { my $w = gtknew('Entry', text => $invictus->{ucarp}{$_}{VHID}); $w->set_width_chars(5); $w }, +} } @interfaces; + +my $master_checkbutton = gtknew('CheckButton', text => N("Start as master"), active => do { + my $m = find { $_->{TAKEOVER} } values %{$invictus->{ucarp}}; + $m && text2bool($m->{TAKEOVER}); +}); +my $password_entry = gtknew('Entry', text => do { + my $p = find { $_->{PASSWORD} } values %{$invictus->{ucarp}}; + $p && $p->{PASSWORD}; +}); +$password_entry->set_visibility(0); +my $ct_sync_interface_list; +my $cmarkbit_entry; + +sub apply_invictus_firewall() { + require interactive; + my $in = 'interactive'->vnew; + $in->do_pkgs->ensure_is_installed('invictus-firewall', '/etc/rc.d/init.d/ct_sync') or return; + $in->do_pkgs->ensure_is_installed('ucarp', '/etc/rc.d/init.d/ucarp') or return; + + my $password = $password_entry->get_text; + $password or err_dialog(N("Error"), N("A password is required.")), return; + foreach (@interfaces) { + @{$invictus->{ucarp}{$_}}{qw(INTERFACE SRCIP VIRTIP VHID PASSWORD TAKEOVER)} = ( + $_, + (map { $_->get_text } @{$interface_addresses{$_}}{qw(real_address virtual_address vid)}), + $password, + bool2yesno($master_checkbutton->get_active), + ); + } + network::invictus::write_config($invictus); + + require services; + services::enable('ct_sync'); + services::enable('ucarp'); +} + +sub update_ct_sync_state() { + my $enable_ct_sync = text2bool($invictus->{ct_sync}{ENABLE}); + $_->set_sensitive($enable_ct_sync) foreach $ct_sync_interface_list, $cmarkbit_entry; + foreach my $interface (@interfaces) { + my $enable = !$enable_ct_sync || $interface ne $invictus->{ct_sync}{INTERFACE}; + $_->set_sensitive($enable) foreach values %{$interface_addresses{$interface}}; + } +} + +gtkadd($w->{window}, + gtknew('VBox', spacing => 5, children_tight => [ + $::isEmbedded ? () : Gtk2::Banner->new('invictus-52', $title), + gtknew('WrappedLabel', text => N("This tool allows to set up network interfaces failover and firewall replication.")), + gtknew('Frame', border_width => 5, + text => N("Network redundancy (leave empty if interface is not used)"), + child => gtknew('VBox', border_width => 10, children_tight => [ + gtknew('Table', children => [ + [ N("Interface"), N("Real address"), N("Virtual shared address"), N("Virtual ID") ], + (map { + [ $_, @{$interface_addresses{$_}}{qw(real_address virtual_address vid)} ]; + } @interfaces), + ]), + gtknew('HBox', spacing => 5, children_tight => [ N("Password"), $password_entry ]), + $master_checkbutton, + ])), + gtknew('Frame', border_width => 5, + text => N("Firewall replication"), + child => gtknew('VBox', border_width => 10, children_tight => [ + gtknew('CheckButton', text => N("Synchronize firewall conntrack tables"), + active => text2bool($invictus->{ct_sync}{ENABLE}), + toggled => sub { + $invictus->{ct_sync}{ENABLE} = bool2yesno($_[0]->get_active); + update_ct_sync_state(); + }), + gtknew('HBox', spacing => 5, children => [ + 0, N("Synchronization network interface"), + 1, $ct_sync_interface_list = + gtknew('ComboBox', list => \@interfaces, text => $invictus->{ct_sync}{INTERFACE}, + changed => sub { + $invictus->{ct_sync}{INTERFACE} = $_[0]->get_active_text; + update_ct_sync_state(); + }), + ]), + gtknew('HBox', spacing => 5, children_tight => [ + N("Connection mark bit"), + $cmarkbit_entry = + gtknew('ComboBox', list => [ 0 .. 31 ], text => $invictus->{ct_sync}{CMARKBIT}, changed => sub { + $invictus->{ct_sync}{CMARKBIT} = $_[0]->get_active_text; + }), + ]), + ])), + gtknew('HButtonBox', layout => 'edge', children_tight => [ + gtknew('Button', text => N("Apply"), clicked => \&apply_invictus_firewall), + gtknew('Button', text => N("Quit"), clicked => sub { $w->exit }), + ]), + ]), + ); + + + + +update_ct_sync_state(); + +$w->main; diff --git a/bin/draknetcenter b/bin/draknetcenter new file mode 100755 index 0000000..7396631 --- /dev/null +++ b/bin/draknetcenter @@ -0,0 +1,28 @@ +#!/usr/bin/perl +# Olivier Blin, 2007 <oblin@mandriva.com> +# Licensed under the GPL + +use strict; +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } + +use common; +use standalone; +use network::network; +use network::monitor; +use network::netcenter; +use dbus_object; + +#- Allow multiple instances, but only one per user: +is_running('draknetcenter') and die "draknetcenter already running\n"; + +my $in = 'interactive'->vnew('su'); +my $net = {}; +network::network::read_net_conf($net); +my $dbus; +eval { $dbus = dbus_object::system_bus() }; +eval { $net->{monitor} = network::monitor->new($dbus) } if $dbus; + +network::netcenter::main($in, $net, $dbus); diff --git a/bin/draknetprofile b/bin/draknetprofile new file mode 100755 index 0000000..7a43689 --- /dev/null +++ b/bin/draknetprofile @@ -0,0 +1,226 @@ +#!/usr/bin/perl + +# Copyright (C) 2006 Mandriva +# Olivier Blin <blino@mandriva.com> +# Thierry Vignaud <tvignaud@mandriva.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +use strict; + +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; + +use common; +use network::network; +use mygtk2; +use Gtk2::SimpleList; +use ugtk2 qw(:create :helpers :wrappers :dialogs :ask); +use POSIX (); + +$ugtk2::wm_icon = 'draknetprofile-16'; +my $title = N("Network profiles"); +my $w = ugtk2->new($title); +$::main_window = $w->{real_window}; #- so that transient_for is defined for wait messages and dialogs + +my $net = {}; +my @profiles; +my $default_profile = "default"; +my %buttons; + +package Gtk2::CellRendererRadio; + +sub new { + my $renderer = Gtk2::CellRendererToggle->new; + $renderer->set_radio(1); + $renderer; +} + +1; + +package main; + +Gtk2::SimpleList->add_column_type( + 'radio', + type => 'Glib::Boolean', + renderer => 'Gtk2::CellRendererRadio', + attr => 'active', +); + +my $modules_list = Gtk2::SimpleList->new( + N("Module") => 'hidden', + N("Enabled") => 'bool', + N("Description") => 'text', +); + +my @r = $modules_list->get_column(0)->get_cell_renderers; +$r[0]->signal_connect('toggled' => sub { + my ($_renderer, $row, $_col) = @_; + if ($modules_list->{data}[$row][1]) { + network::network::netprofile_module_enable($modules_list->{data}[$row][0]); + } else { + network::network::netprofile_module_disable($modules_list->{data}[$row][0]); + } + }); + + +my $profiles_list = Gtk2::SimpleList->new( + "" => 'hidden', + N("Profile") => 'text', +); + +$profiles_list->get_selection->signal_connect('changed' => sub { + if ($profiles_list->sensitive) { + my ($index) = $profiles_list->get_selected_indices; + $_->set_sensitive(defined $index) foreach values %buttons; + } + }); + +sub load_netprofile_modules() { + my @modules = network::network::netprofile_modules(); + foreach (@modules) { + push @{$modules_list->{data}}, [ + $_->{module}, + $_->{enabled}, + $_->{description}, + ]; + } +} + +sub get_selected_profile() { + my ($index) = $profiles_list->get_selected_indices; + if (not $index ) { + my $pc = @{$profiles_list->{data}}; + my $index = 0; + for (my $i = 0; $i < $pc; $i++) { + if ( $profiles_list->{data}[$i][0] == 1 ) { + $index = $i; + } + } + }; + defined $index && $profiles_list->{data}[$index][1]; +} + +sub update_profiles() { + network::network::netprofile_read($net); + @profiles = network::network::netprofile_list(); + @{$profiles_list->{data}} = map { [ $_ eq $net->{PROFILE}, $_ ] } @profiles; + my $index = eval { find_index { $_ eq $net->{PROFILE} } @profiles }; + $profiles_list->select($index) if defined $index; +} + +sub set_selected_profile() { + set_profile(get_selected_profile()); +} + +sub set_profile { + my ($profile) = @_; + gtkset_mousecursor_wait($w->{window}->window); + $profiles_list->set_sensitive(0); + $_->set_sensitive(0) foreach values %buttons; + gtkflush(); + unless (fork()) { + network::network::netprofile_set($net, $profile); + POSIX::_exit(0); + } + $SIG{CHLD} = sub { + $SIG{CHLD} = 'IGNORE'; + gtkset_mousecursor_normal($w->{window}->window); + update_profiles(); + $_->set_sensitive(1) foreach values %buttons; + $profiles_list->set_sensitive(1); + }; +} + +sub clone_profile() { + my $source_profile = get_selected_profile(); + my $dialog = _create_dialog(N("New profile...")); + my $entry_dialog = Gtk2::Entry->new; + gtkpack($dialog->vbox, + Gtk2::WrappedLabel->new(N("Please specify the name of the new network profile to be created (e.g., work, home, roaming, ..). This new profile will be created based on current settings, and you'll be able to configure your system configuration as usual afterwards.")), + $entry_dialog, + ); + gtkpack($dialog->action_area, + gtksignal_connect(Gtk2::Button->new(N("Cancel")), + clicked => sub { $dialog->destroy }), + gtksignal_connect(my $bok = Gtk2::Button->new(N("Ok")), clicked => sub { + my $dest_profile = $entry_dialog->get_text; + # netprofile does not like spaces in profile names... + $dest_profile =~ s/ /_/g; + if (member($dest_profile, @profiles)) { + err_dialog(N("Error"), N("The \"%s\" profile already exists!", $dest_profile), { transient => $dialog }); + return 1; + } + $dialog->destroy; + network::network::netprofile_set($net, $dest_profile); + update_profiles(); + info_dialog(N("New profile created"), N("You are now using network profile %s. You can configure your system as usual, and all your network settings from now on will be saved into this profile.", $dest_profile)); + }), + ); + $bok->can_default(1); + $bok->grab_default; + $dialog->show_all; +} + +sub delete_selected_profile() { + my $profile = get_selected_profile(); + if ($profile eq $default_profile) { + my $ret = warn_dialog(N("Warning"), N("Are you sure you want to delete the default profile?")); + return if not $ret; + } elsif ($profile eq $net->{PROFILE}) { + err_dialog(N("Error"), N("You can not delete the current profile. Please switch to a different profile first.")); + return; + } + network::network::netprofile_delete($profile); + update_profiles(); +} + +# create advanced view to configure modules +my $expander = Gtk2::Expander->new(N("Advanced")); +$expander->add(gtkpack_(Gtk2::VBox->new, + 0, gtkpack_(gtkset_border_width(Gtk2::HBox->new, 1), + 1, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 0), + 0, gtknew('WrappedLabel', text => N("Select the netprofile modules:")), + 0, gtknew('ScrolledWindow', width => 300, height => 150, child => $modules_list), + ), + ), + ), + ); +$expander->show_all; + +#$expander->signal_connect(activate => sub { $w->shrink_topwindow; }); + +gtkadd($w->{window}, + gtknew('VBox', spacing => 5, children => [ + $::isEmbedded ? () : (0, Gtk2::Banner->new('draknetprofile', $title)), + 0, gtknew('WrappedLabel', text => N("This tool allows you to control network profiles.")), + 0, gtknew('WrappedLabel', text => N("Select a network profile:")), + 1, gtknew('ScrolledWindow', width => 300, height => 150, child => $profiles_list), + 0, $expander, + 0, gtknew('HButtonBox', children_loose => [ + $buttons{activate} = gtknew('Button', text => N("Activate"), clicked => \&set_selected_profile, sensitive => 0), + $buttons{clone} = gtknew('Button', text => N("New"), clicked => \&clone_profile, sensitive => 0), + $buttons{delete} = gtknew('Button', text => N("Delete"), clicked => \&delete_selected_profile, sensitive => 0), + gtknew('Button', text => N("Quit"), clicked => sub { Gtk2->main_quit }), + ]), + ]), + ); + +load_netprofile_modules(); +update_profiles(); +$w->main; diff --git a/bin/draknfs b/bin/draknfs new file mode 100755 index 0000000..aa0d8fb --- /dev/null +++ b/bin/draknfs @@ -0,0 +1,629 @@ +#!/usr/bin/perl +# +# Copyright (C) 2005-2006 by Mandriva aginies _ateuh_ mandriva.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + + +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; +use common; +use network::network; +use interactive; +use services; +my $nfsicon = "/usr/share/mcc/themes/default/draknfs.png"; +$ugtk2::wm_icon = $nfsicon; +use mygtk2 qw(gtknew gtkset); +use ugtk2 qw(:ask :wrappers :create :dialogs); + +my $in = 'interactive'->vnew('su'); +$in->do_pkgs->ensure_is_installed('nfs-utils', '/etc/rc.d/init.d/nfs-server') or exit(1); +if (!$in->do_pkgs->is_installed("portmap")) { + $in->do_pkgs->ensure_is_installed('rpcbind') or exit(1); +} + +use constant COLUMN_DIR => 0; +use constant COLUMN_ACCESS => 1; +use constant COLUMN_RIGHT => 2; +use constant COLUMN_OPTIONS => 3; +use constant NUM_COLUMNS => 4; + +my $CONF = "/etc/exports"; +my @listshare; +my $root_squash = N("map root user as anonymous"); +my $all_squash = N("map all users to anonymous user"); +my $no_all_squash = N("No user UID mapping"); +my $no_root_squash = N("allow real remote root access"); +my @listuserid_data = split(", ", qq($root_squash, $all_squash, $no_all_squash, $no_root_squash)); + +my $userid_data = { + root_squash => $root_squash, + no_root_squash => $no_root_squash, + all_squash => $all_squash, + no_all_squash => $no_all_squash, + }; + +my @yesno = qw(yes no); + +sub get_items() { + my @items = ( + [ N("/_File"), undef, undef, undef, '<Branch>', ], + [ N("/_File") . N("/_Write conf"), undef, \&write_conf, 1, '<Item>', ], + [ N("/_File") . N("/_Quit"), N("<control>Q"), \&quit_all, 1, '<Item>', ], + + + [ N("/_NFS Server"), undef, undef, undef, '<Branch>', ], + [ N("/_NFS Server") . N("/_Restart"), undef, \&restart_dialog, 1, '<Item>', ], + [ N("/_NFS Server") . N("/R_eload"), undef, \&reload_dialog, 1, '<Item>', ], + ); + return @items; +} + +sub quit_all() { + ugtk2->exit; +} + +sub restart_dialog() { + wait_action("service nfs-server restart"); +} + +sub reload_dialog() { + wait_action("service nfs-server reload"); +} + +sub wait_action { + my ($cmd) = @_; + my $w = $in->wait_message(N("NFS server"), N("Restarting/Reloading NFS server...")); + run_program::get_stdout($cmd) !~ /unknown|error/ or err_dialog(N("Error"), N("Error Restarting/Reloading NFS server")) and return; + undef $w; +} + +my %size_groups = map { $_ => Gtk2::SizeGroup->new('horizontal') } qw(label widget button); +my $label_and_widgets = sub { + my ($label, $widget, $button) = @_; + gtknew('HBox', children => [ + 0, gtkadd_widget($size_groups{label}, gtknew('Label_Left', text => $label)), + 0, gtkadd_widget($size_groups{widget}, $widget), + 0, gtkadd_widget($size_groups{button}, $button), + ]); +}; + +sub show_file_dialog { + my ($data) = @_; + my $file_dlg = gtknew('FileChooserDialog', title => N("Directory selection"), action => 'select_folder', + modal => 1, transient_for => $dlg); + $file_dlg->set_filename($data->get_text); + $file_dlg->show; + my $answer = $file_dlg->run; + if ($answer eq 'ok') { + my $file = $file_dlg->get_filename; + -d $file or err_dialog(N("Error!"), N("Should be a directory.")) and return; + $data->set_text($file); + } + $file_dlg->hide; + $file_dlg->destroy; +}; + +sub get_nfs_data() { +# /home/nis *(async,rw,no_root_squash) +# /home/nis/guibo/Build *(async,rw,no_root_squash) + foreach (cat_($CONF)) { + my ($dir, $access, $right, $options) = m!^(/\S+)\s+(\S*)\((\S*)\)\s+(\S*)!; + $dir and push @listshare, { + dir => $dir, + access => $access, + right => $right, + options => $options, + }; + } +} + +sub write_conf() { + output($CONF, "# generated by drakhosts.pl\n"); + foreach my $a (@listshare) { + append_to_file($CONF, "$a->{dir} $a->{access}($a->{right}) $a->{options}\n"); + } + +} + +my $help_access; +$help_access = N("<span weight=\"bold\">NFS clients</span> may be specified in a number of ways: + + +<span foreground=\"royalblue3\">single host:</span> a host either by an abbreviated name recognized be the resolver, fully qualified domain name, or an IP address + + +<span foreground=\"royalblue3\">netgroups:</span> NIS netgroups may be given as \@group. + + +<span foreground=\"royalblue3\">wildcards:</span> machine names may contain the wildcard characters * and ?. For instance: *.cs.foo.edu matches all hosts in the domain cs.foo.edu. + + +<span foreground=\"royalblue3\">IP networks:</span> you can also export directories to all hosts on an IP (sub-)network simultaneously. for example, either `/255.255.252.0' or `/22' appended to the network base address result. +"); + +my $help_userid = N("<span weight=\"bold\">User ID options</span> + + +<span foreground=\"royalblue3\">map root user as anonymous:</span> map requests from uid/gid 0 to the anonymous uid/gid (root_squash). + + +<span foreground=\"royalblue3\">allow real remote root access:</span> turn off root squashing. This option is mainly useful for diskless clients (no_root_squash). + + +<span foreground=\"royalblue3\">map all users to anonymous user:</span> map all uids and gids to the anonymous user (all_squash). Useful for NFS-exported public FTP directories, news spool directories, etc. The opposite option is no user UID mapping (no_all_squash), which is the default setting. + + +<span foreground=\"royalblue3\">anonuid and anongid:</span> explicitly set the uid and gid of the anonymous account. +"); + +my %adv_options = ( + sync => N("Synchronous access:"), + secured => N("Secured Connection:"), + ro => N("Read-Only share:"), + subtree_check => N("Subtree checking:") +); +my $help_global = join("\n\n\n", '<b><big>' . N("Advanced Options") . '</big></b>', +N("<span foreground=\"royalblue3\">%s</span> this option requires that requests originate on an internet port less than IPPORT_RESERVED (1024). This option is on by default.", $adv_options{secured}), +N("<span foreground=\"royalblue3\">%s</span> allow either only read or both read and write requests on this NFS volume. The default is to disallow any request which changes the filesystem. This can also be made explicit by using this option.", $adv_options{ro}), +N("<span foreground=\"royalblue3\">%s</span> disallows the NFS server to violate the NFS protocol and to reply to requests before any changes made by these requests have been committed to stable storage (e.g. disc drive).", $adv_options{sync}), +N("<span foreground=\"royalblue3\">%s</span> enable subtree checking which can help improve security in some cases, but can decrease reliability. See exports(5) man page for more details.", $adv_options{subtree_check}), +); + +sub help_b { + my ($help_data) = @_; + gtksignal_connect(gtknew('Button', text => N("Information")), clicked => sub { + my $dialog = _create_dialog(N("Help"), { transient_for => $::main_window, modal => 1 }); + gtkpack_($dialog->vbox, + 1, gtknew('ScrolledWindow', width => 390, height => 300, + child => gtknew('TextView', text => ugtk2::markup_to_TextView_format(formatAlaTeX($help_data))) + ), + 0, gtknew('Button', text => N("Close"), clicked => sub { + $dialog->destroy; + } + ), + ); + $dialog->show_all; + } + ); +} + +sub get_access_list() { + my $net = {}; + network::network::read_net_conf($net); + my $interface = $net->{net_interface}; + my $ip_address = network::tools::get_interface_ip_address($net, $interface); + my $domain = chomp_(`dnsdomainname`); + my @o = split(/\./, $ip_address); + my $ipnet; + if ($ip_address) { + $ipnet = $o[0] . "." . $o[1] . "." . $o[2] . ".0"; + } else { $ipnet = "ip_address" } + my @all = split(", ", qq(*, *.$domain, $ipnet/8, $ipnet/24)); + return @all; +} + +sub get_data_from_id { + my ($id, $what) = @_; + my $data; + if ($what =~ /passwd/) { + setpwent(); + ($data) = (getpwuid($id))[0]; + endpwent(); + } else { + setgrent(); + ($data) = (getgrgid($id))[0]; + endgrent(); + } + return $data; +} + +sub get_user_or_group { + my ($what) = @_; + my $conf = "/etc/" . $what; + my @data = map { if_(m/^([^#:]+):[^:]+:([^:]+):/ && $2 > 499, "$1 [$2]") } cat_($conf); + return sort(@data, " "); +} + + +sub add_modify_entry { + my ($treeview, $wanted) = @_; + my $model = $treeview->get_model; + my $selection = $treeview->get_selection; + my $iter; + my ($i, $dir, $access, $right, $options); + my ($lr, $luserid, $lsecure, $lsync, $lsubtree_check, $lr_data, $lsync_data, $lsecure_data, $lsubtree_check_data); + undef $i; undef $iter; + + $_ = gtknew('Entry') foreach $dir, $options; + $_ = Gtk2::OptionMenu->new foreach $lr, $luserid, $lsecure, $lsync, $lsubtree_check; + + $access = Gtk2::Combo->new; +# $access = gtknew('ComboBox'); + my @access_list = get_access_list(); +# foreach (@access_list) { +# $_ and $access->append_text($_); +# } + $access->set_popdown_strings(@access_list); + + $luserid->set_popdown_strings(@listuserid_data); + $lr->set_popdown_strings(@yesno); + $lsync->set_popdown_strings(@yesno); + $lsecure->set_popdown_strings(@yesno); + $lsubtree_check->set_popdown_strings(@yesno); + + my $button = gtknew('Button', text => N("Directory")); + $button->signal_connect(clicked => sub { show_file_dialog($dir); }); + +# test if modify or add a nfs share + + my $anonuid = gtknew('ComboBox', list => [ get_user_or_group('passwd') ]); + my $anongid = gtknew('ComboBox', list => [ get_user_or_group('group') ]); + $_->set_wrap_width(3) foreach $anonuid, $anongid; + + if ($wanted =~ /modify/) { + $iter = $selection->get_selected; + $iter or info_dialog(N("Error"), N("Please add an NFS share to be able to modify it.")) and return; + my $path = $model->get_path($iter); + $i = ($path->get_indices)[0]; + $dir->set_text($listshare[$i]{dir}); + if (!member($listshare[$i]{access}, @access_list)) { + $access->entry->append_text($listshare[$i]{access}); + } +# $access->child->set_text($listshare[$i]{access}); +# $access->set_text($listshare[$i]{access}); + $access->entry->set_text($listshare[$i]{access}); + + # list of all rigth in bracket + # $anongid, $anonuid, $lr, $luserid, $lsecure, $lsync; + $right = $listshare[$i]{right}; + my @opts = split(/,/, $right); + $_->set_text("") foreach $lr, $lsync, $anonuid, $anongid, $luserid, $lsecure, $lsubtree_check; + + foreach my $opt (@opts) { + if ($opt =~ m/(\bro\b|\brw\b)/) { + if ($opt =~ /ro/) { $lr->set_text("yes") } else { $lr->set_text("no") } + } elsif ($opt =~ m/\bsync\b|\basync\b/) { + if ($opt =~ /async/) { $lsync->set_text("no") } else { $lsync->set_text("yes") } + } elsif ($opt =~ m/anongid=(\d+)/) { + my $gdata = get_data_from_id($1, 'group') . " [$1]"; + $anongid->set_text($gdata); + } elsif ($opt =~ m/anonuid=(\d+)/) { + my $udata = get_data_from_id($1, 'passwd') . " [$1]"; + $anonuid->set_text($udata); + } elsif ($opt =~ m/(no_root_squash|root_squash|all_squash|no_all_squash)/) { + if ($opt =~ /^no_root_squash/) { + $luserid->set_text($userid_data->{no_root_squash}); + } elsif ($opt =~ /^root_squash/) { + $luserid->set_text($userid_data->{root_squash}); + } elsif ($opt =~ /^all_squash/) { + $luserid->set_text($userid_data->{all_squash}); + } elsif ($opt =~ /^no_all_squash/) { + $luserid->set_text($userid_data->{no_all_squash}); + } + } elsif ($opt =~ m/(\bsecure\b|\binsecure\b)/) { + if ($opt =~ /insecure/) { $lsecure->set_text("no") } else { $lsecure->set_text("yes") } + } elsif ($opt =~ m/\bsubtree_check\b|\bno_subtree_check\b/) { + if ($opt =~ /no_subtree_check/) { $lsubtree_check->set_text("no") } + else { $lsubtree_check->set_text("yes") } + } else { next } + } + foreach ($lsecure, $lsync) { if ($_->get_text =~ //) { $_->set_text("yes") } }; + foreach ($lr, $lsubtree_check) { if ($_->get_text =~ //) { $_->set_text("no") } }; + } + + $luserid->signal_connect(changed => sub { + if ($luserid->get_text =~ /$userid_data->{root_squash}/) { + $_->set_sensitive(1) foreach $anongid, $anonuid; + } elsif ($luserid->get_text =~ /$userid_data->{all_squash}/) { + $_->set_sensitive(0) foreach $anongid, $anonuid; + $_->set_text("65534") foreach $anongid, $anonuid; + } else { + $_->set_text("") foreach $anongid, $anonuid; + $_->set_sensitive(0) foreach $anongid, $anonuid; + } + }); + + if ($wanted =~ /add/) { + # default choice root_squash and ro + $luserid->set_text($userid_data->{no_all_squash}); + $lr->set_text("yes"); + $lsecure->set_text("yes"); + $lsync->set_text("no"); + $lsubtree_check->set_text("no"); + } + + if ($luserid->get_text !~ /$userid_data->{root_squash}/) { + $_->set_sensitive(0) foreach $anongid, $anonuid; + } + + my $expender = Gtk2::Expander->new(N("Advanced")); + $expender->add(gtkpack_(Gtk2::HBox->new, + 0, gtkpack_(gtkset_border_width(Gtk2::HBox->new, 1), + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 0), + 0, $label_and_widgets->($adv_options{sync}, $lsync, help_b($help_global)), + 0, $label_and_widgets->($adv_options{secured}, $lsecure, ""), + 0, $label_and_widgets->($adv_options{ro}, $lr, ""), + 0, $label_and_widgets->($adv_options{subtree_check}, $lsubtree_check, ""), + ), + ), + ), + ); + + my $w = ugtk2->new(N("Modify entry")); + $w->{window}->set_modal(1); + $w->{window}->set_position('center'); + + $expender->signal_connect(activate => sub { $w->shrink_topwindow; }); + + gtkadd($w->{window}, + gtknew('VBox', spacing => 0, children_loose => [ +# gtkadd(Gtk2::Frame->new(("")), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, gtknew('Title2', label => N("NFS directory")), + 0, $label_and_widgets->(N("Directory:"), $dir, $button), + 0, gtknew('Title2', label => N("Host access")), + 0, $label_and_widgets->(N("Access:"), $access, help_b($help_access)), + 0, gtknew('Title2', label => N("User ID Mapping")), + 0, $label_and_widgets->(N("User ID:"), $luserid, help_b($help_userid)), + 0, $label_and_widgets->(N("Anonymous user ID:"), $anonuid, ""), + 0, $label_and_widgets->(N("Anonymous Group ID:"), $anongid, ""), + ), +# ), +# gtkadd(Gtk2::Frame->new(""), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $expender, + ), +# ), + create_okcancel({ + cancel_clicked => sub { $w->destroy }, + ok_clicked => sub { + my ($anonu, $anong); + if ($anonuid->get_text) { + my ($uid) = $anonuid->get_text =~ /\[(\S*)\]/; + $anonu = "anonuid=" . $uid; + } + if ($anongid->get_text) { + my ($gid) = $anongid->get_text =~ /\[(\S*)\]/; + $anong = "anongid=" . $gid; + } + if ($lsync->get_text =~ /yes/) { $lsync_data = "sync" } elsif ($lsync->get_text =~ /no/) { $lsync_data = "async" } else { undef $lsync_data } + if ($lr->get_text =~ /yes/) { $lr_data = "ro" } elsif ($lr->get_text =~ /no/) { $lr_data = "rw" } else { undef $lr_data } + if ($lsecure->get_text =~ /yes/) { $lsecure_data = "secure" } elsif ($lsecure->get_text =~ /no/) { $lsecure_data = "insecure" } else { undef $lsecure_data } + if ($lsubtree_check->get_text =~ /yes/) { $lsubtree_check_data = "subtree_check" } elsif ($lsubtree_check->get_text =~ /no/) { $lsubtree_check_data = "no_subtree_check" } else { undef $lsubtree_check } + # test $luserid->get_text + my $luserid_toput; + if ($luserid->get_text =~ /$userid_data->{no_root_squash}/) { + $luserid_toput = "no_root_squash"; + undef $anong; undef $anonu; + } elsif ($luserid->get_text =~ /$userid_data->{root_squash}/) { + $luserid_toput = "root_squash"; + } elsif ($luserid->get_text =~ /$userid_data->{no_all_squash}/) { + $luserid_toput = "no_all_squash"; + undef $anong; undef $anonu; + } elsif ($luserid->get_text =~ /$userid_data->{all_squash}/) { + $luserid_toput = "all_squash"; + $anong = "anongid=65534"; + $anonu = "anonuid=65534"; + } + + my $all_right = join(",", grep { defined $_ } $luserid_toput, $anonu, $anong, $lsync_data, $lsecure_data, $lsubtree_check_data, $lr_data); + my $test_dir = $dir->get_text; + if (! $test_dir) { + err_dialog(N("Error"), N("Please specify a directory to share.")) and return; + } + mkdir_p($test_dir) or err_dialog(N("Error"), N("Can't create this directory.")) and return; + #my $test_access = $access->child->get_text; + my $test_access = $access->entry->get_text; + $test_access or err_dialog(N("Error"), N("You must specify hosts access.")) and return; + if ($wanted =~ /add/) { + $iter = $model->append; + $i = "-1"; + push @listshare, { + dir => $dir->get_text, + #access => $access->child->get_text, + access => $access->entry->get_text, + right => $all_right, + options => $options->get_text, + }; + } + $listshare[$i]{right} = $all_right; + #$listshare[$i]{access} = $access->child->get_text; + $listshare[$i]{access} = $access->entry->get_text; + $listshare[$i]{dir} = $dir->get_text; + $listshare[$i]{options} = $options->get_text; + $model->set($iter, + COLUMN_DIR, $listshare[$i]{dir}, + COLUMN_ACCESS, $listshare[$i]{access}, + COLUMN_RIGHT, $all_right, + COLUMN_OPTIONS, $listshare[$i]{options}, + ); + $w->destroy; +# write_conf(); + }, + }), + ], + ),),; + $w->{window}->show_all; +} + +sub remove_entry { + my ($treeview) = @_; + my $model = $treeview->get_model; + my $selection = $treeview->get_selection; + my $iter = $selection->get_selected; + if ($iter) { + my $path = $model->get_path($iter); + my $i = ($path->get_indices)[0]; + ask_okcancel("Remove entry ?", "Remove $listshare[$i]{dir}") or return; + $model->remove($iter); + splice @listshare, $i, 1; + } +# write_conf(); +} + +sub create_model() { + get_nfs_data(); + my $model = Gtk2::ListStore->new("Glib::String", "Glib::String", "Glib::String", "Glib::String"); + foreach my $a (@listshare) { + my $iter = $model->append; + $model->set($iter, + COLUMN_DIR, $a->{dir}, + COLUMN_ACCESS, $a->{access}, + COLUMN_RIGHT, $a->{right}, + COLUMN_OPTIONS, $a->{options}, + ); + } + return $model; +} + +# add colum to model +sub add_columns { + my $treeview = shift; + my $model = $treeview->get_model; +# my @colsize = (120, 160, 120); +# each_index { +# my $renderer = Gtk2::TreeViewColumn->new_with_attributes($_, Gtk2::CellRendererText->new, 'text' => $::i); +# $renderer->set_sort_column_id($::i); +# $renderer->set_min_width($colsize[$::i]); +# $treeview->append_column($renderer); +# } N("Share Directory"), N("Hosts Wildcard"), N("General Options"), N("Custom Options"); + + each_index { + my $renderer = Gtk2::CellRendererText->new; + $renderer->set(editable => 0); + $renderer->signal_connect(edited => \&cell_edited, $model); + $renderer->set_data(column => $::i); + $treeview->insert_column_with_attributes(-1, $_, $renderer, 'text' => $::i); + } N("Share Directory"), N("Hosts Wildcard"), N("General Options"), N("Custom Options"); +} + +sub cell_edited { + my ($cell, $path_string, $new_text, $model) = @_; + my $path = Gtk2::TreePath->new_from_string($path_string); + my $column = $cell->get_data("column"); + my $iter = $model->get_iter($path); + + if ($column == COLUMN_DIR) { + my $i = ($path->get_indices)[0]; + $listshare[$i]{dir} = $new_text; + -d $new_text or err_dialog(N("Error"), N("Please enter a directory to share.")) and return; + $model->set($iter, $column, $listshare[$i]{dir}); + } elsif ($column == COLUMN_ACCESS) { + my $i = ($path->get_indices)[0]; + $listshare[$i]{access} = $new_text; + $model->set($iter, $column, $listshare[$i]{access}); + } elsif ($column == COLUMN_RIGHT) { + err_dialog(N("Error"), N("Please use the modify button to set right access.")) and return; + } elsif ($column == COLUMN_OPTIONS) { + my $i = ($path->get_indices)[0]; + $listshare[$i]{options} = $new_text; + $model->set($iter, $column, $listshare[$i]{options}); + } + write_conf(); +} + +############### +# Main Program +############### +# create model +my $model = create_model(); + +my $window = ugtk2->new(N("Manage NFS shares")); +$::main_window = $window->{real_window}; +$window->{rwindow}->set_size_request(550, 400) unless $::isEmbedded; +$window->{rwindow}->set_position('center') if !$::isEmbedded; +my $W = $window->{window}; +$W->signal_connect(delete_event => sub { ugtk2->exit }); + +my $treeview = Gtk2::TreeView->new_with_model($model); +$treeview->set_rules_hint(1); +$treeview->get_selection->set_mode('single'); +add_columns($treeview); + +# double clic and popup modify window +$treeview->signal_connect(button_press_event => sub { + my (undef, $event) = @_; + my $selection = $treeview->get_selection; + my $iter = $selection->get_selected; + if ($iter) { + add_modify_entry($treeview, "modify") if $event->type eq '2button-press'; + } + }); + +# create menu +my @items = get_items(); +my $factory = Gtk2::ItemFactory->new('Gtk2::MenuBar', '<main>', undef); +$factory->create_items('menu', @items); +my $menu = $factory->get_widget('<main>'); + +my $okcancel = create_okcancel({ + cancel_clicked => sub { ugtk2->exit }, + ok_clicked => sub { &write_conf; + run_program::raw({ detach => 1 }, "service nfs-server reload"); + ugtk2->exit }, + }, + ); + +my $wait = $in->wait_message(N("Please wait"), N("Starting the NFS-server")); +if (services::service_exists("portmap")) { + services::enable('portmap'); +} elsif (services::service_exists("rpcbind")) { + services::enable('rpcbind'); +} +services::enable('nfs-server'); +undef $wait; + +# main interface +$W->add(gtknew('VBox', children => [ + 0, $menu, + 0, Gtk2::Banner->new($nfsicon, N("DrakNFS manage NFS shares")), + #if_($::isEmbedded, 0, gtknew('Label', text => "Here you can add, remove and alter NFS shares.")), + 1, gtknew('HBox', border_width => 0, children => [ + 1, gtknew('ScrolledWindow', child => $treeview), + 0, gtkpack_(create_vbox('start'), + 0, gtknew('Button', text => N("Add"), clicked => sub { + eval { add_modify_entry($treeview, "add") }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to add NFS share.") . "\n\n" . $err); + } + }), + 0, gtknew('Button', text => N("Modify"), clicked => sub { + eval { add_modify_entry($treeview, "modify") }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to Modify NFS share.") . "\n\n" . $err); + } + }), + 0, gtknew('Button', text => N("Remove"), clicked => sub { + eval { remove_entry($treeview) }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to remove an NFS share.") . "\n\n" . $err); + } + }), + ), + ]), + 0, $okcancel, + ]), + ); + +$W->show_all; +Gtk2->main; diff --git a/bin/drakproxy b/bin/drakproxy new file mode 100755 index 0000000..6c52022 --- /dev/null +++ b/bin/drakproxy @@ -0,0 +1,38 @@ +#!/usr/bin/perl + +# DrakProxy + +# Copyright (C) 1999-2006 Mandriva (damien@mandrakesoft.com) +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; #- warning, standalone must be loaded very first, for 'explanations' +use interactive; +use network::network; +use any; +use common; + +$ugtk2::wm_icon = "/usr/share/mcc/themes/default/drakproxy-mdk.png"; +my $u = { getVarsFromSh('/etc/profile.d/proxy.sh') }; +my $in = 'interactive'->vnew('su'); +if (network::network::miscellaneous_choose($in, $u)) { + network::network::proxy_configure($u); + any::ask_for_X_restart($in); +} +$in->exit(0); diff --git a/bin/drakroam b/bin/drakroam new file mode 100755 index 0000000..0c6c400 --- /dev/null +++ b/bin/drakroam @@ -0,0 +1,28 @@ +#!/usr/bin/perl + +# drakroam: wireless network roaming GUI +# Austin Acton, 2004 <austin@mandriva.org> +# Olivier Blin, 2005-2006 <oblin@mandriva.com> +# Licensed under the GPL + +use strict; +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } + +use standalone; +use common; +use network::drakroam; +use network::monitor; + +my %args = map { if_(/^--(\w+)=(.*)$/ && member($1, qw(ap interface)), $1 => $2) } @ARGV; + +my $in = 'interactive'->vnew('su'); +my $net = {}; +network::network::read_net_conf($net); +my $dbus; +eval { $dbus = dbus_object::system_bus() }; +eval { $net->{monitor} = network::monitor->new($dbus) } if $dbus; + +network::drakroam::main($in, $net, $dbus, $args{interface}, $args{ap}); diff --git a/bin/draksambashare b/bin/draksambashare new file mode 100755 index 0000000..52684fe --- /dev/null +++ b/bin/draksambashare @@ -0,0 +1,1474 @@ +#!/usr/bin/perl +# -*- coding: utf-8 -*- +# Copyright (C) 2006-2008 by Mandriva aginies _ateuh_ mandriva.com +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +use utf8; + +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; +use common; +use network::network; +use interactive; +use mygtk2 qw(gtknew); +use ugtk2 qw(:ask :wrappers :create :dialogs); +use Gtk2::SimpleList; +use Gtk2::Gdk::Keysyms; +use run_program; + +# use libconf +use Libconf::Templates; +use Libconf::Glueconf::Samba::Smb_conf; + +my $in = 'interactive'->vnew('su'); +$in->do_pkgs->ensure_is_installed('samba-server', '/usr/sbin/smbd') or exit(1); + +#if (!-f "/etc/sysconfig/wizard_samba") { +# $in->do_pkgs->ensure_is_installed('drakwizard', '/usr/sbin/drakwizard'); +# err_dialog(N("Error"), N("Please setup a samba server")) and return; +#} + +my $draksambashare = "/etc/sysconfig/draksambashare_first"; +my $icon_path = "/usr/lib/libDrakX/icons"; +my $sambaicon = "/usr/share/mcc/themes/default/diskdrake_samba.png"; +my $fileshare_icon = "$icon_path/IC-winacces2-16.png"; +my $printershare_icon = "$icon_path/IC-sambaprt-16.png"; +my $sambauser_icon = "$icon_path/ic82-users-16.png"; +my $pixbuf_file = Gtk2::Gdk::Pixbuf->new_from_file($fileshare_icon); +my $pixbuf_printer = Gtk2::Gdk::Pixbuf->new_from_file($printershare_icon); +my $pixbuf_user = Gtk2::Gdk::Pixbuf->new_from_file($sambauser_icon); + +my $printer_list = create_printer_list(); +my $share_list = create_share_list(); +my $user_list = create_user_list(); +my $display_share = create_display_share(); + +sub create_user_list() { + my $user_list = Gtk2::SimpleList->new('' => 'pixbuf', + N("User name") => 'text', + ); + $user_list; +} + +sub create_share_list() { + my $share_list = Gtk2::SimpleList->new('' => 'pixbuf', + N("Share name") => 'text', + N("Share directory") => 'text', + N("Comment") => 'text', + N("Browseable") => 'text', + N("Public") => 'text', + N("Writable") => 'text', + N("Create mask") => 'text', + N("Directory mask") => 'text', + N("Read list") => 'text', + N("Write list") => 'text', + N("Admin users") => 'text', + N("Valid users") => 'text', + N("Inherit Permissions") => 'text', + N("Hide dot files") => 'text', + N("Hide files") => 'text', + N("Preserve case") => 'text', + N("Force create mode") => 'text', + N("Force group") => 'text', + N("Default case") => 'text', + ); + foreach (1, 2, 3) { + $share_list->get_column($_)->set_sort_column_id($_ == 0 ? 1 : $_ + 2); + } + $share_list; + } + +sub create_display_share() { + my $display_share = Gtk2::SimpleList->new('' => 'pixbuf', + N("Share name") => 'text', + N("Share directory") => 'text', + N("Comment") => 'text', + ); + $display_share->set_headers_clickable(1); + foreach ($share_list->get_columns) { + $_->set_resizable(1); + } + foreach (1, 2, 3) { + $display_share->get_column($_)->signal_connect('clicked', \&sort_by_column, $display_share->get_model); + $display_share->get_column($_)->set_sort_column_id($_ == 0 ? 1 : $_ + 2); + } + $display_share; +} + +sub create_printer_list() { + my $printer_list = Gtk2::SimpleList->new('' => 'pixbuf', + N("Printer name") => 'text', + N("Path") => 'text', + N("Comment") => 'text', + N("Browseable") => 'text', + N("Printable") => 'text', + N("Print Command") => 'text', + N("LPQ command") => 'text', + N("Guest ok") => 'text', + N("Writable") => 'text', + N("Write list") => 'text', + N("Inherit permissions") => 'text', + N("Printing") => 'text', + N("Create mode") => 'text', + N("Use client driver") => 'text', + ); + $printer_list->set_headers_clickable(1); + foreach (1, 2, 3) { + $printer_list->get_column($_)->signal_connect('clicked', \&sort_by_column, $printer_list->get_model); + $printer_list->get_column($_)->set_sort_column_id($_ == 0 ? 1 : $_ + 2); + } + $printer_list; +} + +sub sort_by_column { + my ($column, $model) = @_; + my $col_id = $column->get_sort_column_id; + my ($old_id, $old_order) = $model->get_sort_column_id; + $model->set_sort_column_id($col_id, $old_id == $col_id && $old_order ne 'descending' ? 'ascending' : 'descending'); +} + +#path comment browseable printable print command guest ok writable write list inherit permissions printing lpq command create mode use client driver + + +my $samba = Libconf::Glueconf::Samba::Smb_conf->new({ filename => '/etc/samba/smb.conf' }); +my (@listshare, @listprinters, @listusers); +my @yesno = qw(yes no); push @yesno, ""; +my @default_case = qw(upper lower); push @default_case, ""; + +my %adv_options = ( + read_list => N("Read List"), + write_list => N("Write List"), + admin_users => N("Admin users"), + valid_users => N("Valid users"), + hide_dot_files => N("Hide dot files"), + hide_files => N("Hide files"), + force_group => N("Force Group"), + force_create_mode => N("Force create group"), + default_case => N("Default case"), + preserve_case => N("Preserve case"), + create_mask => N("Create mask"), + directory_mask => N("Directory mask"), + inherit_permissions => N("Inherit permissions"), + ); + +my $window; + +sub get_items() { + my @items = ( + [ N("/_File"), undef, undef, undef, '<Branch>', ], + [ N("/_File") . N("/_Write conf"), undef, \&write_conf, 1, '<Item>', ], + [ N("/_File") . N("/_Quit"), N("<control>Q"), \&quit_all, 1, '<Item>', ], + + [ N("/_Samba Server"), undef, undef, undef, '<Branch>', ], + [ N("/_Samba Server") . N("/_Configure"), undef, \&launch_samba_wizard, 1, '<Item>', ], + [ N("/_Samba Server") . N("/_Restart"), undef, \&restart_dialog, 1, '<Item>', ], + [ N("/_Samba Server") . N("/R_eload"), undef, \&reload_dialog, 1, '<Item>', ], + + [ N("/_Help") . N("/_Samba Documentation"), undef, sub { + $in->do_pkgs->ensure_is_installed('samba-doc', '/usr/share/doc/samba-doc'); + system("/usr/bin/www-browser /usr/share/doc/samba-doc/htmldocs/index.html &") + }, + 1, '<Item>', ], + + [ N("/_About") . N("/_Report Bug"), undef, sub { run_program::raw({ detach => 1 }, 'drakbug', '--report', 'draksambashare') }, 1, '<Item>', ], + [ N("/_About") . N("/_About..."), undef, sub { + my $license = formatAlaTeX(translate($::license)); + $license =~ s/\n/\n\n/sg; # nicer formatting + my $w = gtknew('AboutDialog', name => N("Draksambashare"), + version => '2008', + copyright => N("Copyright (C) %s by Mandriva", '2001-2008'), + license => $license, wrap_license => 1, + comments => N("This is a simple tool to easily manage Samba configuration."), + website => 'http://mandrivalinux.com', + website_label => N("Mandriva Linux"), + authors => 'Antoine Ginies <aginies@mandriva.com>', + artists => 'Hélène Durosini <ln@mandriva.com>', + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>") + N("_: Translator(s) name(s) & email(s)\n"), + transient_for => $window->{real_window}, modal => 1, position_policy => 'center-on-parent', + ); + $w->show_all; + $w->run; + }, 1, '<Item>', ], + ); + return @items; +} + +sub quit_all() { + ugtk2->exit; +} + +sub restart_dialog() { + wait_action("service smb restart"); +} + +sub reload_dialog() { + wait_action("service smb reload"); +} + +sub wait_action { + my ($cmd) = @_; + my $w = $in->wait_message(N("Please wait"), N("Restarting/Reloading Samba server...")); + run_program::get_stdout($cmd) !~ /unknown|error/ or err_dialog(N("Error!"), N("Error Restarting/Reloading Samba server")) and return; + undef $w; +} + +my %size_groups = map { $_ => Gtk2::SizeGroup->new('horizontal') } qw(label widget button); +my $label_and_widgets = sub { + my ($label, $widget, $button) = @_; + gtkpack_(Gtk2::HBox->new(0,1), + 0, gtkadd_widget($size_groups{label}, $label), + 0, gtkadd_widget($size_groups{widget}, $widget), + if_($button, 0, gtkadd_widget($size_groups{button}, $button)), + ); +}; + +sub show_file_dialog { + my ($data) = @_; + my $file_dlg = gtknew('FileChooserDialog', title => N("Directory selection"), action => 'select_folder', + modal => 1, transient_for => $dlg); + $file_dlg->set_filename($data->get_text); + $file_dlg->show; + my $answer = $file_dlg->run; + if ($answer eq 'ok') { + my $file = $file_dlg->get_filename; + -d $file or err_dialog(N("Error!"), N("Should be a directory.")) and return; + $data->set_text($file); + } + $file_dlg->hide; + $file_dlg->destroy; +}; + +sub get_samba_share() { + undef @listshare; + foreach my $clef (keys %$samba) { + if ($samba->{$clef}{printable} =~ /yes/i || $clef =~ /print\$/) { + print "$clef is a printer\n"; + } elsif ($clef =~ /global/ || $clef =~ /cdrom$/ || $clef eq "Profiles") { + print "unwanted (special shares)\n"; + } else { + push @listshare, { + share_name => $clef, + path => $samba->{$clef}{path}, + comment => $samba->{$clef}{comment}, + browseable => $samba->{$clef}{browseable}, + public => $samba->{$clef}{public}, + writable => $samba->{$clef}{writable}, + create_mask => $samba->{$clef}{'create mask'}, + directory_mask => $samba->{$clef}{'directory mask'}, + read_list => $samba->{$clef}{'read list'}, + write_list => $samba->{$clef}{'write list'}, + admin_users => $samba->{$clef}{'admin users'}, + valid_users => $samba->{$clef}{'valid users'}, + inherit_permissions => $samba->{$clef}{'inherit permissions'}, + hide_dot_files => $samba->{$clef}{'hide dot files'}, + hide_files => $samba->{$clef}{'hide files'}, + preserve_case => $samba->{$clef}{'preserve case'}, + force_create_mode => $samba->{$clef}{'force create mode'}, + force_group => $samba->{$clef}{'force group'}, + default_case => $samba->{$clef}{'default case'}, + }; + } + } + return @listshare; +} + +sub get_samba_user() { + undef @listusers; + foreach (split '\n', `pdbedit -L -w`) { + my ($user) = m!^([\w-]+):!; + $user and push @listusers, { + user_name => $user, + }; + } + return @listusers; +} + + +sub get_samba_printers() { + undef @listprinters; + foreach my $clef (keys %$samba) { + if ($samba->{$clef}{printable} =~ /yes/i || $clef =~ /print\$/) { + push @listprinters, { + share_name => $clef, + path => $samba->{$clef}{path}, + comment => $samba->{$clef}{comment}, + browseable => $samba->{$clef}{browseable}, + printable => $samba->{$clef}{printable}, + print_command => $samba->{$clef}{'print command'}, + lpq_command => $samba->{$clef}{'lpq command'}, + guest_ok => $samba->{$clef}{'guest ok'}, + writable => $samba->{$clef}{writable}, + write_list => $samba->{$clef}{'write list'}, + inherit_permissions => $samba->{$clef}{'inherit permissions'}, + printing => $samba->{$clef}{printing}, + create_mode => $samba->{$clef}{'create mode'}, + use_client_driver => $samba->{$clef}{'use client driver'}, + }; + } + } + return @listprinters; +} + +sub write_conf() { + $samba->write_conf("/etc/samba/smb.conf"); +} + + +sub printdollar_section() { + $samba->{'print$'}{browseable} = "yes"; + $samba->{'print$'}{path} = "/var/lib/samba/printers"; + $samba->{'print$'}{browseable} = "yes"; +# $samba->{'print$'}{'write list'} = '@adm root'; + $samba->{'print$'}{'guest ok'} = "yes"; +# $samba->{'print$'}{'inherit permissions'} = "yes"; +} + +sub pdf_section() { + $samba->{'pdf-gen'}{path} = "/var/tmp"; + $samba->{'pdf-gen'}{'guest ok'} = "no"; + $samba->{'pdf-gen'}{printable} = "yes"; + $samba->{'pdf-gen'}{comment} = "PDF Generator (only valid users)"; + $samba->{'pdf-gen'}{printing} = "bsd"; + $samba->{'pdf-gen'}{'print command'} = '/usr/share/samba/scripts/print-pdf %s %H \//%L/%u\ %m %I %J &'; + $samba->{'pdf-gen'}{'lpq command'} = "/bin/true"; +} + +sub printers_section() { + $samba->{printers}{comment} = "All Printers"; + $samba->{printers}{browseable} = "no"; + $samba->{printers}{'guest ok'} = "yes"; + $samba->{printers}{'create mode'} = "0700"; + $samba->{printers}{path} = "/var/spool/samba"; + $samba->{printers}{writable} = "no"; + $samba->{printers}{printable} = "yes"; + $samba->{printers}{'print command'} = 'lpr-cups -P %p -o raw %s -r'; + $samba->{printers}{'use client driver'} = "yes"; +} + +sub add_entry() { + my ($addshare_name, $addshare_comment, $addshare_dir); + $_ = Gtk2::Entry->new foreach $addshare_name, $addshare_comment, $addshare_dir; + my $button = Gtk2::Button->new(N("Open")); + $button->signal_connect(clicked => sub { show_file_dialog($addshare_dir); }); + + my $dialog = _create_dialog(N("DrakSamba add entry"), { transient_for => $::main_window, modal => 1 }); + local $::main_window = $dialog; + + gtkpack_($dialog->vbox, + 0, gtkadd(Gtk2::Frame->new(N("Add a share")), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 3), + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $label_and_widgets->(N("Name of the share:"), $addshare_name, ""), + 0, $label_and_widgets->(N("Comment:"), $addshare_comment, ""), + 0, $label_and_widgets->(N("Directory:"), $addshare_dir, $button), + ), + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, create_okcancel({ + cancel_clicked => sub { $dialog->destroy }, + ok_clicked => sub { + my $share = $addshare_name->get_text; + my $comment = $addshare_comment->get_text; + my $test_dir = $addshare_dir->get_text; + foreach my $clef (keys %$samba) { + if ($clef =~ /\b$share\b/) { + err_dialog(N("Error"), N("Share with the same name already exist or share name empty, please choose another name.")) and return; + } + } + if ($share ne 'homes' && !-d $test_dir) { + err_dialog(N("Error!"), N("Please enter a directory to share.")) and return; + } + if (! -d $test_dir) { + mkdir_p($test_dir) or err_dialog(N("Error"), N("Can't create the directory, please enter a correct path.")) and return; + } + if (! $comment) { + err_dialog(N("Error"), N("Please enter a Comment for this share.")) and return; + } + push @{$share_list->{data}}, [ + $pixbuf_file, + $share, + $test_dir, + $comment, + ]; + push @{$display_share->{data}}, [ + $pixbuf_file, + $share, + $test_dir, + $comment, + ]; + # update listshare + push @listshare, { + share_name => $share, + path => $test_dir, + comment => $comment, + }; + # update samba conf + $samba->{$share}{path} = $test_dir; + $samba->{$share}{comment} = $comment; + $dialog->destroy; + } + } + ), + ), + ), + ), + ); + $dialog->show_all; +} + +sub add_printers_entry() { + require wizards; + my %print = ( + 1 => N("pdf-gen - a PDF generator"), + 2 => N("printers - all printers available"), + ); + my $wiz_todo; + my $wiz = wizards->new({ + name => N("Add Special Printer share"), + pages => { + welcome => { + name => N("Goal of this wizard is to easily create a new special printer Samba share."), + data => [ + { label => "", type => 'list', val => \$wiz_todo, list => [ keys %print ], format => sub { $print{$_[0]} } } + ], + next => 'end_add', + post => sub { + if ($wiz_todo == 1) { + exists $samba->{'pdf-gen'} and err_dialog(N("Error"), N("A PDF generator already exists.")) and return 'welcome'; + &pdf_section; + push @{$printer_list->{data}}, [ + $pixbuf_printer, + 'pdf-gen', + $samba->{'pdf-gen'}{path}, + $samba->{'pdf-gen'}{comment}, "", + $samba->{'pdf-gen'}{printable}, + $samba->{'pdf-gen'}{'print command'}, + $samba->{'pdf-gen'}{'lpq command'}, + $samba->{'pdf-gen'}{'guest ok'}, "", "", "", + $samba->{'pdf-gen'}{printing}, "", "", + ]; + push @listprinters, { + share_name => $samba->{'pdf-gen'}, + path => $samba->{'pdf-gen'}{path}, + comment => $samba->{'pdf-gen'}{comment}, + printebale => $samba->{'pdf-gen'}{printable}, + printing => $samba->{'pdf-gen'}{printing}, + print_command => $samba->{'pdf-gen'}{'print command'}, + lpq_command => $samba->{'pdf-gen'}{'lpq command'}, + guest_ok => $samba->{'pdf-gen'}{'guest ok'}, + }; + } elsif ($wiz_todo == 2) { + exists $samba->{'print$'} || exists $samba->{printers} and err_dialog(N("Error"), N("Printers and print\$ already exist.")) and return 'welcome'; + &printdollar_section; + &printers_section; + push @{$printer_list->{data}}, [ + $pixbuf_printer, + 'print$', + $samba->{'print$'}{path}, "", + $samba->{'print$'}{browseable}, "", "", "", + $samba->{'print$'}{'guest ok'}, "", + $samba->{'print$'}{'write list'}, + $samba->{'print$'}{'inherit permissions'}, + ]; + push @{$printer_list->{data}}, [ + $pixbuf_printer, + 'printers', + $samba->{printers}{path}, + $samba->{printers}{comment}, + $samba->{printers}{browseable}, + $samba->{printers}{printable}, + $samba->{printers}{'print command'}, "", + $samba->{printers}{'guest ok'}, + $samba->{printers}{writable}, "", "", "", + $samba->{printers}{'create mode'}, + $samba->{printers}{'use client driver'}, + ]; + push @listprinters, { + share_name => 'print$', + path => $samba->{'print$'}{path}, + browseable => $samba->{'print$'}{browseable}, + write_list => $samba->{'print$'}{'write list'}, + guest_ok => $samba->{'print$'}{'guest ok'}, + inherit_permissions => $samba->{'print$'}{'inherit permissions'}, + }; + push @listprinters, { + share_name => "printers", + comment => $samba->{printers}{comment}, + browseable => $samba->{printers}{browseable}, + guest_ok => $samba->{printers}{'guest ok'}, + create_mode => $samba->{printers}{'create mode'}, + path => $samba->{printers}{path}, + writable => $samba->{printers}{writable}, + printable => $samba->{printers}{printable}, + print_command => $samba->{printers}{'print command'}, + use_client_driver => $samba->{printers}{'use client driver'}, + }; + } + return; + }, + }, + end_add => { + name => N("Congratulations"), + data => [ { label => N("The wizard successfully added the printer Samba share") } ], + no_back => 1, + end => 1, + next => 0, + }, + } + }); + $wiz->process($in); + $::isWizard = 0; +} + +sub modify_printers_entry { + my ($selected) = @_; + my ($dir, $comment, $print_command, $guest_ok, $share_name, $browseable, $printable, $write_list, $printing, $lpq_command, $create_mode, $writable, $use_client_driver, $inherit_permissions); + + $share_name = Gtk2::Label->new; + $_ = Gtk2::Entry->new foreach $dir, $comment, $print_command, $write_list, $printing, $lpq_command, $create_mode; + $_ = Gtk2::OptionMenu->new foreach $browseable, $printable, $guest_ok, $writable, $use_client_driver, $inherit_permissions; + $_->set_popdown_strings(@yesno) foreach $browseable, $printable, $guest_ok, $writable, $use_client_driver, $inherit_permissions; + + + my $s = $printer_list->{data}[$selected][1]; + $s or info_dialog(N("Error"), N("Please add or select a Samba printer share to be able to modify it.")) and return; $share_name->set_text($s); + $dir->set_text($printer_list->{data}[$selected][2]); + $comment->set_text($printer_list->{data}[$selected][3]); + $browseable->set_text($printer_list->{data}[$selected][4]); + $printable->set_text($printer_list->{data}[$selected][5]); + $print_command->set_text($printer_list->{data}[$selected][6]); + $lpq_command->set_text($printer_list->{data}[$selected][7]); + $guest_ok->set_text($printer_list->{data}[$selected][8]); + $writable->set_text($printer_list->{data}[$selected][9]); + $write_list->set_text($printer_list->{data}[$selected][10]); + $inherit_permissions->set_text($printer_list->{data}[$selected][11]); + $printing->set_text($printer_list->{data}[$selected][12]); + $create_mode->set_text($printer_list->{data}[$selected][13]); + $use_client_driver->set_text($printer_list->{data}[$selected][14]); + + my $button = Gtk2::Button->new(N("Open")); + $button->signal_connect(clicked => sub { show_file_dialog($dir); }); + + my $dialog = _create_dialog(N("DrakSamba Printers entry"), { transient_for => $::main_window, modal => 1 }); + + local $::main_window = $dialog; + + if ($s eq "printers") { $printable->set_text("yes"); + $printing->set_text(""); + $_->set_sensitive(0) foreach $printable, $printing; + } + if ($s eq "pdf-gen") { $printing->set_text("bsd"); + $printing->set_sensitive(0); + } + + gtkpack_($dialog->vbox, + 0, gtkadd(Gtk2::Frame->new(N("Printer share")), + gtkpack_(gtkset_border_width(Gtk2::HBox->new, 3), + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $label_and_widgets->(N("Printer name:"), $share_name, ""), + 0, $label_and_widgets->(N("Comment:"), $comment, ""), + 0, $label_and_widgets->(N("Directory:"), $dir, $button), + ), + 0, Gtk2::VSeparator->new, + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $label_and_widgets->(N("Writable:"), $writable, ""), + 0, $label_and_widgets->(N("Browseable:"), $browseable, ""), + 0, $label_and_widgets->(N("Printable"), $printable, ""), + ), + ), + ), + 0, gtkadd(Gtk2::Frame->new(N("Advanced options")), + gtkpack_(gtkset_border_width(Gtk2::HBox->new, 3), + 0, gtkadd(Gtk2::Frame->new(N("Printer access")), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $label_and_widgets->(N("Write list"), $write_list, ""), + 0, $label_and_widgets->(N("Inherit permissions"), $inherit_permissions, ""), + 0, $label_and_widgets->(N("Guest ok:"), $guest_ok, ""), + 0, $label_and_widgets->(N("Create mode:"), $create_mode, ""), + ), + ), + 0, Gtk2::VSeparator->new, + 0, gtkadd(Gtk2::Frame->new(N("Printer command")), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $label_and_widgets->(N("Print command:"), $print_command, ""), + 0, $label_and_widgets->(N("LPQ command:"), $lpq_command, ""), + 0, $label_and_widgets->(N("Printing:"), $printing, ""), + ), + ), + ), + ), + 0, create_okcancel({ + cancel_clicked => sub { $dialog->destroy }, + ok_clicked => sub { + my $share = $share_name->get_text; + my $test_dir = $dir->get_text; + $comment->get_text or err_dialog(N("Information"), N("Please enter a Comment for this share.")) and return 1; + if (!-d $test_dir) { + err_dialog(N("Error!"), N("Please enter a directory to share.")) and return; + } + foreach ($create_mode->get_text) { + if ($_ && !/^\d+$/) { + err_dialog(N("Error"), N("create mode should be numeric. ie: 0755.")) and return 1; + } + } + # update gui SimpleList + remove_entry($selected, $printer_list); + push @{$printer_list->{data}}, [ + $pixbuf_printer, + $share, + $dir->get_text, + $comment->get_text, + $browseable->get_text, + $printable->get_text, + $print_command->get_text, + $lpq_command->get_text, + $guest_ok->get_text, + $writable->get_text, + $write_list->get_text, + $inherit_permissions->get_text, + $printing->get_text, + $create_mode->get_text, + $use_client_driver->get_text, + ]; + # update $samba + $samba->{$share}{path} = $dir->get_text; + $samba->{$share}{comment} = $comment->get_text; + $browseable->get_text and $samba->{$share}{browseable} = $browseable->get_text || delete $samba->{$share}{browseable}; + $printable->get_text and $samba->{$share}{printable} = $printable->get_text || delete $samba->{$share}{printable}; + $print_command->get_text and $samba->{$share}{'print command'} = $print_command->get_text || delete $samba->{$share}{'print command'}; + $lpq_command->get_text and $samba->{$share}{'lpq command'} = $lpq_command->get_text || delete $samba->{$share}{'lpq command'}; + $guest_ok->get_text and $samba->{$share}{'guest ok'} = $guest_ok->get_text || delete $samba->{$share}{'guest ok'}; + $writable->get_text and $samba->{$share}{writable} = $writable->get_text || delete $samba->{$share}{writable}; + $write_list->get_text and $samba->{$share}{'write list'} = $write_list->get_text || delete $samba->{$share}{'write list'}; + $inherit_permissions->get_text and $samba->{$share}{'inherit permissions'} = $inherit_permissions->get_text || delete $samba->{$share}{'inherit permissions'}; + $printing->get_text and $samba->{$share}{printing} = $printing->get_text || delete $samba->{$share}{printing}; + $create_mode->get_text and $samba->{$share}{'create mode'} = $create_mode->get_text || delete $samba->{$share}{'create mode'}; + $use_client_driver->get_text and $samba->{$share}{'use client driver'} = $use_client_driver->get_text || delete $samba->{$share}{'use client driver'}; + + # + $dialog->destroy; + } + }, + ), + ); + $dialog->show_all; +} + +sub modify_entry { + my ($selected) = @_; + my ($dir, $comment, $create_mask, $directory_mask, $read_list, $write_list, $admin_users, $valid_users, $force_group, $browseable, $public, $writable, $hide_files, $hide_dot_files, $force_create_mode, $preserve_case, $default_case, $inherit_permissions, $share_name); + + $share_name = Gtk2::Label->new; + $_ = Gtk2::Entry->new foreach $dir, $comment, $create_mask, $directory_mask, $hide_files; + $_ = Gtk2::Entry->new foreach $read_list, $write_list, $admin_users, $valid_users, $force_group, $force_create_mode; + $_ = Gtk2::OptionMenu->new foreach $browseable, $public, $writable, $default_case, $preserve_case, $hide_dot_files, $inherit_permissions; + + $default_case->set_popdown_strings(@default_case); + $_->set_popdown_strings(@yesno) foreach $browseable, $public, $writable, $hide_dot_files, $preserve_case, $inherit_permissions; + + my $button = Gtk2::Button->new(N("Open")); + $button->signal_connect(clicked => sub { show_file_dialog($dir); }); + + my $w = ugtk2->new(N("DrakSamba entry")); + $w->{window}->set_modal(1); + $w->{window}->set_position('center'); + + my $s = $share_list->{data}[$selected][1]; + $s or info_dialog(N("Error"), N("Please add or select a Samba share to be able to modify it.")) and return; + $share_name->set_text($s); + $dir->set_text($share_list->{data}[$selected][2]); + $comment->set_text($share_list->{data}[$selected][3]); + $browseable->set_text($share_list->{data}[$selected][4]); + $public->set_text($share_list->{data}[$selected][5]); + $writable->set_text($share_list->{data}[$selected][6]); + $create_mask->set_text($share_list->{data}[$selected][7]); + $directory_mask->set_text($share_list->{data}[$selected][8]); + $read_list->set_text($share_list->{data}[$selected][9]); + $write_list->set_text($share_list->{data}[$selected][10]); + $admin_users->set_text($share_list->{data}[$selected][11]); + $valid_users->set_text($share_list->{data}[$selected][12]); + $inherit_permissions->set_text($share_list->{data}[$selected][13]); + $hide_dot_files->set_text($share_list->{data}[$selected][14]); + $hide_files->set_text($share_list->{data}[$selected][15]); + $preserve_case->set_text($share_list->{data}[$selected][16]); + $force_create_mode->set_text($share_list->{data}[$selected][17]); + $force_group->set_text($share_list->{data}[$selected][18]); + $default_case->set_text($share_list->{data}[$selected][19]); + + my $expander_user = Gtk2::Expander->new('User options (user access, mask option, force mode)'); + $expander_user->add(gtkpack_(Gtk2::HBox->new, + 0, gtkadd(Gtk2::Frame->new(N("Samba user access")), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $label_and_widgets->($adv_options{read_list}, $read_list, ""), + 0, $label_and_widgets->($adv_options{write_list}, $write_list, ""), + 0, $label_and_widgets->($adv_options{admin_users}, $admin_users, ""), + 0, $label_and_widgets->($adv_options{valid_users}, $valid_users, ""), + ), + ), + 0, gtkadd(Gtk2::Frame->new(N("Mask options")), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $label_and_widgets->($adv_options{create_mask}, $create_mask, ""), + 0, $label_and_widgets->($adv_options{directory_mask}, $directory_mask, ""), + 0, $label_and_widgets->($adv_options{force_group}, $force_group, ""), + 0, $label_and_widgets->($adv_options{force_create_mode}, $force_create_mode, ""), + 0, $label_and_widgets->($adv_options{inherit_permissions}, $inherit_permissions, ""), + ), + ), + ), + ); + + my $expander_file = Gtk2::Expander->new('File options (hide files, case)'); + $expander_file->add(gtkpack_(Gtk2::VBox->new, + 0, gtkadd(Gtk2::Frame->new(N("Display options")), + gtkpack_(gtkset_border_width(Gtk2::HBox->new, 1), + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 0), + 0, $label_and_widgets->($adv_options{hide_dot_files}, $hide_dot_files, ""), + 0, $label_and_widgets->($adv_options{hide_files}, $hide_files, ""), + ), + 0, Gtk2::VSeparator->new, + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 0), + 0, $label_and_widgets->($adv_options{default_case}, $default_case, ""), + 0, $label_and_widgets->($adv_options{preserve_case}, $preserve_case, ""), + ), + ), + ), + ), + ); + + $_->signal_connect(activate => sub { + $w->shrink_topwindow; + }) foreach $expander_file, $expander_user; + + gtkadd($w->{window}, + gtknew('VBox', spacing => 0, children_loose => [ + gtkadd(Gtk2::Frame->new(N("Samba share directory")), + gtkpack_(gtkset_border_width(Gtk2::HBox->new, 1), + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 0), + 0, $label_and_widgets->(N("Share name:"), $share_name), + 0, $label_and_widgets->(N("Directory:"), $dir, $button), + 0, $label_and_widgets->(N("Comment:"), $comment, ""), + ), + 0, Gtk2::VSeparator->new, + 0, gtkpack_(gtkset_border_width(Gtk2::VBox->new, 0), + 0, $label_and_widgets->(N("Public:"), $public, ""), + 0, $label_and_widgets->(N("Writable:"), $writable, ""), + 0, $label_and_widgets->(N("Browseable:"), $browseable, ""), + ), + ), + ), + gtkadd(Gtk2::Frame->new("Advanced options"), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 1), + 0, $expander_user, + 0, Gtk2::HSeparator->new, + 0, $expander_file, + ), + ), + create_okcancel({ + cancel_clicked => sub { $w->destroy }, + ok_clicked => sub { + my $share = $share_name->get_text; + my $test_dir = $dir->get_text; + $comment->get_text or err_dialog(N("Information"), N("Please enter a Comment for this share.")) and return 1; + if ($share ne 'homes' && !-d $test_dir) { + err_dialog(N("Error!"), N("Please enter a directory to share.")) and return; + } + foreach ($create_mask->get_text, $directory_mask->get_text) { + if ($_ && !/^\d+$/) { + err_dialog(N("Error"), N("Create mask, create mode and directory mask should be numeric. ie: 0755.")) and return 1; + } + } + foreach ($read_list->get_text, $write_list->get_text, $admin_users->get_text, $valid_users->get_text) { + my @users = split(" ", $_); + my @known_users = split("\n", `pdbedit -L -w`); + foreach my $user (@users) { + if (!(any { /^$user:/ } @known_users) && !/\@/) { + err_dialog(N("Error"), N("Please create this Samba user: %s", $user)) and return; + } + } + } + # update gui SimpleList + remove_entry($selected, $share_list); + push @{$share_list->{data}}, [ + $pixbuf_file, + $share_name->get_text, + $dir->get_text, + $comment->get_text, + $browseable->get_text, + $public->get_text, + $writable->get_text, + $create_mask->get_text, + $directory_mask->get_text, + $read_list->get_text, + $write_list->get_text, + $admin_users->get_text, + $valid_users->get_text, + $inherit_permissions->get_text, + $hide_dot_files->get_text, + $hide_files->get_text, + $preserve_case->get_text, + $force_create_mode->get_text, + $force_group->get_text, + $default_case->get_text, + ]; + remove_entry($selected, $display_share); + push @{$display_share->{data}}, [ + $pixbuf_file, + $share_name->get_text, + $dir->get_text, + $comment->get_text, + ]; + + # update $samba with the new value + # $samba->{$share}; + $samba->{$share}{path} = $dir->get_text; + $samba->{$share}{comment} = $comment->get_text; + $browseable->get_text and $samba->{$share}{browseable} = $browseable->get_text || delete $samba->{$share}{browseable}; + $public->get_text and $samba->{$share}{public} = $public->get_text || delete $samba->{$share}{public}; + $writable->get_text and $samba->{$share}{writable} = $writable->get_text || delete $samba->{$share}{writable}; + $create_mask->get_text and $samba->{$share}{'create mask'} = $create_mask->get_text || delete $samba->{$share}{'create mask'}; + $directory_mask->get_text and $samba->{$share}{'directory mask'} = $directory_mask->get_text || delete $samba->{$share}{'directory mask'}; + $read_list->get_text and $samba->{$share}{'read list'} = $read_list->get_text || delete $samba->{$share}{'read list'}; + $write_list->get_text and $samba->{$share}{'write list'} = $write_list->get_text || delete $samba->{$share}{'write list'}; + $admin_users->get_text and $samba->{$share}{'admin users'} = $admin_users->get_text || delete $samba->{$share}{'admin users'}; + $valid_users->get_text and $samba->{$share}{'valid users'} = $valid_users->get_text || delete $samba->{$share}{'valid users'}; + $inherit_permissions->get_text and $samba->{$share}{'inherit permissions'} = $inherit_permissions->get_text || delete $samba->{$share}{'inherit permissions'}; + $hide_dot_files->get_text and $samba->{$share}{'hide dot files'} = $hide_dot_files->get_text || delete $samba->{$share}{'hide dot files'}; + $hide_files->get_text and $samba->{$share}{'hide files'} = $hide_files->get_text || delete $samba->{$share}{'hide files'}; + $preserve_case->get_text and $samba->{$share}{'preserve case'} = $preserve_case->get_text || delete $samba->{$share}{'preserve case'}; + $force_create_mode->get_text and $samba->{$share}{'force create mode'} = $force_create_mode->get_text || delete $samba->{$share}{'force create mode'}; + $force_group->get_text and $samba->{$share}{'force group'} = $force_group->get_text || delete $samba->{$share}{'force group'}; + $default_case->get_text and $samba->{$share}{'default case'} = $default_case->get_text || delete $samba->{$share}{'default case'}; + + # update listshare + push @listshare, { + share_name => $share, + path => $samba->{$share}{path}, + comment => $samba->{$share}{comment}, + browseable => $samba->{$share}{browseable}, + public => $samba->{$share}{public}, + writable => $samba->{$share}{writable}, + create_mask => $samba->{$share}{'create mask'}, + directory_mask => $samba->{$share}{'directory mask'}, + read_list => $samba->{$share}{'read list'}, + write_list => $samba->{$share}{'write list'}, + admin_users => $samba->{$share}{'admin users'}, + valid_users => $samba->{$share}{'valid users'}, + inherit_permissions => $samba->{$share}{'inherit permissions'}, + hide_dot_files => $samba->{$share}{'hide dot files'}, + hide_files => $samba->{$share}{'hide files'}, + preserve_case => $samba->{$share}{'preserve case'}, + force_create_mode => $samba->{$share}{'force create mode'}, + force_group => $samba->{$share}{'force group'}, + default_case => $samba->{$share}{'default case'}, + }; + $w->destroy; + }, + }, + ), + ] + ), + ); + $w->{window}->show_all; +} + +sub remove_entry { + my ($selected, $list) = @_; + my $share_name = $list->{data}[$selected][1]; + splice @{$list->{data}}, $selected, 1; + delete $samba->{$share_name}; +} + +sub remove_user { + my ($user) = @_; + system("smbpasswd -x $user"); +} + +sub get_user() { + my $conf = "/etc/passwd"; + my @data = map { if_(m/^([^#:]+):[^:]+:([^:]+):/ && $2 > 499, $1) } cat_($conf); + return sort(@data, " "); +} + + +sub modify_user_info { + my ($user, $_passwd, $todo) = @_; + my ($buser, $bpasswd); + my $dialog = new Gtk2::Dialog(); + $dialog->set_title(N("Add Samba user")); + $dialog->set_modal(1); + $dialog->set_position('center'); + $dialog->set_resizable(0); + if ($todo eq "add") { + $buser = Gtk2::ComboBox->new_with_strings([ get_user() ]); + $buser->set_wrap_width(3); + } else { + $buser = Gtk2::Label->new; + $buser->set_text($user); + } + $bpasswd = Gtk2::Entry->new; + $bpasswd->set_visibility(0); + + gtkpack_($dialog->vbox, + 0, gtkadd(Gtk2::Frame->new(N("User information")), + gtkpack_(gtkset_border_width(Gtk2::VBox->new, 5), + 0, $label_and_widgets->(N("User name:"), $buser, ""), + 0, $label_and_widgets->(N("Password:"), $bpasswd, ""), + ), + ), + 0, create_okcancel({ + cancel_clicked => sub { $dialog->destroy }, + ok_clicked => sub { + my $user_selected = $buser->get_text; + if ($todo eq "add") { + if (any { /^$user_selected:/ } cat_("/etc/samba/smbpasswd")) { + err_dialog(N("Error"), ("Samba User already exist")) and return; + } + system("smbpasswd -a $user_selected -n"); + push @{$user_list->{data}}, [ + $pixbuf_user, + $user_selected, + ]; + push @listusers, { + user_name => $user_selected, + }; + } + my $passwd_e = $bpasswd->get_text; + set_user_passwd($user_selected, $passwd_e); + $dialog->destroy; + } + }, + ), + ); + $dialog->show_all; +} + +sub set_user_passwd { + my ($user, $passwd) = @_; + my $F; + open($F, '|' . qq(smbpasswd $user -s)); + print $F "$passwd\n"; + print $F "$passwd\n"; + close $F; +} + +sub add_data_share_list { + my ($share_list) = @_; + get_samba_share(); + + foreach my $data (@listshare) { + push @{$share_list->{data}}, [ + $pixbuf_file, + $data->{share_name}, + $data->{path}, + $data->{comment}, + $data->{browseable}, + $data->{public}, + $data->{writable}, + $data->{create_mask}, + $data->{directory_mask}, + $data->{read_list}, + $data->{write_list}, + $data->{admin_users}, + $data->{valid_users}, + $data->{inherit_permissions}, + $data->{hide_dot_files}, + $data->{hide_files}, + $data->{preserve_case}, + $data->{force_create_mode}, + $data->{force_group}, + $data->{default_case}, + ]; + push @{$display_share->{data}}, [ + $pixbuf_file, + $data->{share_name}, + $data->{path}, + $data->{comment}, + ]; + } +} + +sub add_data_user_list { + my ($user_list) = @_; + get_samba_user(); + foreach my $data (@listusers) { + push @{$user_list->{data}}, [ + $pixbuf_user, + $data->{user_name}, + ]; + } +} + +sub add_data_printer_list { + my ($printer_list) = @_; + get_samba_printers(); + foreach my $data (@listprinters) { + push @{$printer_list->{data}}, [ + $pixbuf_printer, + $data->{share_name}, + $data->{path}, + $data->{comment}, + $data->{browseable}, + $data->{printable}, + $data->{print_command}, + $data->{lpq_command}, + $data->{guest_ok}, + $data->{writable}, + $data->{write_list}, + $data->{inherit_permissions}, + $data->{printing}, + $data->{create_mode}, + $data->{use_client_driver}, + ]; + } +} + + +sub configure_samba { + require wizards; + my %type = ( + 2 => N("PDC - primary domain controller"), + 3 => N("Standalone - standalone server"), + ); + my @yesorno = qw(yes no); push @yesorno, ""; + my @loglevel = qw(0 1 2 3 4 5 6 7 8 9); + my @security_list = qw(share user domain); + my $wiz = wizards->new({ + name => N("Samba Wizard"), + pages => { + welcome => { + name => N("Samba server configuration Wizard") . "\n\n" . N("Samba allows your server to behave as a file and print server for workstations running non-Linux systems."), + #no_back => 1, + pre => sub { + $o->{var}{wiz_type} = "3"; + }, + post => sub { + if ($o->{var}{wiz_type} == 2) { + return 'pdc' } + elsif ($o->{var}{wiz_type} == 3) { + return 'ask_workgroup' } + }, + data => [ + { label => "", val => \$o->{var}{wiz_type}, type => 'list', list => [ sort keys %type ], format => sub { $type{$_[0]} } }, + ], + }, + pdc => { + name => N("PDC server: primary domain controller") . "\n\n" . N("Server configured as a PDC is responsible for Windows authentication throughout the domain.") . "\n" . N("Single server installations may use smbpasswd or tdbsam password backends") . "\n" . N("Domain master = yes, causes the server to register the NetBIOS name <pdc name>. This name will be recognized by other servers."), + pre => sub { + $o->{var}{wiz_domain_master} = "yes"; + $o->{var}{wiz_security} = "user"; + $o->{var}{wiz_domain_logons} = "yes"; + $o->{var}{wiz_wins_support} ||= $samba->{global}{'wins support'}; + $o->{var}{wiz_oslevel} = "128"; + if (exists $samba->{global}{'passdb backend'}) { + $o->{var}{wiz_passdb_backend_yn} = "yes"; + } + else { + $o->{var}{wiz_passdb_backend_yn} = "no"; + } + }, + data => [ + #{ label => N("Domain logons:"), val_ref => \$o->{var}{wiz_domain_logons} }, + #{ label => N("Domain master:"), val_ref => \$o->{var}{wiz_domain_master} }, + { label => N("Wins support:"), val => \$o->{var}{wiz_wins_support}, list => \@yesorno }, + { label => N("admin users:"), val => \$o->{var}{wiz_admin_users}, help => N("root \@adm") }, + { label => N("Os level:"), val_ref => \$o->{var}{wiz_oslevel}, help => N("The global os level option dictates the operating system level at which Samba will masquerade during a browser election. If you wish to have Samba win an election and become the master browser, you can set the level above that of the operating system on your network with the highest current value. ie: os level = 34") }, + ], + complete => sub { + if (!$o->{var}{wiz_domain_master}) { + $in->ask_warn(N("Error"), N("The domain is wrong.")); + return 1; + } else { return 0 } + }, + next => 'ask_workgroup', + }, + ask_workgroup => { + name => N("Workgroup") . "\n\n" . N("Samba needs to know the Windows Workgroup it will serve."), + pre => sub { + $o->{var}{wiz_workgroup} ||= $samba->{global}{workgroup}; + $o->{var}{wiz_netbios} ||= $samba->{global}{netbios}; + $o->{var}{wiz_netbios_name} ||= $samba->{global}{"netbios name"}; + }, + data => [ + { label => N("Workgroup:"), val => \$o->{var}{wiz_workgroup} }, + { label => N("Netbios name:"), val => \$o->{var}{wiz_netbios_name} }, + ], + complete => sub { + if (!$o->{var}{wiz_workgroup}) { + $in->ask_warn(N("Error"), N("The Workgroup is wrong.")); + return 1; + } else { return 0 } + }, + next => 'ask_security', + }, + ask_security => { + name => N("Security mode") . "\n\n" . N("User level: the client sends a session setup request directly following protocol negotiation. This request provides a username and password.") . "\n" . N("Share level: the client authenticates itself separately for each share") . "\n" . N("Domain level: provides a mechanism for storing all user and group accounts in a central, shared, account repository. The centralized account repository is shared between domain (security) controllers."), + pre => sub { + $o->{var}{wiz_security} ||= $samba->{global}{security}; + $o->{var}{host_allow} ||= $samba->{global}{'hosts allow'}; + if ($o->{var}{wiz_type} == 3) { + # remove domain security mode for standalone server + pop(@security_list); + } + }, + data => [ + { label => N("Security mode"), val => \$o->{var}{wiz_security}, list => \@security_list }, + { label => N("Hosts allow"), val => \$o->{var}{hosts_allow}, help => "127. 192.168.0. 192.168.1.253" }, + ], + next => 'ask_banner', + }, + ask_banner => { + name => N("Server Banner.") . "\n\n" . N("The banner is the way this server will be described in the Windows workstations."), + pre => sub { + $o->{var}{wiz_banner} ||= $samba->{global}{'server string'}; + }, + data => [ + { label => N("Banner:"), val => \$o->{var}{wiz_banner}, help => "Samba Server %v" }, + ], + complete => sub { + if (!$o->{var}{wiz_banner}) { + $in->ask_warn(N("Error"), N("The Server Banner is incorrect.")); + return 1; + } else { return 0 } + }, + next => 'ask_log', + }, + ask_log => { + name => N("Samba Log") . "\n" . N("Log file: use file.%m to use a separate log file for each machine that connects") . "\n" . N("Log level: set the log (verbosity) level (0 <= log level <= 10)") . "\n" . N("Max Log size: put a capping on the size of the log files (in Kb)."), + pre => sub { + $o->{var}{wiz_log_file} ||= $samba->{global}{'log file'}; + $o->{var}{wiz_log_level} ||= $samba->{global}{'log level'}; + $o->{var}{wiz_max_log_size} ||= $samba->{global}{'max log size'}; + }, + data => [ + { label => N("Log file:"), val => \$o->{var}{wiz_log_file}, help => "/var/log/samba/log.%m" }, + { label => N("Max log size:"), val => \$o->{var}{wiz_max_log_size}, help => "50" }, + { label => N("Log level:"), val => \$o->{var}{wiz_log_level}, list => \@loglevel }, + ], + next => 'summary', + }, + summary => { + name => N("The wizard collected the following parameters to configure Samba.") . "\n\n" . N("To accept these values, and configure your server, click the Next button or use the Back button to correct them.") . "\n" . N("If you have previously create some shares, they will appear in this configuration. Run 'drakwizard sambashare' to manage your shares."), + pre => sub { + $o->{var}{wiz_sambatype} = $type{$o->{var}{wiz_type}}; + $o->{var}{wiz_unixcharset} ||= $samba->{global}{'unix charset'}; + $o->{var}{wiz_doscharset} ||= $samba->{global}{'dos charset'}; + $o->{var}{wiz_displaycharset} ||= $samba->{global}{'display charset'}; + }, + data => [ + { label => N("Samba type:"), val_ref => \$o->{var}{wiz_sambatype} }, + { label => N("Workgroup:"), val_ref => \$o->{var}{wiz_workgroup} }, + { label => N("Server banner:"), val_ref => \$o->{var}{wiz_banner} }, + { label => N("Log file:"), val_ref => \$o->{var}{wiz_log_file} }, + { text => N(" "), advanced => 1 }, + { label => N("Unix Charset:"), val => \$o->{var}{wiz_unixcharset}, help => "Unix Charset pecifies the charset the unix machine Samba runs on uses.", advanced => 1 }, + { label => N("Dos Charset:"), val => \$o->{var}{wiz_doscharset}, help => "Dos Charset specifies which charset Samba should talk to DOS clients.", advanced => 1 }, + { label => N("Display Charset:"), val => \$o->{var}{wiz_displaycharset}, help=> "Display Charset specifies the charset that samba will use to print messages to stdout and stderr. The default value is 'LOCALE', which means automatically set, depending on the current locale.", advanced => 1 }, + ], + post => sub { + $samba->{global}{workgroup} = $o->{var}{wiz_workgroup}; + $o->{var}{wiz_netbios_name} ? $samba->{global}{"netbios name"} = $o->{var}{wiz_netbios_name} : delete $samba->{global}{"netbios name"}; + $samba->{global}{'server string'} = $o->{var}{wiz_banner}; + $o->{var}{wiz_log_file} and $samba->{global}{'log file'} = $o->{var}{wiz_log_file}; + $o->{var}{wiz_log_level} and $samba->{global}{'log level'} = $o->{var}{wiz_log_level}; + $o->{var}{wiz_max_log_size} and $samba->{global}{'max log size'} = $o->{var}{wiz_max_log_size}; + global_special_options(); + }, + next => 'endconf', + }, + endconf => { + pre => sub { output($draksambashare, "draksambshare check") }, + name => N("Congratulations") . "\n\n" . N("The wizard successfully configured your Samba server."), + no_back => 1, + end => 1, + }, + }, + }); + $wiz->process($in); + $::isWizard = 0; +} + +sub global_special_options() { + # set charset + $o->{var}{wiz_doscharset} ? $samba->{global}{'dos charset'} = $o->{var}{wiz_doscharset} : delete $samba->{global}{'dos charset'}; + $o->{var}{wiz_unixcharset} ? $samba->{global}{'unix charset'} = $o->{var}{wiz_unixcharset} : delete $samba->{global}{'unix charset'}; + $o->{var}{wiz_displaycharset} ? $samba->{global}{'display charset'} = $o->{var}{wiz_displaycharset} : delete $samba->{global}{'display charset'}; + $o->{var}{wiz_security} ? $samba->{global}{security} = $o->{var}{wiz_security} : delete $samba->{global}{security}; + $o->{var}{hosts_allow} ? $samba->{global}{'hosts allow'} = $o->{var}{hosts_allow} : delete $samba->{global}{'hosts allow'}; +# $samba->{global}{security} = $o->{var}{wiz_security}; + # detect Samba type 3 is standalone + if ($o->{var}{wiz_type} == "3") { + exists $samba->{global}{domain_master} and delete $samba->{global}{domain_master}; + exists $samba->{global}{'domain logons'} and delete $samba->{global}{'domain logons'}; + exists $samba->{global}{'wins support'} and delete $samba->{global}{'wins support'}; + exists $samba->{global}{'os level'} and delete $samba->{global}{'os level'}; + } else { + # so pdc + $o->{var}{wiz_local_master} and $samba->{global}{'local master'} = $o->{var}{wiz_local_master}; + $o->{var}{wiz_preferred_master} and $samba->{global}{'preferred master'} = $o->{var}{wiz_preferred_master}; + $o->{var}{wiz_wins_server} and $samba->{global}{'wins server'} = $o->{var}{wiz_wins_server}; + $o->{var}{wiz_name_resolve_order} and $samba->{global}{'name resolve order'} = $o->{var}{wiz_name_resolve_order}; + $o->{var}{wiz_dns_proxy} and $samba->{global}{'dns proxy'} = $o->{var}{wiz_dns_proxy}; + $o->{var}{wiz_domain_master} and $samba->{global}{'domain master'} = $o->{var}{wiz_domain_master}; + $o->{var}{wiz_domain_logons} and $samba->{global}{'domain logons'} = $o->{var}{wiz_domain_logons}; + $o->{var}{wiz_oslevel} and $samba->{global}{'os level'} = $o->{var}{wiz_oslevel}; + $o->{var}{wiz_passdb_backend} and $samba->{global}{'passdb backend'} = $o->{var}{wiz_passdb_backend}; + $o->{var}{wiz_wins_support} and $samba->{global}{'wins support'} = $o->{var}{wiz_wins_support}; + $o->{var}{wiz_password_server} and $samba->{global}{'password server'} = $o->{var}{wiz_password_server}; + $o->{var}{wiz_admin_users} and $samba->{global}{'admin users'} = $o->{var}{wiz_admin_users}; + $samba->{global}{'add machine script'} = "/usr/sbin/useradd -d /dev/null -g machines -c 'Machine Account' -s /bin/false -M '%u'"; + + } + my $conf = "/etc/group"; + my @groups; + foreach (cat_($conf)) { + push @groups, $1 if m/^([^#:]+):[^:]+:([^:]+):/ and $2 > 499; + } + foreach (@groups) { + system("net groupmap add unixgroup=$_ ntgroup=$_"); + } +} + +sub launch_samba_wizard() { + eval { configure_samba() }; + my $err = $@; + if ($err && $err !~ /wizcancel/) { + err_dialog(N("Error"), N("The Samba wizard has unexpectedly failed:") . "\n\n" . $err); + } +} + +############### +# Main Program +############### +# create model +add_data_share_list($share_list); +add_data_printer_list($printer_list); +add_data_user_list($user_list); +$_->set_rules_hint(1) foreach $display_share, $printer_list, $user_list; + +$ugtk2::wm_icon = $fileshare_icon; +$window = ugtk2->new(N("Manage Samba configuration")); +$::main_window = $window->{real_window}; +$window->{rwindow}->set_size_request(600, 410) unless $::isEmbedded; +$window->{rwindow}->set_position('center') if !$::isEmbedded; +my $W = $window->{window}; +$W->signal_connect(delete_event => sub { ugtk2->exit }); + +# double clic and popup modify window +$display_share->signal_connect(button_press_event => sub { + my (undef, $event) = @_; + my ($selected) = $display_share->get_selected_indices; + $display_share->{data}[$selected][1] and modify_entry($selected) if $event->type eq '2button-press'; + }); + +$printer_list->signal_connect(button_press_event => sub { + my (undef, $event) = @_; + my ($selected) = $printer_list->get_selected_indices; + $printer_list->{data}[$selected][1] and modify_printers_entry($selected) if $event->type eq '2button-press'; + }); + +$user_list->signal_connect(button_press_event => sub { + my (undef, $event) = @_; + my ($selected) = $user_list->get_selected_indices; + $user_list->{data}[$selected][1] and modify_user_info($user_list->{data}[$selected][1], "", "change") if $event->type eq '2button-press'; + }); + +# dont know why "$event->type eq '2button-press'" when starting draksambashare so i can't use mapn :/ +#mapn { +# $_[0]->signal_connect(button_press_event => sub { +# my (undef, $event) = @_; +# my ($selected) = $_[0]->get_selected_indices; +# return unless $event->type eq '2button-press'; +# $_[0]->{data}[$selected][1] and $_[1]($selected); # if $event->type eq '2button-press'; +# }); +#} [ $share_list, $printer_list, $user_list ], [ modify_entry, modify_printers_entry, modify_user_info ]; + +# create popup menu +my $menupopup = Gtk2::Menu->new; +my $menuitem1 = Gtk2::MenuItem->new(N("Modify")); +my $menuitem2 = Gtk2::MenuItem->new(N("Remove")); +$menuitem1->signal_connect(activate => sub { + my ($selected) = $display_share->get_selected_indices; + modify_entry($selected); + }); +$menuitem2->signal_connect(activate => sub { + my ($selected) = $display_share->get_selected_indices; + ask_okcancel("Remove entry ?", "Remove $display_share->{data}[$selected][1]") or return; + remove_entry($selected, $display_share); + }); +$_->show foreach $menuitem1, $menuitem2; +$menupopup->append($_) foreach $menuitem1, $menuitem2; +$display_share->signal_connect('button-press-event' => sub { + my (undef, $event) = @_; + return unless $event->button == 3; + $menupopup->popup(undef, undef, undef, undef, $event->button, $event->time); + } + ); + +$display_share->signal_connect(key_press_event => sub { + my (undef, $event) = @_; + return unless $event->keyval == $Gtk2::Gdk::Keysyms{Return}; + my ($selected) = $display_share->get_selected_indices; + modify_entry($selected); + return 1; +}); + +# create menu +my @items = get_items(); +my $factory = Gtk2::ItemFactory->new('Gtk2::MenuBar', '<main>', undef); +$factory->create_items('menu', @items); +my $menu = $factory->get_widget('<main>'); + +my $okcancel = create_okcancel({ + cancel_clicked => sub { ugtk2->exit }, + ok_clicked => sub { &write_conf; ugtk2->exit }, + }, + ); + +gtkappend_page(my $nb = Gtk2::Notebook->new, gtkpack_(gtkset_border_width(Gtk2::HBox->new, 0), + 1, create_scrolled_window($display_share), + 0, gtkpack_(create_vbox('start'), + 0, gtksignal_connect(Gtk2::Button->new(N("Add")), clicked => \&add_entry), + 0, Gtk2::HSeparator->new, + 0, gtksignal_connect(Gtk2::Button->new(N("Modify")), clicked => sub { + my ($selected) = $display_share->get_selected_indices; + eval { modify_entry($selected) }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to Modify Samba share.") . "\n\n" . $err); + } + }), + 0, gtksignal_connect(Gtk2::Button->new(N("Remove")), clicked => sub { + my ($selected) = $display_share->get_selected_indices; + ask_okcancel("Remove entry ?", "Remove $display_share->{data}[$selected][1]") or return; + eval { remove_entry($selected, $display_share) }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to remove a Samba share.") . "\n\n" . $err); + } + }), + ), + ), + gtkshow(gtkpack_(Gtk2::HBox->new(0,0), + 0, Gtk2::Image->new_from_file($fileshare_icon), + 0, Gtk2::Label->new(N("File share")), + ), + ), + ); + +gtkappend_page($nb, gtkpack_(gtkset_border_width(Gtk2::HBox->new, 0), + 1, create_scrolled_window($printer_list), + 0, gtkpack_(create_vbox('start'), + 0, gtksignal_connect(Gtk2::Button->new(N("Add")), clicked => \&add_printers_entry), + 0, Gtk2::HSeparator->new, + 0, gtksignal_connect(Gtk2::Button->new(N("Modify")), clicked => sub { + my ($selected) = $printer_list->get_selected_indices; + eval { modify_printers_entry($selected) }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to Modify.") . "\n\n" . $err); + } + }), + 0, gtksignal_connect(Gtk2::Button->new(N("Remove")), clicked => sub { + my ($selected) = $printer_list->get_selected_indices; + ask_okcancel("Remove entry ?", "Remove $printer_list->{data}[$selected][1]") or return; + eval { remove_entry($selected, $printer_list) }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to remove.") . "\n\n" . $err); + } + }), + ), + ), + gtkshow(gtkpack_(Gtk2::HBox->new(0,0), + 0, Gtk2::Image->new_from_file($printershare_icon), + 0, Gtk2::Label->new(N("Printers")), + ), + ), + ); + +gtkappend_page($nb, gtkpack_(gtkset_border_width(Gtk2::HBox->new, 0), + 1, create_scrolled_window($user_list), + 0, gtkpack_(create_vbox('start'), + 0, gtksignal_connect(Gtk2::Button->new(N("Add")), clicked => sub { + eval { modify_user_info("", "", "add") }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to add user.") . "\n\n" . $err); + } + }), + 0, Gtk2::HSeparator->new, + 0, gtksignal_connect(Gtk2::Button->new(N("Modify")), clicked => sub { + my ($selected) = $user_list->get_selected_indices; + eval { modify_user_info($user_list->{data}[$selected][1], "", "change") }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to change user password.") . "\n\n" . $err); + } + }), + 0, gtksignal_connect(Gtk2::Button->new(N("Remove")), clicked => sub { + my ($selected) = $user_list->get_selected_indices; + ask_okcancel("Remove entry ?", "Remove $user_list->{data}[$selected][1]") or return; + eval { + remove_user($user_list->{data}[$selected][1]); + remove_entry($selected, $user_list); + }; + my $err = $@; + if ($err) { + err_dialog(N("Error"), N("Failed to delete user.") . "\n\n" . $err); + } + }), + 0, Gtk2::HSeparator->new, + # FIXME: Why do we have both an "add" button and a "userdrake" one ??? + 0, gtksignal_connect(Gtk2::Button->new(N("Userdrake")), clicked => sub { + run_program::raw({ detach => 1 }, 'userdrake'); + } + ), + ), + ), + gtkshow(gtkpack_(Gtk2::HBox->new(0,0), + 0, Gtk2::Image->new_from_file($sambauser_icon), + 0, Gtk2::Label->new(N("Samba Users"))), + ), + ); + +$nb->set_show_border(0); + +sub check_first_launch() { + if (!-f $draksambashare) { + info_dialog(N("Please configure your Samba server"), N("It seems this is the first time you run this tool.\nA wizard will appear to configure a basic Samba server")); +# local $::isEmbedded = 0; + launch_samba_wizard(); + } +} + +# main interface +$W->add(gtkpack_(Gtk2::VBox->new(0,0), + 0, $menu, + 0, Gtk2::Banner->new($sambaicon, N("DrakSamba manage Samba shares")), + #if_($::isEmbedded, 0, Gtk2::Label->new("Here you can add, remove and alter Samba shares.")), + 1, $nb, + 0, $okcancel, + ), + ); + +check_first_launch; +$W->show_all; +Gtk2->main; diff --git a/bin/drakvpn b/bin/drakvpn new file mode 100644 index 0000000..fbf10a6 --- /dev/null +++ b/bin/drakvpn @@ -0,0 +1,17 @@ +#!/usr/bin/perl + +# drakvpn: VPN configuration GUI +# Olivier Blin, 2006 <oblin@mandriva.com> +# Licensed under the GPL + +use strict; +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; +use interactive; +use network::drakvpn; + +my $in = 'interactive'->vnew('su'); +network::drakvpn::create_connection($in); diff --git a/bin/net_applet b/bin/net_applet new file mode 100755 index 0000000..5361c7a --- /dev/null +++ b/bin/net_applet @@ -0,0 +1,585 @@ +#!/usr/bin/perl + +use strict; + +use POSIX ":sys_wait_h"; +use lib qw(/usr/lib/libDrakX); +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use c; +use common; +use standalone; +use network::network; +use network::tools; +use network::connection; +use network::connection::ethernet; +use network::vpn; +use run_program; +use mygtk2 qw(gtknew gtkset); +use dbus_object; +use network::monitor; +use network::signal_strength; +use detect_devices; +use Gtk2::Notify -init, 'notify'; + +use ugtk2 qw(:create :helpers :wrappers :dialogs); + +my $onstartupfile = "$ENV{HOME}/.net_applet"; +my $system_file = '/etc/sysconfig/drakx-net'; +shouldStart() or die "$onstartupfile should be set to TRUE or use net_applet --force\n"; + +#- Allow multiple instances, but only one per user: +is_running('net_applet') and die "net_applet already running\n"; + +package network::net_applet; + +use mygtk2 qw(gtknew gtkset); +use common; + +our ($current_state, $current_interface); +our ($icon, $notification_queue); +our $dbus; +our ($interactive_cb, $ifw, $ifw_alert); + +our %wireless_networks; + +our %pixbufs = + ( + firewall => gtknew('Pixbuf', file => 'drakfirewall'), + firewall_icon => gtknew('Pixbuf', file => 'drakfirewall')->scale_simple(24, 24, 'hyper'), + state => { map { $_ => gtknew('Pixbuf', file => $_) } qw(connected disconnected unconfigured connecting) }, + link_level => { map { + $_ => gtknew('Pixbuf', file => 'wifi-' . sprintf('%03d', $_))->scale_simple(24, 24, 'hyper'); + } qw(20 40 60 80 100) }, + encryption => { map { + $_ => gtknew('Pixbuf', file => "encryption-$_-24"); + } qw(open weak strong) }, + ); + +sub get_current_network() { + detect_devices::is_wireless_interface($current_interface) && find { $_->{current} } values %wireless_networks; +} + +sub get_state_pixbuf() { + my $wnet = $current_state eq 'connected' && get_current_network(); + $wnet ? + network::signal_strength::get_strength_icon($wnet) : + $pixbufs{state}{$current_state}; +} + +sub update_tray_icon() { + if (!$ifw_alert || $icon->get_storage_type ne 'pixbuf') { + $icon->set_from_pixbuf(get_state_pixbuf()); + } else { + $icon->set_from_stock('gtk-dialog-warning'); + } +} + +1; + +package main; + +my ($current_description, $simple_menu, $menu, $wireless_device, $timeout, $update_timeout); +add_icon_path("/usr/share/libDrakX/pixmaps/"); + +my $net = {}; +my $watched_interface; + +my %global_settings = getVarsFromSh($system_file); + +sub get_state_message { + my ($o_interface) = @_; + my $interface = $o_interface || $current_interface; + my $network = network::net_applet::get_current_network(); + formatAlaTeX( + $current_state eq 'connected' ? + N("Network is up on interface %s.", get_interface_name($interface)) . + "\n\n" . N("IP address: %s", network::tools::get_interface_ip_address($net, $interface)) . + "\n\n" . N("Gateway: %s", [ network::tools::get_interface_status($interface) ]->[1]) . + "\n\n" . N("DNS: %s", $net->{resolv}{dnsServer}) . + ($network && "\n\n" . N("Connected to %s (link level: %d %%)", $network->{name}, $network->{signal_strength})) + : $current_state eq 'disconnected' ? + N("Network is down on interface %s.", get_interface_name($interface)) + : $current_state eq 'unconfigured' ? + N("You do not have any configured Internet connection. +Run the \"%s\" assistant from the Mandriva Linux Control Center", N("Set up a new network interface (LAN, ISDN, ADSL, ...)")) + : + N("Connecting...") + ); +} + +sub get_interface_type { + my ($interface) = @_; + my $ifcfg = $net->{ifcfg}{$interface}; + require network::connection; + $ifcfg && network::connection->find_ifcfg_type($ifcfg); +} + +sub get_interface_icon { + my ($interface) = @_; + my $type = get_interface_type($interface); + $type && $type->get_type_icon; +} + +sub get_interface_name { + my ($interface) = @_; + my $type = get_interface_type($interface); + my $type_name = $type && $type->get_type_description; + $type_name ? "$type_name ($interface)" : $interface; +} + +my %actions = ( + 'upNetwork' => { + name => sub { N("Connect %s", get_interface_name($_[0])) }, + launch => sub { network::tools::start_interface($_[0], 1) } + }, + 'downNetwork' => { + name => sub { N("Disconnect %s", get_interface_name($_[0])) }, + launch => sub { network::tools::stop_interface($_[0], 1) } + }, + 'monitorNetwork' => { + name => N("Monitor Network"), + launch => \&run_net_monitor + }, + 'monitorIFW' => { + name => N("Interactive Firewall"), + launch => \&run_drakids + }, + 'wireless' => { + name => N("Manage wireless networks"), + launch => sub { run_drakroam() } + }, + 'drakvpn' => { + name => N("Manage VPN connections"), + launch => sub { run_program::raw({ detach => 1 }, '/usr/sbin/drakvpn'); }, + }, + 'confNetwork' => { + name => N("Configure Network"), + launch => sub { system("/usr/sbin/drakconnect &") } + }, + 'chooseInterface' => { + name => N("Watched interface"), + choices => sub { N("Auto-detect"), sort keys %{$net->{ifcfg}} }, + choice_selected => sub { + $watched_interface ? $_[0] eq $watched_interface : + $_[0] eq N("Auto-detect") + }, + launch => sub { + $watched_interface = $_[0] eq N("Auto-detect") ? undef : $_[0]; + checkNetworkForce(); + } + }, + 'setInterface' => { + name => N("Active interfaces"), + use_checkbox => 1, + choices => sub { sort keys %{$net->{ifcfg}} }, + choice_selected => sub { + my ($is_up, $_gw) = network::tools::get_interface_status($_[0]); + $is_up; + }, + format_choice => \&get_interface_name, + get_icon => \&get_interface_icon, + launch => sub { + my ($is_up, $_gw) = network::tools::get_interface_status($_[0]); + if ($is_up) { + network::tools::stop_interface($_[0], 1); + } else { + network::tools::start_interface($_[0], 1); + } + checkNetworkForce(); + } + }, + 'chooseProfile' => { + name => N("Profiles"), + choices => sub { network::network::netprofile_list() }, + choice_selected => sub { $_[0] eq $net->{PROFILE} }, + launch => sub { + require run_program; + $net->{PROFILE} = $_[0]; + run_program::raw({ detach => 1 }, common::wrap_command_for_root('/sbin/set-netprofile', $net->{PROFILE})); + } + }, + 'chooseVPN' => { + name => N("VPN connection"), + header => "drakvpn", + choices => sub { + map { $_->get_configured_connections } network::vpn::list_types + }, + allow_single_choice => 1, + format_choice => \&network::vpn::get_label, + choice_selected => sub { $_[0]->is_started }, + launch => sub { + require interactive; $_[0]->is_started ? + $_[0]->stop : $_[0]->start(interactive->vnew) + }, + }, + 'help' => { + name => N("Help"), + launch => sub { system("drakhelp --id internet-connection &") } + }, + 'quit' => { + name => N("Quit"), + launch => \&mainQuit + }, +); + + +$icon = Gtk2::StatusIcon->new; + +eval { $dbus = dbus_object::system_bus() } if !defined($global_settings{NET_APPLET_DBUS}) || text2bool($global_settings{NET_APPLET_DBUS}); +eval { $net->{monitor} = network::monitor->new($dbus) } if $dbus; +if ($dbus) { + require network::net_applet::ifw; + network::net_applet::ifw::init(); +} +if ($dbus) { + $dbus->{connection}->add_filter(sub { + my ($_con, $msg) = @_; + if ($msg->get_interface eq 'com.mandriva.network' && $msg->get_member eq 'status') { + my ($status, $interface) = $msg->get_args_list; + print "got connection status event: $status $interface\n"; + if ($status eq "add") { + checkNetworkForce(); + } + } + }); + $dbus->{connection}->add_match("type='signal',interface='com.mandriva.network'"); + dbus_object::set_gtk2_watch_helper($dbus); +} + +$notification_queue = Gtk2::Notify::Queue->new($icon); + +$icon->signal_connect(activate => sub { + my ($_icon, $button, $time) = @_; + if ($ifw_alert) { + run_drakids(); + } elsif ($simple_menu) { + $simple_menu->popup(undef, undef, undef, undef, $button, $time); + } else { + run_netcenter(); + } + }); +$icon->signal_connect(popup_menu => sub { + my ($_icon, $button, $time) = @_; + $menu->popup(undef, undef, undef, undef, $button, $time) if $menu; + }); + +checkNetworkForce(); +cronNetwork(); +gtkflush(); #- for notifications to appear on the status icon position +network::net_applet::ifw::get_unprocessed_ifw_messages() if $ifw; + +$SIG{HUP} = sub { + print "received SIGHUP, reloading network configuration\n"; + checkNetworkForce(); +}; +$SIG{USR1} = sub { + # clear all ifw notifications + my @packets = eval { $network::net_applet::ifw->get_reports }; +}; + +# do not create zombies (#20552) +$SIG{CHLD} = \&harvester; +sub harvester { + my $pid; + do { + # we don't care about our child processes + $pid = waitpid(-1, &WNOHANG); + } while $pid > 0; +} + +Gtk2->main; + +ugtk2::exit(0); + +sub is_running { + my ($name, $o_user) = @_; + my $user = $o_user || $ENV{USER}; + any { + my ($ppid, $pid, $n) = /^\s*(\d+)\s+(\d+)\s+(.*)/; + $ppid != 1 && $pid != $$ && $n eq $name; + } `ps -o '%P %p %c' -u $user`; +} + +sub is_running_match { + # (eugeni) this matches part of a running command. + # Right now it is only used to detect if ifup script is running. + my ($name, $o_user) = @_; + my $user = $o_user || $ENV{USER}; + any { + my ($ppid, $pid, $n) = /^\s*(\d+)\s+(\d+)\s+(.*)/; + $ppid != 1 && $pid != $$ && $n =~ $name; + } `ps -o '%P %p %c' -u $user`; +} + +sub shouldStart() { + my ($opt) = @ARGV; + if ($opt eq '--force' || $opt eq '-f') { + return 1; + } + return getAutoStart(); +} +sub run_net_monitor() { + run_program::raw({ detach => 1 }, '/usr/bin/net_monitor', '--defaultintf', $current_interface) unless is_running('net_monitor'); +} +sub run_netcenter() { + run_program::raw({ detach => 1 }, '/usr/bin/draknetcenter') unless is_running('draknetcenter', 'root'); +} +sub run_drakroam { + my ($o_ap) = @_; + run_program::raw({ detach => 1 }, '/usr/sbin/drakroam', if_($o_ap, "--ap=$o_ap")) unless is_running('drakroam', 'root'); +} +sub run_drakids() { + $ifw_alert = 0; + if (is_running('drakids')) { + eval { $ifw->send_manage_request }; + } else { + run_program::raw({ detach => 1 }, '/usr/sbin/drakids'); + } +} +sub generate_wireless_menuitem { + my ($wnet) = @_; + my $menuitem = {}; + $menuitem->{widget} = Gtk2::CheckMenuItem->new; + $menuitem->{widget}->set_draw_as_radio(1); + $menuitem->{widget}->add(gtkpack_(gtkshow(gtknew('HBox')), + 1, gtkset_alignment($menuitem->{label} = gtknew('Label'), 0, 0.5), + 0, $menuitem->{strength} = Gtk2::Image->new, + 0, $menuitem->{security} = Gtk2::Image->new, + )); + $menuitem->{activate} = $menuitem->{widget}->signal_connect('activate' => sub { + if ($net->{monitor} && exists $wnet->{id}) { + eval { $net->{monitor}->select_network($wnet->{id}) }; + $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); + } else { + run_drakroam($wnet->{ap}); + } + checkNetworkForce(); + }); + update_wireless_item($menuitem, $wnet); + push @{$wnet->{menuitems}}, $menuitem; + return $menuitem->{widget}; +} +sub update_wireless_item { + my ($menuitem, $wnet) = @_; + $menuitem->{label}->set_text($wnet->{name}); + $menuitem->{security}->set_from_pixbuf($pixbufs{encryption}{$wnet->{flags} =~ /WPA/i ? 'strong' : $wnet->{flags} =~ /WEP/i ? 'weak' : 'open'}); + $menuitem->{strength}->set_from_pixbuf(network::signal_strength::get_strength_icon($wnet)); + + $menuitem->{widget}->signal_handler_block($menuitem->{activate}); + $menuitem->{widget}->set_active($wnet->{current}); + $menuitem->{widget}->signal_handler_unblock($menuitem->{activate}); +} +sub checkWireless() { + $wireless_device or return; + my ($networks) = network::monitor::list_wireless($net->{monitor}); + my $force_applet_update; + foreach (keys %$networks) { + exists $wireless_networks{$_} or $force_applet_update = 1; + put_in_hash($wireless_networks{$_} ||= {}, $networks->{$_}); + } + if ($force_applet_update) { + undef $current_state; + } else { + foreach my $wnet (values %wireless_networks) { + my $is_valuable = exists $networks->{$wnet->{ap}}; + foreach (@{$wnet->{menuitems}}) { + update_wireless_item($_, $wnet) if $is_valuable; + $_->{widget}->visible($is_valuable); + } + } + } +} +sub checkNetwork() { + my ($gw_intf, $_is_up, $gw_address) = $watched_interface ? + ($watched_interface, network::tools::get_interface_status($watched_interface)) : + network::tools::get_default_connection($net); + my $connecting = is_running_match('ifup', 'root'); + go2State($gw_address ? 'connected' : $connecting ? 'connecting' : $gw_intf ? 'disconnected' : 'unconfigured', $gw_intf); +} +sub checkNetworkForce() { + $net = {}; + network::network::read_net_conf($net); + undef $current_state; + $wireless_device = detect_devices::get_wireless_interface(); + checkWireless(); + checkNetwork(); +} +sub cronNetwork() { + my $i; + $timeout = Glib::Timeout->add(2000, sub { + checkWireless() if !($i++%30); + checkNetwork(); + 1; + }); +} +sub go2State { + my ($state_type, $interface) = @_; + my $need_update; + my ($old_interface, $old_description); + if ($current_interface ne $interface) { + my $card = find { $_->[0] eq $interface } network::connection::ethernet::get_eth_cards(); + if ($state_type eq 'disconnected') { + $old_interface = $current_interface; + $old_description = $current_description; + } + $current_description = $card && $card->[2]; + $current_interface = $interface; + $need_update = 1; + } + if ($current_state ne $state_type) { + my $show = defined $current_state && $state_type ne 'connecting'; # don't show notification at applet startup and when establishing a connection + $current_state = $state_type; + $notification_queue->add({ + title => $old_description || $current_description || N("Network connection"), + pixbuf => network::net_applet::get_state_pixbuf(), + message => get_state_message($old_interface || $current_interface), + }) if $show; + $need_update = 1; + } + + update_applet() if $need_update; +} + +sub update_applet() { + $wireless_device = detect_devices::get_wireless_interface(); + + # Re-checking wireless networks (#40912) + checkWireless(); + + generate_menu(); + + network::net_applet::update_tray_icon(); + $icon->set_tooltip(get_state_message()); +} + +sub create_menu_choices { + my ($action, $o_allow_single_choice) = @_; + my @choices = $actions{$action}{choices}->(); + #- don't add submenu if only zero or one choice exists + my $allow_single_choice = $actions{$action}{allow_single_choice} || $o_allow_single_choice; + @choices > ($allow_single_choice ? 0 : 1) or return (); + my $selected = $actions{$action}{choice_selected}; + my $format = $actions{$action}{format_choice}; + my $get_icon = $actions{$action}{get_icon}; + map { + my $choice = $_; + my $label = $format ? $format->($choice) : $choice; + my $w = gtkshow(gtkset_active(gtkadd( + Gtk2::CheckMenuItem->new, + gtknew('HBox', children => [ + 1, gtkset_alignment(gtknew('Label', text => $label), 0, 0.5), + $get_icon ? + (0, gtknew('Image', file => $get_icon->($_))) : + (), + ])), $selected->($choice))); + gtksignal_connect($w, activate => sub { $actions{$action}{launch}->($choice) }); + $w->set_draw_as_radio(!$actions{$action}{use_checkbox}); + $w; + } $actions{$action}{choices}->(); +} + +sub create_action_item { + my ($action) = @_; + my $name = ref($actions{$action}{name}) eq 'CODE' ? $actions{$action}{name}->($current_interface) : $actions{$action}{name}; + if (exists $actions{$action}{choices}) { + my @menu = create_menu_choices($action); + @menu || $actions{$action}{header} or return (); + gtkshow(create_menu($name, + $actions{$action}{header} ? ( + create_action_item($actions{$action}{header}), + gtkshow(Gtk2::SeparatorMenuItem->new), + ) : (), + @menu, + )); + } else { + gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label($name)), activate => sub { $actions{$action}{launch}->($current_interface) }); + } +} + +sub empty_menu { + my ($menu) = @_; + delete $_->{menuitems} foreach values %wireless_networks; + $menu->destroy if $menu; + Gtk2::Menu->new; +} + +sub get_wireless_networks_sorted() { + sort { + $b->{current} <=> $a->{current} || $b->{signal_strength} <=> $a->{signal_strength} || $a->{name} cmp $b->{name}; + } values %wireless_networks; +} + +sub generate_simple_menu() { + $simple_menu = empty_menu($simple_menu); + + if ($wireless_device) { + my @networks = get_wireless_networks_sorted(); + my @valuable_networks = splice @networks, 0, 7; + gtkappend($simple_menu, + (map { generate_wireless_menuitem($_) } @valuable_networks), + (@networks ? create_menu(N("More networks"), map { generate_wireless_menuitem($_) } @networks) : ()), + Gtk2::SeparatorMenuItem->new, + ); + } + gtkappend($simple_menu, create_menu_choices('setInterface', 'allow_single_choice')); +} + +sub generate_menu() { + $menu = empty_menu($menu); + + my (@settings); + my $interactive; + eval { $interactive = $ifw->get_interactive }; + + if ($current_state eq 'connected') { + $menu->append(create_action_item($_)) foreach qw(downNetwork monitorNetwork); + } elsif ($current_state eq 'disconnected') { + $menu->append(create_action_item('upNetwork')); + } + $menu->append(create_action_item('monitorIFW')) if $current_state ne 'unconfigured' && defined $interactive; + + $menu->append(create_action_item('confNetwork')); + + push @settings, create_action_item('chooseInterface') if $current_state ne 'unconfigured'; + + push @settings, create_action_item('chooseProfile'); + if (defined $interactive) { + $interactive_cb = gtkshow(gtksignal_connect(gtkset_active(Gtk2::CheckMenuItem->new_with_label(N("Interactive Firewall automatic mode")), + !$interactive), + toggled => sub { eval { $ifw->set_interactive(to_bool(!$_[0]->get_active)) } })); + push @settings, $interactive_cb; + } + push @settings, gtkshow(gtksignal_connect(gtkset_active(Gtk2::CheckMenuItem->new_with_label(N("Always launch on startup")), getAutoStart()), + toggled => sub { setAutoStart(uc(bool2text($_[0]->get_active))) })); + + $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new)); + if ($current_state ne 'unconfigured' && $wireless_device) { + $menu->append(gtkshow(create_menu(N("Wireless networks"), + create_action_item('wireless'), + gtkshow(Gtk2::SeparatorMenuItem->new), + map { generate_wireless_menuitem($_) } get_wireless_networks_sorted()))); + } + if (my $vpn = create_action_item('chooseVPN')) { $menu->append($vpn) } + if (my $set = $current_state ne 'unconfigured' && create_action_item('setInterface')) { $menu->append($set) } + $menu->append(gtkshow(create_menu(N("Settings"), @settings))); + $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new)); + $menu->append(create_action_item('help')); + $menu->append(create_action_item('quit')); + $menu; +} +sub mainQuit() { + Glib::Source->remove($timeout) if $timeout; + Glib::Source->remove($update_timeout) if $update_timeout; + Gtk2->main_quit; +} +sub getAutoStart() { + my %p = getVarsFromSh($onstartupfile); + return to_bool($p{AUTOSTART} ne 'FALSE'); +} +sub setAutoStart { + my $state = shift; + output_p $onstartupfile, + qq(AUTOSTART=$state +); +} diff --git a/bin/net_monitor b/bin/net_monitor new file mode 100755 index 0000000..861fb74 --- /dev/null +++ b/bin/net_monitor @@ -0,0 +1,642 @@ +#!/usr/bin/perl + +# NetMonitor + +# Copyright (C) 1999-2006 Mandriva +# Damien "Dam's" Krotkine +# Thierry Vignaud <tvignaud@mandriva.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +use lib qw(/usr/lib/libDrakX); + +use strict; +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } +use standalone; #- warning, standalone must be loaded very first, for 'explanations' + +use c; +use interactive; +use mygtk2 qw(gtknew gtkset); +use ugtk2 qw(:create :helpers :wrappers); +use common; +use network::network; +use network::tools; +use POSIX; + +$ugtk2::wm_icon = "/usr/share/mcc/themes/default/net_monitor-mdk.png"; + +if ("@ARGV" =~ /--status/) { print network::tools::connected(); exit(0) } +my $force = "@ARGV" =~ /--force/; +my $quiet = "@ARGV" =~ /--quiet/; +my $connect = "@ARGV" =~ /--connect/; +my $disconnect = "@ARGV" =~ /--disconnect/; +my ($default_intf) = "@ARGV" =~ /--defaultintf (\w+)/; + +my $net = {}; +network::network::read_net_conf($net); +$default_intf ||= $net->{net_interface}; + +if ($force) { + $connect and network::tools::start_interface($default_intf, 1); + $disconnect and network::tools::stop_interface($default_intf, 1); + $connect = $disconnect = 0; +} +$quiet and exit(0); + + +my $window1 = ugtk2->new(N("Network Monitoring")); +$window1->{window}->signal_connect(delete_event => \&main_quit); + +unless ($::isEmbedded) { + $window1->{window}->set_position('center'); + $window1->{window}->set_title(N("Network Monitoring")); + $window1->{window}->set_border_width(5); +} +#$::isEmbedded or $window1->{window}->set_size_request(580, 320); + +my $colorr = gtkcolor(50400, 655, 20000); +my $colort = gtkcolor(55400, 55400, 655); +my $colora = gtkcolor(655, 50400, 655); +my $isconnected = -1; +my @interfaces; +my $monitor = {}; +my $c_time = 0; +my $ct_tag; + +my ($pixmap, $darea, $gc_lines); +my ($width, $height) = (300, 150); + +my $left_border = 50; +my $grid_interval = 30; +my $arrow_space = 6; +my $arrow_size = 5; + +my $cfg_file = $< ? "$ENV{HOME}/.net_monitorrc" : "/etc/sysconfig/net_monitorrc"; +my %config = getVarsFromSh($cfg_file); +my $use_same_scale = text2bool($config{use_same_scale}); + +gtkadd($window1->{window}, + gtknew('VBox', spacing => 5, children => [ + 1, gtknew('HBox', spacing => 5, children => [ + 0, my $notebook = gtknew('Notebook'), + 1, gtknew('VBox', spacing => 5, children => [ + 0, gtknew('Frame', text => N("Settings"), shadow_type => 'etched_out', child => + gtknew('VBox', border_width => 5, children_tight => [ + gtknew('HBox', border_width => 5, children_tight => [ + N("Default connection: "), + my $label_cnx_type = gtknew('Label', text => "") ]), + my $button_connect = gtknew('Button', text => N("Wait please"), sensitive => 0, clicked => \&connection), + ]), + ), + 1, gtknew('Frame', text => N("Global statistics"), shadow_type => 'etched_out', child => + gtknew('VBox', border_width => 5, children_tight => [ + gtknew('Table', col_spacings => 1, row_spacings => 5, homogeneous => 1, children => [ + [ gtknew('Label', text => ""), gtknew('Label', text => N("Instantaneous")) , gtknew('Label', text => N("Average")) ], + [ gtknew('WrappedLabel', text => N("Sending\nspeed:")), my $label_st = gtknew('Label', text => ""), my $label_sta = gtknew('Label', text => N("unknown")) ], + [ gtknew('WrappedLabel', text => N("Receiving\nspeed:")), my $label_sr = gtknew('Label', text => ""), my $label_sra = gtknew('Label', text => N("unknown")) ], + ]), + gtknew('HSeparator'), + gtknew('HBox', border_width => 5, children_loose => [ + N("Connection time: "), + my $label_ct = gtknew('Label', text => N("unknown")), + ]), + ]) + ), + ]) + ]), + 0, gtksignal_connect(gtkset_active(gtknew('CheckButton', text => N("Use same scale for received and transmitted")), $use_same_scale), clicked => sub { $use_same_scale = !$use_same_scale }), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + my $button_close = gtknew('Button', text => N("Close"), clicked => \&main_quit), + ]), + 0, my $statusbar = Gtk2::Statusbar->new + ]), +); + +$window1->{window}->show_all; +$window1->{window}->realize; + +my $gct = Gtk2::Gdk::GC->new($window1->{window}->window); +$gct->set_foreground($colort); +my $gcr = Gtk2::Gdk::GC->new($window1->{window}->window); +$gcr->set_foreground($colorr); +my $gca = Gtk2::Gdk::GC->new($window1->{window}->window); +$gca->set_foreground($colora); + +$statusbar->push(1, N("Wait please, testing your connection...")); +$window1->{window}->show_all; + +# make sure widgets got realized before any event callback is called (#36537): +gtkflush(); + +my $time_tag1 = Glib::Timeout->add(1000, \&rescan); +my $time_tag2 = Glib::Timeout->add(1000, \&update); + +update(); +rescan(); + +gtkflush() while $isconnected == -2 || $isconnected == -1; + +Glib::Source->remove($time_tag2); +$time_tag2 = Glib::Timeout->add(5000, \&update); + +connection() if $connect && !$isconnected || $disconnect && $isconnected; + +my $tool_pid; + +$SIG{CHLD} = sub { + my $child_pid; + do { + $child_pid = waitpid(-1, POSIX::WNOHANG); + if ($tool_pid eq $child_pid) { + undef $tool_pid; + $button_close->set_sensitive(1); + } + } while $child_pid > 0; +}; + + +$window1->main; +main_quit(); + +my $during_connection; +my $first; + +sub main_quit() { + foreach my $timeout ($time_tag1, $time_tag2) { + Glib::Source->remove($timeout) if $timeout; + } + $config{use_same_scale} = bool2yesno($use_same_scale); + setVarsInSh($cfg_file, \%config); + ugtk2->exit(0); +} + +sub getcurrentintf { + my $currp = $notebook->get_current_page; + foreach (@interfaces) { + my $intf = $_; + return $intf if ($monitor->{$intf}{page} == $currp) + } +} + +sub intf_reset { + # resets counters for currently selected tab + my $intf = getcurrentintf; + if (defined $intf) { + $monitor->{$intf}{totalt} = 0; + $monitor->{$intf}{totalr} = 0; + } +} + +sub connection() { + $during_connection = 1; + my $wasconnected = $isconnected; + + $button_connect->set_sensitive(0); + $button_close->set_sensitive(0); + $statusbar->pop(1); + $statusbar->push(1, $wasconnected ? N("Disconnecting from Internet ") : N("Connecting to Internet ")); + if ($wasconnected == 0) { + $c_time = time(); + $ct_tag = Glib::Timeout->add(1000, sub { + my ($sec, $min, $hour) = gmtime(time() - $c_time); + my $e = sprintf("%02d:%02d:%02d", $hour, $min, $sec); + gtkset($label_ct, text => $e); 1 }); + } + my $nb_point = 1; + $first = 1; + + my $_tag = Glib::Timeout->add(1000, sub { + $statusbar->pop(1); + $statusbar->push(1, ($wasconnected == 1 ? N("Disconnecting from Internet ") : N("Connecting to Internet ")) + . join('', map { "." } (1..$nb_point))); + $nb_point++; + if ($nb_point < 4) { return 1 } + my $ret = 1; + + my $isconnect = test_connected(0); + + if ($nb_point < 20) { + if ($first == 1) { # first time + if ($isconnect == -2) { # wait for last test to finish + test_connected(2); # not yet terminated, try to cancel it + return 1; + } + test_connected(1); # initiates new connection test + $first = 0; + return 1; + } + if ($isconnect == -2) { return 1 } # no result yet, wait. + if ($isconnect == $wasconnected) { + # we got a test result; but the connection state did not change; retry. + test_connected(1); + return 1; + } + } + # either we got a result, or we timed out. + if ($isconnect != -2 || $nb_point > 20) { + $isconnected = $isconnect; + $ret = 0; + $statusbar->pop(1); + $statusbar->push(1, $wasconnected ? ($isconnected ? + N("Disconnection from Internet failed.") : + N("Disconnection from Internet complete.")) : + ($isconnected ? + N("Connection complete.") : + N("Connection failed.\nVerify your configuration in the Mandriva Linux Control Center.")) + ); + # remove the connection time timer if connection is down or failed + $isconnected or Glib::Source->remove($ct_tag); + my $delay = 1000; + # keep the message displayed longer if there is a problem. + if ($isconnected == $wasconnected) { $delay = 5000 } + my $_tag3 = Glib::Timeout->add($delay, sub { + + $button_connect->set_sensitive(1); + $button_close->set_sensitive(1); + undef $during_connection; + update(); + return 0; + }); + } + return $ret; + }); + + gtkflush(); + + print ("Action on " . getcurrentintf() . "\n"); + + $tool_pid = + $wasconnected == 1 + ? network::tools::stop_interface(getcurrentintf(), 1) + : network::tools::start_interface(getcurrentintf(), 1); +} + +sub graph_window_width() { $width - $left_border } + +sub rescan() { + get_val(); + foreach (@interfaces) { + my $intf = $_; + my $recv = $monitor->{$intf}{val}[0]; + my $transmit = $monitor->{$intf}{val}[8]; + my $refr = $monitor->{$intf}{referencer}; + my $reft = $monitor->{$intf}{referencet}; + my $diffr = $recv - $refr; + my $difft = $transmit - $reft; + + # prevent for case 32 bits or 64 bits unsigned value of /proc (if rotate to zero) + if ($diffr < 0) { + if ($refr < 2**32) { # transition (2^32 - 1) to 0 + $diffr += 2**32 + } else { $diffr += 2**64 } # transition (2^64 - 1) to 0 + # { $diffr = 0; $monitor->{$intf}{totalr} = 0 } # Alternatively, if bug for very big number in perl + }; + # prevent for case 32 bits or 64 bits unsigned value of /proc (if rotate to zero) + if ($difft < 0) { + if ($reft < 2**32) { # transition (2^32 - 1) to 0 + $difft += 2**32 + } else { $difft += 2**64 } # transition (2^64 - 1) to 0 + # { $difft = 0; $monitor->{$intf}{totalt} = 0 } # Alternatively, if bug for very big number in perl + }; + + $monitor->{$intf}{totalr} += $diffr; + $monitor->{$intf}{totalt} += $difft; + $monitor->{sr} += $diffr; + $monitor->{st} += $difft; + + $monitor->{$intf}{recva} += $diffr; + $monitor->{$intf}{recvan}++; + if ($monitor->{$intf}{recvan} > 9) { + push(@{$monitor->{$intf}{stack_ra}}, $monitor->{$intf}{recva}/10); + $monitor->{$intf}{recva} = $monitor->{$intf}{recvan} = 0; + } else { push(@{$monitor->{$intf}{stack_ra}}, -1) } + shift @{$monitor->{$intf}{stack_ra}} if @{$monitor->{$intf}{stack_ra}} > graph_window_width(); + + push(@{$monitor->{$intf}{stack_r}}, $diffr); + shift @{$monitor->{$intf}{stack_r}} if @{$monitor->{$intf}{stack_r}} > graph_window_width(); + $monitor->{$intf}{labelr}->set_label(formatXiB($monitor->{$intf}{totalr})); + $monitor->{$intf}{referencer} = $recv; + + $monitor->{$intf}{transmita} += $difft; + $monitor->{$intf}{transmitan}++; + if ($monitor->{$intf}{transmitan} > 9) { + push(@{$monitor->{$intf}{stack_ta}}, $monitor->{$intf}{transmita}/10); + $monitor->{$intf}{transmita} = $monitor->{$intf}{transmitan} = 0; + } else { push(@{$monitor->{$intf}{stack_ta}}, -1) } + shift @{$monitor->{$intf}{stack_ta}} if @{$monitor->{$intf}{stack_ta}} > graph_window_width(); + + push(@{$monitor->{$intf}{stack_t}}, $difft); + shift @{$monitor->{$intf}{stack_t}} if @{$monitor->{$intf}{stack_t}} > graph_window_width(); + $monitor->{$intf}{labelt}->set_label(formatXiB($monitor->{$intf}{totalt})); + $monitor->{$intf}{referencet} = $transmit; + + draw_monitor($monitor->{$intf}, $intf); + } + gtkset($label_sr, text => formatXiB($monitor->{sr}) . "/s"); + gtkset($label_st, text => formatXiB($monitor->{st}) . "/s"); + $monitor->{sra} += $monitor->{sr}; + $monitor->{sta} += $monitor->{st}; + $monitor->{nba}++; + if ($monitor->{nba} > 9) { + gtkset($label_sra, text => formatXiB($monitor->{sra}/10) . "/s"); + gtkset($label_sta, text => formatXiB($monitor->{sta}/10) . "/s"); + $monitor->{sra} = 0; + $monitor->{sta} = 0; + $monitor->{nba} = 0; + } + gtkset($label_cnx_type, text => N("%s (%s)", translate($net->{type}), $net->{net_interface})); + $monitor->{$_} = 0 foreach 'sr', 'st'; + 1; +} + +sub get_val() { + my $a = cat_("/proc/net/dev"); + $a =~ s/^.*?\n.*?\n//; + $a =~ s/^\s*lo:.*?\n//; + my @line = split(/\n/, $a); + require detect_devices; + my @net_devices = detect_devices::get_net_interfaces(); + map { + s/\s*(\w*)://; + my $intf = $1; + if (member($intf, @net_devices)) { + $monitor->{$intf}{val} = [ split() ]; + $monitor->{$intf}{intf} = $intf; + $intf; + } else { () } + } @line; +} + +sub change_color { + my ($color) = @_; + my $dialog = _create_dialog(N("Color configuration")); + $dialog->vbox->add(my $colorsel = Gtk2::ColorSelection->new); + $colorsel->set_current_color($color); + $dialog->add_button(N("Cancel"), 'cancel'); + $dialog->add_button(N("Ok"), 'ok'); + $dialog->show_all; + if ($dialog->run eq 'ok') { + $color = $colorsel->get_current_color; + } + $dialog->destroy; + $color; +} + +my ($scale_r, $scale_t); +$scale_r = $scale_t = $height; + +sub scale_tranmistted($) { $_[0] * $scale_t } +sub scale_received($) { $_[0] * $scale_r } + +sub color_button { + my ($gc, $color) = @_; + gtknew('Button', relief => 'none', clicked => sub { + $color = change_color($color); + $gc->set_rgb_fg_color($color); + $_[0]->queue_draw; + }, + child => gtksignal_connect(gtkshow(gtksize(gtkset(Gtk2::DrawingArea->new, width => 10, height => 10), 10, 10)), + expose_event => sub { $_[0]->window->draw_rectangle($gc, 1, 0, 0, 10, 10) }) + ); +} + + +sub update() { + if (!$during_connection) { + my $isconnect = test_connected(0); + if ($isconnect != -2) { + $isconnected = $isconnect; # save current state + $isconnect = test_connected(1); # start new test + } + } + + my @intfs = get_val(); # get values from /proc file system + foreach (@intfs) { + my $intf = $_; + if (!member($intf,@interfaces)) { + $default_intf ||= $intf; + $monitor->{$intf}{initialr} = $monitor->{$intf}{val}[0]; + $monitor->{$intf}{initialt} = $monitor->{$intf}{val}[8]; + $monitor->{$intf}{totalr} = 0; + $monitor->{$intf}{totalt} = 0; + $darea->{$intf} = Gtk2::DrawingArea->new; + $darea->{$intf}->set_events(["pointer_motion_mask"]); + $notebook->append_page(gtkshow(my $page = gtknew('VBox', children => [ + 0, gtknew('HBox', border_width => 5, children_tight => [ + gtksize($darea->{$intf}, $width, $height) ]), + 0, gtknew('HBox', children => [ + 1, gtknew('VBox', children_tight => [ + gtknew('HBox', spacing => 5, border_width => 5, children_tight => [ + color_button($gct, $colort), + N("sent: "), $monitor->{$intf}{labelt} = gtknew('Label', text => "0") ]), + gtknew('HBox', spacing => 5, border_width => 5, children_tight => [ + color_button($gcr, $colorr), + N("received: "), $monitor->{$intf}{labelr} = gtknew('Label', text => "0") ]), + gtknew('HBox', spacing => 5, border_width => 5, children_tight => [ + color_button($gca, $colora), + N("average") ]), + gtknew('Button', text => N("Reset counters"), sensitive => 1, clicked => sub { intf_reset }) + ]), + 0, gtknew('VBox', border_width => 5, children_tight => [ + gtknew('Frame', text => N("Local measure"), shadow_type => 'etched_out', child => + gtknew('VBox', border_width => 5, children_tight => [ + gtknew('HBox', children_tight => [ + N("sent: "), + my $measure_t = gtknew('Label', text => "0") + ]), + gtknew('HBox', children_tight => [ + N("received: "), + my $measure_r = gtknew('Label', text => "0") + ]) + ]) + ) + ]) + ]) + ])), + gtknew('Label', text => $intf)); + $monitor->{$intf}{page} = $notebook->page_num($page); + $darea->{$intf}->realize; + $pixmap->{$intf} = Gtk2::Gdk::Pixmap->new($darea->{$intf}->window, $width, $height, $darea->{$intf}->window->get_depth); + $monitor->{$intf}{referencer} = $monitor->{$intf}{val}[0]; + $monitor->{$intf}{referencet} = $monitor->{$intf}{val}[8]; + $pixmap->{$intf}->draw_rectangle($darea->{$intf}->style->black_gc, 1, 0, 0, $width, $height); + $darea->{$intf}->signal_connect(motion_notify_event => sub { + my (undef, $e) = @_; + my $x = $e->x - 50; + my $received = $x >= 0 ? $monitor->{$intf}{stack_r}[$x] : 0; + my $transmitted = $x >= 0 ? $monitor->{$intf}{stack_t}[$x] : 0; + gtkset($measure_r, text => formatXiB($received)); + gtkset($measure_t, text => formatXiB($transmitted)); + }); + $darea->{$intf}->signal_connect(expose_event => sub { + return if !$darea->{$intf}->window; + $darea->{$intf}->window->draw_drawable($darea->{$intf}->style->bg_gc('normal'), $pixmap->{$intf}, 0, 0, 0, 0, $width, $height); + }); + $gc_lines->{$intf} = Gtk2::Gdk::GC->new($darea->{$intf}->window); + $gc_lines->{$intf}->set_foreground($darea->{$intf}->style->white); + $gc_lines->{$intf}->set_line_attributes(1, 'on-off-dash', 'not-last', 'round'); + + } + } + foreach (@interfaces) { + my $intf = $_; + $notebook->remove_page($monitor->{$intf}{page}) unless member($intf,@intfs); + } + if (@intfs && !@interfaces) { + #- select the default interface at start + for (my $num_p = 0; $num_p < $notebook->get_n_pages; $num_p++) { + if ($notebook->get_tab_label_text($notebook->get_nth_page($num_p)) eq $default_intf) { + $notebook->set_current_page($num_p); + last; + } + } + } + @interfaces = @intfs; + if ($isconnected != -2 && $isconnected != -1 && !$during_connection) { + if ($isconnected == 1 && !in_ifconfig($net->{net_interface})) { + $isconnected = 0; + $statusbar->pop(1); + $statusbar->push(1, N("Warning, another internet connection has been detected, maybe using your network")); + } else { + #- translators : $net->{type} is the type of network connection (modem, adsl...) + $statusbar->pop(1); + $statusbar->push(1, $isconnected == 1 ? N("Connected") : N("Not connected")); + } + $button_connect->set_sensitive(1); + $button_connect->set("label", $isconnected == 1 ? N("Disconnect %s", translate($net->{type})) : N("Connect %s", $net->{type})); + } + unless ($default_intf || @interfaces) { + $button_connect->set_sensitive(0); + $button_connect->set("label", N("No internet connection configured")); + } + 1; +} + +sub in_ifconfig { + my ($intf) = @_; + -x '/sbin/ifconfig' or return 1; + $intf eq '' and return 1; + `/sbin/ifconfig` =~ /$intf/; +} + +sub draw_monitor { + my ($o, $intf) = @_; + defined $darea->{$intf} or return; + my $gcl = $gc_lines->{$intf}; + my $pixmap = $pixmap->{$intf}; + my $gc = $darea->{$intf}->style->white_gc; + # fix race on ugtk2->exit that causes a crash (#33023) + return 0 if !$gc; + $pixmap->draw_rectangle($darea->{$intf}->style->black_gc, 1, 0, 0, $width, $height); + my $maxr = 0; + foreach (@{$o->{stack_r}}) { $maxr = $_ if $_ > $maxr } + my $maxt = 0; + foreach (@{$o->{stack_t}}) { $maxt = $_ if $_ > $maxt } + + my ($graph_maxr, $graph_maxt); + if ($use_same_scale) { + $graph_maxr = $graph_maxt = ($maxr + $maxt)/2; + } else { + $graph_maxr = $maxr; + $graph_maxt = $maxt; + } + $scale_r = ($height/2) / max($graph_maxr, 1); + $scale_t = ($height/2) / max($graph_maxt, 1); + + my $step = $left_border - 1; + foreach (@{$o->{stack_t}}) { + $pixmap->draw_rectangle($gct, 1, $step, 0, 1, scale_tranmistted($_)); + $step++; + } + $step = $left_border - 1; + my ($av1, $av2, $last_a); + foreach (@{$o->{stack_ta}}) { + if ($_ != -1) { + if (!defined $av1) { $av1 = $_ } else { defined $av2 or $av2 = $_ } + if ($av1 && $av2) { + $pixmap->draw_line($gca, $step-15, scale_tranmistted($av1), $step-5, scale_tranmistted($av2)); + $av1 = $av2; + undef $av2; + $last_a = $step - $left_border + 1; + } + } + $step++; + } + $step = $left_border - 1; + foreach (@{$o->{stack_r}}) { + $pixmap->draw_rectangle($gcr, 1, $step, $height-scale_received($_), 1, scale_received($_)); + $step++; + } + $step = $left_border - 1; + $av1 = $av2 = undef; + foreach (@{$o->{stack_ra}}) { + if ($_ != -1) { + if (!defined $av1) { $av1 = $_ } else { defined $av2 or $av2 = $_ } + if (defined $av1 && defined $av2) { + $pixmap->draw_line($gca, $step-15, $height-scale_received($av1), $step-5, $height-scale_received($av2)); + $av1 = $av2; + undef $av2; + } + } + $step++; + } + + my ($pix_maxr, $pix_maxt); + if ($last_a) { + $pix_maxr = $height - scale_received(@{$o->{stack_ra}}[$last_a]); + $pix_maxt = scale_tranmistted(@{$o->{stack_ta}}[$last_a]); + } else { + $pix_maxr = $height - scale_received(@{$o->{stack_r}}[@{$o->{stack_r}}-1]); + $pix_maxt = scale_tranmistted(@{$o->{stack_t}}[@{$o->{stack_t}}-1]); + } + + my $x_l = $arrow_size + 1; + my $y_l; + + #- "transmitted" arrow + $y_l = max($arrow_space, min($pix_maxt, $pix_maxr - 2*$arrow_size - $arrow_space)); + $pixmap->draw_line($gct, $x_l, 0, $x_l, $y_l); + $pixmap->draw_line($gct, $x_l-1, 0, $x_l-1, $y_l); + $pixmap->draw_line($gct, $x_l+1, 0, $x_l+1, $y_l); + $pixmap->draw_polygon($gct, 1, $x_l-$arrow_size, $y_l, $x_l+$arrow_size, $y_l, $x_l, $y_l+$arrow_size); + + #- "received" arrow + $y_l = min($height - $arrow_space, max($pix_maxr, $y_l + 2*$arrow_size + $arrow_space)); + $pixmap->draw_line($gcr, $x_l, $height, $x_l, $y_l); + $pixmap->draw_line($gcr, $x_l-1, $height, $x_l-1, $y_l); + $pixmap->draw_line($gcr, $x_l+1, $height, $x_l+1, $y_l); + $pixmap->draw_polygon($gcr, 1, $x_l-$arrow_size, $y_l, $x_l+$arrow_size, $y_l, $x_l, $y_l-$arrow_size); + + for (my $i = $grid_interval; $i <= $height - $grid_interval; $i += $grid_interval) { + $pixmap->draw_line($gcl, $left_border, $i, $width, $i); + my ($gc2, $text); + if ($i > max($grid_interval, $use_same_scale ? $pix_maxt : $height/2)) { + $text = formatXiB(($height-$i)/$scale_r); + $gc2 = $gcr; + } else { + $text = formatXiB($i/$scale_t); + $gc2 = $gct; + } + $pixmap->draw_layout($gc2, 45-string_width($darea->{$intf}, $text), $i-5, $darea->{$intf}->create_pango_layout($text)); + } + $darea->{$intf}->queue_draw; +} + + +sub test_connected { + my ($arg) = @_; + $::testing || network::tools::test_connected($arg); +} |