[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, master, updated. debian/0.24.6-1-356-g5718585
James Turnbull
james at lovedthanlost.net
Fri Jan 23 14:21:37 UTC 2009
The following commit has been merged in the master branch:
commit 3a5dcab28682a1bbf1b71b2d1de39008468b1ca6
Author: Sean E. Millichamp <sean at bruenor.org>
Date: Sun Nov 2 20:05:57 2008 -0500
Refactoring of SELinux functions to use native Ruby SELinux interface
diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb
index 1487489..b181b35 100644
--- a/lib/puppet/util/selinux.rb
+++ b/lib/puppet/util/selinux.rb
@@ -1,74 +1,55 @@
# Provides utility functions to help interfaces Puppet to SELinux.
#
-# Currently this is implemented via the command line tools. At some
-# point support should be added to use the new SELinux ruby bindings
-# as that will be faster and more reliable then shelling out when they
-# are available. At this time (2008-09-26) these bindings aren't bundled on
-# any SELinux-using distribution I know of.
+# This requires the very new SELinux Ruby bindings. These bindings closely
+# mirror the SELinux C library interface.
+#
+# Support for the command line tools is not provided because the performance
+# was abysmal. At this time (2008-11-02) the only distribution providing
+# these Ruby SELinux bindings which I am aware of is Fedora (in libselinux-ruby).
-require 'puppet/util'
+begin
+ require 'selinux'
+rescue LoadError
+ # Nothing
+end
module Puppet::Util::SELinux
- include Puppet::Util
-
def selinux_support?
- FileTest.exists?("/selinux/enforce")
+ unless defined? Selinux
+ return false
+ end
+ if Selinux.is_selinux_enabled == 1
+ return true
+ end
+ return false
end
# Retrieve and return the full context of the file. If we don't have
- # SELinux support or if the stat call fails then return nil.
+ # SELinux support or if the SELinux call fails then return nil.
def get_selinux_current_context(file)
unless selinux_support?
return nil
end
- context = ""
- begin
- execpipe("/usr/bin/stat -c %C #{file}") do |out|
- out.each do |line|
- context << line
- end
- end
- rescue Puppet::ExecutionFailure
- return nil
- end
- context.chomp!
- # Handle the case that the system seems to have SELinux support but
- # stat finds unlabled files.
- if context == "(null)"
+ retval = Selinux.lgetfilecon(file)
+ if retval == -1
return nil
end
- return context
+ return retval[1]
end
- # Use the matchpathcon command, if present, to return the SELinux context
- # which the SELinux policy on the system expects the file to have. We can
- # use this to obtain a good default context. If the command does not
- # exist or the call fails return nil.
- #
- # Note: For this command to work a full, non-relative, filesystem path
- # should be given.
+ # Retrieve and return the default context of the file. If we don't have
+ # SELinux support or if the SELinux call fails to file a default then return nil.
def get_selinux_default_context(file)
unless selinux_support?
return nil
end
- unless FileTest.executable?("/usr/sbin/matchpathcon")
+ filestat = File.lstat(file)
+ retval = Selinux.matchpathcon(file, filestat.mode)
+ if retval == -1
return nil
end
- context = ""
- begin
- execpipe("/usr/sbin/matchpathcon #{file}") do |out|
- out.each do |line|
- context << line
- end
- end
- rescue Puppet::ExecutionFailure
- return nil
- end
- # For a successful match, matchpathcon returns two fields separated by
- # a variable amount of whitespace. The second field is the full context.
- context = context.split(/\s/)[1]
- return context
+ return retval[1]
end
# Take the full SELinux context returned from the tools and parse it
@@ -91,32 +72,52 @@ module Puppet::Util::SELinux
end
# This updates the actual SELinux label on the file. You can update
- # only a single component or update the entire context. It is just a
- # wrapper around the chcon command.
+ # only a single component or update the entire context.
+ # The caveat is that since setting a partial context makes no sense the
+ # file has to already exist. Puppet (via the File resource) will always
+ # just try to set components, even if all values are specified by the manifest.
+ # I believe that the OS should always provide at least a fall-through context
+ # though on any well-running system.
def set_selinux_context(file, value, component = false)
unless selinux_support?
return nil
end
- case component
- when :seluser
- flag = "-u"
- when :selrole
- flag = "-r"
- when :seltype
- flag = "-t"
- when :selrange
- flag = "-l"
- else
- flag = nil
- end
- if flag.nil?
- cmd = ["/usr/bin/chcon","-h",value,file]
+ if component
+ # Must first get existing context to replace a single component
+ context = Selinux.lgetfilecon(file)[1]
+ if context == -1
+ # We can't set partial context components when no context exists
+ # unless/until we can find a way to make Puppet call this method
+ # once for all selinux file label attributes.
+ Puppet.warning "Can't set SELinux context on file unless the file already has some kind of context"
+ return nil
+ end
+ context = context.split(':')
+ case component
+ when :seluser
+ context[0] = value
+ when :selrole
+ context[1] = value
+ when :seltype
+ context[2] = value
+ when :selrange
+ context[3] = value
+ else
+ raise ArguementError, "set_selinux_context component must be one of :seluser, :selrole, :seltype, or :selrange"
+ end
+ context = context.join(':')
+ else
+ context = value
+ end
+
+ retval = Selinux.lsetfilecon(file, context)
+ if retval == 0
+ return true
else
- cmd = ["/usr/bin/chcon","-h",flag,value,file]
+ Puppet.warning "Failed to set SELinux context %s on %s" % [context, file]
+ return false
end
- execute(cmd)
- return true
end
# Since this call relies on get_selinux_default_context it also needs a
diff --git a/spec/unit/util/selinux.rb b/spec/unit/util/selinux.rb
index 7a56f91..076ebd2 100644
--- a/spec/unit/util/selinux.rb
+++ b/spec/unit/util/selinux.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") }
+require File.dirname(__FILE__) + '/../../spec_helper'
require 'puppet/util/selinux'
include Puppet::Util::SELinux
@@ -8,13 +8,19 @@ include Puppet::Util::SELinux
describe Puppet::Util::SELinux do
describe "selinux_support?" do
+ before :all do
+ if not defined? Selinux
+ Selinux = mock()
+ end
+ end
+
it "should return :true if this system has SELinux enabled" do
- FileTest.expects(:exists?).with("/selinux/enforce").returns true
+ Selinux.expects(:is_selinux_enabled).returns 1
selinux_support?.should be_true
end
it "should return :false if this system lacks SELinux" do
- FileTest.expects(:exists?).with("/selinux/enforce").returns false
+ Selinux.expects(:is_selinux_enabled).returns 0
selinux_support?.should be_false
end
end
@@ -27,19 +33,13 @@ describe Puppet::Util::SELinux do
it "should return a context" do
self.expects(:selinux_support?).returns true
- self.expects(:execpipe).with("/usr/bin/stat -c %C /foo").yields ["user_u:role_r:type_t:s0\n"]
+ Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:type_t:s0"]
get_selinux_current_context("/foo").should == "user_u:role_r:type_t:s0"
end
- it "should return nil if an exception is raised calling stat" do
+ it "should return nil if lgetfilecon fails" do
self.expects(:selinux_support?).returns true
- self.expects(:execpipe).with("/usr/bin/stat -c %C /foo").raises(Puppet::ExecutionFailure, 'error')
- get_selinux_current_context("/foo").should be_nil
- end
-
- it "should return nil if stat finds an unlabeled file" do
- self.expects(:selinux_support?).returns true
- self.expects(:execpipe).with("/usr/bin/stat -c %C /foo").yields ["(null)\n"]
+ Selinux.expects(:lgetfilecon).with("/foo").returns -1
get_selinux_current_context("/foo").should be_nil
end
end
@@ -50,23 +50,19 @@ describe Puppet::Util::SELinux do
get_selinux_default_context("/foo").should be_nil
end
- it "should return nil if matchpathcon is not executable" do
- self.expects(:selinux_support?).returns true
- FileTest.expects(:executable?).with("/usr/sbin/matchpathcon").returns false
- get_selinux_default_context("/foo").should be_nil
- end
-
it "should return a context if a default context exists" do
self.expects(:selinux_support?).returns true
- FileTest.expects(:executable?).with("/usr/sbin/matchpathcon").returns true
- self.expects(:execpipe).with("/usr/sbin/matchpathcon /foo").yields ["/foo\tuser_u:role_r:type_t:s0\n"]
+ fstat = stub 'File::Stat', :mode => 0
+ File.expects(:lstat).with("/foo").returns fstat
+ Selinux.expects(:matchpathcon).with("/foo", 0).returns [0, "user_u:role_r:type_t:s0"]
get_selinux_default_context("/foo").should == "user_u:role_r:type_t:s0"
end
- it "should return nil if an exception is raised calling matchpathcon" do
+ it "should return nil if matchpathcon returns failure" do
self.expects(:selinux_support?).returns true
- FileTest.expects(:executable?).with("/usr/sbin/matchpathcon").returns true
- self.expects(:execpipe).with("/usr/sbin/matchpathcon /foo").raises(Puppet::ExecutionFailure, 'error')
+ fstat = stub 'File::Stat', :mode => 0
+ File.expects(:lstat).with("/foo").returns fstat
+ Selinux.expects(:matchpathcon).with("/foo", 0).returns -1
get_selinux_default_context("/foo").should be_nil
end
end
@@ -115,33 +111,37 @@ describe Puppet::Util::SELinux do
set_selinux_context("/foo", "user_u:role_r:type_t:s0").should be_nil
end
- it "should use chcon to set a context" do
+ it "should use lsetfilecon to set a context" do
self.expects(:selinux_support?).returns true
- self.expects(:execute).with(["/usr/bin/chcon","-h","user_u:role_r:type_t:s0","/foo"]).returns 0
+ Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0
set_selinux_context("/foo", "user_u:role_r:type_t:s0").should be_true
end
- it "should use chcon to set user_u user context" do
+ it "should use lsetfilecon to set user_u user context" do
self.expects(:selinux_support?).returns true
- self.expects(:execute).with(["/usr/bin/chcon","-h","-u","user_u","/foo"]).returns 0
+ Selinux.expects(:lgetfilecon).with("/foo").returns [0, "foo:role_r:type_t:s0"]
+ Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0
set_selinux_context("/foo", "user_u", :seluser).should be_true
end
- it "should use chcon to set role_r role context" do
+ it "should use lsetfilecon to set role_r role context" do
self.expects(:selinux_support?).returns true
- self.expects(:execute).with(["/usr/bin/chcon","-h","-r","role_r","/foo"]).returns 0
+ Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:foo:type_t:s0"]
+ Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0
set_selinux_context("/foo", "role_r", :selrole).should be_true
end
- it "should use chcon to set type_t type context" do
+ it "should use lsetfilecon to set type_t type context" do
self.expects(:selinux_support?).returns true
- self.expects(:execute).with(["/usr/bin/chcon","-h","-t","type_t","/foo"]).returns 0
+ Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:foo:s0"]
+ Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0").returns 0
set_selinux_context("/foo", "type_t", :seltype).should be_true
end
- it "should use chcon to set s0:c3,c5 range context" do
+ it "should use lsetfilecon to set s0:c3,c5 range context" do
self.expects(:selinux_support?).returns true
- self.expects(:execute).with(["/usr/bin/chcon","-h","-l","s0:c3,c5","/foo"]).returns 0
+ Selinux.expects(:lgetfilecon).with("/foo").returns [0, "user_u:role_r:type_t:s0"]
+ Selinux.expects(:lsetfilecon).with("/foo", "user_u:role_r:type_t:s0:c3,c5").returns 0
set_selinux_context("/foo", "s0:c3,c5", :selrange).should be_true
end
end
--
Puppet packaging for Debian
More information about the Pkg-puppet-devel
mailing list