summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet/provider/selboolean/getsetsebool.rb47
-rw-r--r--lib/puppet/provider/selmodule/semodule.rb143
-rw-r--r--lib/puppet/type/file.rb1
-rw-r--r--lib/puppet/type/file/selcontext.rb96
-rw-r--r--lib/puppet/type/selboolean.rb29
-rw-r--r--lib/puppet/type/selmodule.rb50
6 files changed, 366 insertions, 0 deletions
diff --git a/lib/puppet/provider/selboolean/getsetsebool.rb b/lib/puppet/provider/selboolean/getsetsebool.rb
new file mode 100644
index 000000000..4614c6c38
--- /dev/null
+++ b/lib/puppet/provider/selboolean/getsetsebool.rb
@@ -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
diff --git a/lib/puppet/provider/selmodule/semodule.rb b/lib/puppet/provider/selmodule/semodule.rb
new file mode 100644
index 000000000..498136691
--- /dev/null
+++ b/lib/puppet/provider/selmodule/semodule.rb
@@ -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
diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb
index 2a5e61de8..371571ff3 100644
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -1157,4 +1157,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
diff --git a/lib/puppet/type/file/selcontext.rb b/lib/puppet/type/file/selcontext.rb
new file mode 100644
index 000000000..f36695075
--- /dev/null
+++ b/lib/puppet/type/file/selcontext.rb
@@ -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
+
diff --git a/lib/puppet/type/selboolean.rb b/lib/puppet/type/selboolean.rb
new file mode 100644
index 000000000..d12dd3bcb
--- /dev/null
+++ b/lib/puppet/type/selboolean.rb
@@ -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
+
diff --git a/lib/puppet/type/selmodule.rb b/lib/puppet/type/selmodule.rb
new file mode 100644
index 000000000..1f02912ad
--- /dev/null
+++ b/lib/puppet/type/selmodule.rb
@@ -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
+