Merged fsweetser's selinux patch against HEAD
This commit is contained in:
Родитель
bb23861e33
Коммит
1b512a9a41
|
@ -0,0 +1,47 @@
|
|||
Puppet::Type.type(:selboolean).provide(:getsetsebool) do
|
||||
desc "Manage SELinux booleans using the getsebool and setsebool binaries."
|
||||
|
||||
commands :getsebool => "/usr/sbin/getsebool"
|
||||
commands :setsebool => "/usr/sbin/setsebool"
|
||||
|
||||
def value
|
||||
self.debug "Retrieving value of selboolean #{@resource[:name]}"
|
||||
|
||||
status = getsebool(@resource[:name])
|
||||
|
||||
if status =~ / off$/ then
|
||||
return :off
|
||||
elsif status =~ / on$/ then
|
||||
return :on
|
||||
else
|
||||
status.chomp!
|
||||
raise Puppet::Error, "Invalid response '%s' returned from getsebool" % [status]
|
||||
end
|
||||
end
|
||||
|
||||
def value=(new)
|
||||
persist = ""
|
||||
if @resource[:persistent] == :true
|
||||
self.debug "Enabling persistence"
|
||||
persist = "-P"
|
||||
end
|
||||
execoutput("#{command(:setsebool)} #{persist} #{@resource[:name]} #{new}")
|
||||
return :file_changed
|
||||
end
|
||||
|
||||
# Required workaround, since SELinux policy prevents setsebool
|
||||
# from writing to any files, even tmp, preventing the standard
|
||||
# 'setsebool("...")' construct from working.
|
||||
|
||||
def execoutput (cmd)
|
||||
output = ''
|
||||
begin
|
||||
execpipe(cmd) do |out|
|
||||
output = out.readlines.join('').chomp!
|
||||
end
|
||||
rescue Puppet::ExecutionFailure
|
||||
raise Puppet::ExecutionFailure, output.split("\n")[0]
|
||||
end
|
||||
return output
|
||||
end
|
||||
end
|
|
@ -0,0 +1,143 @@
|
|||
Puppet::Type.type(:selmodule).provide(:semodule) do
|
||||
desc "Manage SELinux policy modules using the semodule binary."
|
||||
|
||||
commands :semodule => "/usr/sbin/semodule"
|
||||
|
||||
def create
|
||||
begin
|
||||
execoutput("#{command(:semodule)} --install #{selmod_name_to_filename}")
|
||||
rescue Puppet::ExecutionFailure => detail
|
||||
raise Puppet::Error, "Could not load policy module: %s" % [detail];
|
||||
end
|
||||
return :true
|
||||
end
|
||||
|
||||
def destroy
|
||||
begin
|
||||
execoutput("#{command(:semodule)} --remove #{@resource[:name]}")
|
||||
rescue Puppet::ExecutionFailure => detail
|
||||
raise Puppet::Error, "Could not remove policy module: %s" % [detail];
|
||||
end
|
||||
end
|
||||
|
||||
def exists?
|
||||
self.debug "Checking for module #{@resource[:name]}"
|
||||
execpipe("#{command(:semodule)} --list") do |out|
|
||||
out.each do |line|
|
||||
if line =~ /#{@resource[:name]}\b/
|
||||
return :true
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def syncversion
|
||||
self.debug "Checking syncversion on #{@resource[:name]}"
|
||||
|
||||
loadver = selmodversion_loaded
|
||||
|
||||
if(loadver) then
|
||||
filever = selmodversion_file
|
||||
if (filever == loadver) then
|
||||
return :true
|
||||
end
|
||||
end
|
||||
return :false
|
||||
end
|
||||
|
||||
def syncversion= (dosync)
|
||||
begin
|
||||
execoutput("#{command(:semodule)} --upgrade #{selmod_name_to_filename}")
|
||||
rescue Puppet::ExecutionFailure => detail
|
||||
raise Puppet::Error, "Could not upgrade policy module: %s" % [detail];
|
||||
end
|
||||
end
|
||||
|
||||
# Helper functions
|
||||
|
||||
def execoutput (cmd)
|
||||
output = ''
|
||||
begin
|
||||
execpipe(cmd) do |out|
|
||||
output = out.readlines.join('').chomp!
|
||||
end
|
||||
rescue Puppet::ExecutionFailure
|
||||
raise Puppet::ExecutionFailure, output.split("\n")[0]
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
def selmod_name_to_filename
|
||||
if @resource[:selmodulepath]
|
||||
return @resource[:selmodulepath]
|
||||
else
|
||||
return "#{@resource[:selmoduledir]}/#{@resource[:name]}.pp"
|
||||
end
|
||||
end
|
||||
|
||||
def selmod_readnext (handle)
|
||||
len = handle.read(4).unpack('L')[0]
|
||||
return handle.read(len)
|
||||
end
|
||||
|
||||
def selmodversion_file
|
||||
magic = 0xF97CFF8F
|
||||
|
||||
filename = selmod_name_to_filename
|
||||
mod = File.new(filename, "r")
|
||||
|
||||
(hdr, ver, numsec) = mod.read(12).unpack('LLL')
|
||||
|
||||
if hdr != magic
|
||||
raise Puppet::Error, "Found #{hdr} instead of magic #{magic} in #{filename}"
|
||||
end
|
||||
|
||||
if ver != 1
|
||||
raise Puppet::Error, "Unknown policy file version #{ver} in #{filename}"
|
||||
end
|
||||
|
||||
# Read through (and throw away) the file section offsets, and also
|
||||
# the magic header for the first section.
|
||||
|
||||
mod.read((numsec + 1) * 4)
|
||||
|
||||
## Section 1 should be "SE Linux Module"
|
||||
|
||||
selmod_readnext(mod)
|
||||
selmod_readnext(mod)
|
||||
|
||||
# Skip past the section headers
|
||||
mod.read(14)
|
||||
|
||||
# Module name
|
||||
selmod_readnext(mod)
|
||||
|
||||
# At last! the version
|
||||
|
||||
v = selmod_readnext(mod)
|
||||
|
||||
self.debug "file version #{v}"
|
||||
return v
|
||||
end
|
||||
|
||||
def selmodversion_loaded
|
||||
lines = ()
|
||||
begin
|
||||
execpipe("#{command(:semodule)} --list") do |output|
|
||||
lines = output.readlines
|
||||
lines.each do |line|
|
||||
line.chomp!
|
||||
bits = line.split
|
||||
if bits[0] == @resource[:name] then
|
||||
self.debug "load version #{bits[1]}"
|
||||
return bits[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Puppet::ExecutionFailure
|
||||
raise Puppet::ExecutionFailure, "Could not list policy modules: %s" % [lines.join(' ').chomp!]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
|
@ -948,4 +948,5 @@ module Puppet
|
|||
require 'puppet/type/file/group'
|
||||
require 'puppet/type/file/mode'
|
||||
require 'puppet/type/file/type'
|
||||
require 'puppet/type/file/selcontext' # SELinux file context
|
||||
end
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
# Manage SELinux context of files.
|
||||
#
|
||||
# This code actually manages three pieces of data in the context.
|
||||
#
|
||||
# [root@delenn files]# ls -dZ /
|
||||
# drwxr-xr-x root root system_u:object_r:root_t /
|
||||
#
|
||||
# The context of '/' here is 'system_u:object_r:root_t'. This is
|
||||
# three seperate fields:
|
||||
#
|
||||
# system_u is the user context
|
||||
# object_r is the role context
|
||||
# root_t is the type context
|
||||
#
|
||||
# All three of these fields are returned in a single string by the
|
||||
# output of the stat command, but set individually with the chcon
|
||||
# command. This allows the user to specify a subset of the three
|
||||
# values while leaving the others alone.
|
||||
#
|
||||
# See http://www.nsa.gov/selinux/ for complete docs on SELinux.
|
||||
|
||||
module Puppet
|
||||
class SELFileContext < Puppet::Property
|
||||
|
||||
def retrieve
|
||||
unless @resource.stat(false)
|
||||
return :absent
|
||||
end
|
||||
context = `stat -c %C #{@resource[:path]}`
|
||||
context.chomp!
|
||||
if context == "unlabeled"
|
||||
return nil
|
||||
end
|
||||
unless context =~ /^[a-z0-9_]+:[a-z0-9_]+:[a-z0-9_]+/
|
||||
raise Puppet::Error, "Invalid output from stat: #{context}"
|
||||
end
|
||||
bits = context.split(':')
|
||||
ret = {
|
||||
:seluser => bits[0],
|
||||
:selrole => bits[1],
|
||||
:seltype => bits[2]
|
||||
}
|
||||
return ret[name]
|
||||
end
|
||||
|
||||
def sync
|
||||
unless @resource.stat(false)
|
||||
stat = @resource.stat(true)
|
||||
unless stat
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
flag = ''
|
||||
|
||||
case name
|
||||
when :seluser
|
||||
flag = "-u"
|
||||
when :selrole
|
||||
flag = "-r"
|
||||
when :seltype
|
||||
flag = "-t"
|
||||
else
|
||||
raise Puppet::Error, "Invalid SELinux file context component: #{name}"
|
||||
end
|
||||
|
||||
self.debug "Running chcon #{flag} #{@should} #{@resource[:path]}"
|
||||
retval = system("chcon #{flag} #{@should} #{@resource[:path]}")
|
||||
unless retval
|
||||
error = Puppet::Error.new("failed to chcon %s" % [@resource[:path]])
|
||||
raise error
|
||||
end
|
||||
return :file_changed
|
||||
end
|
||||
end
|
||||
|
||||
Puppet.type(:file).newproperty(:seluser, :parent => Puppet::SELFileContext) do
|
||||
desc "What the SELinux User context of the file should be."
|
||||
|
||||
@event = :file_changed
|
||||
end
|
||||
|
||||
Puppet.type(:file).newproperty(:selrole, :parent => Puppet::SELFileContext) do
|
||||
desc "What the SELinux Role context of the file should be."
|
||||
|
||||
@event = :file_changed
|
||||
end
|
||||
|
||||
Puppet.type(:file).newproperty(:seltype, :parent => Puppet::SELFileContext) do
|
||||
desc "What the SELinux Type context of the file should be."
|
||||
|
||||
@event = :file_changed
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#
|
||||
# Simple module for manageing SELinux booleans
|
||||
#
|
||||
|
||||
module Puppet
|
||||
newtype(:selboolean) do
|
||||
@doc = "Enable or disable SELinux booleans."
|
||||
|
||||
newparam(:name) do
|
||||
desc "The name of the SELinux boolean to be managed."
|
||||
isnamevar
|
||||
end
|
||||
|
||||
newproperty(:value) do
|
||||
desc "Whether the the SELinux boolean should be enabled or disabled. Possible values are ``on`` or ``off``."
|
||||
newvalue(:on)
|
||||
newvalue(:off)
|
||||
end
|
||||
|
||||
newparam(:persistent) do
|
||||
desc "If set true, SELinux booleans will be written to disk and persist accross reboots."
|
||||
|
||||
defaultto :false
|
||||
newvalues(:true, :false)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# Simple module for manageing SELinux policy modules
|
||||
#
|
||||
|
||||
Puppet::Type.newtype(:selmodule) do
|
||||
@doc = "Enable or disable SELinux policy modules."
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name) do
|
||||
desc "The name of the SELinux policy to be managed."
|
||||
isnamevar
|
||||
end
|
||||
|
||||
newparam(:selmoduledir) do
|
||||
|
||||
desc "The directory to look for the compiled pp module file in.
|
||||
Currently defaults to /usr/share/selinux/targeted"
|
||||
|
||||
defaultto "/usr/share/selinux/targeted"
|
||||
end
|
||||
|
||||
newparam(:selmodulepath) do
|
||||
|
||||
desc "The full path in which to look for the compiled pp
|
||||
module file in. You only need to use this if the module file
|
||||
is not in the directory pointed at by selmoduledir."
|
||||
|
||||
end
|
||||
|
||||
newproperty(:syncversion) do
|
||||
|
||||
desc "If set to 'true', the policy will be reloaded if the
|
||||
version found in the on-disk file differs from the loaded
|
||||
version. If set to 'false' (the default) the the only check
|
||||
that will be made is if the policy is loaded at all or not."
|
||||
|
||||
newvalue(:true)
|
||||
newvalue(:false)
|
||||
end
|
||||
|
||||
autorequire(:file) do
|
||||
if self[:selmodulepath]
|
||||
[self[:selmodulepath]]
|
||||
else
|
||||
["#{self[:selmoduledir]}/#{self[:name]}.pp"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
||||
|
||||
require 'puppet/type/selboolean'
|
||||
require 'puppet/type/selmodule'
|
||||
|
||||
describe Puppet.type(:file), " when manipulating file contexts" do
|
||||
before :each do
|
||||
@file = Puppet::Type::File.create(
|
||||
:name => "/tmp/foo",
|
||||
:ensure => "file",
|
||||
:seluser => "user_u",
|
||||
:selrole => "role_r",
|
||||
:seltype => "type_t" )
|
||||
end
|
||||
it "should use :seluser to get/set an SELinux user file context attribute" do
|
||||
@file.property(:seluser).should == "user_u"
|
||||
end
|
||||
it "should use :selrole to get/set an SELinux role file context attribute" do
|
||||
@file.property(:selrole).should == "role_r"
|
||||
end
|
||||
it "should use :seltype to get/set an SELinux user file context attribute" do
|
||||
@file.property(:seltype).should == "type_t"
|
||||
end
|
||||
end
|
||||
|
||||
describe Puppet.type(:selboolean), " when manipulating booleans" do
|
||||
before :each do
|
||||
@bool = Puppet::Type::Selboolean.create(
|
||||
:name => "foo",
|
||||
:value => "on",
|
||||
:persistent => true )
|
||||
end
|
||||
it "should be able to access :name" do
|
||||
@bool[:name].should == "foo"
|
||||
end
|
||||
it "should be able to access :value" do
|
||||
@bool.property(:value).should == :on
|
||||
end
|
||||
it "should set :value to off" do
|
||||
@bool[:value] = :off
|
||||
@bool.property(:value).should == :off
|
||||
end
|
||||
it "should be able to access :persistent" do
|
||||
@bool[:persistent].should == :true
|
||||
end
|
||||
it "should set :persistent to false" do
|
||||
@bool[:persistent] = false
|
||||
@bool[:persistent].should == :false
|
||||
end
|
||||
end
|
||||
|
||||
describe Puppet.type(:selmodule), " when checking policy modules" do
|
||||
before :each do
|
||||
@module = Puppet::Type::Selmodule.create(
|
||||
:name => "foo",
|
||||
:selmoduledir => "/some/path",
|
||||
:selmodulepath => "/some/path/foo.pp",
|
||||
:syncversion => true)
|
||||
end
|
||||
it "should be able to access :name" do
|
||||
@module[:name].should == "foo"
|
||||
end
|
||||
it "should be able to access :selmoduledir" do
|
||||
@module[:selmoduledir].should == "/some/path"
|
||||
end
|
||||
it "should be able to access :selmodulepath" do
|
||||
@module[:selmodulepath].should == "/some/path/foo.pp"
|
||||
end
|
||||
it "should be able to access :syncversion" do
|
||||
@module.property(:syncversion).should == :true
|
||||
end
|
||||
it "should set the syncversion value to false" do
|
||||
@module[:syncversion] = :false
|
||||
@module.property(:syncversion).should == :false
|
||||
end
|
||||
end
|
||||
|
Загрузка…
Ссылка в новой задаче