#!/usr/bin/perl # Drakwizard # Copyright (C) 2002,2003 Mandrakesoft # # Authors: Arnaud Desmons # Florent Villard # # 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. package MDK::Wizard::Samba; use interactive; use strict; use MDK::Common; use common; use services; use MDK::Wizard::Wizcommon; my $wiz = new MDK::Wizard::Wizcommon; my $old; my $o = { name => N("Samba wizard"), var => { wiz_box_list => '', wiz_hosts_allow => '', wiz_do_file_sharing => get_file_sharing(), wiz_all_printers => '', wiz_level => '', wiz_do_printer_sharing => 1, wiz_do_homes => get_home_sharing(), wiz_printers => '', wiz_workgroup => '', wiz_dir => '', wiz_banner => '', wiz_write_list => '', wiz_read_list => '', wiz_hosts_deny => '', list_printers => '' }, needed_rpm => [ 'samba-server' ], defaultimage => "$ENV{__WIZ_HOME__}samba_wizard/images/samba.png", init => sub { my $file = "/etc/samba/smb.conf"; if (-f $file) { $old = read_conf($file); } else { return 0, N("%s does not exist.", $file) } } }; my %level = ( 1 => N("All - no access restriction"), 2 => N("My rules - ask me allowed and denied hosts") ); $o->{pages} = { welcome => { name => N("Samba configuration wizard") . "\n\n" . N("Samba allows your server to behave as a file and print server for workstations running non-Linux systems.") . "\n\n" . N("This wizard will help you configuring the Samba services of your server."), no_back => 1, 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} ||= get_workgroup() }, data => [ { label => N("Workgroup:"), val => \$o->{var}{wiz_workgroup} }, ], post => \&check_workgroup, next => 'ask_banner' }, error_in_workgroup => { name => N("Error.") . "\n\n" . N("The Workgroup is wrong"), post => \&check_workgroup, next => 'ask_workgroup' }, 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} ||= get_banner() }, post => \&check_banner, data => [ { label => N("Banner:"), val => \$o->{var}{wiz_banner} }, ], next => 'ask_net' }, error_in_banner => { name => N("Error.") . "\n\n" . N("The server banner is incorrect"), ignore => 1, next => 'ask_banner' }, ask_net => { name => N("Access control") . "\n\n" . "\n\n", pre => sub { $o->{var}{wiz_level} ||= defined $old->{conf}{global}{'hosts allow'} ? 2 : 1 }, post => sub { return 'ask_netmask' if $o->{var}{wiz_level} == 2 }, data => [ { label => N("Access level:"), val => \$o->{var}{wiz_level}, list => [ keys %level ], format => sub { $level{$_[0]} } }, ], next => 'ask_services' }, ask_netmask => { name => N("Access control") . "\n\n" . N("* Example 1: allow all IP in 150.203.*.*; except one\nhosts allow = 150.203. EXCEPT 150.203.6.66") . "\n\n" . N("* Example 2: allow hosts that match the given network/netmask\nhosts allow = 150.203.15.0/255.255.255.0") . "\n\n" . N("* Example 3: allow a couple of hosts\nhosts allow = lapland, arvidsjaur") . "\n\n" . N("* Example 4: allow only hosts in NIS netgroup \"foonet\", but deny access from one particular host\nhosts allow = \@foonet\nhosts deny = pirate") . "\n\n" . N("Note that access still requires suitable user-level passwords."), # pre => sub { # $o->{var}{wiz_hosts_allow} ||= get_allow_host(); # $o->{var}{wiz_hosts_deny} ||= get_deny_host() # }, post => \&check, data => [ { label => N("Allow hosts:"), val => \$o->{var}{wiz_hosts_allow} }, { label => N("Deny hosts:"), val => \$o->{var}{wiz_hosts_deny} }, ], next => 'ask_services' }, ask_services => { name => N("Enabled Samba services") . "\n\n" . N("Samba can provide a common file sharing area to your Windows workstation, and can also provide printer sharing for the printers connected to your server."), pre => sub { $o->{var}{wiz_do_file_sharing} ||= get_file_sharing(); $o->{var}{wiz_do_printer_sharing} ||= 1; $o->{var}{wiz_do_homes} ||= get_home_sharing() }, post => \&check_services, data => [ { text => N("Enable file sharing area"), type => 'bool', val => \$o->{var}{wiz_do_file_sharing} }, { text => N("Enable server Printer Sharing"), type => 'bool', val => \$o->{var}{wiz_do_printer_sharing} }, { text => N("Make home directories available for their owners"), type => 'bool', val => \$o->{var}{wiz_do_homes} }, ], next => 'ask_dir' }, warn_smbpasswd => { name => N("Warning.") . "\n\n" . N("You have selected to allow user access their home directories via samba but you/they must use smbpasswd to set a password."), post => \&ask_dir, ignore => 1, next => 'summary' }, ask_dir => { name => N("Shared directory:") . "\n\n" . N("Type the path of the directory you want being shared."), pre => sub { $o->{var}{wiz_dir} ||= get_dir() }, post => \&check_dir, data => [ { label => N("Shared directory:"), val => \$o->{var}{wiz_dir} }, { text => N("Create shared directory if it doesn't exists"), type => 'bool', val => \$o->{var}{create_missing_directory} }, ], next => 'ask_access' }, error_in_create_missing_dir => { name => N("Error.") . "\n\n" . N("Failed to create directory."), ignore => 1, next => 'ask_dir' }, error_in_dir => { name => N("Error.") . "\n\n" . N("The path you entered does not exist."), ignore => 1, next => 'ask_dir' }, ask_access => { name => N("File permissions") . "\n\n" . N("Type users or group separated by a comma (groups must be preceded by a '\@') like this:\nroot, fred, \@users, \@wheel for each kind of permission.") . "\n\n", pre => sub { $o->{var}{wiz_read_list} ||= get_read(); $o->{var}{wiz_write_list} ||= get_write() }, post => \&check_printers, data => [ { label => N("Read list:"), help => N("root, fred, \@users, \@wheel"), val => \$o->{var}{wiz_read_list} }, { label => N("Write list:"), help => N("root, fred, \@users, \@wheel"), val => \$o->{var}{wiz_write_list} }, ], # complete => sub { # if ($o->{var}{wiz_do_printer_sharing} == "1") { # return 'ask_printers' # } else { return 'summary' } # }, next => 'summary', }, ask_printers => { name => N("Select which printers you want to be accessible from known users"), pre => sub { $o->{var}{list_printers} ||= [ list_printers() ]; $o->{var}{wiz_box_list} ||= get_previous_printers($o->{var}{list_printers}) }, post => \&check, data => [ { text => N("Enable all printers"), type => 'bool', val => \$o->{var}{wiz_all_printers} }, { val => \$o->{var}{wiz_box_list}, boolean_list => \$o->{var}{list_printers}, disabled => sub { $o->{var}{wiz_all_printers} and return 1; 0 } }, ], next => 'summary' }, warning => { name => N("Warning."), data => [ { label => '' } ], ignore => 1, next => 'summary' }, error => { name => N("Error."), data => [ { label => '' } ], ignore => 1, next => 'config' }, summary => { name => N("Configuring Samba") . "\n\n" . 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."), pre => sub { $o->{var}{printers} = get_printers(); $o->{var}{file_sharing} = $o->{var}{wiz_do_file_sharing} ? N("enabled") : N("disabled"); $o->{var}{printer_sharing} = $o->{var}{wiz_do_printer_sharing} ? N("enabled") : N("disabled"); $o->{var}{shared_homes} = $o->{var}{wiz_do_homes} ? N("enabled") : N("disabled") }, data => [ { label => N("Workgroup:"), fixed_val => \$o->{var}{wiz_workgroup} }, { label => N("Server banner:"), fixed_val => \$o->{var}{wiz_banner} }, { label => N("File sharing:"), fixed_val => \$o->{var}{file_sharing} }, { label => N("Shared directory:"), fixed_val => \$o->{var}{wiz_dir} }, { label => N("Print server:"), fixed_val => \$o->{var}{printer_sharing} }, { label => N("Home:"), fixed_val => \$o->{var}{shared_homes} }, { label => N("Printers:"), fixed_val => \$o->{var}{printers} }, ], post => \&do_it, next => 'end' }, end => { name => N("Congratulations") . "\n\n" . N("The wizard successfully configured your Samba server."), end => 1, next => 0 }, error_end => { name => N("Failed"), data => [ { label => N("Relaunch drakwizard, and try to change some parameters.") } ], no_back => 1, end => 1, next => 0, }, }; sub new { my ($class) = @_; bless { o => $o, }, $class; } sub check { $> and return 1; $wiz->{net}->is_dhcp and return 2; 0; } sub check_services { $o->{var}{wiz_do_homes} and return 'warn_smbpasswd'; $o->{var}{wiz_do_file_sharing} and return 'ask_dir'; $o->{var}{wiz_do_printer_sharing} and return 'ask_printers'; } sub wiz_mkdir_p { my ($dir) = @_; if (-d $dir) { # Do nothing, directory exists } elsif (-e $dir) { # Directory is file, we are not going to delete it return 0; } else { # Create parent directory wiz_mkdir_p(dirname($dir)) or return 0; # Create our directory mkdir($dir, 0755) or return 0; chown "nobody", "users", $dir; } 1; } sub check_dir { if (! -d $o->{var}{wiz_dir}) { if ($o->{var}{create_missing_directory}) { wiz_mkdir_p($o->{var}{wiz_dir}) or return 'error_in_create_missing_dir'; } else { return 'error_in_dir'; } } return 0; } # the "__" before comment is to avoid conflicts with possible "comment" variable # for variables value is in value key and comment idem (no risk of conflict) sub read_conf { my $self = {}; my ($file) = @_; my ($menu, @tab, %conf); local *FH; open(FH, $file) or die "$! ($file)"; local $_; while () { if (/^(\s*;?\s*)\[(.*)\]/) { $menu = $2; $conf{$menu}{__comment} = $1; print "$menu COMMENT $1\n"; } elsif (/^(?!#)(\s*;*\s*)(.*?)\s*=\s*(.*)\s*$/) { $conf{$menu}{$2}{value} = $3; $conf{$menu}{$2}{comment} = $1; print "$menu $2 VALUE $3 COMMENT $1\n"; } push @tab, $_; } $self->{conf} = \%conf; $self->{tab} = \@tab; bless $self; } # we parse @tab to check for values in the struct. sub write_conf { my ($self, $file) = @_; my $menu; local *FH; open(FH, "> $file") or die "$!"; foreach (@{$self->{tab}}) { if (/^\s*;?\s*\[(.*)\]/) { $menu = $1; print FH "$self->{conf}->{$menu}{__comment}\[$menu\]\n"; } elsif (/^(?!#)\s*;*\s*(.*?)\s*=/) { print FH "$self->{conf}->{$menu}{$1}{comment}$1 = $self->{conf}->{$menu}{$1}{value}\n"; } else { print FH $_; } } } #section has the name of the printer sub add_printer { my ($self, $printer) = @_; my @sprintername = split(/\|/, $printer); if (exists $self->{conf}{$printer}) { $self->comment_menu($printer, " "); } else { $self->{conf}{$printer}{printable}{comment} = " "; push @{$self->{tab}}, "[$printer]\n"; push @{$self->{tab}}, " printer = $sprintername[0]\n"; push @{$self->{tab}}, " comment = $sprintername[1]\n"; push @{$self->{tab}}, " printable = yes\n"; push @{$self->{tab}}, " browseable = no\n"; push @{$self->{tab}}, " createmode = 0700\n"; push @{$self->{tab}}, " writable =yes\n"; push @{$self->{tab}}, " guestok = yes\n"; $self->{conf}{$printer}{printer}{value} = $sprintername[0]; $self->{conf}{$printer}{comment}{value} = $sprintername[1]; $self->{conf}{$printer}{printable}{value} = "yes"; $self->{conf}{$printer}{writable}{value} = "yes"; $self->{conf}{$printer}{browseable}{value} = "no"; $self->{conf}{$printer}{createmode}{value} = "0700"; $self->{conf}{$printer}{guestok}{value} = "yes"; } } sub list_printers { my @list if 0; return @list if @list; sort grep { /^(?!#)./ } map { /([^:]*):/ and $1 } cat_("/etc/printcap"); } sub check_printers { return 'ask_printers' if $o->{var}{wiz_do_printer_sharing} } sub comment_menu { my ($self, $menu, $str) = @_; return if !$menu || !exists $self->{conf}{$menu}; $self->{conf}{$menu}{__comment} = $str; foreach (keys %{$self->{conf}{$menu}}) { $_ eq "__comment" and next; $self->{conf}{$menu}{$_}{comment} = $str; } } sub comment_var { my ($self, $menu, $var, $str) = @_; $self->{conf}{$menu}{$var}{comment} = $str; } sub chg_var { my ($self, $menu, $var, $str) = @_; $self->{conf}{$menu}{$var}{value} = $str; } # all or selected printers sub printer_sharing { my $self = shift; if ($o->{var}{wiz_all_printers}) { $self->comment_menu('printers', " "); } else { $self->comment_menu("printers", ";"); for (my $i = 0; $i < @{$o->{var}{wiz_box_list}}; $i++) { my $printer = $o->{var}{list_printers}[$i]; if ($o->{var}{wiz_box_list}[$i]) { $self->add_printer($printer); } else { $self->comment_menu($printer, ";"); } } } } sub get_previous_printers { my ($list_printers) = @_; my $previous = []; foreach my $p (grep { defined $old->{conf}{$_}{printer} } keys %{$old->{conf}}) { my $test = any { /\Q$p/ } @$list_printers; push @$previous, $test } $previous } sub get_printers { if ($o->{var}{wiz_do_printer_sharing}) { my $string; $o->{var}{wiz_all_printers} and return "all printers"; for (my $i = 0; $i < @{$o->{var}{wiz_box_list}}; $i++) { $string .= "$o->{var}{list_printers}[$i]\n" if $o->{var}{wiz_box_list}[$i] } $string; } else { "disabled"; } } sub check_workgroup { $o->{var}{wiz_workgroup} or return 'error_in_workgroup' } sub ask_acces { 10; } sub get_write { $old->{conf}{public}{"write list"}{value}; } sub get_read { $old->{conf}{public}{"read list"}{value}; } sub check_banner { $o->{var}{wiz_banner} or return 'error_in_banner' } sub get_workgroup { $old->{conf}{global}{workgroup}{value} } sub get_banner { $old->{conf}{global}{"server string"}{value}; } sub ask_dir { return 'ask_dir' if $o->{var}{wiz_do_file_sharing}; return 'ask_printers' if $o->{var}{wiz_do_printer_sharing}; } sub get_dir { $old->{conf}{public}{path}{value}; } sub get_file_sharing { return 0 if $old->{conf}{public}{__comment} =~ /;|#/; 1; } sub get_home_sharing { return 0 if $old->{conf}{homes}{__comment} =~ /;|#/; 1; } sub get_netmask { "192.168.100.1/255.255.255.0"; } sub get_allow_host { $old->{conf}{global}{"hosts allow"}{value}; } sub get_deny_host { $old->{conf}{global}{"hosts deny"}{value}; } # remember one variable cannot be commented and not in the same file. sub do_it { $::testing and return; my $in = 'interactive'->vnew('su', 'Samba'); my $w = $in->wait_message(N("Samba server"), N("Configuring your Samba server...")); my $file = "/usr/share/wizards//samba_wizard/scripts/smb.conf.default"; my $conf = read_conf($file); $conf->chg_var("global", "workgroup", $o->{var}{wiz_workgroup}); $conf->chg_var("global", "server string", $o->{var}{wiz_banner}); $conf->chg_var("public", "write list", $o->{var}{wiz_write_list}) if $o->{var}{wiz_do_file_sharing}; $conf->chg_var("public", "read list", $o->{var}{wiz_read_list}) if $o->{var}{wiz_do_file_sharing}; #my $ip = $wiz->{net}->itf_get("IPADDR"); if ($o->{var}{wiz_do_file_sharing}) { standalone->explanations("Enabling $o->{var}{wiz_dir} samba file sharing"); $conf->comment_menu("public", " "); $conf->chg_var("public", "path", $o->{var}{wiz_dir}); } else { standalone->explanations("Disabling samba file sharing"); $conf->comment_menu("public", ";"); } if ($o->{var}{wiz_do_homes}) { standalone->explanations("Enabling samba homes sharing"); $conf->comment_menu("homes", " "); } else { standalone->explanations("Disabling samba homes sharing"); $conf->comment_menu("homes", ";"); } standalone->explanations("Samba deny $o->{var}{wiz_hosts_deny}"); standalone->explanations("Samba allow $o->{var}{wiz_hosts_allow}"); $conf->chg_var("global", "hosts deny", $o->{var}{wiz_hosts_deny}); $conf->chg_var("global", "hosts allow", $o->{var}{wiz_hosts_allow}); if ($o->{var}{wiz_do_printer_sharing}) { standalone->explanations("Enabling printer sharing"); $conf->comment_menu("global", " "); $conf->chg_var("global", "printcap name", "cups"); $conf->chg_var("global", "printer admin", "\@adm"); $conf->printer_sharing; } else { standalone->explanations("Disabling printer sharing"); for (my $i = 0; $i < @{$o->{var}{wiz_box_list}}; $i++) { $conf->comment_menu($o->{var}{list_printers}[$i], ";"); } $conf->comment_menu("printers", ";"); } my $smbconf = "/etc/samba/smb.conf"; $conf->write_conf($smbconf); # horrible fix for createmode and guestok substInFile { s/createmode/create mode/; s/guestok/guest ok/; } "/etc/samba/smb.conf"; if (services::is_service_running('smb')) { services::restart('smb') } else { services::start('smb') } undef $w; check_started('smbd'); } 1;