diff --git a/ChangeLog b/ChangeLog index df377ce7..2b62689c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2014-04-14 Richard Haines + + * Updates to apol and the libapol/libqpol libraries to support + new policy statements and rules to version 29 (Note the features + for loading source code (policy.conf etc.) have not been updated + to support the new statements and rules. + These are the enhancements and bug fixes: + * Add permissive type and typebound support to Types tab. + * Add new Constraints tab to search all constraint statements. + * Add new Bounds tab to search for userbound, rolebound and + typebound statements. + * Add new policy capabilities tab. + * Add filename type_transition support on TE Rules tab. + * Add new Default Object tab to support defaultuser, defaultrole, + defaulttype and defaultrange rules. + * Add new Namespaces tab to list CIL namespaces. This will also + show any users, roles, types, classes, booleans, sensitivities + and categories declared in each namespace. + * Update Query/Policy Summary page to show the number of new + rules added plus the policy handle_unknown flag. + * Fixed File Contexts tab to stop hang when building the fc + index when broken links/files found (libsefs). + * Fixed Booleans tab to display CIL namespace booleans. + * Updated apol_help.txt to reflect the changes made plus how to + load the running policy. + 2014-01-16 Chris PeBenito * Fix bug preventing sediffx from starting. diff --git a/apol/Makefile.am b/apol/Makefile.am index 5b64d7db..4fc5562d 100644 --- a/apol/Makefile.am +++ b/apol/Makefile.am @@ -35,6 +35,7 @@ EXTRA_DIST = \ constraints_tab.tcl \ context_dialog.tcl \ context_selector.tcl \ + default_objects_tab.tcl \ directflow_module.tcl \ domaintrans_module.tcl \ file_contexts_tab.tcl \ @@ -45,6 +46,7 @@ EXTRA_DIST = \ initial_sids_tab.tcl \ level_dialog.tcl \ mls_tab.tcl \ + namespaces_tab.tcl \ netcontexts_tab.tcl \ open_policy_dialog.tcl \ perms_map.tcl \ diff --git a/apol/apol_help.txt b/apol/apol_help.txt index 0ff674fa..1ed5a9e6 100644 --- a/apol/apol_help.txt +++ b/apol/apol_help.txt @@ -29,7 +29,7 @@ not report line numbers when searching monolithic binary polices. Apol provides compatibility with the current and previous policy syntax. It supports analysis of monolithic policy versions 12 to the -current version 21 and modular policy versions 5 and 6. +current version 29 and modular policy versions to 17. See setools/ChangeLog for a list of new features in this release. See setools/KNOWN_BUGS for a list of current bugs. @@ -40,7 +40,12 @@ Menus Use 'Open' from the File menu to open a valid policy. The policy may be monolithic or be composed of a base linked with multiple modules. Only one policy can be open at a time; opening a second policy will -result in the first being closed. +result in the first being closed. Note: If the kernel supports reading +the currently loaded policy, then select "monolithic" and set the +"Policy filename" path to either: + /selinux/policy + or + /sys/fs/selinux/policy The Query menu allows the user to save or load a query for a TE Rules search or for an analysis module listed on the Analysis tab. Saving a @@ -85,6 +90,8 @@ relate the core components of an SELinux policy. to search for types and/or attributes using a POSIX-style regular expression. + Permissive and bound types may also be searched. + Classes/Perms tab ----------------- Use the Classes/Perms tab to view and search object classes, common @@ -149,6 +156,23 @@ relate the core components of an SELinux policy. Select the FS Contexts tab to search filesystem-based contexts (fs_use_ and genfscon statements) defined in the policy. + Policy Capabilities tab + --------------- + Select the Policy Capabilities tab to display policy capabilities + defined in the policy. + + Policy Namespaces tab + --------------- + Select the Policy Namespaces tab to display the namespaces defined + in the policy. For policies with a single namespace there will be + one namespace displayed: "GLOBAL-NS". For policies that can define + multiple namespaces (e.g CIL), all namespaces will be displayed + including "GLOBAL-NS". + If the namespace entry is double clicked then a list of Users, Roles, + Types, Attributes, Classes and Booleans applicable to that namespace + will be displayed (also if MLS enabled the Sensitivities and + Categories will also be shown). + Policy Rules tabs ----------------- @@ -326,13 +350,18 @@ rules in a policy based on selected search criteria. Range Transition Rules tab -------------------------- - Select the Range Transition Rules tab to search to search + Select the Range Transition Rules tab to search for range_transition rules by source and target types and by the MLS range. There are three options when searching for ranges; find exact matches to the entered range, find rules that have ranges that contain the entered range, or find rules that have ranges within the entered range. + Bounds Rules tab + -------------------------- + Select the Bounds Rules tab to search for userbound, rolebound or + typebound rules by parent or child types. + File Contexts tab ----------------- diff --git a/apol/bounds_tab.tcl b/apol/bounds_tab.tcl index 73e32ac7..906eaded 100644 --- a/apol/bounds_tab.tcl +++ b/apol/bounds_tab.tcl @@ -95,7 +95,6 @@ proc Apol_Bounds::close {} { proc Apol_Bounds::getTextWidget {} { variable widgets -# return $widgets(results).tb } #### private functions below #### @@ -237,7 +236,6 @@ proc Apol_Bounds::_toggleCheckbutton {cb w name1 name2 ops} { } } - # callback invoked when the user changes which Bounds rule to search proc Apol_Bounds::_ruleChanged {name1 name2 ops} { variable vals @@ -256,7 +254,6 @@ proc Apol_Bounds::_searchBounds {} { return } - if {$vals(rule_selection) == "user"} { Apol_Bounds::_searchUserBounds return diff --git a/apol/default_objects_tab.tcl b/apol/default_objects_tab.tcl new file mode 100644 index 00000000..6cf764b9 --- /dev/null +++ b/apol/default_objects_tab.tcl @@ -0,0 +1,370 @@ +# 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_DefaultObjects { + variable vals + variable widgets + variable mls_enabled {0} + variable statement_count +} + +proc Apol_DefaultObjects::create {tab_name nb} { + variable vals + variable widgets + + _initializeVars + + set frame [$nb insert end $tab_name -text "Default Object Rules"] + set topf [frame $frame.top] + set bottomf [frame $frame.bottom] + pack $topf -expand 0 -fill both -pady 2 + pack $bottomf -expand 1 -fill both -pady 2 + + set rsbox [TitleFrame $topf.rs -ipad 30 -text "Rule Selection"] + set obox [TitleFrame $topf.opts -text "Search Options"] + set dbox [TitleFrame $bottomf.results -text "Default Object Rules Display"] + pack $rsbox -side left -expand 0 -fill both -padx 2 + pack $obox -side left -expand 1 -fill both -padx 2 + pack $dbox -expand 1 -fill both -padx 2 + + # Rule selection subframe + set rs [$rsbox getframe] + checkbutton $rs.default_user -text "default_user" -onvalue 1 -offvalue 0 \ + -variable Apol_DefaultObjects::vals(default_user_enabled) + trace add variable Apol_DefaultObjects::vals(default_user_enabled) write \ + [list Apol_DefaultObjects::_ruleChanged] + checkbutton $rs.default_role -text "default_role" -onvalue 1 -offvalue 0 \ + -variable Apol_DefaultObjects::vals(default_role_enabled) + trace add variable Apol_DefaultObjects::vals(default_role_enabled) write \ + [list Apol_DefaultObjects::_ruleChanged] + checkbutton $rs.default_type -text "default_type" -onvalue 1 -offvalue 0 \ + -variable Apol_DefaultObjects::vals(default_type_enabled) + trace add variable Apol_DefaultObjects::vals(default_type_enabled) write \ + [list Apol_DefaultObjects::_ruleChanged] + checkbutton $rs.default_range -text "default_range" -onvalue 1 -offvalue 0 \ + -variable Apol_DefaultObjects::vals(default_range_enabled) + trace add variable Apol_DefaultObjects::vals(default_range_enabled) write \ + [list Apol_DefaultObjects::_ruleChanged] + pack $rs.default_user $rs.default_role $rs.default_type $rs.default_range -side top -anchor w + + set widgets(options_pm) [PagesManager [$obox getframe].opts] + + _defaultObjectCreate [$widgets(options_pm) add default_object] + + $widgets(options_pm) compute_size + pack $widgets(options_pm) -expand 1 -fill both -side left + $widgets(options_pm) raise default_object + + set ok [button [$obox getframe].ok -text OK -width 6 -command Apol_DefaultObjects::_searchDefaultObjects] + pack $ok -side right -padx 5 -pady 5 -anchor ne + + set widgets(results) [Apol_Widget::makeSearchResults [$dbox getframe].results] + pack $widgets(results) -expand yes -fill both + + return $frame +} + +proc Apol_DefaultObjects::open {ppath} { + variable vals + variable widgets + variable mls_enabled + + if {[ApolTop::is_capable "mls"]} { + set mls_enabled 1 + } else { + set mls_enabled 0 + } + + $widgets(default_object:class) configure -values [Apol_Class_Perms::getClasses] + $widgets(default_object:default) configure -values {"source" "target"} + $widgets(default_object:range) configure -values {"low" "high" "low_high"} + + set vals(default_range_enabled) $mls_enabled + set vals(default_type_enabled) [ApolTop::is_capable "default_type"] +} + +proc Apol_DefaultObjects::close {} { + variable widgets + variable mls_enabled + + _initializeVars + $widgets(default_object:class) configure -values {} + $widgets(default_object:default) configure -values {} + $widgets(default_object:range) configure -values {} + set mls_enabled 0 +} + +proc Apol_DefaultObjects::getTextWidget {} { + variable widgets +} + +proc Apol_DefaultObjects::_initializeVars {} { + variable vals + + array set vals { + class:use 0 + class:sym {} + default:sym {} + default:use 0 + range:sym {} + range:use 0 + + default_user_enabled 1 + default_role_enabled 1 + default_type_enabled 1 + default_range_enabled 0 + } +} + +proc Apol_DefaultObjects::_defaultObjectCreate {r_c} { + variable vals + variable widgets + + set class [frame $r_c.class] + set class_cb [checkbutton $class.enable -text "Object class" \ + -variable Apol_DefaultObjects::vals(class:use)] + set widgets(default_object:class) [ComboBox $class.cb -width 20 -state disabled \ + -entrybg $ApolTop::default_bg_color \ + -textvariable Apol_DefaultObjects::vals(class:sym)] + + trace add variable Apol_DefaultObjects::vals(class:use) write \ + [list Apol_DefaultObjects::_toggleCheckbutton $widgets(default_object:class) {}] + pack $class_cb -side top -anchor w + pack $widgets(default_object:class) -side top -expand 0 -fill x -padx 4 + pack $class -side left -padx 4 -pady 2 -expand 0 -anchor nw + + set default [frame $r_c.default] + set widgets(default_object:default_cb) [checkbutton $default.enable -text "Default" \ + -variable Apol_DefaultObjects::vals(default:use)] + set widgets(default_object:default) [ComboBox $default.cb -width 20 -state disabled \ + -entrybg $ApolTop::default_bg_color \ + -textvariable Apol_DefaultObjects::vals(default:sym)] + trace add variable Apol_DefaultObjects::vals(default:use) write \ + [list Apol_DefaultObjects::_toggleCheckbutton $widgets(default_object:default) {}] + pack $widgets(default_object:default_cb) -side top -anchor w + pack $widgets(default_object:default) -side top -expand 0 -fill x -padx 4 + pack $default -side left -padx 4 -pady 2 -expand 0 -fill y + + set range [frame $r_c.range] + set widgets(default_object:range_cb) [checkbutton $range.enable -text "Range" \ + -variable Apol_DefaultObjects::vals(range:use)] + set widgets(default_object:range) [ComboBox $range.cb -width 20 -state disabled \ + -entrybg $ApolTop::default_bg_color \ + -textvariable Apol_DefaultObjects::vals(range:sym)] + trace add variable Apol_DefaultObjects::vals(range:use) write \ + [list Apol_DefaultObjects::_toggleCheckbutton $widgets(default_object:range) {}] + pack $widgets(default_object:range_cb) -side top -anchor w + pack $widgets(default_object:range) -side top -expand 0 -fill x -padx 4 + pack $range -side left -padx 4 -pady 2 -expand 0 -fill y +} + +proc Apol_DefaultObjects::_toggleCheckbutton {cb w name1 name2 ops} { + variable vals + variable mls_enabled + + if {$name2 == "range:use" && $mls_enabled == 0 || $vals(default_range_enabled) == 0} { + set vals(range:use) 0 + $cb configure -state disabled + } + + if {$vals($name2)} { + $cb configure -state normal -entrybg white + foreach x $w { + $x configure -state normal + } + } else { + $cb configure -state disabled -entrybg $ApolTop::default_bg_color + foreach x $w { + $x configure -state disabled + } + } +} + +proc Apol_DefaultObjects::_ruleChanged {name1 name2 ops} { + variable vals + variable widgets + Apol_Widget::clearSearchResults $widgets(results) + + if {$vals(default_user_enabled) == 0} { + set vals(user:use) 0 + } + if {$vals(default_role_enabled) == 0} { + set vals(role:use) 0 + } + if {$vals(default_type_enabled) == 0} { + set vals(type:use) 0 + } + if {$vals(default_range_enabled) == 0} { + set vals(range:use) 0 + } +} + +proc Apol_DefaultObjects::_searchDefaultObjects {} { + variable vals + variable widgets + variable statement_count + + Apol_Widget::clearSearchResults $widgets(results) + if {![ApolTop::is_policy_open]} { + tk_messageBox -icon error -type ok -title "Error" -message "No current policy file is opened." + } + + if {$vals(class:use) == 1 && $vals(class:sym) == {}} { + tk_messageBox -icon error -type ok -title "Default object Rule Search" -message "No class selected." + return + } + if {$vals(default:use) == 1 && $vals(default:sym) == {}} { + tk_messageBox -icon error -type ok -title "Default object Rule Search" -message "No default selected." + return + } + if {$vals(range:use) == 1 && $vals(range:sym) == {}} { + tk_messageBox -icon error -type ok -title "Default object Rule Search" -message "No range selected." + return + } + + set results {} + set header {} + set print_results {} + + if {$vals(default_user_enabled) == 1} { + append results [Apol_DefaultObjects::searchForDefault "user" get_user_default] + append header "$statement_count default_user rules match the search criteria.\n" + } + if {$vals(default_role_enabled) == 1} { + append results [Apol_DefaultObjects::searchForDefault "role" get_role_default] + append header "$statement_count default_role rules match the search criteria.\n" + } + if {$vals(default_type_enabled) == 1} { + append results [Apol_DefaultObjects::searchForDefault "type" get_type_default] + append header "$statement_count default_type rules match the search criteria.\n" + } + if {$vals(default_range_enabled) == 1} { + append results [Apol_DefaultObjects::searchDefaultRange "range" get_range_default] + append header "$statement_count default_range rules match the search criteria.\n" + } + append print_results "$header\n$results" + Apol_Widget::appendSearchResultText $widgets(results) $print_results +} + +proc Apol_DefaultObjects::searchForDefault {type type_cmd} { + variable vals + variable widgets + variable statement_count + set results {} + set printit 0 + set class_regexp 0 + set default_regexp 0 + set statement_count 0 + + if {$vals(class:use)} { + set class_regexp 1 + } + if {$vals(default:use)} { + set default_regexp 1 + } + + set q [new_apol_default_object_query_t] + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set q [qpol_default_object_from_void [$v get_element $i]] + set class [$q get_class $::ApolTop::qpolicy] + set default [$q $type_cmd $::ApolTop::qpolicy] + if {$default != ""} { + if {$class_regexp == 1 && $class == $vals(class:sym) && $default_regexp == 1 && $default == $vals(default:sym)} { + set printit 1 + } elseif {$class_regexp == 1 && $class == $vals(class:sym) && $default_regexp == 0} { + set printit 1 + } elseif {$default_regexp == 1 && $default == $vals(default:sym) && $class_regexp == 0} { + set printit 1 + } elseif {$class_regexp == 0 && $default_regexp == 0} { + set printit 1 + } + if {$printit == 1} { + append results "default_$type $class $default;\n" + set statement_count [expr $statement_count + 1] + } + } + set printit 0 + } + } + return "$results\n" +} + +proc Apol_DefaultObjects::searchDefaultRange {type type_cmd} { + variable vals + variable widgets + variable statement_count + set results {} + set printit 0 + set class_regexp 0 + set default_regexp 0 + set range_regexp 0 + set statement_count 0 + + if {$vals(class:use)} { + set class_regexp 1 + } + if {$vals(default:use)} { + set default_regexp 1 + } + if {$vals(range:use)} { + set range_regexp 1 + } + + set q [new_apol_default_object_query_t] + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set q [qpol_default_object_from_void [$v get_element $i]] + set class [$q get_class $::ApolTop::qpolicy] + set default [$q $type_cmd $::ApolTop::qpolicy] + if {$default != ""} { + # split into the two components + set entries [split $default " "] + lassign $entries src_tgt range + + if {$class_regexp == 1 && $class == $vals(class:sym) && $default_regexp == 1 && \ + $src_tgt== $vals(default:sym) && $range_regexp == 1 && $range == $vals(range:sym)} { + set printit 1 + } elseif {$class_regexp == 1 && $class == $vals(class:sym) && $default_regexp == 0 && $range_regexp == 0} { + set printit 1 + } elseif {$class_regexp == 0 && $default_regexp == 1 && $src_tgt == $vals(default:sym) && $range_regexp == 0} { + set printit 1 + } elseif {$class_regexp == 0 && $default_regexp == 0 && $range_regexp == 1 && $range == $vals(range:sym)} { + set printit 1 + } elseif {$class_regexp == 0 && $default_regexp == 1 && $src_tgt == $vals(default:sym) && \ + $range_regexp == 1 && $range == $vals(range:sym)} { + set printit 1 + } elseif {$class_regexp == 1 && $class == $vals(class:sym) && $default_regexp == 0 && \ + $range_regexp == 1 && $range == $vals(range:sym)} { + set printit 1 + } elseif {$class_regexp == 0 && $default_regexp == 0 && $range_regexp == 0} { + set printit 1 + } + if {$printit == 1} { + append results "default_$type $class $default;\n" + set statement_count [expr $statement_count + 1] + } + } + set printit 0 + } + } + return "$results\n" +} diff --git a/apol/namespaces_tab.tcl b/apol/namespaces_tab.tcl new file mode 100644 index 00000000..da8a1afa --- /dev/null +++ b/apol/namespaces_tab.tcl @@ -0,0 +1,206 @@ +# 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_Namespaces { + variable widgets + variable namespace_list {} +} + +proc Apol_Namespaces::create {tab_name nb} { + variable widgets + variable namespace_list {} + + set frame [$nb insert end $tab_name -text "Policy Namespaces"] + set pw [PanedWindow $frame.pw -side top] + set leftf [$pw add -weight 0] + set rightf [$pw add -weight 1] + pack $pw -fill both -expand yes + + set namespaces_box [TitleFrame $leftf.namespaces_box -text "Policy Namespaces"] + pack $namespaces_box -fill both -expand yes + + set nlistbox [Apol_Widget::makeScrolledListbox [$namespaces_box getframe].lb \ + -width 60 -listvar Apol_Namespaces::namespace_list] + Apol_Widget::setListboxCallbacks $nlistbox \ + {{"Show Namespace Users, Roles, Types, Attributes and Classes Info" {Apol_Namespaces::popupNsInfo nfi}}} + pack $nlistbox -expand 1 -fill both + pack $nlistbox -fill both -expand yes + + return $frame +} + +proc Apol_Namespaces::open {ppath} { + variable namespace_list {} + + append list1 "$Apol_Users::users_list $Apol_Roles::role_list $Apol_Types::typelist $Apol_Types::attriblist $Apol_Class_Perms::class_list" + set names [split $list1 " "] + # Split on the ns separator, chop off the end entry then add "." back + set list1 {} + foreach n $names { + set ns [split $n "."] + set ns [lreplace $ns end end] + set l [string length $ns] + if {$l > 0} { + regsub -all " " $ns "." ns + lappend list1 "$ns" + } + } + set list2 {} + set namespace_list "GLOBAL-NS\n" + lappend list2 [lsort -dictionary -unique $list1] + + foreach entry $list2 { + append namespace_list "$entry\n" + } +} + +proc Apol_Namespaces::close {} { + variable namespace_list {} + + set namespace_list {} +} + +proc Apol_Namespaces::getTextWidget {} { + variable widgets +} + + +proc Apol_Namespaces::popupNsInfo {which ns} { + + set w .ns_infobox + destroy $w + + set w [Dialog .ns_infobox -cancel 0 -default 0 -modal none -parent . -separator 1 -title $ns] + $w add -text "Close" -command [list destroy $w] + + set notebook [NoteBook [$w getframe].nb] + pack $notebook -expand 1 -fill both + + set user_info_tab [$notebook insert end user_info_tab -text "Users"] + set role_info_tab [$notebook insert end role_info_tab -text "Roles"] + set type_info_tab [$notebook insert end type_info_tab -text "Types"] + set attrib_info_tab [$notebook insert end attrib_info_tab -text "Attributes"] + set class_info_tab [$notebook insert end class_info_tab -text "Classes"] + set boolean_info_tab [$notebook insert end boolean_info_tab -text "Booleans"] + + if {[ApolTop::is_capable "mls"]} { + set sensitivity_info_tab [$notebook insert end sensitivity_info_tab -text "Sensitivities"] + set category_info_tab [$notebook insert end category_info_tab -text "Categories"] + } + + # Display users + set sw [ScrolledWindow [$notebook getframe user_info_tab].sw -scrollbar both -auto both] + set user_text [text [$sw getframe].text -wrap none -font {helvetica 10} -bg white] + $sw setwidget $user_text + pack $sw -expand 1 -fill both + Apol_Namespaces::DisplayMatches $Apol_Users::users_list $user_text $ns "users" + + # Display roles + set sw [ScrolledWindow [$notebook getframe role_info_tab].sw -scrollbar both -auto both] + set role_text [text [$sw getframe].text -wrap none -font {helvetica 10} -bg white] + $sw setwidget $role_text + pack $sw -expand 1 -fill both + Apol_Namespaces::DisplayMatches $Apol_Roles::role_list $role_text $ns "roles" + + # Display types + set sw [ScrolledWindow [$notebook getframe type_info_tab].sw -scrollbar both -auto both] + set type_text [text [$sw getframe].text -wrap none -font {helvetica 10} -bg white] + $sw setwidget $type_text + pack $sw -expand 1 -fill both + Apol_Namespaces::DisplayMatches $Apol_Types::typelist $type_text $ns "types" + + # Display attributes + set sw [ScrolledWindow [$notebook getframe attrib_info_tab].sw -scrollbar both -auto both] + set attrib_text [text [$sw getframe].text -wrap none -font {helvetica 10} -bg white] + $sw setwidget $attrib_text + pack $sw -expand 1 -fill both + Apol_Namespaces::DisplayMatches $Apol_Types::attriblist $attrib_text $ns "attributes" + + # Display classes + set sw [ScrolledWindow [$notebook getframe class_info_tab].sw -scrollbar both -auto both] + set class_text [text [$sw getframe].text -wrap none -font {helvetica 10} -bg white] + $sw setwidget $class_text + pack $sw -expand 1 -fill both + Apol_Namespaces::DisplayMatches $Apol_Class_Perms::class_list $class_text $ns "classes" + + # Display booleans + set sw [ScrolledWindow [$notebook getframe boolean_info_tab].sw -scrollbar both -auto both] + set boolean_text [text [$sw getframe].text -wrap none -font {helvetica 10} -bg white] + $sw setwidget $boolean_text + pack $sw -expand 1 -fill both + Apol_Namespaces::DisplayMatches $Apol_Cond_Bools::cond_bools_list $boolean_text $ns "booleans" + + if {[ApolTop::is_capable "mls"]} { + # Display sensitivities + set sw [ScrolledWindow [$notebook getframe sensitivity_info_tab].sw -scrollbar both -auto both] + set sensitivity_text [text [$sw getframe].text -wrap none -font {helvetica 10} -bg white] + $sw setwidget $sensitivity_text + pack $sw -expand 1 -fill both + Apol_Namespaces::DisplayMatches $Apol_MLS::vals(senslist) $sensitivity_text $ns "sensitivities" + + # Display categories + set sw [ScrolledWindow [$notebook getframe category_info_tab].sw -scrollbar both -auto both] + set category_text [text [$sw getframe].text -wrap none -font {helvetica 10} -bg white] + $sw setwidget $category_text + pack $sw -expand 1 -fill both + Apol_Namespaces::DisplayMatches $Apol_MLS::vals(catslist) $category_text $ns "categories" + } + + $notebook raise [$notebook page 0] + $w draw {} 0 600x400 +} + +proc Apol_Namespaces::DisplayMatches {item_list display_entry ns text} { + set counter 0 + set print_list {} + + if {$ns == "GLOBAL-NS"} { + set ns {} + set off_set 0 + } else { + set off_set 1 + } + # Get len of the ns selected + set l [string length $ns] + #For each entry check if in this ns + foreach t $item_list { + set i [string compare -length $l $t $ns] + # kludge to get round a problem. + # If $z is same as $ns, but no . in $t then ignore as $t just + # happens to begin with a match to $ns. So reset $i + set z [string range $t 0 $l-1] + if {![regexp -nocase {[.]} $t] && $z == $ns && $ns != ""} { + set i 1 + } + + if {$i == 0} { + set x [string range $t $l+$off_set end] + if {![regexp -nocase {[.]} $x]} { + append print_list " $x\n" + set counter [expr $counter + 1] + } + } + } + if {$counter == 0} { + $display_entry insert end "No entries\n" + } else { + if {$ns == ""} { + set ns "global" + } + $display_entry insert end "$ns namespace ($counter $text)\n$print_list" + } + $display_entry configure -state disabled + +} diff --git a/apol/terules_tab.tcl b/apol/terules_tab.tcl index c36e206a..3b51c641 100644 --- a/apol/terules_tab.tcl +++ b/apol/terules_tab.tcl @@ -139,6 +139,7 @@ proc Apol_TE::open {ppath} { set vals(cp:classes) [Apol_Class_Perms::getClasses] set enabled(cp:classes) 1 set enabled(cp:perms) 1 + set vals(ta:use_filename) 0 } proc Apol_TE::close {} { @@ -625,7 +626,8 @@ proc Apol_TE::_maybe_enable_filename {col name1 name2 op} { break } } - if {$typerule_set} { + + if {$typerule_set && [ApolTop::is_capable "filename_trans"]} { set enabled(ta:use_filename) 1 } else { set enabled(ta:use_filename) 0 diff --git a/apol/top.tcl b/apol/top.tcl index 3a1f42c2..a267dde6 100644 --- a/apol/top.tcl +++ b/apol/top.tcl @@ -69,13 +69,15 @@ namespace eval ApolTop { {Apol_Initial_SIDS components {}} {Apol_NetContexts components {}} {Apol_FSContexts components {}} - {Apol_Polcaps components {}} + {Apol_Polcaps components {tag_polcap}} + {Apol_Namespaces 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_Bounds rules {}} + {Apol_Bounds rules {tag_bounds}} + {Apol_DefaultObjects rules {tag_default_objects}} {Apol_File_Contexts {} {}} {Apol_Analysis {} {tag_query_saveable}} {Apol_PolicyConf {} {tag_source}} @@ -112,6 +114,12 @@ proc ApolTop::is_capable {capability} { "neverallow" { set cap $::QPOL_CAP_NEVERALLOW } "source" { set cap $::QPOL_CAP_SOURCE } "syntactic rules" { set cap $::QPOL_CAP_SYN_RULES } + "polcap" { set cap $::QPOL_CAP_POLCAPS } + "bounds" { set cap $::QPOL_CAP_BOUNDS } + "default_objects" { set cap $::QPOL_CAP_DEFAULT_OBJECTS } + "default_type" { set cap $::QPOL_CAP_DEFAULT_TYPE } + "permissive" { set cap $::QPOL_CAP_PERMISSIVE } + "filename_trans" { set cap $::QPOL_CAP_FILENAME_TRANS } default { return 0 } } variable qpolicy @@ -372,6 +380,15 @@ proc ApolTop::_toplevel_policy_open {ppath} { if {![is_capable "source"]} { _toplevel_enable_tabs tag_source disabled } + if {![is_capable "polcap"]} { + _toplevel_enable_tabs tag_polcap disabled + } + if {![is_capable "bounds"]} { + _toplevel_enable_tabs tag_bounds disabled + } + if {![is_capable "default_objects"]} { + _toplevel_enable_tabs tag_default_objects disabled + } _toplevel_tab_switched variable mainframe @@ -559,56 +576,93 @@ proc ApolTop::_toplevel_update_stats {} { set policy_stats(mlsvalidatetrans) 0 } - # Determine number of typebounds statements - set q [new_apol_typebounds_query_t] - set v [$q run $::ApolTop::policy] - $q -acquire - $q -delete - set counter 0 - for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + # Determine number of bounds statements + set policy_stats(userbounds) 0 + set policy_stats(rolebounds) 0 + set policy_stats(typebounds) 0 + + if {[is_capable "bounds"]} { + # Determine number of userbounds statements + set q [new_apol_userbounds_query_t] + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { - set q [qpol_typebounds_from_void [$v get_element $i]] - set parent [$q get_parent_name $::ApolTop::qpolicy] - if {$parent != ""} { - set counter [expr $counter + 1] + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set q [qpol_userbounds_from_void [$v get_element $i]] + set parent [$q get_parent_name $::ApolTop::qpolicy] + if {$parent != ""} { + set policy_stats(userbounds) [expr $policy_stats(userbounds) + 1] + } } } - } - set policy_stats(typebounds) $counter - # Determine number of rolebounds statements - set q [new_apol_rolebounds_query_t] - set v [$q run $::ApolTop::policy] - $q -acquire - $q -delete - set counter 0 - for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + # Determine number of rolebounds statements + set q [new_apol_rolebounds_query_t] + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { - set q [qpol_rolebounds_from_void [$v get_element $i]] - set parent [$q get_parent_name $::ApolTop::qpolicy] - if {$parent != ""} { - set counter [expr $counter + 1] + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set q [qpol_rolebounds_from_void [$v get_element $i]] + set parent [$q get_parent_name $::ApolTop::qpolicy] + if {$parent != ""} { + set policy_stats(rolebounds) [expr $policy_stats(rolebounds) + 1] + } + } + } + + # Determine number of typebounds statements + set q [new_apol_typebounds_query_t] + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set q [qpol_typebounds_from_void [$v get_element $i]] + set parent [$q get_parent_name $::ApolTop::qpolicy] + if {$parent != ""} { + set policy_stats(typebounds) [expr $policy_stats(typebounds) + 1] + } } } } - set policy_stats(rolebounds) $counter - # Determine number of userbounds statements - set q [new_apol_userbounds_query_t] - set v [$q run $::ApolTop::policy] - $q -acquire - $q -delete - set counter 0 - for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + # Determine number of default_object statements + set policy_stats(default_user) 0 + set policy_stats(default_role) 0 + set policy_stats(default_type) 0 + set policy_stats(default_range) 0 + + if {[is_capable "default_objects"]} { + set q [new_apol_default_object_query_t] + set v [$q run $::ApolTop::policy] + $q -acquire + $q -delete for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { - set q [qpol_userbounds_from_void [$v get_element $i]] - set parent [$q get_parent_name $::ApolTop::qpolicy] - if {$parent != ""} { - set counter [expr $counter + 1] + for {set i 0} {$v != "NULL" && $i < [$v get_size]} {incr i} { + set q [qpol_default_object_from_void [$v get_element $i]] + set default [$q get_user_default $::ApolTop::qpolicy] + if {$default != ""} { + set policy_stats(default_user) [expr $policy_stats(default_user) + 1] + } + set default [$q get_role_default $::ApolTop::qpolicy] + if {$default != ""} { + set policy_stats(default_role) [expr $policy_stats(default_role) + 1] + } + if {[is_capable "default_type"]} { + set default [$q get_type_default $::ApolTop::qpolicy] + if {$default != ""} { + set policy_stats(default_type) [expr $policy_stats(default_type) + 1] + } + } + set default [$q get_range_default $::ApolTop::qpolicy] + if {$default != ""} { + set policy_stats(default_range) [expr $policy_stats(default_range) + 1] + } } } } - set policy_stats(userbounds) $counter set policy_stats_summary "" append policy_stats_summary "Classes: $policy_stats(classes) " @@ -672,7 +726,9 @@ proc ApolTop::_close_policy {} { _toplevel_enable_tabs tag_conditionals normal _toplevel_enable_tabs tag_mls normal - _toplevel_enable_tabs tag_source normal + _toplevel_enable_tabs tag_polcap normal + _toplevel_enable_tabs tag_bounds normal + _toplevel_enable_tabs tag_default_objects normal } proc ApolTop::_exit {} { @@ -830,6 +886,12 @@ proc ApolTop::_show_policy_summary {} { "allows" role_allow "role_transitions" role_trans } + "Number of Default Object Rules" { + "default_user" default_user + "default_role" default_role + "default_type" default_type + "default_range" default_range + } } { set ltext "$title:" set rtext {} diff --git a/apol/types_tab.tcl b/apol/types_tab.tcl index 34b131f7..fed82fac 100644 --- a/apol/types_tab.tcl +++ b/apol/types_tab.tcl @@ -109,6 +109,11 @@ proc Apol_Types::create {tab_name nb} { } proc Apol_Types::open {ppath} { + variable opts + + set opts(permissive:show_names) [ApolTop::is_capable "permissive"] + set opts(typebounds:show_names) [ApolTop::is_capable "bounds"] + set q [new_apol_type_query_t] set v [$q run $::ApolTop::policy] $q -acquire @@ -193,8 +198,8 @@ proc Apol_Types::_initializeVars {} { array set opts { types 1 types:show_attribs 1 types:show_aliases 1 attribs 0 attribs:show_types 1 attribs:show_attribs 1 - permissive 1 permissive:show_names 1 permissive:show_names 1 - typebounds 1 typebounds:show_names 1 typebounds:show_names 1 + permissive 1 permissive:show_names 0 + typebounds 1 typebounds:show_names 0 } } @@ -211,7 +216,7 @@ proc Apol_Types::_toggleCheckbuttons {w name1 name2 op} { $x configure -state disabled } } - if {!$opts(types) && !$opts(attribs) && !$opts(permissive) && !$opts(typebounds)} { + if {!$opts(types) && !$opts(attribs) && !$opts(typebounds)} { Apol_Widget::setRegexpEntryState $widgets(regexp) 0 } else { Apol_Widget::setRegexpEntryState $widgets(regexp) 1 @@ -347,7 +352,7 @@ proc Apol_Types::_searchTypes {} { append results "[_renderAttrib $a $opts(attribs:show_types) $opts(attribs:show_attribs)]\n" } } - if {$opts(permissive)} { + if {$opts(permissive) && [ApolTop::is_capable "permissive"]} { set q [new_apol_permissive_query_t] $q set_name $::ApolTop::policy $regexp $q set_regex $::ApolTop::policy $use_regexp @@ -365,7 +370,7 @@ proc Apol_Types::_searchTypes {} { append results "[_renderType $p 0 0]\n" } } - if {$opts(typebounds)} { + if {$opts(typebounds) && [ApolTop::is_capable "bounds"]} { set bounds {} set counter 0 diff --git a/libapol/include/apol/Makefile.am b/libapol/include/apol/Makefile.am index 72b5ab0d..dd94452a 100644 --- a/libapol/include/apol/Makefile.am +++ b/libapol/include/apol/Makefile.am @@ -9,6 +9,7 @@ apol_HEADERS = \ condrule-query.h \ constraint-query.h \ context-query.h \ + default-object-query.h \ domain-trans-analysis.h \ fscon-query.h \ infoflow-analysis.h \ diff --git a/libapol/include/apol/default-object-query.h b/libapol/include/apol/default-object-query.h new file mode 100644 index 00000000..d30e0024 --- /dev/null +++ b/libapol/include/apol/default-object-query.h @@ -0,0 +1,78 @@ +/** + * @file + * + * Routines to query default objects in policy. + * + * @author Richard Haines richard_c_haines@btinternet.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef APOL_DEFAULT_OBJECT_QUERY_H +#define APOL_DEFAULT_OBJECT_QUERY_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "policy.h" +#include "vector.h" +#include + + typedef struct apol_default_object_query apol_default_object_query_t; +/** + * Execute a query against all policy capabilities within the policy. + * + * @param p Policy within which to look up policy capabilities. + * @param t Structure containing parameters for query. If this is + * NULL then return all policy capabilities. + * @param v Reference to a vector of qpol_default_object_t. The vector will be + * allocated by this function. The caller must call + * apol_vector_destroy() afterwards. This will be set to NULL upon no + * results or upon error. + * + * @return 0 on success (including none found), negative on error. + */ + extern int apol_default_object_get_by_query(const apol_policy_t * p, apol_default_object_query_t * t, apol_vector_t ** v); + +/** + * Allocate and return a new default_object query structure. All fields are + * initialized, such that running this blank query results in + * returning all policy capabilities within the policy. The caller must call + * apol_default_object_query_destroy() upon the return value afterwards. + * + * @return An initialized default_object query structure, or NULL upon error. + */ + extern apol_default_object_query_t *apol_default_object_query_create(void); + +/** + * Deallocate all memory associated with the referenced default_object query, + * and then set it to NULL. This function does nothing if the query + * is already NULL. + * + * @param t Reference to a default_object query structure to destroy. + */ + extern void apol_default_object_query_destroy(apol_default_object_query_t ** t); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libapol/include/apol/policy-query.h b/libapol/include/apol/policy-query.h index cc1df9b8..f1a5c291 100644 --- a/libapol/include/apol/policy-query.h +++ b/libapol/include/apol/policy-query.h @@ -67,6 +67,7 @@ extern "C" #include "permissive-query.h" #include "polcap-query.h" #include "bounds-query.h" +#include "default-object-query.h" #include "avrule-query.h" #include "terule-query.h" diff --git a/libapol/src/Makefile.am b/libapol/src/Makefile.am index c37233f5..22c80cfb 100644 --- a/libapol/src/Makefile.am +++ b/libapol/src/Makefile.am @@ -20,6 +20,7 @@ libapol_a_SOURCES = \ condrule-query.c \ constraint-query.c \ context-query.c \ + default-object-query.c \ domain-trans-analysis.c domain-trans-analysis-internal.h \ fscon-query.c \ infoflow-analysis.c infoflow-analysis-internal.h \ diff --git a/libapol/src/bounds-query.c b/libapol/src/bounds-query.c index de76bced..06662f48 100644 --- a/libapol/src/bounds-query.c +++ b/libapol/src/bounds-query.c @@ -43,7 +43,7 @@ int apol_typebounds_get_by_query(const apol_policy_t * p, apol_typebounds_query_ { qpol_iterator_t *iter; int retval = -1; - int compval = 6; + *v = NULL; if (qpol_policy_get_typebounds_iter(p->p, &iter) < 0) { return -1; @@ -113,7 +113,7 @@ int apol_rolebounds_get_by_query(const apol_policy_t * p, apol_rolebounds_query_ { qpol_iterator_t *iter; int retval = -1; - int compval = 6; + *v = NULL; if (qpol_policy_get_rolebounds_iter(p->p, &iter) < 0) { return -1; @@ -169,7 +169,7 @@ int apol_userbounds_get_by_query(const apol_policy_t * p, apol_userbounds_query_ { qpol_iterator_t *iter; int retval = -1; - int compval = 6; + *v = NULL; if (qpol_policy_get_userbounds_iter(p->p, &iter) < 0) { return -1; diff --git a/libapol/src/default-object-query.c b/libapol/src/default-object-query.c new file mode 100644 index 00000000..3724e69b --- /dev/null +++ b/libapol/src/default-object-query.c @@ -0,0 +1,87 @@ +/** + * @file + * + * Provides a way for setools to make queries about policy capabilities + * within a policy. The caller obtains a query object, + * fills in its parameters, and then runs the query; it obtains a + * vector of results. Searches are conjunctive -- all fields of the + * search query must match for a datum to be added to the results + * query. + * + * @author Richard Haines richard_c_haines@btinternet.com + * + * Copyright (C) 2006-2007 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "policy-query-internal.h" + +#include + +struct apol_default_object_query +{ + char *name; +}; + +int apol_default_object_get_by_query(const apol_policy_t * p, apol_default_object_query_t * q, apol_vector_t ** v) +{ + qpol_iterator_t *iter; + int retval = -1; + + *v = NULL; + if (qpol_policy_get_default_object_iter(p->p, &iter) < 0) { + return -1; + } + if ((*v = apol_vector_create(NULL)) == NULL) { + ERR(p, "%s", strerror(errno)); + goto cleanup; + } + for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) { + const qpol_default_object_t *default_object; + if (qpol_iterator_get_item(iter, (void **)&default_object) < 0) { + goto cleanup; + } + if (q != NULL) { + if (apol_vector_append(*v, (void *)default_object)) { + ERR(p, "%s", strerror(ENOMEM)); + goto cleanup; + } + } + } + + retval = 0; +cleanup: + if (retval != 0) { + apol_vector_destroy(v); + } + qpol_iterator_destroy(&iter); + return retval; +} + +apol_default_object_query_t *apol_default_object_query_create(void) +{ + return calloc(1, sizeof(apol_default_object_query_t)); +} + +void apol_default_object_query_destroy(apol_default_object_query_t ** q) +{ + if (*q != NULL) { + free((*q)->name); + free(*q); + *q = NULL; + } +} + diff --git a/libapol/src/libapol.map b/libapol/src/libapol.map index b64345d5..8741bf42 100644 --- a/libapol/src/libapol.map +++ b/libapol/src/libapol.map @@ -87,4 +87,5 @@ VERS_4.2{ apol_rolebounds_*; apol_userbounds_*; apol_polcap_*; + apol_default_object_*; } VERS_4.1; diff --git a/libapol/swig/apol.i b/libapol/swig/apol.i index ae2038d1..53172e4b 100644 --- a/libapol/swig/apol.i +++ b/libapol/swig/apol.i @@ -2804,6 +2804,36 @@ typedef struct apol_userbounds_query {} apol_userbounds_query_t; }; }; +/* apol default_object query */ +typedef struct apol_default_object_query {} apol_default_object_query_t; +%extend apol_default_object_query_t { + apol_default_object_query() { + apol_default_object_query_t *arq; + BEGIN_EXCEPTION + arq = apol_default_object_query_create(); + if (!arq) { + SWIG_exception(SWIG_MemoryError, "Out of memory"); + } + END_EXCEPTION + fail: + return arq; + }; + ~apol_default_object_query() { + apol_default_object_query_destroy(&self); + }; + %newobject run(apol_policy_t*); + apol_vector_t *run(apol_policy_t *p) { + apol_vector_t *v; + BEGIN_EXCEPTION + if (apol_default_object_get_by_query(p, self, &v)) { + SWIG_exception(SWIG_RuntimeError, "Could not run default object query"); + } + END_EXCEPTION + fail: + return v; + }; +}; + /* domain transition analysis */ #define APOL_DOMAIN_TRANS_DIRECTION_FORWARD 0x01 #define APOL_DOMAIN_TRANS_DIRECTION_REVERSE 0x02 diff --git a/libqpol/include/qpol/Makefile.am b/libqpol/include/qpol/Makefile.am index 11009a0f..cfd4b123 100644 --- a/libqpol/include/qpol/Makefile.am +++ b/libqpol/include/qpol/Makefile.am @@ -7,6 +7,7 @@ qpol_HEADERS = \ cond_query.h \ constraint_query.h \ context_query.h \ + default_object_query.h \ fs_use_query.h \ genfscon_query.h \ isid_query.h \ diff --git a/libqpol/include/qpol/default_object_query.h b/libqpol/include/qpol/default_object_query.h new file mode 100644 index 00000000..cd40b55b --- /dev/null +++ b/libqpol/include/qpol/default_object_query.h @@ -0,0 +1,113 @@ +/** + * @file + * Defines the public interface for searching and iterating over default objects. + * + * @author Richard Haines richard_c_haines@btinternet.com + * + * Copyright (C) 2006-2009 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef QPOL_DEFAULT_OBJECT_QUERY_H +#define QPOL_DEFAULT_OBJECT_QUERY_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include +#include + + + typedef struct qpol_default_object qpol_default_object_t; + +/** + * Get an iterator for the default_object types in a policy. + * @param policy The policy from which to create the iterator. + * @param iter Iterator over items of type qpol_isid_t returned. + * The caller is responsible for calling qpol_iterator_destroy + * to free memory used by this iterator. + * It is important to note that this iterator is only valid as long + * as the policy is unmodified. + * @return 0 on success and < 0 on failure; if the call fails, + * errno will be set and *iter will be NULL. + */ + extern int qpol_policy_get_default_object_iter(const qpol_policy_t *policy, qpol_iterator_t **iter); + +/** + * Get the name which identifies a default_object class from its datum. + * @param policy The policy with which class is associated. + * @param datum default_object datum for which to get the name. Must be non-NULL. + * @param name Pointer to the string in which to store the name. + * Must be non-NULL. The caller should not free the string. + * @return Returns 0 on success and < 0 on failure; if the call fails, + * errno will be set and *name will be NULL. + */ + extern int qpol_default_object_get_class(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **name); + +/** + * Get the value of a default user source/dest from its datum. + * @param policy The policy with which the default object is associated. + * @param datum default_object datum for which to get the value. Must be non-NULL. + * @param default Pointer to the value in which to store the default. + * Must be non-NULL. The caller should not free the string. + * @return Returns 0 on success and < 0 on failure; if the call fails, + * errno will be set and *default will be 0. + */ + extern int qpol_default_object_get_user_default(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **value); + +/** + * Get the value of a default role source/dest from its datum. + * @param policy The policy with which the default object type is associated. + * @param datum default_object datum for which to get the value. Must be non-NULL. + * @param default Pointer to the value in which to store the default. + * Must be non-NULL. The caller should not free the string. + * @return Returns 0 on success and < 0 on failure; if the call fails, + * errno will be set and *default will be 0. + */ + extern int qpol_default_object_get_role_default(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **value); + +/** + * Get the value of a default type source/dest from its datum. + * @param policy The policy with which the default object type is associated. + * @param datum default_object datum for which to get the value. Must be non-NULL. + * @param default Pointer to the value in which to store the default. + * Must be non-NULL. The caller should not free the string. + * @return Returns 0 on success and < 0 on failure; if the call fails, + * errno will be set and *default will be 0. + */ + extern int qpol_default_object_get_type_default(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **value); + +/** + * Get the value of a default range source/dest from its datum. + * @param policy The policy with which the default object type is associated. + * @param datum default_object datum for which to get the value. Must be non-NULL. + * @param default Pointer to the value in which to store the default. + * Must be non-NULL. The caller should not free the string. + * @return Returns 0 on success and < 0 on failure; if the call fails, + * errno will be set and *default will be 0. + */ + extern int qpol_default_object_get_range_default(const qpol_policy_t *policy, const qpol_default_object_t *datum, const char **value_1, const char **value_2); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libqpol/include/qpol/policy.h b/libqpol/include/qpol/policy.h index 9b90ed02..4e01cdbe 100644 --- a/libqpol/include/qpol/policy.h +++ b/libqpol/include/qpol/policy.h @@ -53,6 +53,7 @@ extern "C" #include #include #include +#include #include #include #include @@ -118,7 +119,18 @@ extern "C" /** The policy source may be displayed. */ QPOL_CAP_SOURCE, /** The policy supports and was loaded with neverallow rules. */ - QPOL_CAP_NEVERALLOW + QPOL_CAP_NEVERALLOW, + /** The policy supports bounds rules. */ + QPOL_CAP_BOUNDS, + /** The policy supports default object rules. */ + QPOL_CAP_DEFAULT_OBJECTS, + QPOL_CAP_DEFAULT_TYPE, + /** The policy supports permissive types. */ + QPOL_CAP_PERMISSIVE, + /** The policy supports filename type_transition rules. */ + QPOL_CAP_FILENAME_TRANS, + /** The policy supports role transition rules. */ + QPOL_CAP_ROLETRANS } qpol_capability_e; /** diff --git a/libqpol/src/Makefile.am b/libqpol/src/Makefile.am index 26389711..77213f4d 100644 --- a/libqpol/src/Makefile.am +++ b/libqpol/src/Makefile.am @@ -21,6 +21,7 @@ libqpol_a_SOURCES = \ cond_query.c \ constraint_query.c \ context_query.c \ + default_object_query.c \ expand.c \ expand.h \ fs_use_query.c \ diff --git a/libqpol/src/bounds_query.c b/libqpol/src/bounds_query.c index fe71ebf4..c3eb020c 100644 --- a/libqpol/src/bounds_query.c +++ b/libqpol/src/bounds_query.c @@ -44,6 +44,11 @@ int qpol_typebounds_get_parent_name(const qpol_policy_t *policy, const qpol_type errno = EINVAL; return STATUS_ERR; } + *name = NULL; + + /* The bounds rules started in ver 24 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) + return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (type_datum_t *)datum; @@ -51,8 +56,6 @@ int qpol_typebounds_get_parent_name(const qpol_policy_t *policy, const qpol_type /* This will be zero if not a typebounds statement */ if (internal_datum->flavor == TYPE_TYPE && internal_datum->bounds != 0) { *name = db->p_type_val_to_name[internal_datum->bounds - 1]; - } else { - *name = NULL; } return STATUS_SUCCESS; } @@ -69,14 +72,17 @@ int qpol_typebounds_get_child_name(const qpol_policy_t *policy, const qpol_typeb errno = EINVAL; return STATUS_ERR; } + *name = NULL; + + /* The bounds rules started in ver 24 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) + return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (type_datum_t *)datum; if (internal_datum->flavor == TYPE_TYPE && internal_datum->bounds != 0) { *name = db->p_type_val_to_name[internal_datum->s.value - 1]; - } else { - *name = NULL; } return STATUS_SUCCESS; } @@ -147,6 +153,11 @@ int qpol_rolebounds_get_parent_name(const qpol_policy_t *policy, const qpol_role errno = EINVAL; return STATUS_ERR; } + *name = NULL; + + /* The bounds rules started in ver 24 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) + return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (role_datum_t *)datum; @@ -154,8 +165,6 @@ int qpol_rolebounds_get_parent_name(const qpol_policy_t *policy, const qpol_role /* This will be zero if not a rolebounds statement */ if (internal_datum->flavor == ROLE_ROLE && internal_datum->bounds != 0) { *name = db->p_role_val_to_name[internal_datum->bounds - 1]; - } else { - *name = NULL; } return STATUS_SUCCESS; } @@ -172,14 +181,17 @@ int qpol_rolebounds_get_child_name(const qpol_policy_t *policy, const qpol_roleb errno = EINVAL; return STATUS_ERR; } + *name = NULL; + + /* The bounds rules started in ver 24 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) + return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (role_datum_t *)datum; if (internal_datum->flavor == ROLE_ROLE && internal_datum->bounds != 0) { *name = db->p_role_val_to_name[internal_datum->s.value - 1]; - } else { - *name = NULL; } return STATUS_SUCCESS; } @@ -236,6 +248,11 @@ int qpol_userbounds_get_parent_name(const qpol_policy_t *policy, const qpol_user errno = EINVAL; return STATUS_ERR; } + *name = NULL; + + /* The bounds rules started in ver 24 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) + return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (user_datum_t *)datum; @@ -243,8 +260,6 @@ int qpol_userbounds_get_parent_name(const qpol_policy_t *policy, const qpol_user /* This will be zero if not a userbounds statement */ if (internal_datum->bounds != 0) { *name = db->p_user_val_to_name[internal_datum->bounds - 1]; - } else { - *name = NULL; } return STATUS_SUCCESS; } @@ -261,14 +276,17 @@ int qpol_userbounds_get_child_name(const qpol_policy_t *policy, const qpol_userb errno = EINVAL; return STATUS_ERR; } + *name = NULL; + + /* The bounds rules started in ver 24 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_BOUNDS)) + return STATUS_SUCCESS; db = &policy->p->p; internal_datum = (user_datum_t *)datum; if (internal_datum->bounds != 0) { *name = db->p_user_val_to_name[internal_datum->s.value - 1]; - } else { - *name = NULL; } return STATUS_SUCCESS; } diff --git a/libqpol/src/default_object_query.c b/libqpol/src/default_object_query.c new file mode 100644 index 00000000..f4bea8aa --- /dev/null +++ b/libqpol/src/default_object_query.c @@ -0,0 +1,290 @@ +/** +* @file +* Defines the public interface for searching and iterating over default objects. +* +* @author Richard Haines richard_c_haines@btinternet.com +* +* Copyright (C) 2006-2007 Tresys Technology, LLC +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "qpol_internal.h" +#include "iterator_internal.h" + +int qpol_default_object_get_class(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **name) +{ + class_datum_t *internal_datum = NULL; + policydb_t *db = NULL; + + if (policy == NULL || datum == NULL || name == NULL) { + if (name != NULL) + *name = NULL; + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + *name = NULL; + + db = &policy->p->p; + internal_datum = (class_datum_t *)datum; + + /* These will be zero if no default_objects set */ + if (internal_datum->default_user || internal_datum->default_role || + internal_datum->default_type || + internal_datum->default_range) { + *name = db->p_class_val_to_name[internal_datum->s.value - 1]; + } + return STATUS_SUCCESS; +} + +int qpol_default_object_get_user_default(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **value) +{ + class_datum_t *internal_datum = NULL; + policydb_t *db = NULL; + + if (policy == NULL || datum == NULL || value == NULL) { + if (value != NULL) + *value = NULL; + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + *value = NULL; + + /* The user default started in ver 27 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_DEFAULT_OBJECTS)) + return STATUS_SUCCESS; + + db = &policy->p->p; + internal_datum = (class_datum_t *)datum; + + if (internal_datum->default_user == DEFAULT_SOURCE) { + *value = "source"; + } else if (internal_datum->default_user == DEFAULT_TARGET) { + *value = "target"; + } + return STATUS_SUCCESS; +} + +int qpol_default_object_get_role_default(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **value) +{ + class_datum_t *internal_datum = NULL; + policydb_t *db = NULL; + + if (policy == NULL || datum == NULL || value == NULL) { + if (value != NULL) + *value = NULL; + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + *value = NULL; + + /* The role default started in ver 27 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_DEFAULT_OBJECTS)) + return STATUS_SUCCESS; + + db = &policy->p->p; + internal_datum = (class_datum_t *)datum; + + if (internal_datum->default_role == DEFAULT_SOURCE) { + *value = "source"; + } else if (internal_datum->default_role == DEFAULT_TARGET) { + *value = "target"; + } + return STATUS_SUCCESS; +} + +int qpol_default_object_get_type_default(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **value) +{ + class_datum_t *internal_datum = NULL; + policydb_t *db = NULL; + + if (policy == NULL || datum == NULL || value == NULL) { + if (value != NULL) + *value = NULL; + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + *value = NULL; + + /* The type default started in ver 28 */ + if (!qpol_policy_has_capability(policy, QPOL_CAP_DEFAULT_TYPE)) + return STATUS_SUCCESS; + + db = &policy->p->p; + internal_datum = (class_datum_t *)datum; + + if (internal_datum->default_type == DEFAULT_SOURCE) { + *value = "source"; + } else if (internal_datum->default_type == DEFAULT_TARGET) { + *value = "target"; + } + return STATUS_SUCCESS; +} + +int qpol_default_object_get_range_default(const qpol_policy_t *policy, const qpol_default_object_t * datum, const char **value_1, const char **value_2) +{ + class_datum_t *internal_datum = NULL; + policydb_t *db = NULL; + + if (policy == NULL || datum == NULL || value_1 == NULL || value_2 == NULL) { + if (value_1 != NULL) + *value_1 = NULL; + if (value_2 != NULL) + *value_2 = NULL; + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + *value_1 = NULL; + *value_2 = NULL; + + /* The range default started in ver 27 */ + int policy_version; + if (!qpol_policy_has_capability(policy, QPOL_CAP_DEFAULT_OBJECTS)) + return STATUS_SUCCESS; + + db = &policy->p->p; + internal_datum = (class_datum_t *)datum; + + switch (internal_datum->default_range) { + case DEFAULT_SOURCE_LOW: + *value_1 = "source"; + *value_2 = "low"; + break; + case DEFAULT_SOURCE_HIGH: + *value_1 = "source"; + *value_2 = "high"; + break; + case DEFAULT_SOURCE_LOW_HIGH: + *value_1 = "source"; + *value_2 = "low_high"; + break; + case DEFAULT_TARGET_LOW: + *value_1 = "target"; + *value_2 = "low"; + break; + case DEFAULT_TARGET_HIGH: + *value_1 = "target"; + *value_2 = "high"; + break; + case DEFAULT_TARGET_LOW_HIGH: + *value_1 = "target"; + *value_2 = "low_high"; + break; + default: + break; + } + return STATUS_SUCCESS; +} + +/* As default objects are in classes use these, however will need to calc number of default objects manually in top.tcl*/ +int qpol_policy_get_default_object_iter(const qpol_policy_t *policy, qpol_iterator_t **iter) +{ + policydb_t *db; + int error = 0; + hash_state_t *hs = NULL; + + if (policy == NULL || iter == NULL) { + if (iter != NULL) + *iter = NULL; + ERR(policy, "%s", strerror(EINVAL)); + errno = EINVAL; + return STATUS_ERR; + } + + db = &policy->p->p; +/* + class_datum_t *cladatum; + sepol_security_class_t tclass; + char *class; + + for (tclass = 1; tclass <= db->p_classes.nprim; tclass++) { + cladatum = db->class_val_to_struct[tclass - 1]; + class = db->p_class_val_to_name[tclass - 1]; + + if (cladatum->default_user == DEFAULT_SOURCE) { + printf("default_user %s source;\n", class); + } else if (cladatum->default_user == DEFAULT_TARGET) { + printf("default_user %s target;\n", class); + } + + if (cladatum->default_role == DEFAULT_SOURCE) { + printf("default_role %s source;\n", class); + } else if (cladatum->default_role == DEFAULT_TARGET) { + printf("default_role %s target;\n", class); + } + + if (cladatum->default_type == DEFAULT_SOURCE) { + printf("default_type %s source;\n", class); + } else if (cladatum->default_type == DEFAULT_TARGET) { + printf("default_type %s target;\n", class); + } + + switch (cladatum->default_range) { + case DEFAULT_SOURCE_LOW: + printf("default_range %s source low;\n", class); + break; + case DEFAULT_SOURCE_HIGH: + printf("default_range %s source high;\n", class); + break; + case DEFAULT_SOURCE_LOW_HIGH: + printf("default_range %s source low_high;\n", class); + break; + case DEFAULT_TARGET_LOW: + printf("default_range %s target low;\n", class); + break; + case DEFAULT_TARGET_HIGH: + printf("default_range %s target high;\n", class); + break; + case DEFAULT_TARGET_LOW_HIGH: + printf("default_range %s target low_high;\n", class); + break; + default: + break; + } + } +*/ + hs = calloc(1, sizeof(hash_state_t)); + if (hs == NULL) { + error = errno; + ERR(policy, "%s", strerror(ENOMEM)); + errno = error; + return STATUS_ERR; + } + hs->table = &db->p_classes.table; + hs->node = (*(hs->table))->htable[0]; + + if (qpol_iterator_create(policy, (void *)hs, hash_state_get_cur, + hash_state_next, hash_state_end, hash_state_size, free, iter)) { + free(hs); + return STATUS_ERR; + } + + if (hs->node == NULL) + hash_state_next(*iter); + + return STATUS_SUCCESS; +} diff --git a/libqpol/src/libqpol.map b/libqpol/src/libqpol.map index f05b6ca8..1e803082 100644 --- a/libqpol/src/libqpol.map +++ b/libqpol/src/libqpol.map @@ -75,4 +75,5 @@ VERS_1.5 { qpol_userbounds_*; qpol_policy_polcap_*; qpol_polcap_*; + qpol_default_object_*; } VERS_1.4; diff --git a/libqpol/src/policy.c b/libqpol/src/policy.c index 2bf7fbaa..91648238 100644 --- a/libqpol/src/policy.c +++ b/libqpol/src/policy.c @@ -1553,6 +1553,55 @@ int qpol_policy_has_capability(const qpol_policy_t * policy, qpol_capability_e c return 1; break; } + case QPOL_CAP_BOUNDS: + { + if (version >= 24 && policy->type != QPOL_POLICY_MODULE_BINARY) + return 1; + if (version >= 9 && policy->type == QPOL_POLICY_MODULE_BINARY) + return 1; + break; + } + case QPOL_CAP_PERMISSIVE: + { + if (version >= 23 && policy->type != QPOL_POLICY_MODULE_BINARY) + return 1; + if (version >= 8 && policy->type == QPOL_POLICY_MODULE_BINARY) + return 1; + break; + } + case QPOL_CAP_FILENAME_TRANS: + { + if (version >= 25 && policy->type != QPOL_POLICY_MODULE_BINARY) + return 1; + if (version >= 11 && policy->type == QPOL_POLICY_MODULE_BINARY) + return 1; + break; + } + case QPOL_CAP_ROLETRANS: + { + if (version >= 26 && policy->type != QPOL_POLICY_MODULE_BINARY) + return 1; + if (version >= 12 && policy->type == QPOL_POLICY_MODULE_BINARY) + return 1; + break; + } + /* This indicates the user, role and range - types were ate 28/16 */ + case QPOL_CAP_DEFAULT_OBJECTS: + { + if (version >= 27 && policy->type != QPOL_POLICY_MODULE_BINARY) + return 1; + if (version >= 15 && policy->type == QPOL_POLICY_MODULE_BINARY) + return 1; + break; + } + case QPOL_CAP_DEFAULT_TYPE: + { + if (version >= 28 && policy->type != QPOL_POLICY_MODULE_BINARY) + return 1; + if (version >= 16 && policy->type == QPOL_POLICY_MODULE_BINARY) + return 1; + break; + } case QPOL_CAP_RULES_LOADED: { if (!(policy->options & QPOL_POLICY_OPTION_NO_RULES)) diff --git a/libqpol/swig/qpol.i b/libqpol/swig/qpol.i index 7bb92cf6..98ea70be 100644 --- a/libqpol/swig/qpol.i +++ b/libqpol/swig/qpol.i @@ -326,7 +326,14 @@ typedef enum qpol_capability QPOL_CAP_MODULES, QPOL_CAP_RULES_LOADED, QPOL_CAP_SOURCE, - QPOL_CAP_NEVERALLOW + QPOL_CAP_NEVERALLOW, + QPOL_CAP_POLCAPS, + QPOL_CAP_BOUNDS, + QPOL_CAP_DEFAULT_OBJECTS, + QPOL_CAP_DEFAULT_TYPE, + QPOL_CAP_PERMISSIVE, + QPOL_CAP_FILENAME_TRANS, + QPOL_CAP_ROLETRANS } qpol_capability_e; %extend qpol_policy_t { @@ -3167,4 +3174,76 @@ typedef struct qpol_userbounds {} qpol_userbounds_t; return (qpol_userbounds_t*)x; }; %} + +/* qpol default_object */ +typedef struct qpol_default_object {} qpol_default_object_t; +%extend qpol_default_object_t { + qpol_default_object() { + BEGIN_EXCEPTION + SWIG_exception(SWIG_RuntimeError, "Cannot directly create qpol_default_object_t objects"); + END_EXCEPTION + fail: + return NULL; + }; + ~qpol_default_object() { + /* no op */ + return; + }; + const char *get_class(qpol_policy_t *p) { + const char *name; + BEGIN_EXCEPTION + if (qpol_default_object_get_class(p, self, &name)) { + SWIG_exception(SWIG_ValueError, "Could not get class name"); + } + END_EXCEPTION + fail: + return name; + }; + const char *get_user_default(qpol_policy_t *p) { + const char *value; + BEGIN_EXCEPTION + if (qpol_default_object_get_user_default(p, self, &value)) { + SWIG_exception(SWIG_ValueError, "Could not get user default"); + } + END_EXCEPTION + fail: + return value; + }; + const char *get_role_default(qpol_policy_t *p) { + const char *value; + BEGIN_EXCEPTION + if (qpol_default_object_get_role_default(p, self, &value)) { + SWIG_exception(SWIG_ValueError, "Could not get role default"); + } + END_EXCEPTION + fail: + return value; + }; + const char *get_type_default(qpol_policy_t *p) { + const char *value; + BEGIN_EXCEPTION + if (qpol_default_object_get_type_default(p, self, &value)) { + SWIG_exception(SWIG_ValueError, "Could not get type default"); + } + END_EXCEPTION + fail: + return value; + }; + const char *get_range_default(qpol_policy_t *p) { + const char *value_1; + const char *value_2; + BEGIN_EXCEPTION + if (qpol_default_object_get_range_default(p, self, &value_1, &value_2)) { + SWIG_exception(SWIG_ValueError, "Could not get range defaults"); + } + END_EXCEPTION + fail: + return value_1; + }; +}; +%inline %{ + qpol_default_object_t *qpol_default_object_from_void(void *x) { + return (qpol_default_object_t*)x; + }; +%} // vim:ft=c noexpandtab diff --git a/libsefs/src/db.cc b/libsefs/src/db.cc index 88ad5881..191d796b 100644 --- a/libsefs/src/db.cc +++ b/libsefs/src/db.cc @@ -479,8 +479,13 @@ int db_create_from_filesystem(sefs_fclist * fclist __attribute__ ((unused)), con struct stat64 sb; if (stat64(path, &sb) == -1) { - SEFS_ERR(dbc->_db, "%s", strerror(errno)); - throw std::bad_alloc(); + /* If sym link broken/file not found, then ignore as this will allow + the index to be built. Useful when investigating broken systems. + Also see new_ftw.c comment regarding "lstat calls go through the + wrapper function" to stop index hanging on broken files. */ + link_target[127] = '\0'; + sb.st_mode = 0; + SEFS_WARN(dbc->_db, "Could not stat file: %s - ignoring", path); } if (S_ISLNK(sb.st_mode)) { diff --git a/libsefs/src/new_ftw.c b/libsefs/src/new_ftw.c index 5ebaf299..10eb78fd 100644 --- a/libsefs/src/new_ftw.c +++ b/libsefs/src/new_ftw.c @@ -131,7 +131,11 @@ extern char *xgetcwd(void); /* Arrange to make lstat calls go through the wrapper function on systems with an lstat function that does not dereference symlinks that are specified with a trailing slash. */ -#if ! _LIBC && ! LSTAT_FOLLOWS_SLASHED_SYMLINK +/* If this is used on Linux (Fedora) when a sym link or file is broken, + the file context function will hang forever: + #if ! _LIBC && ! LSTAT_FOLLOWS_SLASHED_SYMLINK + Therefore changed to this so uses Linux lstat function. */ +#if _LIBC && ! LSTAT_FOLLOWS_SLASHED_SYMLINK int rpl_lstat(const char *, struct stat *); # undef lstat # define lstat(Name, Stat_buf) rpl_lstat(Name, Stat_buf)