def upload_xml(xml_file, path): """ Updates XML files (rules and decoders) :param xml_file: content of the XML file :param path: Destination of the new XML file :return: Confirmation message """ # path of temporary files for parsing xml input tmp_file_path = '{}/tmp/api_tmp_file_{}_{}.xml'.format( common.ossec_path, time.time(), random.randint(0, 1000)) # create temporary file for parsing xml input try: with open(tmp_file_path, 'w') as tmp_file: # beauty xml file xml = parseString('<root>' + xml_file + '</root>') # remove first line (XML specification: <? xmlversion="1.0" ?>), <root> and </root> tags, and empty lines pretty_xml = '\n'.join( filter(lambda x: x.strip(), xml.toprettyxml(indent=' ').split('\n')[2:-2])) + '\n' # revert xml.dom replacings # (https://github.com/python/cpython/blob/8e0418688906206fe59bd26344320c0fc026849e/Lib/xml/dom/minidom.py#L305) pretty_xml = pretty_xml.replace("&", "&").replace("<", "<").replace(""", "\"", ) \ .replace(">", ">").replace('&apos', "'") tmp_file.write(pretty_xml) chmod(tmp_file_path, 0o640) except IOError: raise WazuhException(1005) except ExpatError: raise WazuhException(1113) except Exception as e: raise WazuhException(1000, str(e)) try: # check xml format try: load_wazuh_xml(tmp_file_path) except Exception as e: raise WazuhException(1113, str(e)) # move temporary file to group folder try: new_conf_path = join(common.ossec_path, path) move(tmp_file_path, new_conf_path) except Error: raise WazuhException(1016) except Exception: raise WazuhException(1000) return 'File updated successfully' except Exception as e: # remove created temporary file if an exception happens remove(tmp_file_path) raise e
def get_agent_conf_multigroup(group_id=None, offset=0, limit=common.database_limit, filename=None): """ Returns agent.conf as dictionary. :return: agent.conf as dictionary. """ if group_id: #if not Agent.multi_group_exists(group_id): #raise WazuhException(1710, group_id) agent_conf = "{0}/{1}".format(common.multi_groups_path, group_id) if filename: agent_conf_name = filename else: agent_conf_name = 'agent.conf' agent_conf += "/{0}".format(agent_conf_name) if not os_path.exists(agent_conf): raise WazuhException(1006, agent_conf) try: # Read XML xml_data = load_wazuh_xml(agent_conf) # Parse XML to JSON data = _agentconf2json(xml_data) except Exception as e: raise WazuhException(1101, str(e)) return {'totalItems': len(data), 'items': cut_array(data, offset, limit)}
def get_ossec_conf(section=None, field=None, conf_file=common.ossec_conf): """ Returns ossec.conf (manager) as dictionary. :param section: Filters by section (i.e. rules). :param field: Filters by field in section (i.e. included). :param conf_file: Path of the configuration file to read. :return: ossec.conf (manager) as dictionary. """ try: # Read XML xml_data = load_wazuh_xml(conf_file) # Parse XML to JSON data = _ossecconf2json(xml_data) except Exception as e: raise WazuhException(1101, str(e)) if section: try: data = data[section] except KeyError as e: if section not in conf_sections.keys(): raise WazuhException(1102, e.args[0]) else: raise WazuhException(1106, e.args[0]) if section and field: try: data = data[field] # data[section][field] except: raise WazuhException(1103) return data
def get_agent_conf(group_id=None, offset=0, limit=common.database_limit, filename='agent.conf', return_format=None): """ Returns agent.conf as dictionary. :return: agent.conf as dictionary. """ agent_conf = os_path.join(common.shared_path, group_id if group_id is not None else '', filename) if not os_path.exists(agent_conf): raise WazuhException(1006, agent_conf) try: # Read RAW file if filename == 'agent.conf' and return_format and 'xml' == return_format.lower(): with open(agent_conf, 'r') as xml_data: data = xml_data.read().replace('\n', '') return data # Parse XML to JSON else: # Read XML xml_data = load_wazuh_xml(agent_conf) data = _agentconf2json(xml_data) except Exception as e: raise WazuhException(1101, str(e)) return {'totalItems': len(data), 'items': cut_array(data, offset, limit)}
def __load_decoders_from_file(decoder_file, decoder_path, decoder_status): try: decoders = [] position = 0 root = load_wazuh_xml( os.path.join(common.ossec_path, decoder_path, decoder_file)) for xml_decoder in list(root): # New decoder if xml_decoder.tag.lower() == "decoder": decoder = Decoder() decoder.path = decoder_path decoder.file = decoder_file decoder.status = decoder_status decoder.name = xml_decoder.attrib['name'] decoder.position = position position += 1 for k in xml_decoder.attrib: if k != 'name': decoder.details[k] = xml_decoder.attrib[k] for xml_decoder_tags in list(xml_decoder): decoder.add_detail(xml_decoder_tags.tag.lower(), xml_decoder_tags.text) decoders.append(decoder) except Exception as e: raise WazuhException( 1501, "{0}. Error: {1}".format(decoder_file, str(e))) return decoders
def __load_rules_from_file(rule_file, rule_path, rule_status): try: rules = [] root = load_wazuh_xml("{}/{}".format(rule_path, rule_file)) for xml_group in root.getchildren(): if xml_group.tag.lower() == "group": general_groups = xml_group.attrib['name'].split(',') for xml_rule in xml_group.getchildren(): # New rule if xml_rule.tag.lower() == "rule": groups = [] rule = Rule() rule.file = rule_file rule.path = rule_path rule.id = int(xml_rule.attrib['id']) rule.level = int(xml_rule.attrib['level']) rule.status = rule_status for k in xml_rule.attrib: if k != 'id' and k != 'level': rule.details[k] = xml_rule.attrib[k] for xml_rule_tags in xml_rule.getchildren(): tag = xml_rule_tags.tag.lower() value = xml_rule_tags.text if value == None: value = '' if tag == "group": groups.extend(value.split(",")) elif tag == "description": rule.description += value elif tag == "field": rule.add_detail( xml_rule_tags.attrib['name'], value) else: rule.add_detail(tag, value) # Set groups groups.extend(general_groups) pci_groups = [] ossec_groups = [] for g in groups: if 'pci_dss_' in g: pci_groups.append(g.strip()[8:]) else: ossec_groups.append(g) rule.set_group(ossec_groups) rule.set_pci(pci_groups) rules.append(rule) except Exception as e: raise WazuhException(1201, "{0}. Error: {1}".format(rule_file, str(e))) return rules
def upload_xml(xml_file, path): """ Upload XML files (rules and decoders) :param xml_file: content of the XML file :param path: Destination of the new XML file :return: Confirmation message """ # -- characters are not allowed in XML comments xml_file = replace_in_comments(xml_file, '--', '%wildcard%') # path of temporary files for parsing xml input tmp_file_path = '{}/tmp/api_tmp_file_{}_{}.xml'.format( common.ossec_path, time.time(), random.randint(0, 1000)) # create temporary file for parsing xml input try: with open(tmp_file_path, 'w') as tmp_file: # beauty xml file xml = parseString('<root>' + xml_file + '</root>') # remove first line (XML specification: <? xmlversion="1.0" ?>), <root> and </root> tags, and empty lines indent = ' ' # indent parameter for toprettyxml function pretty_xml = '\n'.join( filter( lambda x: x.strip(), xml.toprettyxml(indent=indent).split('\n')[2:-2])) + '\n' # revert xml.dom replacings # (https://github.com/python/cpython/blob/8e0418688906206fe59bd26344320c0fc026849e/Lib/xml/dom/minidom.py#L305) pretty_xml = pretty_xml.replace("&", "&").replace("<", "<").replace(""", "\"", ) \ .replace(">", ">").replace(''', "'") # delete two first spaces of each line final_xml = re.sub(fr'^{indent}', '', pretty_xml, flags=re.MULTILINE) final_xml = replace_in_comments(final_xml, '%wildcard%', '--') tmp_file.write(final_xml) chmod(tmp_file_path, 0o660) except IOError: raise WazuhException(1005) except ExpatError: raise WazuhException(1113) except Exception as e: raise WazuhException(1000, str(e)) try: # check xml format try: load_wazuh_xml(tmp_file_path) except Exception as e: raise WazuhException(1113, str(e)) # move temporary file to group folder try: new_conf_path = join(common.ossec_path, path) safe_move(tmp_file_path, new_conf_path, permissions=0o660) except Error: raise WazuhException(1016) except Exception: raise WazuhException(1000) return 'File updated successfully' except Exception as e: # remove created temporary file if an exception happens remove(tmp_file_path) raise e
def __load_rules_from_file(rule_file, rule_path, rule_status): try: rules = [] root = load_wazuh_xml( os.path.join(common.ossec_path, rule_path, rule_file)) for xml_group in root.getchildren(): if xml_group.tag.lower() == "group": general_groups = xml_group.attrib['name'].split(',') for xml_rule in xml_group.getchildren(): # New rule if xml_rule.tag.lower() == "rule": groups = [] rule = Rule() rule.file = rule_file rule.path = rule_path rule.id = int(xml_rule.attrib['id']) rule.level = int(xml_rule.attrib['level']) rule.status = rule_status for k in xml_rule.attrib: if k != 'id' and k != 'level': rule.details[k] = xml_rule.attrib[k] for xml_rule_tags in xml_rule.getchildren(): tag = xml_rule_tags.tag.lower() value = xml_rule_tags.text if value == None: value = '' if tag == "group": groups.extend(value.split(",")) elif tag == "description": rule.description += value elif tag == "field": rule.add_detail( xml_rule_tags.attrib['name'], value) elif tag in ("list", "info"): list_detail = {'name': value} for attrib, attrib_value in xml_rule_tags.attrib.items( ): list_detail[attrib] = attrib_value rule.add_detail(tag, list_detail) # show rule variables elif tag in { 'regex', 'match', 'user', 'id' } and value != '' and value[0] == "$": for variable in filter( lambda x: x.get('name') == value[1: ], root.findall('var')): rule.add_detail(tag, variable.text) else: rule.add_detail(tag, value) # Set groups groups.extend(general_groups) pci_groups = [] gdpr_groups = [] ossec_groups = [] for g in groups: if 'pci_dss_' in g: pci_groups.append(g.strip()[8:]) elif 'gdpr_' in g: gdpr_groups.append(g.strip()[5:]) else: ossec_groups.append(g) rule.set_group(ossec_groups) rule.set_pci(pci_groups) rule.set_gdpr(gdpr_groups) rules.append(rule) except Exception as e: raise WazuhException(1201, "{0}. Error: {1}".format(rule_file, str(e))) return rules
def upload_group_configuration(group_id, xml_file): """ Updates group configuration :param group_id: Group to update :param xml_file: File contents of the new configuration in string. :return: Confirmation message. """ # check if the group exists if not Agent.group_exists(group_id): raise WazuhException(1710) # path of temporary files for parsing xml input tmp_file_path = '{}/tmp/api_tmp_file_{}.xml'.format( common.ossec_path, datetime.strftime(datetime.utcnow(), '%Y-%m-%d-%m-%s')) # create temporary file for parsing xml input try: with open(tmp_file_path, 'w') as tmp_file: # beauty xml file xml = parseString('<root>' + xml_file + '</root>') # remove first line (XML specification: <? xmlversion="1.0" ?>), <root> and </root> tags, and empty lines pretty_xml = '\n'.join( filter(lambda x: x.strip(), xml.toprettyxml(indent=' ').split('\n')[2:-2])) + '\n' # revert xml.dom replacings # (https://github.com/python/cpython/blob/8e0418688906206fe59bd26344320c0fc026849e/Lib/xml/dom/minidom.py#L305) pretty_xml = pretty_xml.replace("&", "&").replace("<", "<").replace(""", "\"",)\ .replace(">", ">") tmp_file.write(pretty_xml) except Exception as e: raise WazuhException(1113, str(e)) try: # check xml format try: load_wazuh_xml(tmp_file_path) except Exception as e: raise WazuhException(1113, str(e)) # check Wazuh xml format try: subprocess.check_output([ '{}/bin/verify-agent-conf'.format(common.ossec_path), '-f', tmp_file_path ], stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: # extract error message from output. # Example of raw output # 2019/01/08 14:51:09 verify-agent-conf: ERROR: (1230): Invalid element in the configuration: 'agent_conf'.\n2019/01/08 14:51:09 verify-agent-conf: ERROR: (1207): Syscheck remote configuration in '/var/ossec/tmp/api_tmp_file_2019-01-08-01-1546959069.xml' is corrupted.\n\n # Example of desired output: # Invalid element in the configuration: 'agent_conf'. Syscheck remote configuration in '/var/ossec/tmp/api_tmp_file_2019-01-08-01-1546959069.xml' is corrupted. output_regex = re.findall( pattern= r"\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2} verify-agent-conf: ERROR: " r"\(\d+\): ([\w \/ \_ \- \. ' :]+)", string=e.output) raise WazuhException(1114, ' '.join(output_regex)) except Exception as e: raise WazuhException(1743, str(e)) # move temporary file to group folder try: new_conf_path = "{}/{}/agent.conf".format(common.shared_path, group_id) move(tmp_file_path, new_conf_path) except Exception as e: raise WazuhException(1017, str(e)) return 'Agent configuration was updated successfully' except Exception as e: # remove created temporary file remove(tmp_file_path) raise e