Merged fsweetser's selinux patch against HEAD

This commit is contained in:
Brett Lentz 2008-07-24 18:13:14 -07:00 коммит произвёл James Turnbull
Родитель bb23861e33
Коммит 1b512a9a41
7 изменённых файлов: 445 добавлений и 0 удалений

Просмотреть файл

@ -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