diff --git a/examples/ansible.cfg b/examples/ansible.cfg index 4cf9d513e59..85eada17cc8 100644 --- a/examples/ansible.cfg +++ b/examples/ansible.cfg @@ -223,3 +223,8 @@ accelerate_daemon_timeout = 30 # is "no". #accelerate_multi_key = yes +[selinux] +# file systems that require special treatment when dealing with security context +# the default behaviour that copies the existing context or uses the user default +# needs to be changed to use the file system dependant context. +#special_context_filesystems=nfs,vboxsf,fuse diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 089de5b7c5b..2cdc08d8ce8 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -134,7 +134,10 @@ DEFAULT_SU_FLAGS = get_config(p, DEFAULTS, 'su_flags', 'ANSIBLE_SU_FLAG DEFAULT_SU_USER = get_config(p, DEFAULTS, 'su_user', 'ANSIBLE_SU_USER', 'root') DEFAULT_ASK_SU_PASS = get_config(p, DEFAULTS, 'ask_su_pass', 'ANSIBLE_ASK_SU_PASS', False, boolean=True) DEFAULT_GATHERING = get_config(p, DEFAULTS, 'gathering', 'ANSIBLE_GATHERING', 'implicit').lower() -DEFAULT_LOG_PATH = shell_expand_path(get_config(p, DEFAULTS, 'log_path', 'ANSIBLE_LOG_PATH', '')) +DEFAULT_LOG_PATH = shell_expand_path(get_config(p, DEFAULTS, 'log_path', 'ANSIBLE_LOG_PATH', '')) + +# selinux +DEFAULT_SELINUX_SPECIAL_FS = get_config(p, 'selinux', 'special_context_filesystems', None, 'fuse, nfs, vboxsf', islist=True) #TODO: get rid of ternary chain mess BECOME_METHODS = ['sudo','su','pbrun','pfexec','runas'] diff --git a/lib/ansible/inventory/__init__.py b/lib/ansible/inventory/__init__.py index 2048046d3c1..f012246e227 100644 --- a/lib/ansible/inventory/__init__.py +++ b/lib/ansible/inventory/__init__.py @@ -36,7 +36,7 @@ class Inventory(object): Host inventory for ansible. """ - __slots__ = [ 'host_list', 'groups', '_restriction', '_also_restriction', '_subset', + __slots__ = [ 'host_list', 'groups', '_restriction', '_also_restriction', '_subset', 'parser', '_vars_per_host', '_vars_per_group', '_hosts_cache', '_groups_list', '_pattern_cache', '_vault_password', '_vars_plugins', '_playbook_basedir'] @@ -53,7 +53,7 @@ class Inventory(object): self._vars_per_host = {} self._vars_per_group = {} self._hosts_cache = {} - self._groups_list = {} + self._groups_list = {} self._pattern_cache = {} # to be set by calling set_playbook_basedir by playbook code diff --git a/lib/ansible/module_common.py b/lib/ansible/module_common.py index 118c757f8dc..fba5b9137da 100644 --- a/lib/ansible/module_common.py +++ b/lib/ansible/module_common.py @@ -33,6 +33,8 @@ REPLACER_ARGS = "\"<>\"" REPLACER_COMPLEX = "\"<>\"" REPLACER_WINDOWS = "# POWERSHELL_COMMON" REPLACER_VERSION = "\"<>\"" +REPLACER_SELINUX = "<>" + class ModuleReplacer(object): @@ -41,14 +43,14 @@ class ModuleReplacer(object): transfer. Rather than doing classical python imports, this allows for more efficient transfer in a no-bootstrapping scenario by not moving extra files over the wire, and also takes care of embedding arguments in the transferred - modules. + modules. This version is done in such a way that local imports can still be used in the module code, so IDEs don't have to be aware of what is going on. Example: - from ansible.module_utils.basic import * + from ansible.module_utils.basic import * ... will result in the insertion basic.py into the module @@ -94,7 +96,7 @@ class ModuleReplacer(object): module_style = 'new' elif 'WANT_JSON' in module_data: module_style = 'non_native_want_json' - + output = StringIO() lines = module_data.split('\n') snippet_names = [] @@ -167,6 +169,7 @@ class ModuleReplacer(object): # these strings should be part of the 'basic' snippet which is required to be included module_data = module_data.replace(REPLACER_VERSION, repr(__version__)) + module_data = module_data.replace(REPLACER_SELINUX, ','.join(C.DEFAULT_SELINUX_SPECIAL_FS)) module_data = module_data.replace(REPLACER_ARGS, encoded_args) module_data = module_data.replace(REPLACER_COMPLEX, encoded_complex) diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index 54a1a9cfff7..0c2e57f81a6 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -38,6 +38,8 @@ BOOLEANS_TRUE = ['yes', 'on', '1', 'true', 1] BOOLEANS_FALSE = ['no', 'off', '0', 'false', 0] BOOLEANS = BOOLEANS_TRUE + BOOLEANS_FALSE +SELINUX_SPECIAL_FS="<>" + # ansible modules can be written in any language. To simplify # development of Python modules, the functions available here # can be inserted in any module source automatically by including @@ -528,10 +530,10 @@ class AnsibleModule(object): path = os.path.dirname(path) return path - def is_nfs_path(self, path): + def is_special_selinux_path(self, path): """ - Returns a tuple containing (True, selinux_context) if the given path - is on a NFS mount point, otherwise the return will be (False, None). + Returns a tuple containing (True, selinux_context) if the given path is on a + NFS or other 'special' fs mount point, otherwise the return will be (False, None). """ try: f = open('/proc/mounts', 'r') @@ -542,9 +544,13 @@ class AnsibleModule(object): path_mount_point = self.find_mount_point(path) for line in mount_data: (device, mount_point, fstype, options, rest) = line.split(' ', 4) - if path_mount_point == mount_point and 'nfs' in fstype: - nfs_context = self.selinux_context(path_mount_point) - return (True, nfs_context) + + if path_mount_point == mount_point: + for fs in SELINUX_SPECIAL_FS.split(','): + if fs in fstype: + special_context = self.selinux_context(path_mount_point) + return (True, special_context) + return (False, None) def set_default_selinux_context(self, path, changed): @@ -562,9 +568,9 @@ class AnsibleModule(object): # Iterate over the current context instead of the # argument context, which may have selevel. - (is_nfs, nfs_context) = self.is_nfs_path(path) - if is_nfs: - new_context = nfs_context + (is_special_se, sp_context) = self.is_special_selinux_path(path) + if is_special_se: + new_context = sp_context else: for i in range(len(cur_context)): if len(context) > i: