summaryrefslogtreecommitdiffstats
path: root/lib/puppet/provider/selmodule/semodule.rb
blob: 64197156f84cc4137186670a260134fea02b458c (plain)
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
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}";
    end
    :true
  end

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

  def exists?
    self.debug "Checking for module #{@resource[:name]}"
    execpipe("#{command(:semodule)} --list") do |out|
      out.each do |line|
        if line =~ /#{@resource[:name]}\b/
          return :true
        end
      end
    end
    nil
  end

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

    loadver = selmodversion_loaded

    if(loadver) then
      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}";
  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]
    end
    output
  end

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

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

  def selmodversion_file
    magic = 0xF97CFF8F

    filename = selmod_name_to_filename
    mod = File.new(filename, "r")

    (hdr, ver, numsec) = mod.read(12).unpack('LLL')

    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)

    self.debug "file version #{v}"
    v
  end

  def selmodversion_loaded
    lines = ()
    begin
      execpipe("#{command(:semodule)} --list") do |output|
        lines = output.readlines
        lines.each do |line|
          line.chomp!
          bits = line.split
          if bits[0] == @resource[:name]
            self.debug "load version #{bits[1]}"
            return bits[1]
          end
        end
      end
    rescue Puppet::ExecutionFailure
      raise Puppet::ExecutionFailure, "Could not list policy modules: #{lines.join(' ').chomp!}"
    end
    nil
  end
end