chef/cookbooks/selinux/resources/fcontext.rb

133 lines
4.2 KiB
Ruby

#
# Cookbook:: selinux
# Resource:: fcontext
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
unified_mode true
property :file_spec, String,
name_property: true,
description: 'Path to or regex matching the files or directoriesto label'
property :secontext, String,
required: %i(add modify manage),
description: 'SELinux context to assign'
property :file_type, String,
default: 'a',
equal_to: %w(a f d c b s l p),
description: 'The type of the file being labeled'
action_class do
include SELinux::Cookbook::StateHelpers
def current_file_context
file_hash = {
'a' => 'all files',
'f' => 'regular file',
'd' => 'directory',
'c' => 'character device',
'b' => 'block device',
's' => 'socket',
'l' => 'symbolic link',
'p' => 'named pipe',
}
contexts = shell_out!('semanage fcontext -l').stdout.split("\n")
# pull out file label from user:role:type:level context string
contexts.grep(/^#{Regexp.escape(new_resource.file_spec)}\s+#{file_hash[new_resource.file_type]}/) do |c|
c.match(/.+ (?<user>.+):(?<role>.+):(?<type>.+):(?<level>.+)$/)[:type]
# match returns ['foo'] or [], shift converts that to 'foo' or nil
end.shift
end
# Run restorecon to fix label
# https://github.com/sous-chefs/selinux_policy/pull/72#issuecomment-338718721
def relabel_files
spec = new_resource.file_spec
escaped = Regexp.escape spec
# find common path between regex and string
common = if spec == escaped
spec
else
index = spec.size.times { |i| break i if spec[i] != escaped[i] }
::File.dirname spec[0...index]
end
# if path is not absolute, ignore it and search everything
common = '/' if common[0] != '/'
if ::File.exist? common
shell_out!("find #{common.shellescape} -ignore_readdir_race -regextype posix-egrep -regex #{spec.shellescape} -prune -print0 | xargs -0 restorecon -iRv")
end
end
end
action :manage do
run_action(:add)
run_action(:modify)
end
action :addormodify do
Chef::Log.warn('The :addormodify action for selinux_fcontext is deprecated and will be removed in a future release. Use the :manage action instead.')
run_action(:manage)
end
# Create if doesn't exist, do not touch if fcontext is already registered
action :add do
if selinux_disabled?
Chef::Log.warn("Unable to add SELinux fcontext #{new_resource.name} as SELinux is disabled")
return
end
unless current_file_context
converge_by "adding label #{new_resource.secontext} to #{new_resource.file_spec}" do
shell_out!("semanage fcontext -a -f #{new_resource.file_type} -t #{new_resource.secontext} '#{new_resource.file_spec}'")
relabel_files
end
end
end
# Only modify if fcontext exists & doesn't have the correct label already
action :modify do
if selinux_disabled?
Chef::Log.warn("Unable to modify SELinux fcontext #{new_resource.name} as SELinux is disabled")
return
end
if current_file_context && current_file_context != new_resource.secontext
converge_by "modifying label #{new_resource.secontext} to #{new_resource.file_spec}" do
shell_out!("semanage fcontext -m -f #{new_resource.file_type} -t #{new_resource.secontext} '#{new_resource.file_spec}'")
relabel_files
end
end
end
# Delete if exists
action :delete do
if selinux_disabled?
Chef::Log.warn("Unable to delete SELinux fcontext #{new_resource.name} as SELinux is disabled")
return
end
if current_file_context
converge_by "deleting label for #{new_resource.file_spec}" do
shell_out!("semanage fcontext -d -f #{new_resource.file_type} '#{new_resource.file_spec}'")
relabel_files
end
end
end