Module: Puppet::Util::SELinux
- Included in:
- SELFileContext, FileType
- Defined in:
- lib/puppet/util/selinux.rb
Instance Method Summary collapse
-
#find_fs(path) ⇒ Object
Internal helper function to return which type of filesystem a given file path resides on.
-
#get_selinux_current_context(file) ⇒ Object
Retrieve and return the full context of the file.
-
#get_selinux_default_context(file) ⇒ Object
Retrieve and return the default context of the file.
- #parent_directory(path) ⇒ Object
-
#parse_selinux_context(component, context) ⇒ Object
Take the full SELinux context returned from the tools and parse it out to the three (or four) component parts.
-
#read_mounts ⇒ Object
Internal helper function to read and parse /proc/mounts.
- #realpath(path) ⇒ Object
-
#selinux_label_support?(file) ⇒ Boolean
Check filesystem a path resides on for SELinux support against whitelist of known-good filesystems.
- #selinux_support? ⇒ Boolean
-
#set_selinux_context(file, value, component = false) ⇒ Object
This updates the actual SELinux label on the file.
-
#set_selinux_default_context(file) ⇒ Object
Since this call relies on get_selinux_default_context it also needs a full non-relative path to the file.
Instance Method Details
#find_fs(path) ⇒ Object
Internal helper function to return which type of filesystem a given file path resides on
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/puppet/util/selinux.rb', line 186 def find_fs(path) unless mnts = read_mounts return nil end # For a given file: # Check if the filename is in the data structure; # return the fstype if it is. # Just in case: return something if you're down to "/" or "" # Remove the last slash and everything after it, # and repeat with that as the file for the next loop through. path = realpath(path) while not path.empty? return mnts[path] if mnts.has_key?(path) path = parent_directory(path) end mnts['/'] end |
#get_selinux_current_context(file) ⇒ Object
Retrieve and return the full context of the file. If we don’t have SELinux support or if the SELinux call fails then return nil.
26 27 28 29 30 31 32 33 |
# File 'lib/puppet/util/selinux.rb', line 26 def get_selinux_current_context(file) return nil unless selinux_support? retval = Selinux.lgetfilecon(file) if retval == -1 return nil end retval[1] end |
#get_selinux_default_context(file) ⇒ Object
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.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/puppet/util/selinux.rb', line 37 def get_selinux_default_context(file) return nil unless selinux_support? # If the filesystem has no support for SELinux labels, return a default of nil # instead of what matchpathcon would return return nil unless selinux_label_support?(file) # If the file exists we should pass the mode to matchpathcon for the most specific # matching. If not, we can pass a mode of 0. begin filestat = File.lstat(file) mode = filestat.mode rescue Errno::ENOENT mode = 0 end retval = Selinux.matchpathcon(file, mode) if retval == -1 return nil end retval[1] end |
#parent_directory(path) ⇒ Object
180 181 182 |
# File 'lib/puppet/util/selinux.rb', line 180 def parent_directory(path) Pathname.new(path).dirname.to_s end |
#parse_selinux_context(component, context) ⇒ Object
Take the full SELinux context returned from the tools and parse it out to the three (or four) component parts. Supports :seluser, :selrole, :seltype, and on systems with range support, :selrange.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/puppet/util/selinux.rb', line 60 def parse_selinux_context(component, context) if context.nil? or context == "unlabeled" return nil end unless context =~ /^([a-z0-9_]+):([a-z0-9_]+):([a-zA-Z0-9_]+)(?::([a-zA-Z0-9:,._-]+))?/ raise Puppet::Error, "Invalid context to parse: #{context}" end ret = { :seluser => $1, :selrole => $2, :seltype => $3, :selrange => $4, } ret[component] end |
#read_mounts ⇒ Object
Internal helper function to read and parse /proc/mounts
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/puppet/util/selinux.rb', line 140 def read_mounts mounts = "" begin if File.instance_methods.include? "read_nonblock" # If possible we use read_nonblock in a loop rather than read to work- # a linux kernel bug. See ticket #1963 for details. mountfh = File.open("/proc/mounts") mounts += mountfh.read_nonblock(1024) while true else # Otherwise we shell out and let cat do it for us mountfh = IO.popen("/bin/cat /proc/mounts") mounts = mountfh.read end rescue EOFError # that's expected rescue return nil ensure mountfh.close if mountfh end mntpoint = {} # Read all entries in /proc/mounts. The second column is the # mountpoint and the third column is the filesystem type. # We skip rootfs because it is always mounted at / mounts.collect do |line| params = line.split(' ') next if params[2] == 'rootfs' mntpoint[params[1]] = params[2] end mntpoint end |
#realpath(path) ⇒ Object
174 175 176 177 178 |
# File 'lib/puppet/util/selinux.rb', line 174 def realpath(path) path, rest = Pathname.new(path), [] path, rest = path.dirname, [path.basename] + rest while ! path.exist? File.join( path.realpath, *rest ) end |
#selinux_label_support?(file) ⇒ Boolean
Check filesystem a path resides on for SELinux support against whitelist of known-good filesystems. Returns true if the filesystem can support SELinux labels and false if not.
209 210 211 212 213 214 |
# File 'lib/puppet/util/selinux.rb', line 209 def selinux_label_support?(file) fstype = find_fs(file) return false if fstype.nil? filesystems = ['ext2', 'ext3', 'ext4', 'gfs', 'gfs2', 'xfs', 'jfs'] filesystems.include?(fstype) end |
#selinux_support? ⇒ Boolean
16 17 18 19 20 21 22 |
# File 'lib/puppet/util/selinux.rb', line 16 def selinux_support? return false unless defined?(Selinux) if Selinux.is_selinux_enabled == 1 return true end false end |
#set_selinux_context(file, value, component = false) ⇒ Object
This updates the actual SELinux label on the file. You can update 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.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/puppet/util/selinux.rb', line 83 def set_selinux_context(file, value, component = false) return nil unless selinux_support? && selinux_label_support?(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 Puppet.warning "Failed to set SELinux context #{context} on #{file}" return false end end |
#set_selinux_default_context(file) ⇒ Object
Since this call relies on get_selinux_default_context it also needs a full non-relative path to the file. Fortunately, that seems to be all Puppet uses. This will set the file’s SELinux context to the policy’s default context (if any) if it differs from the context currently on the file.
128 129 130 131 132 133 134 135 136 137 |
# File 'lib/puppet/util/selinux.rb', line 128 def set_selinux_default_context(file) new_context = get_selinux_default_context(file) return nil unless new_context cur_context = get_selinux_current_context(file) if new_context != cur_context set_selinux_context(file, new_context) return new_context end nil end |