# module Puppet::Util::SELinux

### Public Instance Methods

get_selinux_current_context(file) click to toggle source

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.

    # 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) click to toggle source

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.

    # 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::EACCES, Errno::ENOENT
        mode = 0
      end

      retval = Selinux.matchpathcon(file, mode)
      if retval == -1
        return nil
      end
      retval[1]
    end

parse_selinux_context(component, context) click to toggle source

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.

    # File lib/puppet/util/selinux.rb, line 61
    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

selinux_support?() click to toggle source

    # 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) click to toggle source

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.

    # File lib/puppet/util/selinux.rb, line 84
    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) click to toggle source

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.

    # File lib/puppet/util/selinux.rb, line 129
    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