diff options
Diffstat (limited to 'perl-install/standalone/drakperm')
| -rwxr-xr-x | perl-install/standalone/drakperm | 760 |
1 files changed, 403 insertions, 357 deletions
diff --git a/perl-install/standalone/drakperm b/perl-install/standalone/drakperm index 09c83ffd9..fa69be838 100755 --- a/perl-install/standalone/drakperm +++ b/perl-install/standalone/drakperm @@ -1,396 +1,442 @@ #!/usr/bin/perl use strict; +use diagnostics; use lib qw(/usr/lib/libDrakX); use standalone; +use MDK::Common; use common; -use my_gtk qw(:wrappers :helpers); -use interactive; +use mygtk3 qw(gtknew gtkset); +use ugtk3 qw(:create :dialogs :helpers :wrappers); -my $in = 'interactive'->vnew('su', 'default'); -local $_ = join '', @ARGV; +$ugtk3::wm_icon = "/usr/share/mcc/themes/default/drakperm-mdk.png"; +require_root_capability(); #- vars declaration -my ($default_perm_level) = "level ".chomp_(`cat /etc/sysconfig/msec | grep SECURE_LEVEL= |cut -d= -f2`); -my %CURENT; -my $perm_path = '/usr/share/msec/'; -my $local_path = '/etc/security/msec/'; -my %perm = ( 'level 1' => $perm_path.'perm.1', - 'level 2' => $perm_path.'perm.2', - 'level 3' => $perm_path.'perm.3', - 'level 4' => $perm_path.'perm.4', - 'level 5' => $perm_path.'perm.5', - 'editable' => $local_path.'perm.local', - ); -my $rows_cnt = 0; -my $editable = 0; -my $modified = 0; -my $prec_txt = $default_perm_level; -#my $bg = Gtk::Gdk::Color->parse_color('grey'); +my ($level) = chomp_(`cat /etc/sysconfig/msec | grep SECURE_LEVEL= |cut -d= -f2`); +my $default_perm_level = "level " . $level; +my %perm_files = ($default_perm_level => '/usr/share/msec/perm.' . $level, + 'editable' => '/etc/security/msec/perm.local', + ); + +my %perm_l10n = ($default_perm_level => N("System settings"), + 'editable' => N("Custom settings"), + 'all' => N("Custom & system settings"), + ); +my %rev_perm_l10n = reverse %perm_l10n; +my ($editable, $modified) = (0, 0); + +my @rules; + #- Widget declaration -my $w = my_gtk->new('drakperm'); +my $w = ugtk3->new(N("Security Permissions")); +$w->{rwindow}->set_size_request(620, 400) unless $::isEmbedded; my $W = $w->{window}; -$W->signal_connect(delete_event => sub { my_gtk->exit }); -my $scroll = new Gtk::ScrolledWindow; -my $Perm_list = new_with_titles Gtk::CList(N("path"), N("user"), N("group"), N("permissions")); -my $vb = new Gtk::VBox(0,5); -my $select_box = new Gtk::HBox(0,5); -my $action_box = new Gtk::HBox(0,5); -my $up_down_box = new Gtk::HBox(0,5); -my $B_quit = new Gtk::Button('quit'); -my $B_sav = new Gtk::Button('save'); -my $B_up = new Gtk::Button(N("Up")); -my $B_del = new Gtk::Button(N("delete")); -my $B_edit = new Gtk::Button(N("edit")); -my $B_down = new Gtk::Button(N("Down")); -my $B_add = new Gtk::Button(N("add a rule")); -my $label_perm = new Gtk::Label(N("select perm file to see/edit")); -my $combo_perm = new Gtk::Combo; -my $tips = new Gtk::Tooltips; -my $pres = new Gtk::Label(N("Drakperm is used to see files to use in order to fix permissions, owners, and groups via msec.\nYou can also edit your own rules which will owerwrite the default rules.")); -my $F = new Gtk::Frame; +$W->signal_connect(delete_event => sub { ugtk3->exit }); +my $model = Gtk3::ListStore->new("Gtk3::Gdk::Pixbuf", ("Glib::String") x 5); +my $permList = Gtk3::TreeView->new_with_model($model); + +my $pixbuf = gtknew('Pixbuf', file => 'non-editable'); + +my @column_sizes = (150, 100, 100, 15, -1); + +# TreeView layout is (Editable, Path, User, Group, Permissions, [hidden]index_id) +$permList->append_column(Gtk3::TreeViewColumn->new_with_attributes(N("Editable"), Gtk3::CellRendererPixbuf->new, 'pixbuf' => 0)); +each_index { + my $col = Gtk3::TreeViewColumn->new_with_attributes($_, Gtk3::CellRendererText->new, 'text' => $::i + 1); + $col->set_min_width($column_sizes[$::i+1]); + $permList->append_column($col); +} (N("Path"), N("User"), N("Group"), N("Permissions")); + +my $index = 0; +load_perms(); + #- widgets settings -$combo_perm->set_popdown_strings(sort(keys %perm)); - -$tips->set_tip($B_add, N("Add a new rule at the end")); -$tips->set_tip($B_edit, N("Edit curent rule")); -$tips->set_tip($B_up, N("Up selected rule one level")); -$tips->set_tip($B_down, N("Down selected rule one level")); -$tips->set_tip($B_del, N("Delete selected rule")); - -#- signal management -$W->signal_connect(delete_event => sub { my_gtk->exit }); -$Perm_list->signal_connect( select_row => \&row_setting_data); -#$Perm_list->signal_connect( unselect_row => sub { undef(%CURENT)}); -$B_sav->signal_connect( clicked => \&save_perm); -$B_quit->signal_connect( clicked => sub { my_gtk->exit }); -$B_edit->signal_connect( clicked => \&row_setting_dialog); -$B_add->signal_connect( clicked => sub { - $Perm_list->insert( $rows_cnt , ''); - $Perm_list->select_row($rows_cnt , 0); - &row_setting_dialog; - $rows_cnt++; - }); -$B_del->signal_connect( clicked => sub { - $Perm_list->remove(${$CURENT{clicked}}{row}); - $rows_cnt--; - $modified++; - }); -$B_down->signal_connect( clicked => sub { - my $row = ${$CURENT{clicked}}{row}; - $Perm_list->row_move($row, $row+1); - $Perm_list->unselect_all; - $Perm_list->select_row($row+1,0); - $CURENT{clicked}{row} = $row+1; - }); -$B_up->signal_connect( clicked => sub { - my $row = ${$CURENT{clicked}}{row}; - $Perm_list->row_move($row, $row-1); - $Perm_list->unselect_all; - $Perm_list->select_row($row-1,0); - $CURENT{clicked}{row} = $row-1; - }); -my $combo_sig = $combo_perm->entry->signal_connect( changed => sub { &display_perm($combo_perm->entry->get_text , @_) }); -$Perm_list->signal_connect( button_press_event => sub { - $editable or return 0; - my ($clist, $event) = @_; - if ($event->{type} eq '2button_press') { - &row_setting_dialog; - } - }); - -#Viewing management -$select_box->add($label_perm); -$select_box->add($combo_perm); - -$scroll->add($Perm_list); -$scroll->set_policy('automatic', 'automatic'); - - -$Perm_list->set_shadow_type('out'); -$Perm_list->set_column_width(0, 150); -$Perm_list->set_column_width(1, 100); -$Perm_list->set_column_width(2, 100); -$Perm_list->set_column_width(3, 15); - -$up_down_box->add($B_up); -$up_down_box->add($B_down); -$up_down_box->add($B_add); -$up_down_box->add($B_del); -$up_down_box->add($B_edit); - -$action_box->add($B_sav); -$action_box->add($B_quit); - -$vb->pack_start($select_box,0,0,5); -$vb->pack_start($scroll,1,1,5); -$vb->pack_start($up_down_box,0,0,5); -$vb->pack_start($action_box,0,0,5); - -my $vb_ = new Gtk::VBox(0,5); -$F->add($vb); -$vb_->pack_start($pres,0,0,5); -$vb_->pack_start($F,1,1,5); - -$W->add($vb_); +my $combo_perm_value = $perm_l10n{all}; +my $combo_perm = gtknew('ComboBox', list => [ sort(values %perm_l10n) ], text_ref => \$combo_perm_value); + +sub add_callback() { + row_setting_dialog(N("Add a new rule")); + $modified++; +} + +sub edit_callback() { + my (undef, $iter) = $permList->get_selection->get_selected; + return unless $iter; + row_setting_dialog(N("Edit current rule"), $iter); +} + +my @buttons; + +sub del_callback() { + my ($tree, $iter) = $permList->get_selection->get_selected; + my $removed_idx = $tree->get($iter, 5); + @rules = grep { $_->{index} ne $removed_idx } @rules; + $tree->remove($iter); + sensitive_buttons(0); + $modified++; +} + +sub move_callback { + my ($direction) = @_; + my ($model, $iter) = $permList->get_selection->get_selected; + return if !$iter; + my $path = $model->get_path($iter) or return; + $direction eq 'up' ? $path->prev : $path->next; + my $iter2 = $model->get_iter($path); + return if !$iter2 || $model->get($iter2, 0); + $model->swap($iter, $iter2); + $modified = 1; + hide_up_button_iffirst_item($path); + hide_down_button_iflast_item($path); + $permList->get_selection->select_iter($iter); + $permList->queue_draw; +} + +$permList->signal_connect(button_press_event => sub { + return unless $editable; + my (undef, $event) = @_; + my (undef, $iter) = $permList->get_selection->get_selected; + return unless $iter; + row_setting_dialog(N("Edit current rule"), $iter) if $event->type eq '2button-press'; + }); + + +$W->add(gtknew('VBox', spacing => 5, children => [ + if_(!$::isEmbedded, 0, Gtk3::Banner->new('/usr/share/mcc/themes/default/drakperm-mdk.png', N("Permissions"))), + 0, gtknew('Label_Left', text => N("Here you can see files to use in order to fix permissions, owners, and groups via msec.\nYou can also edit your own rules which will overwrite the default rules."), alignment => [ 0.5, 0 ]), + 1, gtknew('VBox', border_width => 0, children => [ + 0, gtknew('Label_Left', text => N("The current security level is %s. +Select permissions to see/edit", $level), alignment => [ 0, 0 ]), + 0, gtknew('HButtonBox', layout => 'start', children => [ + 0, $combo_perm, + ]), + 0, gtknew('Label'), + 1, gtknew('ScrolledWindow', child => $permList), + 0, my $up_down_box = gtknew('HBox', spacing => 5, children_loose => [ @buttons = + map { + gtkset_tip( + gtknew('Button', text => $_->[0], clicked => $_->[2]), + $_->[1]); + } ([ N("Up"), N("Move selected rule up one level"), sub { move_callback('up') } ], + [ N("Down"), N("Move selected rule down one level"), sub { move_callback('down') } ], + [ N("Add a rule"), N("Add a new rule at the end"), \&add_callback ], + [ N("Delete"), N("Delete selected rule"), \&del_callback ], + [ N("Edit"), N("Edit current rule"), \&edit_callback ]) ]), + 0, gtknew('VBox'), + ]), + 0, create_okcancel({ + cancel_clicked => sub { ugtk3->exit }, + ok_clicked => \&save_perm, + }, + undef, undef, '', + [ N("Help"), sub { run_program::raw({ detach => 1 }, 'drakhelp', '--id', 'drakperm') } ], + ) + ]) + ); $W->show_all; $w->{rwindow}->set_position('center') unless $::isEmbedded; -&display_perm($default_perm_level); -$combo_perm->entry->set_text($default_perm_level); +display_perm('all'); +my $_combo_sig = $combo_perm->entry->signal_connect(changed => sub { + my $class = $rev_perm_l10n{$combo_perm_value}; + $permList->set_reorderable($class eq 'editable'); + display_perm($class , @_); + }); + +$permList->get_selection->signal_connect('changed' => sub { + my ($select) = @_; + my (undef, $iter) = $select->get_selected; + return if !$iter; + my $locked = $model->get($iter, 0); + sensitive_buttons($iter ? $editable && !$locked : 0); + return if $locked; + my $curr_path = $model->get_path($iter); + hide_up_button_iffirst_item($curr_path); + hide_down_button_iflast_item($curr_path); + }); -#- Gtk loop start here $w->main; +ugtk3->exit; -#- Should never get here -my_gtk->exit; +sub hide_up_button_iffirst_item { + my ($curr_path) = @_; + my $first_path = $model->get_path($model->get_iter_first); + $buttons[0]->set_sensitive($first_path && $first_path->compare($curr_path)); +} -#- Built in functions -sub check_save { - $modified or return 0; - my $sav_ = $in->ask_okcancel('Warning', 'your changed will be lost do you wish to continue?'); - $sav_ - and $modified = 0; - return $sav_; +sub hide_down_button_iflast_item { + my ($curr_path) = @_; + $curr_path->next; + my $next_item = $model->get_iter($curr_path); + $buttons[1]->set_sensitive($next_item && !$model->get($next_item, 0)); } -#- Desc => set the Perm_list CList with the appropriate value + sub display_perm { - my $perm_level = shift @_; - my $file = $perm{$perm_level}; - my $sav_ = &check_save; - my $i = 0; - if ($modified && ! $sav_) { - $combo_perm->entry->signal_handler_block($combo_sig); - $combo_perm->entry->set_text($prec_txt); - $combo_perm->entry->signal_handler_unblock($combo_sig); - return 0; - } - - $editable = $perm_level =~ /^level \d/ ? 0 : 1; - - $Perm_list->clear(); - open F, $file; - while (<F>) { - m/^([^#]\S+)\s+([^.\s]+)(\.(\S+))?\s+(\d+)/ or next; - $Perm_list->insert($i++, ($1, $2, $4, $5)); - } - close F; - $up_down_box->set_sensitive($editable); - - $rows_cnt = $i; - $prec_txt = $perm_level; - undef(%CURENT); + my ($perm_level) = @_; + return unless $perm_level; + my $show_sys_rules = $perm_level eq $default_perm_level; + my $show_user_rules = $perm_level eq 'editable'; + my $show_all_rules = $perm_level eq 'all'; + # cleaner way: only remove filtered out rules, add those not any more filtered rather than refilling the whole tree + $model->clear; + foreach my $rule (@rules) { + next if !$show_all_rules && ($show_user_rules && $rule->{editable} || $show_sys_rules && !$rule->{editable}); + $model->append_set(map_index { if_(defined $rule->{$_}, $::i => $rule->{$_}) } qw(editable path user group perms index)); + } + + # alter button box behavior + $editable = $perm_level =~ /^level \d/ ? 0 : 1; + $up_down_box->set_sensitive($editable); + sensitive_buttons(0) if $editable; } -#- Desc => save the perm.local file if modification made -sub save_perm { - $modified or return 0; - open F, '>'.$local_path.'perm.local' or die("F CHIER BORDEL"); - foreach my $i (0..$rows_cnt) { - my $line = $Perm_list->get_text($i, 0) . "\t" . $Perm_list->get_text($i,1) . ($Perm_list->get_text($i,2) ? "." . $Perm_list->get_text($i,2) : "") . "\t" . $Perm_list->get_text($i,3) . "\n"; - print F $line; - } - close F; - $modified = 0; +sub save_perm() { + my $val; + if ($modified) { + my $F; + open $F, '>' . $perm_files{editable} or die(qq(Impossible to process "$perm_files{editable}")); + $model->foreach(sub { + my ($model, $_path, $iter) = @_; + return 0 if $model->get($iter, 0); + my $line = $model->get($iter, 1) . "\t" . $model->get($iter, 2) . ($model->get($iter, 3) ? "." . $model->get($iter, 3) : "") . "\t" . $model->get($iter, 4) . "\n"; + print $F $line; + return 0; + }, $val); + close $F; + } + $modified = 0; + ugtk3->exit; } -#- on list selection we get all data concerning the curent selection -sub row_setting_data { - my ( $widget, $row, $column, $event ) = @_; - %CURENT = ('clicked' => {'row' => $row, - 'col' => $column - }, - 'data' => [ $Perm_list->get_text($row,0), - $Perm_list->get_text( $row,1), - $Perm_list->get_text( $row,2), - $Perm_list->get_text( $row,3), - ]); - #print(%{$CURENT{'clicked'}});print("\n"); + +sub load_perms() { + foreach my $file (@perm_files{($default_perm_level, 'editable')}) { + my @editable = if_($file ne $perm_files{editable}, editable => $pixbuf); + local $_; + foreach (cat_($file)) { + next if /^#/; + # Editable, Path, User, Group, Permissions + if (m/^(\S+)\s+([^.\s]+)\.(\S+)?\s+(\d+)/) { + push @rules, { @editable, path => $1, user => $2, group => $3, perms => $4, index => $index }; + } elsif (m/^(\S+)\s+current?\s+(\d+)/) { + push @rules, { @editable, path => $1, user => 'current', group => '', perms => $2, index => $index }; + } else { + warn qq(unparsable "$_"line); + } + $index++; + } + } } -#- Desc => Here is the complete subwindow for rule settings sub row_setting_dialog { - - $editable or return 0; - - my $row = ${$CURENT{clicked}}{row}; - - #- dlg widgets declaration - my $dlg = new Gtk::Dialog(); - my $ok = new Gtk::Button('ok'); - my $cancel = new Gtk::Button('cancel'); - my $browse = new Gtk::Button(N("browse")); - my $users = new Gtk::Combo; - my $groups = new Gtk::Combo; - my $file = new Gtk::Entry; - my $file_hbox=new Gtk::HBox(0,5); - my $usr_hbox = new Gtk::HBox(0,5); - my $usr_vbox = new Gtk::VBox(0,5); - my $usr_check=new Gtk::CheckButton(N("Current user")); - my @rights = ('user', 'group', 'other'); - my @check = ('', 'read', 'write', 'execute'); - my $hb_rights = new Gtk::HBox(0,15); - my $vb_rights = new Gtk::VBox(0,15); - my $F_rights = new Gtk::Frame(N("Permissions")); - my $F_path = new Gtk::Frame(N("Path")); - my $F_usr = new Gtk::Frame(N("Property")); - my $vb_specials = new Gtk::VBox(0,5); - my $sticky = new Gtk::CheckButton(N("sticky-bit")); - my $suid = new Gtk::CheckButton(N("Set-UID")); - my $gid = new Gtk::CheckButton(N("Set-GID")); - my $rght = ${$CURENT{data}}[3]; - my $s = length($rght) == 4 ? substr($rght,0,1) : 0; - my $user = $s ? substr($rght,1,1) : substr($rght,0,1); - my $group = $s ? substr($rght,2,1) : substr($rght,1,1); - my $other = $s ? substr($rght,3,1) : substr($rght,2,1); - foreach (@check) { - $vb_rights->add(new Gtk::Label($_)); - } - $hb_rights->add($vb_rights); - foreach my $r (@rights) { - %{$r} = &get_right(${$r}); - ${'_vb'.$r} = new Gtk::VBox(0,5); - ${'_vb'.$r}->add(new Gtk::Label($r)); - foreach my $c (@check) { - $c eq '' and next; - ${ $r . "_$c" } = Gtk::CheckButton->new; - ${$r}{$c} and ${ $r . "_$c" }->set_active(1); - ${"_vb$r"}->add(${ $r . "_$c" }); - } - $hb_rights->add(${'_vb'.$r}); - } - - $vb_specials->add(new Gtk::Label(' ')); - $vb_specials->add($suid); - $vb_specials->add($gid); - $vb_specials->add($sticky); - $hb_rights->add($vb_specials); - - #- dlg widgets settings - my %s_right = &get_right($s); - $s_right{execute} and $sticky->set_active(1); - $s_right{write} and $gid->set_active(1); - $s_right{read} and $suid->set_active(1); - - $file->set_text(${$CURENT{data}}[0]); - - $users->set_popdown_strings(&get_user_or_group('users')); - $users->entry->set_text(${$CURENT{data}}[1]); - $users->entry->set_editable(0); - - $groups->set_popdown_strings(&get_user_or_group); - $groups->entry->set_text(${$CURENT{data}}[2]); - $groups->entry->set_editable(0); - $dlg->set_policy(0,0,1); - $dlg->set_modal(1); - - - if (${$CURENT{data}}[1] eq 'current') { - $usr_check->set_active(1); - $groups->set_sensitive(0); - $users->set_sensitive(0); - } - - $tips->set_tip($sticky, N("Used for directory:\n only owner of directory or file in this directory can delete it")); - $tips->set_tip($suid, N("Use owner id for execution")); - $tips->set_tip($gid, N("Use group id for execution")); - $tips->set_tip($usr_check, N("when checked, owner and group won't be changed")); - - #- event management - $cancel->signal_connect( clicked => sub { $dlg->destroy }); - $browse->signal_connect( clicked => sub { - my $file_dlg = new Gtk::FileSelection(N("Path selection")); - $file_dlg->set_modal(1); - $file_dlg->show; - $file_dlg->set_filename($file->get_text); - $file_dlg->cancel_button->signal_connect( clicked => sub { $file_dlg->destroy }); - $file_dlg->ok_button->signal_connect( clicked => sub { - $file->set_text($file_dlg->get_filename); - $file_dlg->destroy; - }); - - }); - $ok->signal_connect( clicked => sub { - $Perm_list->set_text($row, 0, $file->get_text); - if ($usr_check->get_active) { - $Perm_list->set_text($row, 1, 'current'); - $Perm_list->set_text($row, 2, ''); - } else { - $Perm_list->set_text($row, 1, $users->entry->get_text); - $Perm_list->set_text($row, 2, $groups->entry->get_text); - } - #- mod calculation - #$user = ($user_read->get_active ? 4 : 0)+($user_write->get_active ? 2 : 0)+($user_execute->get_active ? 1 : 0); - #$group = ($group_read->get_active ? 4 : 0)+($group_write->get_active ? 2 : 0)+($group_execute->get_active ? 1 : 0); - #$other = ($other_read->get_active ? 4 : 0)+($other_write->get_active ? 2 : 0)+($other_execute->get_active ? 1 : 0); - my $s = ($sticky->get_active ? 1 : 0) + ($suid->get_active ? 4 : 0) + ($gid->get_active ? 2 : 0); - $Perm_list->set_text($row,3, ($s ? $s : '') . $user . $group . $other); - $dlg->destroy; - $modified++; - }); - $usr_check->signal_connect( clicked => sub { - if ($usr_check->get_active) { - $groups->set_sensitive(0); - $users->set_sensitive(0); - } else { - $groups->set_sensitive(1); - $users->set_sensitive(1); - } - }); - - #- dlg widgets placement - $file_hbox->add($file); - $file_hbox->add($browse); - - $usr_vbox->add($usr_check); - $usr_vbox->add($usr_hbox); - - $usr_hbox->add(new Gtk::Label(N("user :"))); - $usr_hbox->add($users); - $usr_hbox->add(new Gtk::Label(N("group :"))); - $usr_hbox->add($groups); - - $F_path->add($file_hbox); - $F_rights->add($hb_rights); - $F_usr->add($usr_vbox); - - $dlg->vbox->add($F_path); - $dlg->vbox->add($F_usr); - $dlg->vbox->add($F_rights); - - $dlg->action_area->add($ok); - $dlg->action_area->add($cancel); - - $dlg->show_all; + my ($title, $o_iter) = @_; + + my $dlg = gtknew('Dialog', transient_for => $w->{real_window}, title => $title); +# $dlg->set_resizable(0); + my $browse = gtknew('Button', text => N("browse")); + my $file = gtknew('Entry', $o_iter ? (text => $model->get($o_iter, 1)) : ()); + my ($other, $group, $user, $s) = $o_iter ? reverse(split(//, $model->get($o_iter, 4))) : (); + my @bits = qw(sticky gid suid); + my @rights = qw(read write execute); + my @owners = (N_("user"), N_("group"), N_("other")); + + my %rights = (user => $user, group => $group, other => $other); + my %rights_labels = (user => N("User"), group => N("Group"), other => N("Other")); + my %checks = ('read' => { + label => N("Read"), + tip => { map { $_ => + #-PO: here %s will be either "user", "group" or "other" + N("Enable \"%s\" to read the file", translate($_)); + } keys %rights }, + }, + 'write' => { + label => N("Write"), + tip => { map { $_ => + #-PO: here %s will be either "user", "group" or "other" + N("Enable \"%s\" to write the file", translate($_)); + } keys %rights }, + }, + 'execute' => { + label => N("Execute"), + tip => { map { $_ => + #-PO: here %s will be either "user", "group" or "other" + N("Enable \"%s\" to execute the file", translate($_)); + } keys %rights }, + }, + sticky => { label => N("Sticky-bit"), tip => N("Used for directory:\n only owner of directory or file in this directory can delete it") }, + suid => { label => N("Set-UID"), tip => N("Use owner id for execution") }, + gid => { label => N("Set-GID"), tip => N("Use group id for execution") }, + ); + + #- dlg widgets settings + my %s_right = get_right($s); + + my $alrd_exsts = defined $o_iter; + + my $users = gtknew('ComboBox', list => [ my @users = get_user_or_group('users') ]); + $users->entry->set_text($model->get($o_iter, 2)) if $o_iter; + $users->set_wrap_width(3); + + my $groups = gtknew('ComboBox', list => [ my @groups = get_user_or_group('groups') ]); + $groups->entry->set_text($model->get($o_iter, 3)) if $o_iter; + $groups->set_wrap_width(3); + + my $id_box = gtknew('Table', homogeneous => 0, xpadding => 0.1, ypadding => 0, border_width => 0, children => [ + [ gtknew('Label_Left', text => N("User:")), $users ], + [ gtknew('Label_Left', text => N("Group:")), $groups ], + ] + ); + + my $usr_check = gtksignal_connect(gtkset_tip(gtknew('CheckButton', text => N("Current user")), + N("When checked, owner and group will not be changed")), + clicked => sub { $id_box->set_sensitive(!$_[0]->get_active) }); + + if ($o_iter && $model->get($o_iter, 2) eq 'current') { + $usr_check->set_active(1); + $id_box->set_sensitive(0); + } else { $usr_check->set_active(0) } + + + $browse->signal_connect(clicked => sub { + my $file_dlg = gtknew('FileChooserDialog', title => N("Path selection"), action => 'select_folder', + modal => 1, transient_for => $dlg); + $file_dlg->set_filename($file->get_text); + $file_dlg->show; + my $answer = $file_dlg->run; + if ($answer eq 'ok') { + $file->set_text($file_dlg->get_filename); + } + $file_dlg->hide; + $file_dlg->destroy; + }); + my %perms; + + gtkpack_($dlg->get_child, + 0, gtknew('Title2', label => N("Path")), + 0, gtknew('HBox', border_width => 18, children => [ + 1, $file, + 0, $browse + ] + ), + 0, gtknew('Title2', label => N("Property")), + 0, gtknew('VBox', border_width => 18, children => [ + 0, $usr_check, + ] + ), + 0, $id_box, + 0, gtknew('Title2', label => N("Permissions")), + 1, gtknew('HBox', border_width => 0, children_loose => [ + gtknew('VBox', border_width => 0, children_loose => [ + gtknew('Label', text => ""), + map { gtknew('Label_Left', text => $checks{$_}{label}, alignment => [ 0, 0 ]) } @rights, + ]), + (map { + my $owner = $_; + $perms{$owner} = { get_right($rights{$owner}) }; + my $vbox = gtknew('VBox', children_loose => [ + gtknew('Label', text => $rights_labels{$owner}), + map { + my $c = $_; + my $active = $perms{$owner}{$c}; + $perms{$owner}{$c} = gtkset_tip(gtknew('CheckButton'), + $checks{$c}{tip}{$owner}, + ); + gtkset_active($perms{$owner}{$c}, $active); + } @rights, + ]); + + $vbox; + } @owners), + gtknew('VBox', children_loose => [ + gtknew('Label', text => ' '), + map { $perms{$_} = gtkset(gtknew('CheckButton', text => $checks{$_}{label}), tip => $checks{$_}{tip}) } @bits, + ]), + ]), + ); + $perms{sticky}->set_active($s_right{execute}); + $perms{gid}->set_active($s_right{write}); + $perms{suid}->set_active($s_right{read}); + + gtkadd($dlg->get_action_area, + create_okcancel(my $w = + { + cancel_clicked => sub { $dlg->destroy }, + ok_clicked => sub { + my ($path, $user, $group, $perms, $_idx); + $path = $file->get_text; + if ($path !~ m!^/!) { + err_dialog(N("Warning"), N("The first character of the path must be a slash (\"/\"):\n\"%s\"", $path)); + return 1; + } + if ($usr_check->get_active) { + $user = 'current'; + $group = ''; + } else { + $user = $users->entry->get_text; + $group = $groups->entry->get_text; + if (!member($user, @users) || !member($group, @groups)) { + err_dialog(N("Warning"), join("\n", N("Both the username and the group must valid!"), + N("User: %s", $user), + N("Group: %s", $group), + ) + ); + return 1; + } + } + $perms = sprintf("%03o", eval(join('', "0b", + (map { $perms{$_}->get_active || 0 } reverse @bits), + (map { my $owner = $_;map_index { + $perms{$owner}{$_}->get_active || 0; + } @rights } @owners)))); + # create new item if needed (that is when adding a new one) at end of list + if (!$o_iter) { + $o_iter = $model->append; + push @rules, { path => $path, user => $user, group => $group, perms => $perms, index => $index }; + $model->set($o_iter, 5 => $index++); + } + $model->set($o_iter, 1 => $path, 2 => $user, 3 => $group, 4 => $perms); + $dlg->destroy; + $modified++; + } + }, + ), + ); + + $w->{ok}->set_sensitive(!$model->get($o_iter, 0)) if $alrd_exsts; + $dlg->show_all; } -#- Desc => return an array of the available users on the machine sub get_user_or_group { - my $what = @_; - my @users; - local *F; - $what eq 'users' - and open F, '/etc/passwd' - or open F, '/etc/group'; - - while (<F>) { - m/^([^#:]+):[^:]+:[^:]+:/ or next; - push @users, $1; - } - close F; - return sort(@users); + my ($what) = @_; + my @users; + + local $_; + my $is_users = $what eq 'users'; + foreach (cat_($is_users ? '/etc/passwd' : '/etc/group')) { + if ($is_users) { + push @users, $1 if m/^([^#:]+):[^:]+:[^:]+:/; # or next; + } else { + push @users, $1 if m/^([^#:]+):[^:]*:[^:]*:/; # or next; + } + } + return sort(@users); } -#- Desc => return hash of boolean value for read write and execution permission from a value between 0 - 7 sub get_right { - my $right = shift @_; - my %rght = ('read' => 0, 'write' => 0, 'execute' => 0); - $right - 4 >= 0 and $rght{read}=1 and $right = $right-4; - $right - 2 >= 0 and $rght{write}=1 and $right = $right-2; - $right - 1 >= 0 and $rght{execute}=1 and $right = $right-1; - return %rght; + my ($right) = @_; + my %rght = ('read' => 0, 'write' => 0, 'execute' => 0); + $right - 4 >= 0 and $rght{read}=1 and $right = $right-4; + $right - 2 >= 0 and $rght{write}=1 and $right = $right-2; + $right - 1 >= 0 and $rght{execute}=1 and $right = $right-1; + return %rght; } +sub sensitive_buttons { + foreach my $i (0, 1, 3, 4) { + $buttons[$i]->set_sensitive($_[0]); + } +} |
