Module: Puppet::Util::SELinux Private

Included in:
SELFileContext, FileType
Defined in:
lib/puppet/util/selinux.rb

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Constant Summary collapse

S_IFREG =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

0100000
S_IFDIR =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

0040000
S_IFLNK =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

0120000

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.selinux_support?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

20
21
22
23
24
25
26
# File 'lib/puppet/util/selinux.rb', line 20

def self.selinux_support?
  return false unless defined?(Selinux)
  if Selinux.is_selinux_enabled == 1
    return true
  end
  false
end

Instance Method Details

#get_selinux_current_context(file) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.


34
35
36
37
38
39
40
41
# File 'lib/puppet/util/selinux.rb', line 34

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, resource_ensure = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/puppet/util/selinux.rb', line 45

def get_selinux_default_context(file, resource_ensure=nil)
  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
    mode = 0
  rescue Errno::ENOENT
    if resource_ensure
      mode = get_create_mode(resource_ensure)
    else
      mode = 0
    end
  end

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

#parse_selinux_context(component, context) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/puppet/util/selinux.rb', line 75

def parse_selinux_context(component, context)
  if context.nil? or context == "unlabeled"
    return nil
  end
  components = /^([^\s:]+):([^\s:]+):([^\s:]+)(?::([\sa-zA-Z0-9:,._-]+))?$/.match(context)
  unless components
    raise Puppet::Error, _("Invalid context to parse: %{context}") % { context: context }
  end
  case component
  when :seluser
    components[1]
  when :selrole
    components[2]
  when :seltype
    components[3]
  when :selrange
    components[4]
  else
    raise Puppet::Error, _("Invalid SELinux parameter type")
  end
end

#selinux_category_to_label(category) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

selinux_category_to_label is an internal method that converts all selinux categories to their internal representation, avoiding potential issues when mcstransd is not functional.

It is not marked private because it is needed by File's selcontext.rb, but it is not intended for use outside of Puppet's code.

Parameters:

  • category (String)

    An selinux category, such as “s0” or “SystemLow”

Returns:

  • (String)

    the numeric category name, such as “s0”


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/puppet/util/selinux.rb', line 172

def selinux_category_to_label(category)
  # We don't cache this, but there's already a ton of duplicate work
  # in the selinux handling code.

  path = Selinux.selinux_translations_path
  begin
    File.open(path).each do |line|
      line.strip!
      next if line.empty?
      next if line[0] == "#" # skip comments
      line.gsub!(/[[:space:]]+/m, '')
      mapping = line.split("=", 2)
      if category == mapping[1]
        return mapping[0]
      end
    end
  rescue SystemCallError => ex
    log_exception(ex)
    raise Puppet::Error, _("Could not open SELinux category translation file %{path}.") % { context: context }
  end

  category
end

#selinux_support?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)

28
29
30
# File 'lib/puppet/util/selinux.rb', line 28

def selinux_support?
  Puppet::Util::SELinux.selinux_support?
end

#set_selinux_context(file, value, component = false) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/puppet/util/selinux.rb', line 104

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 ArgumentError, _("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}") % { context: context, file: file }
    return false
  end
end

#set_selinux_default_context(file, resource_ensure = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.


149
150
151
152
153
154
155
156
157
158
# File 'lib/puppet/util/selinux.rb', line 149

def set_selinux_default_context(file, resource_ensure=nil)
  new_context = get_selinux_default_context(file, resource_ensure)
  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