#!/usr/bin/python # -*- coding: utf-8 -*- # (c) 2012, Derek Carter # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . ANSIBLE_METADATA = {'status': ['stableinterface'], 'supported_by': 'core', 'version': '1.0'} DOCUMENTATION = ''' --- module: selinux short_description: Change policy and state of SELinux description: - Configures the SELinux mode and policy. A reboot may be required after usage. Ansible will not issue this reboot but will let you know when it is required. version_added: "0.7" options: policy: description: - "name of the SELinux policy to use (example: C(targeted)) will be required if state is not C(disabled)" required: false default: null state: description: - The SELinux mode required: true default: null choices: [ "enforcing", "permissive", "disabled" ] conf: description: - path to the SELinux configuration file, if non-standard required: false default: "/etc/selinux/config" notes: - Not tested on any debian based system requirements: [ libselinux-python ] author: "Derek Carter (@goozbach) " ''' EXAMPLES = ''' # Enable SELinux - selinux: policy: targeted state: enforcing # Put SELinux in permissive mode, logging actions that would be blocked. - selinux: policy: targeted state: permissive # Disable SELinux - selinux: state: disabled ''' import os import re import sys try: import selinux HAS_SELINUX = True except ImportError: HAS_SELINUX = False # getter subroutines def get_config_state(configfile): myfile = open(configfile, "r") lines = myfile.readlines() myfile.close() for line in lines: stateline = re.match('^SELINUX=.*$', line) if (stateline): return(line.split('=')[1].strip()) def get_config_policy(configfile): myfile = open(configfile, "r") lines = myfile.readlines() myfile.close() for line in lines: stateline = re.match('^SELINUXTYPE=.*$', line) if (stateline): return(line.split('=')[1].strip()) # setter subroutines def set_config_state(state, configfile): #SELINUX=permissive # edit config file with state value stateline='SELINUX=%s' % state myfile = open(configfile, "r") lines = myfile.readlines() myfile.close() myfile = open(configfile, "w") for line in lines: myfile.write(re.sub(r'^SELINUX=.*', stateline, line)) myfile.close() def set_state(state): if (state == 'enforcing'): selinux.security_setenforce(1) elif (state == 'permissive'): selinux.security_setenforce(0) elif (state == 'disabled'): pass else: msg = 'trying to set invalid runtime state %s' % state module.fail_json(msg=msg) def set_config_policy(policy, configfile): # edit config file with state value #SELINUXTYPE=targeted policyline='SELINUXTYPE=%s' % policy myfile = open(configfile, "r") lines = myfile.readlines() myfile.close() myfile = open(configfile, "w") for line in lines: myfile.write(re.sub(r'^SELINUXTYPE=.*', policyline, line)) myfile.close() def main(): module = AnsibleModule( argument_spec = dict( policy=dict(required=False), state=dict(choices=['enforcing', 'permissive', 'disabled'], required=True), configfile=dict(aliases=['conf','file'], default='/etc/selinux/config') ), supports_check_mode=True ) if not HAS_SELINUX: module.fail_json(msg='libselinux-python required for this module') # global vars changed=False msgs = [] configfile = module.params['configfile'] policy = module.params['policy'] state = module.params['state'] runtime_enabled = selinux.is_selinux_enabled() runtime_policy = selinux.selinux_getpolicytype()[1] runtime_state = 'disabled' if (runtime_enabled): # enabled means 'enforcing' or 'permissive' if (selinux.security_getenforce()): runtime_state = 'enforcing' else: runtime_state = 'permissive' config_policy = get_config_policy(configfile) config_state = get_config_state(configfile) # check to see if policy is set if state is not 'disabled' if (state != 'disabled'): if not policy: module.fail_json(msg='policy is required if state is not \'disabled\'') else: if not policy: policy = config_policy # check changed values and run changes if (policy != runtime_policy): if module.check_mode: module.exit_json(changed=True) # cannot change runtime policy msgs.append('reboot to change the loaded policy') changed=True if (policy != config_policy): if module.check_mode: module.exit_json(changed=True) msgs.append('config policy changed from \'%s\' to \'%s\'' % (config_policy, policy)) set_config_policy(policy, configfile) changed=True if (state != runtime_state): if module.check_mode: module.exit_json(changed=True) if (runtime_enabled): if (state == 'disabled'): if (runtime_state != 'permissive'): # Temporarily set state to permissive set_state('permissive') msgs.append('runtime state temporarily changed from \'%s\' to \'permissive\', state change will take effect next reboot' % (runtime_state)) else: msgs.append('state change will take effect next reboot') else: set_state(state) msgs.append('runtime state changed from \'%s\' to \'%s\'' % (runtime_state, state)) else: msgs.append('state change will take effect next reboot') changed=True if (state != config_state): if module.check_mode: module.exit_json(changed=True) msgs.append('config state changed from \'%s\' to \'%s\'' % (config_state, state)) set_config_state(state, configfile) changed=True module.exit_json(changed=changed, msg=', '.join(msgs), configfile=configfile, policy=policy, state=state) ################################################# # import module snippets from ansible.module_utils.basic import * if __name__ == '__main__': main()