selinux October 2012 archive
Main Archive Page > Month Archives  > selinux archives
selinux: [PATCH 1/1] setools-3.3.7:apol: Add constraints search

[PATCH 1/1] setools-3.3.7:apol: Add constraints search tab

From: Richard Haines <richard_c_haines_at_nospam>
Date: Thu Oct 25 2012 - 15:19:27 GMT
To: selinux@tycho.nsa.gov, setools@tresys.com

I've been using this to investigate constraints in policies with no
problems for a few weeks. Thought it maybe a useful addition to APOL.

The "Constraints" tab will allow searching for mls/constrain and
mls/validatetrans rules based on keyword, user, role, type or type
attribute of a constraint expression. Help text is available that
explains the search rules. The Query:Policy Summary has also been
updated to reflect the number of these rules within the current policy.

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
--- apol/Makefile.am | 1 + apol/apol_help.txt | 81 +++ apol/constraints_tab.tcl | 1790 ++++++++++++++++++++++++++++++++++++++++++++++ apol/top.tcl | 59 ++ 4 files changed, 1931 insertions(+), 0 deletions(-) create mode 100644 apol/constraints_tab.tcl diff --git a/apol/Makefile.am b/apol/Makefile.am index 646d8b1..4ea51b0 100644 --- a/apol/Makefile.am +++ b/apol/Makefile.am @@ -31,6 +31,7 @@ EXTRA_DIST = \ common_widgets.tcl \ cond_bools_tab.tcl \ cond_rules_tab.tcl \ + constraints_tab.tcl \ context_dialog.tcl \ context_selector.tcl \ directflow_module.tcl \ diff --git a/apol/apol_help.txt b/apol/apol_help.txt index aad309b..cda2ccc 100644 --- a/apol/apol_help.txt +++ b/apol/apol_help.txt @@ -260,6 +260,87 @@ rules in a policy based on selected search criteria. [Enabled] - indicates the rule is enabled [Disabled] - indicates the rule is disabled + Constraints tab + --------------- + Select the Constraints tab to search through the constrain and + validatetrans constraint rules. If the current policy supports MLS + then these variants are also enabled. + + Four different types of search criteria exist for constraints: + + 1. CONSTRAINT SELECTION: provides options to limit the scope of the + search as only those constraints selected will be included in the + search. At least one must be selected. NOTE: If no additional + search criteria is specified, apol will search for all of the + selected constraints. + + 2. CLASSES/PERMISSIONS SUBTAB: provides options to refine a search + using object classes and/or permissions in the same way as the + TE Rules tab described above. Note that the validatetrans rules + do not use permissions. + + 3. LEFT SIDE OF EXPRESSION SUBTAB: provides an option to refine a + search based on the left keyword of a constraint. When checked + the left hand side of each expression is read from the policy and + displayed in the drop down box. A single keyword may then be + selected. + + 4. RIGHT SIDE OF EXPRESSION SUBTAB: provides options to refine a + search based on either the right keyword, user, role, type or type + attribute of a constraint. When one of the boxes is checked + the right keywords, users, roles, types or type attributes are + read from the policy and displayed in the drop down box. A single + item may then be selected. + + If a type or attribute is selected the "Only direct matches" box + can be used to determine searching as follows: + - If selected, the type or type attribute identifier will be + used for the match. + + - If unselected and a type is selected: + The type identifier will be used for matching, also any + type attributes found within the constraints expression + will be expanded and its list of types searched for a + match. + + - If unselected and an attribute is selected: + The type attribute identifier will be used for matching, + also any types found within the constraints expression + will have its associated type attributes searched for a + match. + If "Replace types" is also selected the attribute is + expanded to a set of types. If all types are present, + then this will be considered an attribute match and the + attribute identifer will replace this list of types + within the constrain statement. Should the attribute + expand to an <empty_set>, then all constraints with + empty sets will be shown (as there are no types to match + against therefore it could be all, some or none of the + rules shown). + + NOTES: + 1) Be aware that the "Replace types" option will replace the + set of types with the selected attribute identifier, + however it is possible that other attribute indentifiers + could have the same associated type list. This option + works best if there is only one attribute identifier in + the expression - this is usually the case for the + Reference Policy (see the constraints, mcs and mls + configuration files in the Reference Policy source). + + 2) Either "Only direct matches" or "Replace types" may be + selected. + + The Constraints Tab also supports multiple results windows. Each + active window remembers the search options used for it, and will set + all the options accordingly when selected. Use the "Update Search" + button to change the results displayed for the current window based + on the current search option. "New Search" creates a new results + window based on the current search options. Use the "Close Tab" bar + at the bottom to destroy a results window. Also, the Constraints tab + provides the means to save/load search criteria to a file (see Menus + section above). + RBAC Rules tab -------------- Select the RBAC Rules tab to search role-based access control rules. diff --git a/apol/constraints_tab.tcl b/apol/constraints_tab.tcl new file mode 100644 index 0000000..7500b93 --- /dev/null +++ b/apol/constraints_tab.tcl @@ -0,0 +1,1790 @@ +# This tab will allow searching of constrain and validatetrans constraint +# rules within the policy. The mls versions are also searched if an +# mls policy is loaded. +# +# This tab has been derived from the terules_tab. +# +# Author: Richard Haines richard_c_haines@btinternet.com +# +# Copyright (C) 2001-2007 Tresys Technology, LLC +# 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 of the License, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +namespace eval Apol_Constraint { + variable vals + variable widgets + variable tabs + variable enabled + + variable opts + variable constraint_list {} + variable left_expr_list {} + variable right_expr_list {} + variable mls_enabled {0} + variable match_right_type_names 0 + variable statement_count 0 +} + +proc Apol_Constraint::create {tab_name nb} { + variable vals + variable widgets + + _initializeVars + + set frame [$nb insert end $tab_name -text "Constraints"] + set pw [PanedWindow $frame.pw -side left -weights extra] + set topf [$pw add -weight 0] + set bottomf [$pw add -weight 1] + pack $pw -expand 1 -fill both + + # Major SubFrames: + # rsbox - constrain selection + # rbox - holds display window widgets + # abox - action buttons + set top_leftf [frame $topf.tl] + set widgets(search_opts) [NoteBook $topf.nb] + set abox [frame $topf.abox] + pack $top_leftf -side left -expand 0 -fill y + pack $widgets(search_opts) -side left -expand 1 -fill both -padx 10 + pack $abox -side right -fill y -padx 5 + set rsbox [TitleFrame $top_leftf.rsbox -text "Constraint Selection"] + set rbox [TitleFrame $bottomf.rbox -text "Constraint Search Results"] + pack $rsbox -side top -fill both -expand 1 + pack $rbox -expand yes -fill both -padx 2 + + # Constraint selection subframe + set fm_constraints [$rsbox getframe] + set constrain [checkbutton $fm_constraints.constrain -text "constrain" \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(rs:constrain_enabled)] + set mlsconstrain [checkbutton $fm_constraints.mlsconstrain -text "mlsconstrain" \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(rs:mlsconstrain_enabled)] + set validatetrans [checkbutton $fm_constraints.validatetrans -text "validatetrans" \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(rs:validatetrans_enabled)] + set mlsvalidatetrans [checkbutton $fm_constraints.mlsvalidatetrans -text "mlsvalidatetrans" \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(rs:mlsvalidatetrans_enabled)] + grid $constrain -sticky w -padx 10 + grid $mlsconstrain -sticky w -padx 10 + grid $validatetrans -sticky w -padx 10 -pady {30 0} + grid $mlsvalidatetrans -sticky w -padx 10 + + _createClassesPermsTab + _createLeftExpressionTab + _createRightExpressionTab + + # Action buttons + set widgets(new) [button $abox.new -text "New Search" -width 12 \ + -command [list Apol_Constraint::_search_constraints new]] + set widgets(update) [button $abox.update -text "Update Search" -width 12 -state disabled \ + -command [list Apol_Constraint::_search_constraints update]] + set widgets(reset) [button $abox.reset -text "Reset Criteria" -width 12 \ + -command Apol_Constraint::_reset] + pack $widgets(new) $widgets(update) $widgets(reset) \ + -side top -pady 5 -padx 5 -anchor ne + + $widgets(search_opts) compute_size + + # Popup menu widget + set popupTab_Menu [menu .popup_constrain_rules -tearoff 0] + set tab_menu_callbacks \ + [list {"Close Tab" Apol_Constraint::_delete_results} \ + {"Rename Tab" Apol_Constraint::_display_rename_tab_dialog}] + + # Notebook creation for results + set widgets(results) [NoteBook [$rbox getframe].results] + $widgets(results) bindtabs <Button-1> Apol_Constraint::_switch_to_tab + $widgets(results) bindtabs <Button-3> \ + [list ApolTop::popup \ + %W %x %y $popupTab_Menu $tab_menu_callbacks] + set close [button [$rbox getframe].close -text "Close Tab" \ + -command Apol_Constraint::_delete_current_results] + pack $widgets(results) -expand 1 -fill both -padx 4 + pack $close -expand 0 -fill x -padx 4 -pady 2 + + _initializeVars + return $frame +} + + +proc Apol_Constraint::open {ppath} { + variable mls_enabled + + if {[ApolTop::is_capable "mls"]} { + set mls_enabled 1 + } else { + set mls_enabled 0 + } + + _initializeVars + _initializeWidgets + _initializeTabs + + variable vals + variable enabled + set vals(cp:classes) [Apol_Class_Perms::getClasses] + set enabled(cp:classes) 1 + set enabled(cp:perms) 1 +} + + +proc Apol_Constraint::close {} { + _initializeTabs + _initializeWidgets + _initializeVars + set enabled(cp:perms) 1 + + variable constraint_list {} + variable left_expr_list {} + variable right_expr_list {} +} + + +proc Apol_Constraint::getTextWidget {} { + variable widgets + variable tabs + + if {[$widgets(results) pages] != {}} { + set raisedPage [$widgets(results) raise] + if {$raisedPage != {}} { + return $tabs($raisedPage).tb + } + } + return {} +} + + +proc Apol_Constraint::save_query_options {file_channel query_file} { + variable vals + + foreach {key value} [array get vals] { + if {$key != "cp:classes" && $key != "cp:perms"} { + puts $file_channel "$key $value" + } + } +} + + +proc Apol_Constraint::load_query_options {file_channel} { + variable vals + variable widgets + variable enabled + _initializeVars + + # load as many values as possible + set classes_selected {} + set perms_selected {} + while {[gets $file_channel line] >= 0} { + set line [string trim $line] + # Skip empty lines and comments + if {$line == {} || [string index $line 0] == "#"} { + continue + } + regexp -line -- {^(\S+)( (.+))?} $line -> key --> value + if {$key == "cp:classes_selected"} { + set classes_selected $value + } elseif {$key == "cp:perms_selected"} { + set perms_selected $value + } else { + set vals($key) $value + } + } + + # update the display + _initializeWidgets + set vals(cp:classes) [Apol_Class_Perms::getClasses] + set enabled(cp:classes) 1 + set enabled(cp:perms) 1 + _toggle_perms_toshow -> -> reset + + # then verify that selected object classes and permissions exist + # for this policy + set unknowns {} + set vals(cp:classes_selected) {} + foreach class $classes_selected { + if {[set i [lsearch $vals(cp:classes) $class]] >= 0} { + $widgets(cp:classes) selection set $i + lappend vals(cp:classes_selected) $class + } else { + lappend unknowns $class + } + } + if {[llength $unknowns] > 0} { + tk_messageBox -icon warning -type ok -title "Open Apol Query" \ + -message "The following object classes do not exist in the currently loaded policy and were ignored:\n\n[join $unknowns ", "]" \ + -parent . + } + + _toggle_perms_toshow {} {} {} + set unknowns {} + set vals(cp:perms_selected) {} + foreach perm $perms_selected { + if {[set i [lsearch $vals(cp:perms) $perm]] >= 0} { + $widgets(cp:perms) selection set $i + lappend vals(cp:perms_selected) $perm + } else { + lappend unknowns $perm + } + } + if {[llength $unknowns] > 0} { + tk_messageBox -icon warning -type ok -title "Open Apol Query" \ + -message "The following permissions do not exist in the currently loaded policy and were ignored:\n\n[join $unknowns ", "]" \ + -parent $parentDlg + } +} + + +#### private functions below #### + +proc Apol_Constraint::_initializeVars {} { + variable vals + variable mls_enabled + + array set vals [list \ + rs:constrain_enabled 1 \ + rs:mlsconstrain_enabled $mls_enabled \ + rs:validatetrans_enabled 1 \ + rs:mlsvalidatetrans_enabled $mls_enabled \ + + kta:left_expr,left_keyword 1 \ + kta:right_expr,right_keyword 0 \ + kta:right_expr,types 0 \ + kta:right_expr,users 0 \ + kta:right_expr,roles 0 \ + kta:right_expr,attribs 0 \ + ] + + array set vals { + kta:use_left_expr 0 + kta:left_expr {} + + kta:use_right_expr 0 + kta:right_expr {} + kta:right_expr_direct 0 + kta:right_expr_replace_types 0 + + cp:classes {} + cp:classes_selected {} + cp:perms {} + cp:perms_selected {} + cp:perms_toshow all + cp:perms_matchall 0 + } + + variable enabled + array set enabled { + kta:use_left_expr 1 + kta:use_right_expr 1 + + cp:classes 0 + cp:perms 0 + } +} + + +proc Apol_Constraint::_initializeTabs {} { + variable widgets + variable tabs + + array set tabs { + next_result_id 1 + } + foreach p [$widgets(results) pages 0 end] { + _delete_results $p + } +} + + +proc Apol_Constraint::_initializeWidgets {} { + variable widgets + + $widgets(search_opts) raise left_expr_entry + $widgets(search_opts) raise right_expr_entry + + $widgets(cp:classes) selection clear 0 end + $widgets(cp:perms) selection clear 0 end +} + + +proc Apol_Constraint::_createLeftExpressionTab {} { + variable vals + variable widgets + variable enabled + + set ta_tab [$widgets(search_opts) insert end left_expr_entry -text "Left Side of Expression"] + set fm_left_expr [frame $ta_tab.left_expr] + grid $fm_left_expr -padx 4 -sticky ewns + foreach i {0} { + grid columnconfigure $ta_tab $i -weight 1 -uniform 1 + } + grid rowconfigure $ta_tab 0 -weight 1 +# prefix frame title left_side right_side + _create_expression_box left_expr $fm_left_expr "Keyword" 1 0 + + $widgets(search_opts) raise left_expr_entry +} + + +proc Apol_Constraint::_createRightExpressionTab {} { + variable vals + variable widgets + variable enabled + + set ta_tab [$widgets(search_opts) insert end right_expr_entry -text "Right Side of Expression"] + set fm_right_expr [frame $ta_tab.right_expr] + grid $fm_right_expr -padx 4 -sticky ewns + foreach i {0} { + grid columnconfigure $ta_tab $i -weight 1 -uniform 1 + } + grid rowconfigure $ta_tab 0 -weight 1 +# prefix frame title left_side right_side + _create_expression_box right_expr $fm_right_expr "Select either a keyword, user, role, type or type attribute" 0 1 + + $widgets(search_opts) raise right_expr_entry +} + + +proc Apol_Constraint::_create_expression_box {prefix f title left_expr right_expr} { + variable vals + variable widgets + + set widgets(kta:use_${prefix}) [checkbutton $f.use -text $title \ + -variable Apol_Constraint::vals(kta:use_${prefix})] + pack $widgets(kta:use_${prefix}) -side top -anchor w + trace add variable Apol_Constraint::vals(kta:use_${prefix}) write \ + [list Apol_Constraint::_toggle_expression_box $prefix] + + set w {} + + if {$right_expr} { + set helptext "Select a keyword, user, role, type or type attribute for the right hand side of the constraint expression e.g.: \ +\n (left right) \ +\n (t1 == mlstrustedobject) \ +\n (r1 dom r2) \ +\n (r1 != system_r)\n \ +\nIf a type or attribute is selected the \"Only direct matches\" box can be used to determine searching as follows:\n \ +\n - If selected the type or type attribute identifier will be used for the match.\n \ +\n - If unselected and a type is selected: \ +\n The type identifier will be used for matching, also any type attributes found within the constraints expression will \ +\n be expanded and its list of types searched for a match.\n \ +\n - If unselected and an attribute is selected: \ +\n The type attribute identifier will be used for matching, also any types found within the constraints expression will \ +\n have its associated type attributes searched for a match.\n \ +\n If \"Replace types\" is also selected the attribute is expanded to a set of types. If all types are present, then this \ +\n will be considered an attribute match and the attribute identifer will replace this list of types within the constrain \ +\n statement. Should the attribute expand to an <empty_set>, then all constraints with empty sets will be shown \ +\n (as there are no types to match against therefore it could be all, some or none of the rules shown).\n \ +\nNotes: \ +\n 1) Be aware that the \"Replace types\" option will replace the set of types with the selected attribute identifier, however \ +\n it is possible that other attribute indentifiers could have the same associated type list. This option works best if \ +\n there is only one attribute identifier the expression - this is usually the case for the Reference Policy \ +\n (see the constraints, mcs and mls configuration files). \ +\n 2) Either \"Only direct matches\" or \"Replace types\" may be selected.\n" + + } else { + set helptext "Select a keyword for the left hand side of the constraint expression e.g.: \ +\n (left right)\n (r1 == r2)" + } + + set widgets(kta:${prefix}) [ComboBox $f.sym \ + -state disabled -entrybg $ApolTop::default_bg_color \ + -textvariable Apol_Constraint::vals(kta:${prefix}) \ + -helptext $helptext -autopost 1] + pack $widgets(kta:${prefix}) -expand 0 -fill x -padx 8 + lappend w $widgets(kta:${prefix}) + + if {$left_expr} { + set ta_frame [frame $f.ta] + pack $ta_frame -expand 0 -anchor center -pady 2 + trace add variable Apol_Constraint::vals(kta:${prefix},left_keyword) write \ + [list Apol_Constraint::_toggle_left_side $prefix] + pack $widgets(kta:${prefix}) -expand 0 -fill x -padx 8 + lappend w $widgets(kta:${prefix}) + + } + + if {$right_expr} { + set ta_frame [frame $f.ta] + pack $ta_frame -expand 0 -anchor w -pady 2 + set right_keyword [checkbutton $ta_frame.right_keyword -text "Keyword" -state disabled \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(kta:${prefix},right_keyword)] + + set users [checkbutton $ta_frame.users -text "Users" -state disabled \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(kta:${prefix},users)] + + set roles [checkbutton $ta_frame.roles -text "Roles" -state disabled \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(kta:${prefix},roles)] + + set types [checkbutton $ta_frame.types -text "Types" -state disabled \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(kta:${prefix},types)] + set attribs [checkbutton $ta_frame.attribs -text "Attributes" -state disabled \ + -onvalue 1 -offvalue 0 \ + -variable Apol_Constraint::vals(kta:${prefix},attribs)] + + set replace_types [checkbutton $ta_frame.replace_types -text "Replace types" \ + -state disabled -variable Apol_Constraint::vals(kta:${prefix}_replace_types) \ + -onvalue 1 -offvalue 0] + + set direct [checkbutton $f.direct -text "Only direct matches" \ + -state disabled -variable Apol_Constraint::vals(kta:${prefix}_direct) \ + -onvalue 1 -offvalue 0] + + $right_keyword configure -command [list Apol_Constraint::_toggle_kta_pushed $prefix $right_keyword] + $users configure -command [list Apol_Constraint::_toggle_kta_pushed $prefix $users] + $roles configure -command [list Apol_Constraint::_toggle_kta_pushed $prefix $roles] + $types configure -command [list Apol_Constraint::_toggle_kta_pushed $prefix $types] + $attribs configure -command [list Apol_Constraint::_toggle_kta_pushed $prefix $attribs] + + $replace_types configure -command [list Apol_Constraint::_toggle_dir_exp $prefix $replace_types] + $direct configure -command [list Apol_Constraint::_toggle_dir_exp $prefix $direct] + + trace add variable Apol_Constraint::vals(kta:${prefix},right_keyword) write \ + [list Apol_Constraint::_toggle_right_side $prefix] + trace add variable Apol_Constraint::vals(kta:${prefix},users) write \ + [list Apol_Constraint::_toggle_right_side $prefix] + trace add variable Apol_Constraint::vals(kta:${prefix},roles) write \ + [list Apol_Constraint::_toggle_right_side $prefix] + trace add variable Apol_Constraint::vals(kta:${prefix},types) write \ + [list Apol_Constraint::_toggle_right_side $prefix] + trace add variable Apol_Constraint::vals(kta:${prefix},attribs) write \ + [list Apol_Constraint::_toggle_right_side $prefix] + + pack $right_keyword $users $roles $types $attribs $replace_types -side left -anchor w -padx 2 + lappend w $right_keyword $users $roles $types $attribs $replace_types + + pack $direct -side top -anchor w -padx 250 + lappend w $direct + } + + set widgets(kta:${prefix}_widgets) $w + trace add variable Apol_Constraint::enabled(kta:use_${prefix}) write \ + [list Apol_Constraint::_toggle_left_right_box $prefix] +} + + +## lots of obscure callbacks here to determine when to enable a ta box ## + +# called when there is a change in state to the top checkbutton within +# an expression box +proc Apol_Constraint::_toggle_expression_box {col name1 name2 op} { + variable enabled + + # force a refresh of this box's state; this invokes + # _toggle_left_right_box callback + set enabled(kta:use_${col}) $enabled(kta:use_${col}) +} + + +# disallow keyword, types and attribs to be selected within a kta box +proc Apol_Constraint::_toggle_kta_pushed {col cb} { + variable vals + + if {($vals(kta:${col},right_keyword) && $vals(kta:${col},attribs)) || \ + ($vals(kta:${col},right_keyword) && $vals(kta:${col},users)) || \ + ($vals(kta:${col},right_keyword) && $vals(kta:${col},roles)) || \ + ($vals(kta:${col},right_keyword) && $vals(kta:${col},types)) || \ + ($vals(kta:${col},attribs) && $vals(kta:${col},users)) || \ + ($vals(kta:${col},attribs) && $vals(kta:${col},roles)) || \ + ($vals(kta:${col},attribs) && $vals(kta:${col},types)) || \ + ($vals(kta:${col},users) && $vals(kta:${col},roles)) || \ + ($vals(kta:${col},users) && $vals(kta:${col},types)) || \ + ($vals(kta:${col},roles) && $vals(kta:${col},types)) } { + tk_messageBox -icon error -type ok -title "Constraint Search" -message "Select either a keyword, user, role, type or type attribute." + $cb deselect + return + } +} + + +# called whenever the left or right box is enabled or disabled +proc Apol_Constraint::_toggle_left_right_box {col name1 name2 op} { + variable vals + variable widgets + variable enabled + + if {$enabled(kta:use_${col})} { + $widgets(kta:use_${col}) configure -state normal + } else { + $widgets(kta:use_${col}) configure -state disabled + } + if {$enabled(kta:use_${col}) && $vals(kta:use_${col})} { + foreach w $widgets(kta:${col}_widgets) { + $w configure -state normal + } + $widgets(kta:${col}) configure -entrybg white + } else { + foreach w $widgets(kta:${col}_widgets) { + $w configure -state disabled + } + $widgets(kta:${col}) configure -entrybg $ApolTop::default_bg_color + } + + # update this tab's name if one of the columns is enabled and used + if {($enabled(kta:use_left_expr) && $vals(kta:use_left_expr))} { + $widgets(search_opts) itemconfigure left_expr_entry -text "Left Side of Expression *" + } else { + $widgets(search_opts) itemconfigure left_expr_entry -text "Left Side of Expression" + } + + if {($enabled(kta:use_right_expr) && $vals(kta:use_right_expr))} { + $widgets(search_opts) itemconfigure right_expr_entry -text "Right Side of Expression *" + } else { + $widgets(search_opts) itemconfigure right_expr_entry -text "Right Side of Expression" + } +} + + +# disallow direct and expand attributes to be selected within a kta box +proc Apol_Constraint::_toggle_dir_exp {col cb} { + variable vals + + if {$vals(kta:${col}_direct) == 1 && $vals(kta:${col}_replace_types) == 1 } { + $cb deselect + return + } +} + + +proc Apol_Constraint::_toggle_left_side {col name1 name2 op} { + variable vals + variable widgets + + set items {} + + if {$vals(kta:${col},left_keyword)} { + append items [Apol_Constraint::getLeftKeyword] + } + $widgets(kta:${col}) configure -values $items +} + + +proc Apol_Constraint::_toggle_right_side {col name1 name2 op} { + variable vals + variable widgets + + set items {} + + if {$vals(kta:${col},right_keyword)} { + append items [Apol_Constraint::getRightKeyword] + } + if {$vals(kta:${col},users)} { + append items [Apol_Users::getUsers] + } + if {$vals(kta:${col},roles)} { + append items [Apol_Roles::getRoles] + } + if {$vals(kta:${col},types)} { + append items [Apol_Types::getTypes] + } + if {$vals(kta:${col},attribs)} { + append items [Apol_Types::getAttributes] + } + + $widgets(kta:${col}) configure -values $items +} + + +# Returns a list of left keywords +proc Apol_Constraint::getLeftKeyword {} { + variable vals + variable left_expr_list + set left_expr_list {} + + if {[ApolTop::is_policy_open]} { + if { $vals(rs:constrain_enabled) == 1 || $vals(rs:mlsconstrain_enabled) == 1 } { + append left_expr_list [Apol_Constraint::_getKeywords "l" new_apol_constraint_query_t] + } + if { $vals(rs:validatetrans_enabled) == 1 || $vals(rs:mlsvalidatetrans_enabled) == 1 } { + append left_expr_list [Apol_Constraint::_getKeywords "l" new_apol_validatetrans_query_t] + } + lsort -unique $left_expr_list + } else { + set left_expr_list "" + } +} + + +# Returns a list of right keywords +proc Apol_Constraint::getRightKeyword {} { + variable vals + variable right_expr_list + set right_expr_list {} + + if {[ApolTop::is_policy_open]} { + if { $vals(rs:constrain_enabled) == 1 || $vals(rs:mlsconstrain_enabled) == 1 } { + append right_expr_list [Apol_Constraint::_getKeywords "r" new_apol_constraint_query_t] + } + if { $vals(rs:validatetrans_enabled) == 1 || $vals(rs:mlsvalidatetrans_enabled) == 1 } { + append right_expr_list [Apol_Constraint::_getKeywords "r" new_apol_validatetrans_query_t] + } + lsort -unique $right_expr_list + } else { + set right_expr_list "" + } +} + + + +# code to create and handle the classe/permissions subtab +proc Apol_Constraint::_createClassesPermsTab {} { + variable vals + variable widgets + variable enabled + + set objects_tab [$widgets(search_opts) insert end classperms -text "Classes/Permissions"] + set fm_objs [TitleFrame $objects_tab.objs -text "Object Classes"] + set fm_perms [TitleFrame $objects_tab.perms -text "Permissions"] + pack $fm_objs -side left -expand 0 -fill both -padx 2 -pady 2 + pack $fm_perms -side left -expand 1 -fill both -padx 2 -pady 2 + + # object classes subframe + set sw [ScrolledWindow [$fm_objs getframe].sw -auto both] + set widgets(cp:classes) [listbox [$sw getframe].lb -height 5 -width 24 \ + -highlightthickness 0 -selectmode multiple \ + -exportselection 0 -state disabled \ + -bg $ApolTop::default_bg_color \ + -listvar Apol_Constraint::vals(cp:classes)] + $sw setwidget $widgets(cp:classes) + update + grid propagate $sw 0 + bind $widgets(cp:classes) <<ListboxSelect>> \ + [list Apol_Constraint::_toggle_cp_select classes] + pack $sw -expand 1 -fill both + set clear [button [$fm_objs getframe].b -text "Clear" -width 6 -state disabled \ + -command [list Apol_Constraint::_clear_cp_listbox $widgets(cp:classes) classes]] + pack $clear -expand 0 -pady 2 + set widgets(cp:classes_widgets) [list $widgets(cp:classes) $clear] + + # permissions subframe + set f [$fm_perms getframe] + set sw [ScrolledWindow $f.sw -auto both] + set widgets(cp:perms) [listbox [$sw getframe].lb -height 5 -width 24 \ + -highlightthickness 0 -selectmode multiple \ + -exportselection 0 -bg white \ + -listvar Apol_Constraint::vals(cp:perms)] + $sw setwidget $widgets(cp:perms) + update + grid propagate $sw 0 + bind $widgets(cp:perms) <<ListboxSelect>> \ + [list Apol_Constraint::_toggle_cp_select perms] + set clear [button $f.clear -text "Clear" \ + -command [list Apol_Constraint::_clear_cp_listbox $widgets(cp:perms) perms]] + set reverse [button $f.reverse -text "Reverse" \ + -command [list Apol_Constraint::_reverse_cp_listbox $widgets(cp:perms)]] + set perm_opts_f [frame $f.perms] + set perm_rb_f [frame $perm_opts_f.rb] + set l [label $perm_rb_f.l -text "Permissions to show:" -state disabled] + set all [radiobutton $perm_rb_f.all -text "All" \ + -variable Apol_Constraint::vals(cp:perms_toshow) -value all] + set union [radiobutton $perm_rb_f.union -text "All for selected classes" \ + -variable Apol_Constraint::vals(cp:perms_toshow) -value union] + set intersect [radiobutton $perm_rb_f.inter -text "Common to selected classes" \ + -variable Apol_Constraint::vals(cp:perms_toshow) -value intersect] + trace add variable Apol_Constraint::vals(cp:perms_toshow) write \ + Apol_Constraint::_toggle_perms_toshow + pack $l $all $union $intersect -anchor w + set all_perms [checkbutton $perm_opts_f.all -text "Constraint must have all selected permissions" \ + -variable Apol_Constraint::vals(cp:perms_matchall)] + pack $perm_rb_f $all_perms -anchor w -pady 4 -padx 4 + grid $sw - $perm_opts_f -sticky nsw + grid $clear $reverse ^ -pady 2 -sticky ew + grid columnconfigure $f 0 -weight 0 -uniform 1 -pad 2 + grid columnconfigure $f 1 -weight 0 -uniform 1 -pad 2 + grid columnconfigure $f 2 -weight 1 + grid rowconfigure $f 0 -weight 1 + set widgets(cp:perms_widgets) \ + [list $widgets(cp:perms) $clear $reverse $l $all $union $intersect $all_perms] + + trace add variable Apol_Constraint::vals(cp:classes_selected) write \ + [list Apol_Constraint::_update_cp_tabname] + trace add variable Apol_Constraint::vals(cp:perms_selected) write \ + [list Apol_Constraint::_update_cp_tabname] + trace add variable Apol_Constraint::enabled(cp:classes) write \ + [list Apol_Constraint::_toggle_enable_cp classes] + trace add variable Apol_Constraint::enabled(cp:perms) write \ + [list Apol_Constraint::_toggle_enable_cp perms] +} + + +proc Apol_Constraint::_toggle_enable_cp {prefix name1 name2 op} { + variable vals + variable widgets + variable enabled + + if {$enabled(cp:${prefix})} { + foreach w $widgets(cp:${prefix}_widgets) { + $w configure -state normal + } + $widgets(cp:${prefix}) configure -bg white + } else { + foreach w $widgets(cp:${prefix}_widgets) { + $w configure -state disabled + } + $widgets(cp:${prefix}) configure -bg $ApolTop::default_bg_color + } + # force a refresh of this tab's name + set vals(cp:${prefix}_selected) $vals(cp:${prefix}_selected) +} + + +proc Apol_Constraint::_toggle_perms_toshow {name1 name2 op} { + variable vals + variable widgets + + if {$vals(cp:perms_toshow) == "all"} { + # don't change the list of permissions if there was a new + # object class selection and the current radiobutton is all + if {$op != "update"} { + set vals(cp:perms) $Apol_Class_Perms::perms_list + set vals(cp:perms_selected) {} + } + } elseif {$vals(cp:perms_toshow) == "union"} { + set vals(cp:perms) {} + set vals(cp:perms_selected) {} + foreach class $vals(cp:classes_selected) { + set vals(cp:perms) [lsort -unique -dictionary [concat $vals(cp:perms) [Apol_Class_Perms::getPermsForClass $class]]] + } + } else { ;# intersection + set vals(cp:perms) {} + set vals(cp:perms_selected) {} + set classes {} + foreach i [$widgets(cp:classes) curselection] { + lappend classes [$widgets(cp:classes) get $i] + } + if {$classes == {}} { + return + } + set vals(cp:perms) [Apol_Class_Perms::getPermsForClass [lindex $classes 0]] + foreach class [lrange $classes 1 end] { + set this_perms [Apol_Class_Perms::getPermsForClass $class] + set new_perms {} + foreach p $vals(cp:perms) { + if {[lsearch -exact $this_perms $p] >= 0} { + lappend new_perms $p + } + } + set vals(cp:perms) $new_perms + } + } +} + + +# called whenever an item with a class/perm listbox is +# selected/deselected +proc Apol_Constraint::_toggle_cp_select {col} { + variable vals + variable widgets + + set items {} + foreach i [$widgets(cp:${col}) curselection] { + lappend items [$widgets(cp:${col}) get $i] + } + set vals(cp:${col}_selected) $items + if {$col == "classes"} { + _toggle_perms_toshow {} {} update + } +} + + +proc Apol_Constraint::_clear_cp_listbox {lb prefix} { + variable vals + + $lb selection clear 0 end + set vals(cp:${prefix}_selected) {} + if {$prefix == "classes"} { + _toggle_perms_toshow {} {} update + } +} + + +proc Apol_Constraint::_reverse_cp_listbox {lb} { + variable vals + + set old_selection [$lb curselection] + set items {} + for {set i 0} {$i < [$lb index end]} {incr i} { + if {[lsearch $old_selection $i] >= 0} { + $lb selection clear $i + } else { + $lb selection set $i + lappend items [$lb get $i] + } + } + set vals(cp:perms_selected) $items +} + + +proc Apol_Constraint::_update_cp_tabname {name1 name2 op} { + variable vals + variable widgets + variable enabled + + if {($enabled(cp:classes) && $vals(cp:classes_selected) > 0) || \ + ($enabled(cp:perms) && $vals(cp:perms_selected) > 0)} { + $widgets(search_opts) itemconfigure classperms -text "Classes/Permissions *" + } else { + $widgets(search_opts) itemconfigure classperms -text "Classes/Permissions" + } +} + + +proc Apol_Constraint::_delete_results {pageID} { + variable widgets + variable tabs + + # Remove tab and its widgets + set curpos [$widgets(results) index $pageID] + $widgets(results) delete $pageID + array unset tabs $pageID:* + array unset tabs $pageID + + # try to raise the next tab + if {[set next_id [$widgets(results) pages $curpos]] != {}} { + _switch_to_tab $next_id + } elseif {$curpos > 0} { + # raise the previous page instead + _switch_to_tab [$widgets(results) pages [expr {$curpos - 1}]] + } else { + # no tabs remaining + $widgets(update) configure -state disabled + } +} + + +proc Apol_Constraint::_display_rename_tab_dialog {pageID} { + variable widgets + variable tabs + + set d [Dialog .apol_te_tab_rename -homogeneous 1 -spacing 2 -cancel 1 \ + -default 0 -modal local -parent . -place center -separator 1 \ + -side bottom -title "Rename Results Tab"] + $d add -text "OK" -command [list $d enddialog "ok"] + $d add -text "Cancel" -command [list $d enddialog "cancel"] + set f [$d getframe] + set l [label $f.l -text "Tab name:"] + set tabs(tab:new_name) [$widgets(results) itemcget $pageID -text] + set e [entry $f.e -textvariable Apol_Constraint::tabs(tab:new_name) -width 16 -bg white] + pack $l $e -side left -padx 2 + set retval [$d draw] + destroy $d + if {$retval == "ok"} { + $widgets(results) itemconfigure $pageID -text $tabs(tab:new_name) + } +} + + +proc Apol_Constraint::_delete_current_results {} { + variable widgets + + if {[set curid [$widgets(results) raise]] != {}} { + _delete_results $curid + } +} + + +proc Apol_Constraint::_create_new_results_tab {} { + variable vals + variable widgets + variable tabs + + set i $tabs(next_result_id) + incr tabs(next_result_id) + set id "results$i" + set frame [$widgets(results) insert end "$id" -text "Results $i"] + $widgets(results) raise $id + set tabs($id) [Apol_Widget::makeSearchResults $frame.results] + pack $tabs($id) -expand 1 -fill both + + set tabs($id:vals) [array get vals] + return $tabs($id) +} + + +proc Apol_Constraint::_switch_to_tab {pageID} { + variable vals + variable widgets + variable tabs + + # check if switching to already visible tab + if {[$Apol_Constraint::widgets(results) raise] == $pageID} { + return + } + $widgets(results) raise $pageID + set cur_search_opts [$widgets(search_opts) raise] + + # restore the tab's search criteria + array set tmp_vals $tabs($pageID:vals) + set classes_selected $tmp_vals(cp:classes_selected) + set perms_selected $tmp_vals(cp:perms_selected) + array set vals $tabs($pageID:vals) + _initializeWidgets + set vals(cp:classes_selected) $classes_selected + set vals(cp:perms_selected) $perms_selected + foreach c $classes_selected { + $widgets(cp:classes) selection set [lsearch $vals(cp:classes) $c] + } + foreach p $perms_selected { + $widgets(cp:perms) selection set [lsearch $vals(cp:perms) $p] + } + $widgets(search_opts) raise $cur_search_opts +} + + +proc Apol_Constraint::_reset {} { + variable enabled + + set old_classes_enabled $enabled(cp:classes) + _initializeVars + _initializeWidgets + if {[set enabled(cp:classes) $old_classes_enabled]} { + variable vals + set vals(cp:classes) [Apol_Class_Perms::getClasses] + set enabled(cp:classes) 1 + set enabled(cp:perms) 1 + } +} + +# This is the main constraint search option +proc Apol_Constraint::_search_constraints {whichButton} { + variable vals + variable widgets + variable enabled + variable tabs + variable statement_count + + if {![ApolTop::is_policy_open]} { + tk_messageBox -icon error -type ok -title "Constraint Search" \ + -message "No current policy file is opened." + return + } + + if { $vals(rs:constrain_enabled) == 0 && \ + $vals(rs:mlsconstrain_enabled) == 0 && \ + $vals(rs:validatetrans_enabled) == 0 && \ + $vals(rs:mlsvalidatetrans_enabled) == 0 } { + tk_messageBox -icon error -type ok -title "Constraint Search" \ + -message "At least one constraint must be selected." + return + } + + if {$whichButton == "new"} { + set sr [_create_new_results_tab] + } else { + set id [$widgets(results) raise] + set tabs($id:vals) [array get vals] + set sr $tabs($id) + Apol_Widget::clearSearchResults $sr + } + + if {$enabled(kta:use_left_expr) && $vals(kta:use_left_expr) && $vals(kta:left_expr) == {}} { + tk_messageBox -icon error -type ok -title "Constraint Search" -message "No left keyword has been selected." + return + } + if {$enabled(kta:use_right_expr) && $vals(kta:use_right_expr) && $vals(kta:right_expr) == {}} { + tk_messageBox -icon error -type ok -title "Constraint Search" -message "No right keyword, type or attribute has been selected." + return + } + + set results {} + set header {} + + # Check if the statements are enabled for mls/constrain and then get info + if { $vals(rs:constrain_enabled) == 1 } { + append results [Apol_Constraint::_searchForMatch "constrain" "constrain" new_apol_constraint_query_t] + append header "$statement_count constrain rules match the search criteria.\n" + } + if { $vals(rs:mlsconstrain_enabled) == 1 } { + append results [Apol_Constraint::_searchForMatch "mlsconstrain" "constrain" new_apol_constraint_query_t] + append header "$statement_count mlsconstrain rules match the search criteria.\n" + } + + # Check if the statements are enabled for mls/validatetrans and then get info + if { $vals(rs:validatetrans_enabled) == 1 } { + append results [Apol_Constraint::_searchForMatch "validatetrans" "validatetrans" new_apol_validatetrans_query_t] + append header "$statement_count validatetrans rules match the search criteria.\n" + } + if { $vals(rs:mlsvalidatetrans_enabled) == 1 } { + append results [Apol_Constraint::_searchForMatch "mlsvalidatetrans" "validatetrans" new_apol_validatetrans_query_t] + append header "$statement_count mlsvalidatetrans match the search criteria.\n" + } + + + foreach x {new update reset} { + $widgets($x) configure -state disabled + } + + Apol_Widget::appendSearchResultText $sr "$header\n" + Apol_Widget::appendSearchResultText $sr $results + + $widgets(new) configure -state normal + $widgets(reset) configure -state normal + if {[$widgets(results) pages] != {} || $retval == 0} { + $widgets(update) configure -state normal + } + return +} + + +# Start here to process constraints +proc Apol_Constraint::_searchForMatch {statement family command} { + variable vals + variable widgets + variable enabled + variable match_right_type_names + variable statement_count + + set statement_count 0 + set entries {} + + set q [$command] + # This reads in the constraint info + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete + + # This loop will process each constraint in the policy + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set constrain_type {} + set perm_list {} + set class_list {} + set expr_type {} + set op {} + set sym_type {} + + # These are used to check if the search criteria has been met when + # the left or right expression info has been set. + set match_left_keyword_names 0 + set match_left_keyword_attr 0 + set match_right_keyword_attr 0 + set match_right_type_names 0 + + set q [qpol_constraint_from_void [$v get_element $i]] + + # Find if this is an mls rule or not + set x [$q get_expr_iter $::ApolTop::qpolicy] + while {![$x end]} { + foreach t [iter_to_list $x] { + set t [qpol_constraint_expr_node_from_void $t] + # Get Symbol type and save it + set sym_type [$t get_sym_type $::ApolTop::qpolicy] + if { $sym_type >= $::QPOL_CEXPR_SYM_L1L2 } { + set constrain_type "mls" + break + } + } + } + append constrain_type $family + $x -acquire + $x -delete + + # Check if the statement is the requested type + if { $statement != $constrain_type } { + continue + } + + # This gets the class name + set match_class 0 + append class_list "\{ " + set class_name [[$q get_class $::ApolTop::qpolicy] get_name $::ApolTop::qpolicy] + append class_list $class_name + append class_list " \}" + + # Check if class selected + if {($enabled(cp:classes) && $vals(cp:classes_selected) > 0)} { + foreach c $vals(cp:classes_selected) { + if { $c == $class_name } { + set match_class 1 + } + } + } + # Skip this constraint if it does not match criteria + if {($match_class == 0 && $vals(cp:classes_selected) > 0)} { + continue + } + + # validatetrans does not use permissions + if { $family == "constrain" } { + # This gets perm list: + set x [$q get_perm_iter $::ApolTop::qpolicy] + set match_perm 0 + append perm_list "\{ " + foreach perm [iter_to_str_list $x] { + append perm_list "$perm " + # Check if perm selected + if {($enabled(cp:perms) && $vals(cp:perms_selected) > 0)} { + foreach c $vals(cp:perms_selected) { + if { $c == $perm } { + set match_perm 1 + } + } + } + } + # Skip this constraint as it does not match criteria + if {($match_perm == 0 && $vals(cp:perms_selected) > 0)} { + continue + } + append perm_list "\}" + $x -acquire + $x -delete + } + + # This get expressions + set x [$q get_expr_iter $::ApolTop::qpolicy] + + # This contains the number of constraint expr's processed. + set constraint_expr_counter 0 + # This is the constraint_expr buffer that is indexed by the + # $constraint_expr_counter + set array constraint_expr_buf($constraint_expr_counter) + array unset constraint_expr_buf + + # This loop will process each part of the expression consisting of: + # Operators: !, &&, ||. The ! applies only to an operand. + # Operands/expressions such as: (r1 == r2), (t1 != name) + while {![$x end]} { + foreach t [iter_to_list $x] { + set t [qpol_constraint_expr_node_from_void $t] + + # Get Operator and save it + set op [$t get_op $::ApolTop::qpolicy] + + # Get Symbol type and save it + set sym_type [$t get_sym_type $::ApolTop::qpolicy] + + # Get expression and save it + set expr_type [$t get_expr_type $::ApolTop::qpolicy] + + # Now check expression for entry type !, && or ||. + # These are the operators between constraint expressions + if { $expr_type == $::QPOL_CEXPR_TYPE_NOT } { + set constraint_expr_counter [expr $constraint_expr_counter + 1] + append constraint_expr_buf($constraint_expr_counter) "not" + } + + if { $expr_type == $::QPOL_CEXPR_TYPE_AND } { + set constraint_expr_counter [expr $constraint_expr_counter + 1] + append constraint_expr_buf($constraint_expr_counter) "and" + } + + if { $expr_type == $::QPOL_CEXPR_TYPE_OR } { + set constraint_expr_counter [expr $constraint_expr_counter + 1] + append constraint_expr_buf($constraint_expr_counter) "or" + } + + # If the expression is TYPE_ATTR then it's form is (t1 == t2) + if { $expr_type == $::QPOL_CEXPR_TYPE_ATTR } { + set constraint_expr_counter [expr $constraint_expr_counter + 1] + + # Get the symbol name, this will be used twice, once + # to retrieve the string name for source entry, then + # the string name for the target entry. + set sym_name [Apol_Constraint::_getSym $sym_type] + append constraint_expr_buf($constraint_expr_counter) "( $sym_name " + + # Check if keyword selected + if {$vals(kta:use_left_expr) == 1 && $vals(kta:left_expr) == $sym_name} { + set match_left_keyword_attr 1 + } + + # Get the operator and change to "eq" if required + set op [$t get_op $::ApolTop::qpolicy] + set op_name [Apol_Constraint::_getOp $op] + if { $op_name == "==" && \ + ([string compare -length 1 $sym_name "r"] == 0 || \ + [string compare -length 1 $sym_name "l"] == 0 || \ + [string compare -length 1 $sym_name "h"] == 0) } { + set op_name "eq" + } + append constraint_expr_buf($constraint_expr_counter) $op_name + + # Then using the sym_name again, get the target entry. + set sym_type [expr $sym_type | $::QPOL_CEXPR_SYM_TARGET] + set sym_name [Apol_Constraint::_getSym $sym_type] + append constraint_expr_buf($constraint_expr_counter) " $sym_name )" + + # Check if keyword selected + if {$vals(kta:use_right_expr) == 1 && \ + $vals(kta:right_expr) == $sym_name && \ + $vals(kta:right_expr,right_keyword) == 1} { + set match_right_keyword_attr 1 + } + } + + # If the expression is TYPE_NAMES then expand the source + # types or attributes using 'get_names_iter' + # Example entries: ( t1 == mlstrustedobject ) + # ( t1 != { unconfined_t init_t } ) + # Note that if an attribute has been selected it could be + # an empty_set. + if { $expr_type == $::QPOL_CEXPR_TYPE_NAMES } { + set constraint_expr_counter [expr $constraint_expr_counter + 1] + + # Get the symbol name, this is only used once to + # to retrieve the string name for source entry. + set sym_name [Apol_Constraint::_getSym $sym_type] + append constraint_expr_buf($constraint_expr_counter) "( $sym_name " + + # Check if keyword selected + if {$vals(kta:use_left_expr) == 1 && \ + $vals(kta:left_expr) == $sym_name} { + set match_left_keyword_names 1 + } + + set op [$t get_op $::ApolTop::qpolicy] + set op_name [Apol_Constraint::_getOp $op] + append constraint_expr_buf($constraint_expr_counter) $op_name + + # Need to get the number of entries. These can be + # type or attribute identifiers. + set tmp_list {} + set return_list {} + set n [$t get_names_iter $::ApolTop::qpolicy] + set n_size [[$t get_names_iter $::ApolTop::qpolicy] get_size] + + # If > 0 then put entries in a tmp_list for later processing. + if { $n_size > 0 } { + foreach name [iter_to_str_list $n] { + append tmp_list "$name " + } + # + # Now check search parameters for the $name entries of + # the right side of the expression. The $tmp_list can + # contain user, role, type or type attribute names + # depending on the initial letter of $sym_name. + # + if { ([string compare -length 1 $sym_name "t"] == 0 && \ + $vals(kta:use_right_expr) == 1) && \ + ($vals(kta:right_expr,types) == 1 || \ + $vals(kta:right_expr,attribs) == 1) } { + # This calls type and attribute processing: + set tmp_list [Apol_Constraint::_process_TA $vals(kta:right_expr) $tmp_list] + } elseif { ($vals(kta:use_right_expr) == 1 && \ + $vals(kta:right_expr,roles) == 1 && \ + [string compare -length 1 $sym_name "r"] == 0) || \ + ($vals(kta:use_right_expr) == 1 && \ + $vals(kta:right_expr,users) == 1 && \ + [string compare -length 1 $sym_name "u"] == 0) } { + foreach c $tmp_list { + if { $c == $vals(kta:right_expr) } { + set match_right_type_names 1 + set tmp_list $name + continue + } + } + } + # else if size == 0 then just say an empty set. Also + # check if the requested attribute is an empty set. + } elseif { $n_size == 0 } { + set tmp_list "<empty_set>" + if { [Apol_Constraint::_checkIfEmptyAttr $vals(kta:right_expr)] && \ + [string compare -length 1 $sym_name "t"] == 0 } { + set match_right_type_names 1 + } + } + + # Copy tmp_list to the constraint buffer. + if { [llength $tmp_list] > 1 } { + append constraint_expr_buf($constraint_expr_counter) " \{ $tmp_list\} )" + } else { + append constraint_expr_buf($constraint_expr_counter) " $tmp_list )" + } + $n -acquire + $n -delete + } + } + } + $x -acquire + $x -delete + # Done with processing all the expressions, now check if they + # were enabled or not and valid search entries found. + if {($vals(kta:use_left_expr) == 1 && $vals(kta:use_right_expr) == 1) && \ + [expr (($match_left_keyword_names | $match_left_keyword_attr) & \ + ($match_right_keyword_attr | $match_right_type_names))] == 0} { + continue + } + + if {($vals(kta:use_left_expr) == 1 && $vals(kta:use_right_expr) == 0) && \ + [expr $match_left_keyword_names | $match_left_keyword_attr] == 0} { + continue + } + + if {($vals(kta:use_left_expr) == 0 && $vals(kta:use_right_expr) == 1) && \ + ($vals(kta:right_expr,users) == 1 || \ + $vals(kta:right_expr,roles) == 1 || \ + $vals(kta:right_expr,attribs) == 1 || \ + $vals(kta:right_expr,types) == 1 || \ + $vals(kta:right_expr,right_keyword) == 1) && \ + [expr $match_right_type_names | $match_right_keyword_attr ] == 0} { + continue + } + + # + # This takes each entry in the RPN formatted constraint_expr_buf and + # converts to infix format that resembles the constraint string in + # policy language format. It is a modified version from: + # http://rosettacode.org/wiki/Parsing/RPN_to_infix_conversion + # + set stack {} + foreach entry [lsort -integer [array names constraint_expr_buf]] { + set token $constraint_expr_buf($entry) + switch $token { + "not" - "and" - "or" { + lassign [Apol_Constraint::_pop stack] expr2rec expr2 + # The ! is not treated the same as && || as it only + # applies to a single expression i.e. !(expression) + # So just pop the stack and add the !. Should there be + # another ! in the expression, then add brackets. + if { $token == "not" } { + set ans [string compare -length 1 $expr2 "not"] + if { $ans == 0 } { + lappend stack [list 1 "$token \($expr2\)"] + } else { + lappend stack [list 1 "$token$expr2"] + } + continue + } else { + lassign [Apol_Constraint::_pop stack] expr1rec expr1 + lappend stack [list 1 "$expr1 $token $expr2"] + } + } + default { + lappend stack [list 2 $token] + } + } + } + if { [array size constraint_expr_buf] == 1 } { + set expression "[lindex $stack end 1];" + } else { + set expression "([lindex $stack end 1]);" + } + set statement_count [expr $statement_count + 1] + append entries "$constrain_type $class_list $perm_list" "\n $expression\n\n" + } + return $entries +} + +######### End of search routine - Start supporting procs ################ + +# The pop stack routine for RPN conversion +proc Apol_Constraint::_pop {stk} { + upvar 1 $stk s + set val [lindex $s end] + set s [lreplace $s end end] + return $val +} + + +# Take an attribute name and expands it to a list of types. +proc Apol_Constraint::_renderAttrib {attrib_name} { + set type_list {} + set qpol_type_datum [new_qpol_type_t $::ApolTop::qpolicy $attrib_name] + set i [$qpol_type_datum get_type_iter $::ApolTop::qpolicy] + foreach t [iter_to_list $i] { + set t [qpol_type_from_void $t] + lappend type_list [$t get_name $::ApolTop::qpolicy] + } + if { $type_list == "" } { + lappend type_list "<empty_set>" + } + $i -acquire + $i -delete + return $type_list +} + + +# This will return a list of attributes linked to the type_name +proc Apol_Constraint::_renderType {type_name} { + set qpol_type_datum [new_qpol_type_t $::ApolTop::qpolicy $type_name] + set aliases {} + set attribs {} + + set i [$qpol_type_datum get_alias_iter $::ApolTop::qpolicy] + set aliases [iter_to_str_list $i] + $i -acquire + $i -delete + + set i [$qpol_type_datum get_attr_iter $::ApolTop::qpolicy] + foreach a [iter_to_list $i] { + set a [qpol_type_from_void $a] + lappend attribs [$a get_name $::ApolTop::qpolicy] + } + $i -acquire + $i -delete + return $attribs +} + + +# Check if the name is a type or attribute. +proc Apol_Constraint::_checkTypeOrAttr {name} { + set type_list {} + + set qpol_type_datum [new_qpol_type_t $::ApolTop::qpolicy $name] + set x [$qpol_type_datum get_isattr $::ApolTop::qpolicy ] + if { $x == 1 } { + return "attribute" + } else { + return "type" + } + $x -acquire + $x -delete +} + + +# Return Left or Right expr keywords +proc Apol_Constraint::_getKeywords {side command} { + set list {} + set left_list {} + set right_list {} + + set q [$command] + # This reads in the constraint info + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete + + # This loop will process each constraint in the policy + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set expr_type {} + set sym_type {} + set q [qpol_constraint_from_void [$v get_element $i]] + + # This get expressions + set x [$q get_expr_iter $::ApolTop::qpolicy] + while {![$x end]} { + foreach t [iter_to_list $x] { + set t [qpol_constraint_expr_node_from_void $t] + set sym_type [$t get_sym_type $::ApolTop::qpolicy] + set expr_type [$t get_expr_type $::ApolTop::qpolicy] + + if { $expr_type == $::QPOL_CEXPR_TYPE_ATTR } { + set sym_name [Apol_Constraint::_getSym $sym_type] + append left_list "$sym_name " + # Then using the sym_name again, get the target entry. + set sym_type [expr $sym_type | $::QPOL_CEXPR_SYM_TARGET] + set sym_name [Apol_Constraint::_getSym $sym_type] + append right_list "$sym_name " + } + + if { $expr_type == $::QPOL_CEXPR_TYPE_NAMES } { + set sym_name [Apol_Constraint::_getSym $sym_type] + append left_list "$sym_name " + } + } + } + $x -acquire + $x -delete + + if {$side == "l"} { + append list $left_list + } else { + append list $right_list + } + } + $v -acquire + $v -delete + return $list +} + + +# +# Here because a type or type_attribute search has been actioned, so: +# 1) If type and processing type and it matches, set $match_right_type_names = 1. +# If an attribute and direct == 0 then expand attribute to check for +# the type. If the type is found set $match_right_type_names = 1. +# +# 2) If attribute and processing attribute check if it matches. If it +# does then set $match_right_type_names = 1. +# If type found and direct == 0 then check if type is associated with +# the attribute. If so, then set $match_right_type_names = 1. +# +proc Apol_Constraint::_process_TA {name search_list} { + variable match_right_type_names + variable vals + + # If type search & direct == 0: + if { $vals(kta:right_expr,types) == 1 && \ + $vals(kta:right_expr_direct) == 0 } { + foreach ta $search_list { + if { [Apol_Constraint::_checkTypeOrAttr $ta] == "type" && \ + $ta == $name } { + set match_right_type_names 1 + return $search_list + } elseif { [Apol_Constraint::_checkTypeOrAttr $ta] == "attribute" } { + #This returns a set of types associated to the attribute: + set type_list [Apol_Constraint::_renderAttrib $ta] + foreach t $type_list { + if { $t == $name } { + set match_right_type_names 1 + return $search_list + } + } + } + } + } elseif { $vals(kta:right_expr,types) == 1 && \ + $vals(kta:right_expr_direct) == 1 } { + foreach ta $search_list { + if { $ta == $name } { + set match_right_type_names 1 + return $search_list + } + } + } + + # If attribute search & direct == 0: + if { $vals(kta:right_expr,attribs) == 1 && \ + $vals(kta:right_expr_direct) == 0 && \ + $vals(kta:right_expr_replace_types) == 0} { + foreach ta $search_list { + if { [Apol_Constraint::_checkTypeOrAttr $ta] == "attribute" && \ + $ta == $name } { + set match_right_type_names 1 + return $search_list + } elseif { [Apol_Constraint::_checkTypeOrAttr $ta] == "type" } { + # This returns a set of attributes associated to the type: + set attr_list [Apol_Constraint::_renderType $ta] + foreach a $attr_list { + if { $a == $name } { + set match_right_type_names 1 + return $search_list + } + } + } + } + } elseif { $vals(kta:right_expr,attribs) == 1 && \ + $vals(kta:right_expr_direct) == 1 } { + foreach ta $search_list { + if { $ta == $name } { + set match_right_type_names 1 + return $search_list + } + } + } elseif { $vals(kta:right_expr,attribs) == 1 && \ + $vals(kta:right_expr_direct) == 0 && \ + $vals(kta:right_expr_replace_types) == 1 } { + # Check if all the types in the list match. _checkTypes will set + # $match_right_type_names 1 if there is a match. + set search_list [Apol_Constraint::_checkTypes $name $search_list] + } + return $search_list +} + + +# +# att_name contains the attribute and type_list contains a list of types +# from the constraint expression. +# The routine will check the types against the $attr_to_type_list and +# returns either the types unchanged, or an attribute to replace the +# matching types + any remaining types. +# +proc Apol_Constraint::_checkTypes {att_name type_list} { + variable match_right_type_names + set attr_to_type_list {} + set types {} + set return_list {} + + # If an empty set then set match to display all empty sets as there + # is no way to know which attribute set this. + if { $type_list == "<empty_set>" } { + set match_right_type_names 1 + return $type_list + } + + # The $name matches an attribute in list so just return list + if {[lsearch -exact $type_list $att_name] >= 0} { + set match_right_type_names 1 + return $type_list + } + + # If not empty find the list of types for this attribute + append items [Apol_Types::getAttributes] + foreach c $items { + if { $c == $att_name } { + # Now get the list of types from the attribute + set attr_to_type_list [Apol_Constraint::_renderAttrib $c] + continue + } + } + + if { [llength $type_list] < [llength $attr_to_type_list] } { + return $type_list + } + + set return_list "$att_name " + set list_count [llength $attr_to_type_list] + + if { [llength $type_list] > [llength $attr_to_type_list] } { + foreach al $type_list { + set result [lsearch -exact -ascii $attr_to_type_list $al] + if { $result == -1} { + append return_list "$al " + } else { + set list_count [expr $list_count - 1] + } + } + } else { + foreach al $attr_to_type_list { + set result [lsearch -exact -ascii $type_list $al] + if { $result == -1} { + append return_list "$al " + } else { + set list_count [expr $list_count - 1] + } + } + } + + if { $list_count != 0 } { + return $type_list + } else { + set match_right_type_names 1 + return $return_list + } +} + + +# If the requested search attribute is empty return true. +proc Apol_Constraint::_checkIfEmptyAttr {entry} { + variable vals + + set attr_to_type_list {} + if { $vals(kta:right_expr,attribs) == 1 && \ + $vals(kta:right_expr_direct) == 0 && \ + $vals(kta:right_expr_replace_types) == 1 } { + append items [Apol_Types::getAttributes] + foreach c $items { + if { $c == $entry } { + # Now get the list of types from the attribute + set attr_to_type_list [Apol_Constraint::_renderAttrib $c] + continue + } + } + } + if { $attr_to_type_list == "<empty_set>"} { + return 1 + } + return 0 +} + + +# Get symbol from expression +proc Apol_Constraint::_getSym {sym_type} { + set symbol {} + + # These are source for mls/constrain and old for mls/validatetrans + if { $sym_type == $::QPOL_CEXPR_SYM_USER } { + append symbol "u1" + } + if { $sym_type == $::QPOL_CEXPR_SYM_ROLE } { + append symbol "r1" + } + if { $sym_type == $::QPOL_CEXPR_SYM_TYPE } { + append symbol "t1" + } + + # These are target for mls/constrain and new for mls/validatetrans + if { $sym_type == $::QPOL_CEXPR_SYM_USER+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "u2" + } + if { $sym_type == $::QPOL_CEXPR_SYM_ROLE+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "r2" + } + if { $sym_type == $::QPOL_CEXPR_SYM_TYPE+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "t2" + } + # These are source for mls/validatetrans + if { $sym_type == $::QPOL_CEXPR_SYM_USER+$::QPOL_CEXPR_SYM_XTARGET } { + append symbol "u3" + } + if { $sym_type == $::QPOL_CEXPR_SYM_ROLE+$::QPOL_CEXPR_SYM_XTARGET } { + append symbol "r3" + } + if { $sym_type == $::QPOL_CEXPR_SYM_TYPE+$::QPOL_CEXPR_SYM_XTARGET } { + append symbol "t3" + } + + # Source levels for mlsconstrain and mlsvalidatetrans + if { $sym_type == $::QPOL_CEXPR_SYM_L1L2 } { + append symbol "l1" + } + if { $sym_type == $::QPOL_CEXPR_SYM_L1H2 } { + append symbol "l1" + } + if { $sym_type == $::QPOL_CEXPR_SYM_H1L2 } { + append symbol "h1" + } + if { $sym_type == $::QPOL_CEXPR_SYM_H1H2 } { + append symbol "h1" + } + if { $sym_type == $::QPOL_CEXPR_SYM_L1H1 } { + append symbol "l1" + } + if { $sym_type == $::QPOL_CEXPR_SYM_L2H2 } { + append symbol "l2" + } + + # Target levels for mlsconstrain and mlsvalidatetrans + if { $sym_type == $::QPOL_CEXPR_SYM_L1L2+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "l2" + } + if { $sym_type == $::QPOL_CEXPR_SYM_L1H2+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "h2" + } + if { $sym_type == $::QPOL_CEXPR_SYM_H1L2+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "l2" + } + if { $sym_type == $::QPOL_CEXPR_SYM_H1H2+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "h2" + } + if { $sym_type == $::QPOL_CEXPR_SYM_L1H1+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "h1" + } + if { $sym_type == $::QPOL_CEXPR_SYM_L2H2+$::QPOL_CEXPR_SYM_TARGET } { + append symbol "h2" + } + if { $symbol == "" } { + append symbol "err_sym_missing" + } + return $symbol +} + + +# Get Operator +proc Apol_Constraint::_getOp {op} { + set entry {} + + if { $op == $::QPOL_CEXPR_OP_EQ } { + append entry "==" + } + if { $op == $::QPOL_CEXPR_OP_NEQ } { + append entry "!=" + } + if { $op == $::QPOL_CEXPR_OP_DOM } { + append entry "dom" + } + if { $op == $::QPOL_CEXPR_OP_DOMBY } { + append entry "domby" + } + if { $op == $::QPOL_CEXPR_OP_INCOMP } { + append entry "incomp" + } + if { $entry == "" } { + append entry "op_missing" + } + return $entry +} diff --git a/apol/top.tcl b/apol/top.tcl index e0f87a3..f8f4442 100644 --- a/apol/top.tcl +++ b/apol/top.tcl @@ -70,6 +70,7 @@ namespace eval ApolTop { {Apol_FSContexts components {}} {Apol_TE rules {tag_query_saveable}} {Apol_Cond_Rules rules {tag_conditionals}} + {Apol_Constraint rules {tag_query_saveable}} {Apol_RBAC rules {}} {Apol_Range rules {tag_mls}} {Apol_File_Contexts {} {}} @@ -457,6 +458,8 @@ proc ApolTop::_toplevel_update_stats {} { "sens" get_level_iter "cats" get_cat_iter "range_trans" get_range_trans_iter + "constraints" get_constraint_iter + "validatetrans" get_validatetrans_iter "sids" get_isid_iter "portcons" get_portcon_iter @@ -518,6 +521,21 @@ proc ApolTop::_toplevel_update_stats {} { $i -delete } + # Determine number of mlsconstrain and mlsvalidatetrans rules and + # recalculate the numbers accordingly. + if {[ApolTop::is_capable "mls"]} { + set mlsconstrain_count [ApolTop::_get_mls_count new_apol_constraint_query_t] + set policy_stats(constraints) [expr $policy_stats(constraints) - $mlsconstrain_count] + set policy_stats(mlsconstraints) $mlsconstrain_count + + set mlsvalidatetrans_count [ApolTop::_get_mls_count new_apol_validatetrans_query_t] + set policy_stats(validatetrans) [expr $policy_stats(validatetrans) - $mlsvalidatetrans_count] + set policy_stats(mlsvalidatetrans) $mlsvalidatetrans_count + } else { + set policy_stats(mlsconstraints) 0 + set policy_stats(mlsvalidatetrans) 0 + } + set policy_stats_summary "" append policy_stats_summary "Classes: $policy_stats(classes) " append policy_stats_summary "Perms: $policy_stats(perms) " @@ -762,12 +780,18 @@ proc ApolTop::_show_policy_summary {} { "Number of Booleans" { "Booleans" bools } + "Number of Constraints" { + "constrain" constraints + "validatetrans" validatetrans + } "Number of MLS Components" { "Sensitivities" sens "Categories" cats } "Number of MLS Rules" { "range_transitions" range_trans + "mlsconstrain" mlsconstraints + "mlsvalidatetrans" mlsvalidatetrans } "Number of Initial SIDs" { "SIDs" sids @@ -1071,6 +1095,41 @@ proc ApolTop::_write_configuration_file {} { close $f } +# This will work out how many mlsconstrain and mlsvalidatetrans rules +# there are as the get_iter numbers are overall count. +proc ApolTop::_get_mls_count {command} { + + set q [$command] + # This reads in the constraint info + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete + + set mls_count 0 + + # This loop will process each constraint in the policy + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set q [qpol_constraint_from_void [$v get_element $i]] + + # Find if this is an mls rule or not + set x [$q get_expr_iter $::ApolTop::qpolicy] + while {![$x end]} { + foreach t [iter_to_list $x] { + set t [qpol_constraint_expr_node_from_void $t] + # Get Symbol type + set sym_type [$t get_sym_type $::ApolTop::qpolicy] + if { $sym_type >= $::QPOL_CEXPR_SYM_L1L2 } { + set mls_count [expr $mls_count + 1] + break + } + } + } + $x -acquire + $x -delete + } + return $mls_count +} + ####################################################### # Start script here -- 1.7.7.6 -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message.