mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Add selinux support to file module
This adds the options: seuser, serole, setype, and serange to the file module. If the python selinux module doesn't exist, this will set HAVE_SELINUX to False and punt in the related modules. This takes the options the user provides and applies those to the default selinux context as provided from matchpathcon(). If there is no default context, this uses the value from the current context. This implies that if you set the setype and later remove it, the file module will rever the setype to the default if available.
This commit is contained in:
parent
08c593bee1
commit
1e5d34ba35
1 changed files with 65 additions and 7 deletions
70
library/file
70
library/file
|
@ -29,6 +29,11 @@ import shutil
|
||||||
import stat
|
import stat
|
||||||
import grp
|
import grp
|
||||||
import pwd
|
import pwd
|
||||||
|
try:
|
||||||
|
import selinux
|
||||||
|
HAVE_SELINUX=True
|
||||||
|
except ImportError:
|
||||||
|
HAVE_SELINUX=False
|
||||||
|
|
||||||
def debug(msg):
|
def debug(msg):
|
||||||
# ansible ignores stderr, so it's safe to use for debug
|
# ansible ignores stderr, so it's safe to use for debug
|
||||||
|
@ -61,6 +66,8 @@ def add_path_info(kwargs):
|
||||||
kwargs['state'] = 'file'
|
kwargs['state'] = 'file'
|
||||||
else:
|
else:
|
||||||
kwargs['state'] = 'directory'
|
kwargs['state'] = 'directory'
|
||||||
|
if HAVE_SELINUX:
|
||||||
|
kwargs['secontext'] = ':'.join(selinux_context(path))
|
||||||
else:
|
else:
|
||||||
kwargs['state'] = 'absent'
|
kwargs['state'] = 'absent'
|
||||||
return kwargs
|
return kwargs
|
||||||
|
@ -91,8 +98,12 @@ group = params.get('group', None)
|
||||||
# presently unused, we always use -R (FIXME?)
|
# presently unused, we always use -R (FIXME?)
|
||||||
recurse = params.get('recurse', 'false')
|
recurse = params.get('recurse', 'false')
|
||||||
|
|
||||||
# presently unused, implement (FIXME)
|
# selinux related options
|
||||||
secontext = params.get('secontext', None)
|
seuser = params.get('seuser', None)
|
||||||
|
serole = params.get('serole', None)
|
||||||
|
setype = params.get('setype', None)
|
||||||
|
serange = params.get('serange', 's0')
|
||||||
|
secontext = [seuser, serole, setype, serange]
|
||||||
|
|
||||||
if state not in [ 'file', 'directory', 'link', 'absent']:
|
if state not in [ 'file', 'directory', 'link', 'absent']:
|
||||||
fail_json(msg='invalid state: %s' % state)
|
fail_json(msg='invalid state: %s' % state)
|
||||||
|
@ -119,12 +130,59 @@ def user_and_group(filename):
|
||||||
debug("got user=%s and group=%s" % (user, group))
|
debug("got user=%s and group=%s" % (user, group))
|
||||||
return (user, group)
|
return (user, group)
|
||||||
|
|
||||||
|
def selinux_context(path):
|
||||||
|
context = [None, None, None, None]
|
||||||
|
if not HAVE_SELINUX:
|
||||||
|
return context
|
||||||
|
try:
|
||||||
|
ret = selinux.lgetfilecon(path)
|
||||||
|
except:
|
||||||
|
fail_json(path=path, msg='failed to retrieve selinux context')
|
||||||
|
if ret[0] == -1:
|
||||||
|
return context
|
||||||
|
context = ret[1].split(':')
|
||||||
|
debug("got current secontext=%s" % ret[1])
|
||||||
|
return context
|
||||||
|
|
||||||
|
# If selinux fails to find a default, return an array of None
|
||||||
|
def selinux_default_context(path, mode=0):
|
||||||
|
context = [None, None, None, None]
|
||||||
|
print >>sys.stderr, path
|
||||||
|
if not HAVE_SELINUX:
|
||||||
|
return context
|
||||||
|
try:
|
||||||
|
ret = selinux.matchpathcon(path, mode)
|
||||||
|
except OSError:
|
||||||
|
return context
|
||||||
|
if ret[0] == -1:
|
||||||
|
return context
|
||||||
|
context = ret[1].split(':')
|
||||||
|
debug("got default secontext=%s" % ret[1])
|
||||||
|
return context
|
||||||
|
|
||||||
def set_context_if_different(path, context, changed):
|
def set_context_if_different(path, context, changed):
|
||||||
if context is None:
|
if not HAVE_SELINUX:
|
||||||
return changed
|
return changed
|
||||||
if context is not None:
|
cur_context = selinux_context(path)
|
||||||
fail_json(path=path, msg='context not yet supported')
|
new_context = selinux_default_context(path)
|
||||||
|
for i in range(len(context)):
|
||||||
|
if context[i] is not None and context[i] != cur_context[i]:
|
||||||
|
debug('new context was %s' % new_context[i])
|
||||||
|
new_context[i] = context[i]
|
||||||
|
debug('new context is %s' % new_context[i])
|
||||||
|
elif new_context[i] is None:
|
||||||
|
new_context[i] = cur_context[i]
|
||||||
|
debug("current secontext is %s" % ':'.join(cur_context))
|
||||||
|
debug("new secontext is %s" % ':'.join(new_context))
|
||||||
|
if cur_context != new_context:
|
||||||
|
try:
|
||||||
|
rc = selinux.lsetfilecon(path, ':'.join(new_context))
|
||||||
|
except OSError:
|
||||||
|
fail_json(path=path, msg='invalid selinux context')
|
||||||
|
if rc != 0:
|
||||||
|
fail_json(path=path, msg='set selinux context failed')
|
||||||
|
changed = True
|
||||||
|
return changed
|
||||||
|
|
||||||
def set_owner_if_different(path, owner, changed):
|
def set_owner_if_different(path, owner, changed):
|
||||||
if owner is None:
|
if owner is None:
|
||||||
|
|
Loading…
Reference in a new issue