File: semodule.rb

package info (click to toggle)
puppet-agent 8.10.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 27,392 kB
  • sloc: ruby: 286,820; sh: 492; xml: 116; makefile: 88; cs: 68
file content (155 lines) | stat: -rw-r--r-- 3,901 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
71
72
73
74
75
76
77
78
79
80
81
82
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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: #{detail}", detail.backtrace
    end
    :true
  end

  def destroy
    execoutput("#{command(:semodule)} --remove #{@resource[:name]}")
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, "Could not remove policy module: #{detail}", detail.backtrace
  end

  def exists?
    debug "Checking for module #{@resource[:name]}"
    selmodules_loaded.key?(@resource[:name])
  end

  def syncversion
    debug "Checking syncversion on #{@resource[:name]}"

    loadver = selmodversion_loaded

    if loadver
      filever = selmodversion_file
      if filever == loadver
        return :true
      end
    end
    :false
  end

  def syncversion=(_dosync)
    execoutput("#{command(:semodule)} --upgrade #{selmod_name_to_filename}")
  rescue Puppet::ExecutionFailure => detail
    raise Puppet::Error, "Could not upgrade policy module: #{detail}", detail.backtrace
  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], $ERROR_INFO.backtrace
    end
    output
  end

  def selmod_name_to_filename
    if @resource[:selmodulepath]
      @resource[:selmodulepath]
    else
      "#{@resource[:selmoduledir]}/#{@resource[:name]}.pp"
    end
  end

  def selmod_readnext(handle)
    len = handle.read(4).unpack('V')[0]
    handle.read(len)
  end

  def selmodversion_file
    magic = 0xF97CFF8F
    v = nil

    filename = selmod_name_to_filename
    # Open a file handle and parse the bytes until version is found
    Puppet::FileSystem.open(filename, nil, 'rb') do |mod|
      (hdr, ver, numsec) = mod.read(12).unpack('VVV')

      raise Puppet::Error, "Found #{hdr} instead of magic #{magic} in #{filename}" if hdr != magic

      raise Puppet::Error, "Unknown policy file version #{ver} in #{filename}" if ver != 1

      # 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)
    end

    debug "file version #{v}"
    v
  end

  def selmodversion_loaded
    selmodules_loaded[@resource[:name]]
  end

  def selmodules_loaded
    self.class.selmodules_loaded
  end

  # Extend Class

  class << self
    attr_accessor :loaded_modules
  end

  # Prefetch loaded selinux modules.
  def self.prefetch(_resources)
    selmodules_loaded
  end

  def self.selmodules_loaded
    if @loaded_modules.nil?
      debug 'Fetching loaded selinux modules'
      modules = {}
      selmodule_cmd = "#{command(:semodule)} --list"
      output = []
      begin
        execpipe(selmodule_cmd) do |pipe|
          pipe.each_line do |line|
            line.chomp!
            output << line
            name, version = line.split
            modules[name] = version
          end
        end
        @loaded_modules = modules
      rescue Puppet::ExecutionFailure
        raise Puppet::Error,
              _('Could not list policy modules: "%{selmodule_command}" failed with "%{selmod_output}"') %
              { selmodule_command: selmodule_cmd, selmod_output: output.join(' ') },
              $ERROR_INFO.backtrace
      end
    end
    @loaded_modules
  end
end