diff options
Diffstat (limited to 'perl-install/standalone/drakperm')
| -rwxr-xr-x | perl-install/standalone/drakperm | 442 | 
1 files changed, 442 insertions, 0 deletions
| diff --git a/perl-install/standalone/drakperm b/perl-install/standalone/drakperm new file mode 100755 index 000000000..fa69be838 --- /dev/null +++ b/perl-install/standalone/drakperm @@ -0,0 +1,442 @@ +#!/usr/bin/perl  + +use strict; +use diagnostics; +use lib qw(/usr/lib/libDrakX); +use standalone; + +use MDK::Common; +use common; +use mygtk3 qw(gtknew gtkset); +use ugtk3 qw(:create :dialogs :helpers :wrappers); + +$ugtk3::wm_icon = "/usr/share/mcc/themes/default/drakperm-mdk.png"; +require_root_capability(); + +#- vars declaration +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 = ugtk3->new(N("Security Permissions")); +$w->{rwindow}->set_size_request(620, 400) unless $::isEmbedded; +my $W = $w->{window}; +$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 +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('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); +                                           }); + +$w->main; +ugtk3->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)); +} + +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)); +} + + +sub display_perm { +    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; +} + +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; +} + +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++; +        } +    } +} + +sub row_setting_dialog { +    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; + +} + +sub get_user_or_group { +    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); +} + +sub get_right { +    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]); +    } +} | 
