class PFSenseAuthserverLDAP(object): def __init__(self, module): self.module = module self.pfsense = PFSenseModule(module) self.system = self.pfsense.get_element('system') self.authservers = self.system.findall('authserver') def _find_authserver_ldap(self, name): found = None i = 0 for authserver in self.authservers: i = list(self.system).index(authserver) if authserver.find('name').text == name and authserver.find('type').text == 'ldap': found = authserver break return (found, i) def add(self, authserver): authserver_elt, i = self._find_authserver_ldap(authserver['name']) changed = False # Replace the text CA name with the caref id authserver['ldap_caref'] = self.pfsense.get_caref(authserver['ca']) if authserver['ldap_caref'] is None and authserver['transport'] != 'tcp': self.module.fail_json(msg="could not find CA '%s'" % (authserver['ca'])) del authserver['ca'] if authserver_elt is None: changed = True if self.module.check_mode: self.module.exit_json(changed=True) authserver_elt = self.pfsense.new_element('authserver') authserver['refid'] = self.pfsense.uniqid() self.pfsense.copy_dict_to_element(authserver, authserver_elt) self.system.insert(i + 1, authserver_elt) self.pfsense.write_config(descr='ansible pfsense_authserver_ldap added %s' % (authserver['name'])) else: changed = self.pfsense.copy_dict_to_element(authserver, authserver_elt) if self.module.check_mode: self.module.exit_json(changed=changed) if changed: self.pfsense.write_config(descr='ansible pfsense_authserver_ldap updated "%s"' % (authserver['name'])) self.module.exit_json(changed=changed) def remove(self, authserver): authserver_elt, dummy = self._find_authserver_ldap(authserver['name']) changed = False if authserver_elt is not None: if self.module.check_mode: self.module.exit_json(changed=True) self.authservers.remove(authserver_elt) changed = True self.pfsense.write_config(descr='ansible pfsense_authserver_ldap removed "%s"' % (authserver['name'])) self.module.exit_json(changed=changed)
class pfSenseGroup(object): def __init__(self, module): self.module = module self.pfsense = PFSenseModule(module) self.system = self.pfsense.get_element('system') self.groups = self.system.findall('group') def _find_group(self, name): found = None i = 0 for group in self.groups: i = list(self.system).index(group) if group.find('name').text == name: found = group break return (found, i) def add(self, group): group_elt, i = self._find_group(group['name']) changed = False if group_elt is None: changed = True if self.module.check_mode: self.module.exit_json(changed=True) group_elt = self.pfsense.new_element('group') self.pfsense.copy_dict_to_element(group, group_elt) self.system.insert(i + 1, group_elt) self.pfsense.write_config(descr='ansible pfsense_group added %s' % (group['name'])) else: changed = self.pfsense.copy_dict_to_element(group, group_elt) if self.module.check_mode: self.module.exit_json(changed=changed) if changed: self.pfsense.write_config( descr='ansible pfsense_group updated "%s"' % (group['name'])) self.module.exit_json(changed=changed) def remove(self, group): group_elt, dummy = self._find_group(group['name']) changed = False if group_elt is not None: if self.module.check_mode: self.module.exit_json(changed=True) self.groups.remove(group_elt) changed = True self.pfsense.write_config( descr='ansible pfsense_group removed "%s"' % (group['name'])) self.module.exit_json(changed=changed)
class pfSenseCA(object): def __init__(self, module): self.module = module self.pfsense = PFSenseModule(module) self.cas = self.pfsense.get_elements('ca') self.crls = self.pfsense.get_elements('crl') def _find_ca(self, name): found = None i = 0 for ca in self.cas: i = self.pfsense.get_index(ca) if ca.find('descr').text == name: found = ca break return (found, i) def _find_crl(self, caref): found = None i = 0 for crl in self.crls: i = self.pfsense.get_index(crl) if crl.find('caref').text == caref: found = crl break return (found, i) def validate_cert(self, cert): lines = cert.splitlines() if lines[0] == '-----BEGIN CERTIFICATE-----' and lines[ -1] == '-----END CERTIFICATE-----': return base64.b64encode(cert) elif re.match('LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t', cert): return cert else: self.module.fail_json( msg='Could not recognize certificate format: %s' % (cert)) def validate_crl(self, crl): lines = crl.splitlines() if lines[0] == '-----BEGIN X509 CRL-----' and lines[ -1] == '-----END X509 CRL-----': return base64.b64encode(crl) elif re.match('LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0t', crl): return crl else: self.module.fail_json(msg='Could not recognize CRL format: %s' % (crl)) def add(self, ca): ca_elt, i = self._find_ca(ca['descr']) changed = False crl = {} diff = {} if 'crl' in ca: crl['method'] = 'existing' crl['text'] = ca.pop('crl') if ca_elt is None: diff['before'] = '' changed = True ca_elt = self.pfsense.new_element('ca') ca['refid'] = self.pfsense.uniqid() if 'text' in crl: crl_elt = self.pfsense.new_element('crl') crl['refid'] = self.pfsense.uniqid() crl['descr'] = ca['descr'] + ' CRL' crl['caref'] = ca['refid'] self.pfsense.copy_dict_to_element(crl, crl_elt) self.pfsense.root.insert(i + 1, crl_elt) self.pfsense.copy_dict_to_element(ca, ca_elt) self.pfsense.root.insert(i + 1, ca_elt) descr = 'ansible pfsense_ca added %s' % (ca['descr']) else: diff['before'] = self.pfsense.element_to_dict(ca_elt) if 'text' in crl: crl_elt, crl_index = self._find_crl(ca_elt.find('refid').text) if crl_elt is None: changed = True crl_elt = self.pfsense.new_element('crl') crl['refid'] = self.pfsense.uniqid() crl['descr'] = ca['descr'] + ' CRL' crl['caref'] = ca_elt.find('refid').text self.pfsense.copy_dict_to_element(crl, crl_elt) self.pfsense.root.insert(crl_index + 1, crl_elt) else: diff['before']['crl'] = crl_elt.find('text').text changed = self.pfsense.copy_dict_to_element(crl, crl_elt) if self.pfsense.copy_dict_to_element(ca, ca_elt): changed = True descr = 'ansible pfsense_ca updated "%s"' % (ca['descr']) if changed and not self.module.check_mode: self.pfsense.write_config(descr=descr) if 'text' in crl: self.pfsense.phpshell(""" openvpn_refresh_crls(); vpn_ipsec_configure();""") diff['after'] = self.pfsense.element_to_dict(ca_elt) if 'text' in crl: diff['after']['crl'] = crl['text'] self.module.exit_json(changed=changed, diff=diff) def remove(self, ca): ca_elt, dummy = self._find_ca(ca['descr']) changed = False diff = {} diff['after'] = {} if ca_elt is not None: changed = True diff['before'] = self.pfsense.element_to_dict(ca_elt) crl_elt, dummy = self._find_crl(ca_elt.find('refid').text) self.cas.remove(ca_elt) if crl_elt is not None: diff['before']['crl'] = crl_elt.find('text').text self.crls.remove(crl_elt) else: diff['before'] = {} if changed and not self.module.check_mode: self.pfsense.write_config(descr='ansible pfsense_ca removed "%s"' % (ca['descr'])) self.module.exit_json(changed=changed, diff=diff)
class pfSenseUser(object): def __init__(self, module): self.module = module self.pfsense = PFSenseModule(module) self.system = self.pfsense.get_element('system') self.users = self.system.findall('user') self.groups = self.system.findall('group') self.diff = {} self.change_descr = '' def _find_user(self, name): found = None i = 0 for user in self.users: if user.find('name').text == name: found = user break i += 1 return (found, i) def _find_group(self, name): found = None i = 0 for group in self.groups: if group.find('name').text == name: found = group break i += 1 return (found, i) def _find_last_user_idx(self): found = False i = 0 for elt in self.system: if elt.tag == 'user': i += 1 found = True if not found: i += 1 return i def _nextuid(self): nextuid_elt = self.system.find('nextuid') nextuid = nextuid_elt.text nextuid_elt.text = str(int(nextuid) + 1) return nextuid def _format_diff_priv(self, priv): if isinstance(priv, str): return [priv] else: return priv def _validate_password(self, user): if re.match(r'\$2b\$', user['password']): user['bcrypt-hash'] = user['password'] else: self.module.fail_json( msg='Password (%s) does not appear to be a bcrypt hash' % user['password']) del user['password'] def add(self, user): changed = False stdout = None stderr = None # Allow authorizedkeys to be clear or base64 encoded if 'authorizedkeys' in user and 'ssh-' in user['authorizedkeys']: user['authorizedkeys'] = base64.b64encode(user['authorizedkeys']) user_elt, user_idx = self._find_user(user['name']) if user_elt is None: changed = True self.diff['before'] = '' if 'password' in user: self._validate_password(user) else: self.module.fail_json( msg='Password is required when adding a user') if 'uid' not in user: user['uid'] = self._nextuid() self.diff['after'] = user user_elt = self.pfsense.new_element('user') self.pfsense.copy_dict_to_element(user, user_elt) self.system.insert(self._find_last_user_idx(), user_elt) self.change_descr = 'ansible pfsense_user added %s' % ( user['name']) else: if 'password' in user: self._validate_password(user) self.diff['before'] = self.pfsense.element_to_dict(user_elt) if 'priv' in self.diff['before']: self.diff['before']['priv'] = self._format_diff_priv( self.diff['before']['priv']) changed = self.pfsense.copy_dict_to_element(user, user_elt) self.diff['after'] = self.pfsense.element_to_dict(user_elt) if 'priv' in self.diff['after']: self.diff['after']['priv'] = self._format_diff_priv( self.diff['after']['priv']) self.change_descr = 'ansible pfsense_user updated "%s"' % ( user['name']) # Handle group member element - need uid set or retrieved above if 'groupname' in user: group_elt, group_idx = self._find_group(user['groupname']) if group_elt is None: self.module.fail_json(msg='Group (%s) does not exist' % user['groupname']) member_found = False for member_elt in group_elt.findall('member'): if member_elt.text == user_elt.find('uid').text: member_found = True if not member_found: changed = True group_elt.append( self.pfsense.new_element('member', user_elt.find('uid').text)) # Decode keys for diff for k in self.diff: if 'authorizedkeys' in self.diff[k]: self.diff[k]['authorizedkeys'] = base64.b64decode( self.diff[k]['authorizedkeys']) if changed and not self.module.check_mode: self.pfsense.write_config(descr=self.change_descr) (dummy, stdout, stderr) = self.pfsense.phpshell( USER_PHP_COMMAND_SET.format(idx=user_idx)) self.module.exit_json(changed=changed, diff=self.diff, stdout=stdout, stderr=stderr) def remove(self, user): user_elt, user_idx = self._find_user(user['name']) changed = False stdout = None stderr = None self.diff['after'] = '' if user_elt is not None: changed = True self.diff['before'] = self.pfsense.element_to_dict(user_elt) # Remove uid from all group member elements for group_elt in self.groups: member_found = False for member_elt in group_elt.findall('member'): if member_elt.text == user_elt.find('uid').text: group_elt.remove(member_elt) self.system.remove(user_elt) if changed and not self.module.check_mode: (dummy, stdout, stderr) = self.pfsense.phpshell( USER_PHP_COMMAND_DEL.format(cmd='del', idx=user_idx)) self.pfsense.write_config( descr='ansible pfsense_user removed "%s"' % (user['name'])) self.module.exit_json(changed=changed, diff=self.diff, stdout=stdout, stderr=stderr)
class pfSenseCA(object): def __init__(self, module): self.module = module self.pfsense = PFSenseModule(module) self.cas = self.pfsense.get_elements('ca') self.crls = self.pfsense.get_elements('crl') def _find_ca(self, name): found = None i = 0 for ca in self.cas: i = self.pfsense.get_index(ca) if ca.find('descr').text == name: found = ca break return (found, i) def _find_crl(self, caref): found = None i = 0 for crl in self.crls: i = self.pfsense.get_index(crl) if crl.find('caref').text == caref: found = crl break return (found, i) def validate_cert(self, cert): # TODO - Make sure certificate purpose includes CA lines = cert.splitlines() if lines[0] == '-----BEGIN CERTIFICATE-----' and lines[ -1] == '-----END CERTIFICATE-----': return base64.b64encode(cert) elif re.match('LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t', cert): return cert else: self.module.fail_json( msg='Could not recognize certificate format: %s' % (cert)) def validate_crl(self, crl): lines = crl.splitlines() if lines[0] == '-----BEGIN X509 CRL-----' and lines[ -1] == '-----END X509 CRL-----': return base64.b64encode(crl) elif re.match('LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0t', crl): return crl else: self.module.fail_json(msg='Could not recognize CRL format: %s' % (crl)) def add(self, ca): ca_elt, ca_idx = self._find_ca(ca['descr']) changed = False crl = {} diff = {} stdout = None stderr = None if 'crl' in ca: crl['method'] = 'existing' crl['text'] = ca.pop('crl') if ca_elt is None: diff['before'] = '' changed = True ca_elt = self.pfsense.new_element('ca') ca['refid'] = self.pfsense.uniqid() self.pfsense.copy_dict_to_element(ca, ca_elt) self.pfsense.root.append(ca_elt) if 'text' in crl: crl_elt = self.pfsense.new_element('crl') crl['refid'] = self.pfsense.uniqid() crl['descr'] = ca['descr'] + ' CRL' crl['caref'] = ca['refid'] self.pfsense.copy_dict_to_element(crl, crl_elt) self.pfsense.root.append(crl_elt) descr = 'ansible pfsense_ca added %s' % (ca['descr']) else: diff['before'] = self.pfsense.element_to_dict(ca_elt) if 'text' in crl: crl_elt, crl_index = self._find_crl(ca_elt.find('refid').text) if crl_elt is None: changed = True crl_elt = self.pfsense.new_element('crl') crl['refid'] = self.pfsense.uniqid() crl['descr'] = ca['descr'] + ' CRL' crl['caref'] = ca_elt.find('refid').text self.pfsense.copy_dict_to_element(crl, crl_elt) # Add after the existing ca entry self.pfsense.root.insert(ca_idx + 1, crl_elt) else: diff['before']['crl'] = crl_elt.find('text').text changed = self.pfsense.copy_dict_to_element(crl, crl_elt) if self.pfsense.copy_dict_to_element(ca, ca_elt): changed = True descr = 'ansible pfsense_ca updated "%s"' % (ca['descr']) if changed and not self.module.check_mode: self.pfsense.write_config(descr=descr) # ca_import will base64 encode the cert + key and will fix 'caref' for CAs that reference each other # $ca needs to be an existing reference (particularly 'refid' must be set) before calling ca_import # key and serial are optional arguments. TODO - handle key and serial (dummy, stdout, stderr) = self.pfsense.phpshell(""" init_config_arr(array('ca')); $ca =& lookup_ca('{refid}'); ca_import($ca, '{cert}'); print_r($ca); print_r($config['ca']); write_config();""".format(refid=ca_elt.find('refid').text, cert=base64.b64decode( ca_elt.find('crt').text))) if 'text' in crl: self.pfsense.phpshell(""" require_once("openvpn.inc"); openvpn_refresh_crls(); require_once("vpn.inc"); vpn_ipsec_configure();""") diff['after'] = self.pfsense.element_to_dict(ca_elt) if 'text' in crl: diff['after']['crl'] = crl['text'] self.module.exit_json(changed=changed, diff=diff, stdout=stdout, stderr=stderr) def remove(self, ca): ca_elt, dummy = self._find_ca(ca['descr']) changed = False diff = {} diff['after'] = {} if ca_elt is not None: changed = True diff['before'] = self.pfsense.element_to_dict(ca_elt) crl_elt, dummy = self._find_crl(ca_elt.find('refid').text) self.cas.remove(ca_elt) if crl_elt is not None: diff['before']['crl'] = crl_elt.find('text').text self.crls.remove(crl_elt) else: diff['before'] = {} if changed and not self.module.check_mode: self.pfsense.write_config(descr='ansible pfsense_ca removed "%s"' % (ca['descr'])) self.module.exit_json(changed=changed, diff=diff)