Skip to content

Commit

Permalink
Merge pull request #364 from EmRowlands/selinux_login_fix
Browse files Browse the repository at this point in the history
selinux::login: Miscellaneous fixes
  • Loading branch information
kenyon authored Aug 18, 2023
2 parents 45b11f3 + a99009c commit 1294668
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 23 deletions.
6 changes: 6 additions & 0 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,12 @@ The name of the linux user or group to map.

The selinux user to map to.

##### `source`

Valid values: `policy`, `local`

Source of the login configuration - either policy or local

#### Parameters

The following parameters are available in the `selinux_login` type.
Expand Down
43 changes: 30 additions & 13 deletions lib/puppet/provider/selinux_login/semanage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,29 @@ def self.parse_helper_lines(lines)
lines.each do |line|
split = line.split(%r{\s+})
# helper format is:
# root unconfined_u
# system_u system_u
# __default__ unconfined_u
# %cn_cegbu_aconex_fr-dev-ops-priv unconfined_u
# %cn_cegbu_aconex_fr-dev-platform-priv unconfined_u
selinux_login_name, selinux_user = split

key = selinux_login_name.to_s
# policy root unconfined_u
# policy system_u system_u
# policy __default__ unconfined_u
# policy %cn_cegbu_aconex_fr-dev-ops-priv unconfined_u
# policy %cn_cegbu_aconex_fr-dev-platform-priv unconfined_u
# local %cn_cegbu_aconex_fr-dev-ops-priv unconfined_u
# local %cn_cegbu_aconex_fr-dev-platform-priv unconfined_u
source_str, selinux_login_name, selinux_user = split

key = "#{selinux_login_name}_#{selinux_user}"
source =
case source_str
when 'policy' then :policy
when 'local' then :local
else
raise Puppet::ResourceError, "Selinux_login['#{key}']: unknown mapping source #{source_str}."
end

ret[key] = {
ensure: :present,
title: key,
name: key,
source: source,
selinux_login_name: selinux_login_name,
selinux_user: selinux_user
}
Expand All @@ -85,22 +97,22 @@ def self.instances
end

def self.prefetch(resources)
# is there a better way to do this? map port/protocol pairs to the provider regardless of the title
# is there a better way to do this? Map selinux_user/selinux_login_name to the provider regardless of the title
# and make sure all system resources have ensure => :present so that we don't try to remove them
instances.each do |provider|
resource = resources[provider.name]
if resource
unless resource[:selinux_user].to_s == provider.selinux_user && resource[:selinux_login_name].to_s == provider.selinux_login_name || resource.purging?
raise Puppet::ResourceError, "Selinux_port['#{resource[:name]}']: title does not match its port and protocol, and a conflicting resource exists"
unless resource[:selinux_login_name].to_s == provider.selinux_login_name || resource.purging?
raise Puppet::ResourceError, "Selinux_login['#{resource[:name]}']: title does not match its login ('#{provider.name}' != '#{provider.selinux_login_name}'), and a conflicting resource exists"
end

resource.provider = provider
resource[:ensure] = :present if provider.source == :policy
else
resources.each_value do |res|
resources.each_values do |res|
next unless res[:selinux_user] == provider.selinux_user && res[:selinux_login_name] == provider.selinux_login_name

warning("Selinux_login['#{resource[:name]}']: title does not match format selinux_login_name_selinux_user")
warning("Selinux_login['#{res[:name]}']: title does not match its login ('#{provider.name}' != '#{provider.selinux_login_name}')")
resource.provider = provider
resource[:ensure] = :present if provider.source == :policy
end
Expand All @@ -113,6 +125,11 @@ def create
semanage(*args)
end

def sync
args = ['login', '-m', '-s', @resource[:selinux_user], @resource[:selinux_login_name]]
semanage(*args)
end

def destroy
args = ['login', '-d', @property_hash[:selinux_login_name]]
semanage(*args)
Expand Down
15 changes: 15 additions & 0 deletions lib/puppet/type/selinux_login.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@
newproperty(:selinux_user) do
desc 'The selinux user to map to.'
isrequired

def sync
event = super
provider.sync
event
end
end

newproperty(:source) do
desc 'Source of the login configuration - either policy or local'
newvalues(:policy, :local)

validate do |_value|
raise ArgumentError, ':source is a read-only property'
end
end

autorequire(:package) do
Expand Down
4 changes: 4 additions & 0 deletions lib/puppet_x/voxpupuli/selinux/semanage_ports.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,15 @@ def print_port(kind, port):

# Always list local ports afterwards so that the provider works correctly
retval, ports = semanage.semanage_port_list(handle)
if retval < 0:
raise ValueError("Could not list port config")

for port in ports:
print_port('policy', port)

retval, ports = semanage.semanage_port_list_local(handle)
if retval < 0:
raise ValueError("Could not list local port config")

for port in ports:
print_port('local', port)
Expand Down
28 changes: 19 additions & 9 deletions lib/puppet_x/voxpupuli/selinux/semanage_users.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# This script uses libsemanage directly to access the ports list
# it is *much* faster than semanage port -l
# This script uses libsemanage directly to access the logins list
# This is *much* faster than semanage login -l

# will work with python 2.6+
from __future__ import print_function
from sys import exit
try:
import semanage
except ImportError:
# The semanage python library does not exist, so let's assume SELinux is disabled...
# In this case, the correct response is to return no ports when puppet does a
# prefetch, to avoid an error. We depend on the semanage binary anyway, which
# is uses the library
# The semanage python library does not exist, so let's assume SELinux is
# disabled. In this case, the correct response is to return no logins when
# puppet does a prefetch, to avoid an error. We depend on the semanage binary
# anyway, which uses the library
exit(0)


Expand All @@ -21,16 +21,26 @@
if semanage.semanage_connect(handle) < 0:
exit(1)

def print_seuser(seuser):
def print_seuser(kind, seuser):
seuser_login = semanage.semanage_seuser_get_name(seuser)
selinux_user = semanage.semanage_seuser_get_sename(seuser)
print("{} {}".format(seuser_login, selinux_user))
print("{} {} {}".format(kind, seuser_login, selinux_user))


# Always list local config afterwards so that the provider works correctly
(status, seusers) = semanage.semanage_seuser_list(handle)
if status < 0:
raise ValueError("Could not list user config")

for seuser in seusers:
print_seuser(seuser)
print_seuser('policy', seuser)

(status, seusers) = semanage.semanage_seuser_list_local(handle)
if status < 0:
raise ValueError("Could not list local user config")

for seuser in seusers:
print_seuser('local', seuser)


semanage.semanage_disconnect(handle)
Expand Down
2 changes: 1 addition & 1 deletion manifests/login.pp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

# Do nothing unless SELinux is enabled
if $facts['os']['selinux']['enabled'] {
selinux_login { "${selinux_login_name}_${selinux_user}":
selinux_login { $selinux_login_name:
ensure => $ensure,
selinux_login_name => $selinux_login_name,
selinux_user => $selinux_user,
Expand Down

0 comments on commit 1294668

Please sign in to comment.