def test_status(manager_glob, manager_exists, test_manager, process_status): """ Tests manager.status() function in two cases: * PID files are created and processed are running, * No process is running and therefore no PID files have been created :param manager_glob: mock of glob.glob function :param manager_exists: mock of os.path.exists function :param test_manager: pytest fixture :param process_status: status to test (valid values: running/stopped/failed/restarting). :return: """ def mock_glob(path_to_check): return [path_to_check.replace('*', '0234') ] if process_status == 'running' else [] def mock_exists(path_to_check): if path_to_check == '/proc/0234': return process_status == 'running' else: return path_to_check.endswith(f'.{process_status.replace("ing","").replace("re", "")}') or \ path_to_check.endswith(f'.{process_status.replace("ing","")}') manager_glob.side_effect = mock_glob manager_exists.side_effect = mock_exists manager_status = status() assert isinstance(manager_status, dict) assert all(process_status == x for x in manager_status.values()) if process_status == 'running': manager_exists.assert_any_call("/proc/0234")
def remove(self): """ Deletes the agent. :return: Message. """ # Check if authd is running manager_status = manager.status() if 'ossec-authd' not in manager_status or manager_status['ossec-authd'] == 'running': raise WazuhException(1704) # Get info from DB self._load_info_from_DB() f_keys_temp = '{0}.tmp'.format(common.client_keys) f_tmp = open(f_keys_temp, 'w') agent_found = False with open(common.client_keys) as f_k: for line in f_k.readlines(): line_data = line.strip().split(' ') # 0 -> id, 1 -> name, 2 -> ip, 3 -> key if self.id == line_data[0] and line_data[1][0] not in ('#!'): f_tmp.write('{0} !{1} {2} {3}\n'.format(line_data[0], line_data[1], line_data[2], line_data[3])) agent_found = True else: f_tmp.write(line) f_tmp.close() if agent_found: # Overwrite client.keys move(f_keys_temp, common.client_keys) root_uid = getpwnam("ossec").pw_uid ossec_gid = getgrnam("ossec").gr_gid chown(common.client_keys, root_uid, ossec_gid) chmod(common.client_keys, 0o640) # Remove agent files agent_files = [] agent_files.append('{0}/queue/agent-info/{1}-{2}'.format(common.ossec_path, self.name, self.ip)) agent_files.append('{0}/queue/syscheck/({1}) {2}->syscheck'.format(common.ossec_path, self.name, self.ip)) agent_files.append('{0}/queue/syscheck/.({1}) {2}->syscheck.cpt'.format(common.ossec_path, self.name, self.ip)) agent_files.append('{0}/queue/syscheck/({1}) {2}->syscheck-registry'.format(common.ossec_path, self.name, self.ip)) agent_files.append('{0}/queue/syscheck/.({1}) {2}->syscheck-registry.cpt'.format(common.ossec_path, self.name, self.ip)) agent_files.append('{0}/queue/rootcheck/({1}) {2}->rootcheck'.format(common.ossec_path, self.name, self.ip)) agent_files.append('{0}/queue/rids/{1}'.format(common.ossec_path, self.id)) agent_files.append('{0}/var/db/agents/{1}-{2}.db'.format(common.ossec_path, self.id, self.name)) agent_files.append('{0}/var/db/agents/{1}-{2}.db-wal'.format(common.ossec_path, self.id, self.name)) agent_files.append('{0}/var/db/agents/{1}-{2}.db-shm'.format(common.ossec_path, self.id, self.name)) for agent_file in agent_files: if path.exists(agent_file): remove(agent_file) else: remove(f_keys_temp) raise WazuhException(1701, self.id) return 'Agent removed'
def check_wazuh_status(self): """ There are some services that are required for wazuh to correctly process API requests. If any of those services is not running, the API must raise an exception indicating that: * It's not ready yet to process requests if services are restarting * There's an error in any of those services that must be adressed before using the API if any service is in failed status. * Wazuh must be started before using the API is the services are stopped. The basic services wazuh needs to be running are: wazuh-modulesd, ossec-remoted, ossec-analysisd, ossec-execd and wazuh-db """ if self.input_json['function'] == '/manager/status' or self.input_json['function'] == '/cluster/:node_id/status': return basic_services = ('wazuh-modulesd', 'ossec-remoted', 'ossec-analysisd', 'ossec-execd', 'wazuh-db') status = operator.itemgetter(*basic_services)(manager.status()) for status_name, exc_code in [('failed', 1019), ('restarting', 1017), ('stopped', 1018)]: if status_name in status: raise exception.WazuhException(exc_code, status)
def remove(self): """ Deletes the agent. :return: Message. """ # Check if authd is running if manager.status()['ossec-authd'] == 'running': raise WazuhException(1704) f_keys_temp = '{0}.tmp'.format(common.client_keys) f_tmp = open(f_keys_temp, 'w') agent_found = False with open(common.client_keys) as f_k: for line in f_k.readlines(): line_data = line.strip().split( ' ') # 0 -> id, 1 -> name, 2 -> ip, 3 -> key if self.id == line_data[0] and line_data[1][0] not in ('#!'): f_tmp.write('{0} !{1} {2} {3}\n'.format( line_data[0], line_data[1], line_data[2], line_data[3])) agent_found = True else: f_tmp.write(line) f_tmp.close() if agent_found: # Overwrite client.keys move(f_keys_temp, common.client_keys) root_uid = getpwnam("ossec").pw_uid ossec_gid = getgrnam("ossec").gr_gid chown(common.client_keys, root_uid, ossec_gid) chmod(common.client_keys, 0o640) else: remove(f_keys_temp) raise WazuhException(1701, self.id) return 'Agent removed'
def check_wazuh_status(self, basic_services=None): """ There are some services that are required for wazuh to correctly process API requests. If any of those services is not running, the API must raise an exception indicating that: * It's not ready yet to process requests if services are restarting * There's an error in any of those services that must be adressed before using the API if any service is in failed status. * Wazuh must be started before using the API is the services are stopped. The basic services wazuh needs to be running are: wazuh-modulesd, ossec-remoted, ossec-analysisd, ossec-execd and wazuh-db """ if self.input_json['function'] == '/manager/status' or self.input_json[ 'function'] == '/cluster/:node_id/status': return if not basic_services: basic_services = ('wazuh-modulesd', 'ossec-analysisd', 'ossec-execd', 'wazuh-db') if common.install_type != "local": basic_services += ('ossec-remoted', ) status = manager.status() not_ready_daemons = { k: status[k] for k in basic_services if status[k] in ('failed', 'restarting', 'stopped') } if not_ready_daemons: extra_info = { 'node_name': self.node_info.get('node', 'UNKNOWN NODE'), 'not_ready_daemons': ', '.join([ f'{key}->{value}' for key, value in not_ready_daemons.items() ]) } raise exception.WazuhException(1017, extra_message=extra_info)
def remove(self): """ Deletes the agent. :return: Message. """ # Check if authd is running if manager.status()['ossec-authd'] == 'running': raise WazuhException(1704) f_keys_temp = '{0}.tmp'.format(common.client_keys) f_tmp = open(f_keys_temp, 'w') agent_found = False with open(common.client_keys) as f_k: for line in f_k.readlines(): line_data = line.strip().split(' ') # 0 -> id, 1 -> name, 2 -> ip, 3 -> key if self.id == line_data[0] and line_data[1][0] not in ('#!'): f_tmp.write('{0} !{1} {2} {3}\n'.format(line_data[0], line_data[1], line_data[2], line_data[3])) agent_found = True else: f_tmp.write(line) f_tmp.close() if agent_found: # Overwrite client.keys move(f_keys_temp, common.client_keys) root_uid = getpwnam("ossec").pw_uid ossec_gid = getgrnam("ossec").gr_gid chown(common.client_keys, root_uid, ossec_gid) chmod(common.client_keys, 0o640) else: remove(f_keys_temp) raise WazuhException(1701, self.id) return 'Agent removed'
# set appropiate permissions to the cluster.log file chown('{0}/logs/cluster.log'.format(common.ossec_path), common.ossec_uid, common.ossec_gid) chmod('{0}/logs/cluster.log'.format(common.ossec_path), 0o660) if error_msg: logger.error(error_msg) exit() # Signals signal(SIGINT, signal_handler) signal(SIGTERM, signal_handler) # Check if it is already running if status()['wazuh-clusterd'] == 'running': clean_exit(reason="wazuh_clusterd is already running", error=True) # Foreground/Daemon if not args.f: res_code = pyDaemon() # Get cluster config try: cluster_config = read_config() except WazuhException as e: clean_exit(reason=str(e), error=True) if not cluster_config or cluster_config['disabled'] == 'yes': clean_exit(reason="Cluster disabled", error=True)
def get_status_json(): return { "enabled": "yes" if check_cluster_status() else "no", "running": "yes" if status()['wazuh-clusterd'] == 'running' else "no" }
def _add(self, name, ip, id=None, key=None, force=-1): """ Adds a agent to OSSEC. 2 uses: - name and ip [force]: Add an agent like manage_agents (generate id and key). - name, ip, id, key [force]: Insert an agent with an existing id and key. :param name: name of the new agent. :param ip: IP of the new agent. It can be an IP, IP/NET or ANY. :param id: ID of the new agent. :param key: Key of the new agent. :param force: Remove old agents with same IP if disconnected since <force> seconds :return: Agent ID. """ # Check arguments if id: id = id.zfill(3) if key and len(key) < 64: raise WazuhException(1709) force = force if type(force) == int else int(force) # Check if authd is running manager_status = manager.status() if 'ossec-authd' not in manager_status or manager_status[ 'ossec-authd'] == 'running': raise WazuhException(1704) # Check if ip, name or id exist in client.keys last_id = 0 with open(common.client_keys) as f_k: for line in f_k.readlines(): if line[0] in ('# '): # starts with # or ' ' continue line_data = line.strip().split( ' ') # 0 -> id, 1 -> name, 2 -> ip, 3 -> key line_id = int(line_data[0]) if last_id < line_id: last_id = line_id if line_data[1][0] in ('#!'): # name starts with # or ! continue if id and id == line_data[0]: raise WazuhException(1708, id) if name == line_data[1]: raise WazuhException(1705, name) if ip.lower() != 'any' and ip == line_data[2]: if force < 0: raise WazuhException(1706, ip) else: if force == 0 or Agent.check_if_delete_agent( line_data[0], force): Agent.remove_agent(line_data[0], backup=True) else: raise WazuhException(1706, ip) if not id: agent_id = str(last_id + 1).zfill(3) else: agent_id = id if not key: # Generate key epoch_time = int(time()) str1 = "{0}{1}{2}".format(epoch_time, name, platform()) str2 = "{0}{1}".format(ip, agent_id) hash1 = md5(str1.encode()) hash1.update(urandom(64)) hash2 = md5(str2.encode()) hash1.update(urandom(64)) agent_key = hash1.hexdigest() + hash2.hexdigest() else: agent_key = key # Tmp file f_keys_temp = '{0}.tmp'.format(common.client_keys) copyfile(common.client_keys, f_keys_temp) # Write key with open(f_keys_temp, 'a') as f_kt: f_kt.write('{0} {1} {2} {3}\n'.format(agent_id, name, ip, agent_key)) # Overwrite client.keys move(f_keys_temp, common.client_keys) root_uid = getpwnam("ossec").pw_uid ossec_gid = getgrnam("ossec").gr_gid chown(common.client_keys, root_uid, ossec_gid) chmod(common.client_keys, 0o640) self.id = agent_id
def remove(self, backup=False): """ Deletes the agent. :param backup: Create backup before removing the agent. :return: Message. """ # Check if authd is running manager_status = manager.status() if 'ossec-authd' not in manager_status or manager_status[ 'ossec-authd'] == 'running': raise WazuhException(1704) # Get info from DB self._load_info_from_DB() f_keys_temp = '{0}.tmp'.format(common.client_keys) f_tmp = open(f_keys_temp, 'w') agent_found = False with open(common.client_keys) as f_k: for line in f_k.readlines(): line_data = line.strip().split( ' ') # 0 -> id, 1 -> name, 2 -> ip, 3 -> key if self.id == line_data[0] and line_data[1][0] not in ('#!'): f_tmp.write('{0} !{1} {2} {3}\n'.format( line_data[0], line_data[1], line_data[2], line_data[3])) agent_found = True else: f_tmp.write(line) f_tmp.close() if not agent_found: remove(f_keys_temp) raise WazuhException(1701, self.id) # Overwrite client.keys move(f_keys_temp, common.client_keys) root_uid = getpwnam("ossec").pw_uid ossec_gid = getgrnam("ossec").gr_gid chown(common.client_keys, root_uid, ossec_gid) chmod(common.client_keys, 0o640) # Remove rid file rids_file = '{0}/queue/rids/{1}'.format(common.ossec_path, self.id) if path.exists(rids_file): remove(rids_file) if not backup: # Remove agent files agent_files = [] agent_files.append('{0}/queue/agent-info/{1}-{2}'.format( common.ossec_path, self.name, self.ip)) agent_files.append('{0}/queue/syscheck/({1}) {2}->syscheck'.format( common.ossec_path, self.name, self.ip)) agent_files.append( '{0}/queue/syscheck/.({1}) {2}->syscheck.cpt'.format( common.ossec_path, self.name, self.ip)) agent_files.append( '{0}/queue/syscheck/({1}) {2}->syscheck-registry'.format( common.ossec_path, self.name, self.ip)) agent_files.append( '{0}/queue/syscheck/.({1}) {2}->syscheck-registry.cpt'.format( common.ossec_path, self.name, self.ip)) agent_files.append( '{0}/queue/rootcheck/({1}) {2}->rootcheck'.format( common.ossec_path, self.name, self.ip)) agent_files.append('{0}/queue/rids/{1}'.format( common.ossec_path, self.id)) agent_files.append('{0}/var/db/agents/{1}-{2}.db'.format( common.ossec_path, self.id, self.name)) agent_files.append('{0}/var/db/agents/{1}-{2}.db-wal'.format( common.ossec_path, self.id, self.name)) agent_files.append('{0}/var/db/agents/{1}-{2}.db-shm'.format( common.ossec_path, self.id, self.name)) for agent_file in agent_files: if path.exists(agent_file): remove(agent_file) else: # Create backup directory # /var/ossec/backup/agents/yyyy/Mon/dd/id-name-ip[tag] date_part = date.today().strftime('%Y/%b/%d') main_agent_backup_dir = '{0}/backup/agents/{1}/{2}-{3}-{4}'.format( common.ossec_path, date_part, self.id, self.name, self.ip) agent_backup_dir = main_agent_backup_dir not_agent_dir = True i = 0 while not_agent_dir: if path.exists(agent_backup_dir): i += 1 agent_backup_dir = '{0}-{1}'.format( main_agent_backup_dir, str(i).zfill(3)) else: makedirs(agent_backup_dir) chmod_r(agent_backup_dir, 0o750) not_agent_dir = False # Move agent file agent_files = [] agent_files.append([ '{0}/queue/agent-info/{1}-{2}'.format(common.ossec_path, self.name, self.ip), '{0}/agent-info'.format(agent_backup_dir) ]) agent_files.append([ '{0}/queue/syscheck/({1}) {2}->syscheck'.format( common.ossec_path, self.name, self.ip), '{0}/syscheck'.format(agent_backup_dir) ]) agent_files.append([ '{0}/queue/syscheck/.({1}) {2}->syscheck.cpt'.format( common.ossec_path, self.name, self.ip), '{0}/syscheck.cpt'.format(agent_backup_dir) ]) agent_files.append([ '{0}/queue/syscheck/({1}) {2}->syscheck-registry'.format( common.ossec_path, self.name, self.ip), '{0}/syscheck-registry'.format(agent_backup_dir) ]) agent_files.append([ '{0}/queue/syscheck/.({1}) {2}->syscheck-registry.cpt'.format( common.ossec_path, self.name, self.ip), '{0}/syscheck-registry.cpt'.format(agent_backup_dir) ]) agent_files.append([ '{0}/queue/rootcheck/({1}) {2}->rootcheck'.format( common.ossec_path, self.name, self.ip), '{0}/rootcheck'.format(agent_backup_dir) ]) for agent_file in agent_files: if path.exists( agent_file[0]) and not path.exists(agent_file[1]): rename(agent_file[0], agent_file[1]) return 'Agent removed'
def _add(self, name, ip): """ Adds the agent to OSSEC. :param name: name of the new agent. :param ip: IP of the new agent. It can be an IP, IP/NET or ANY. :return: Agent ID. """ # Check if authd is running if manager.status()['ossec-authd'] == 'running': raise WazuhException(1704) # Check if ip or name exist in client.keys last_id = 0 with open(common.client_keys) as f_k: for line in f_k.readlines(): if line[0] in ('# '): # starts with # or ' ' continue line_data = line.strip().split( ' ') # 0 -> id, 1 -> name, 2 -> ip, 3 -> key if line_data[1][0] in ('#!'): # name starts with # or ! continue if name == line_data[1]: raise WazuhException(1705, name) if ip.lower() != 'any' and ip == line_data[2]: raise WazuhException(1706, ip) id = int(line_data[0]) if last_id < id: last_id = id last_id = str(last_id + 1).zfill(3) # Tmp file f_keys_temp = '{0}.tmp'.format(common.client_keys) copyfile(common.client_keys, f_keys_temp) # Generate key random_number = randrange(1, 999999) epoch_time = int(time()) str1 = "{0}{1}{2}{3}".format(epoch_time, name, random_number, platform()) random_number = randrange(1, 999999) str2 = "{0}{1}{2}".format(ip, last_id, random_number) hash1 = md5() hash1.update(str1.encode()) hash2 = md5() hash2.update(str2.encode()) new_key = hash1.hexdigest() + hash2.hexdigest() # Write key with open(f_keys_temp, 'a') as f_kt: f_kt.write('{0} {1} {2} {3}\n'.format(last_id, name, ip, new_key)) # Overwrite client.keys move(f_keys_temp, common.client_keys) root_uid = getpwnam("ossec").pw_uid ossec_gid = getgrnam("ossec").gr_gid chown(common.client_keys, root_uid, ossec_gid) chmod(common.client_keys, 0o640) self.id = last_id
def _add(self, name, ip): """ Adds the agent to OSSEC. :param name: name of the new agent. :param ip: IP of the new agent. It can be an IP, IP/NET or ANY. :return: Agent ID. """ # Check if authd is running if manager.status()['ossec-authd'] == 'running': raise WazuhException(1704) # Check if ip or name exist in client.keys last_id = 0 with open(common.client_keys) as f_k: for line in f_k.readlines(): if line[0] in ('# '): # starts with # or ' ' continue line_data = line.strip().split(' ') # 0 -> id, 1 -> name, 2 -> ip, 3 -> key if line_data[1][0] in ('#!'): # name starts with # or ! continue if name == line_data[1]: raise WazuhException(1705, name) if ip.lower() != 'any' and ip == line_data[2]: raise WazuhException(1706, ip) id = int(line_data[0]) if last_id < id: last_id = id last_id = str(last_id + 1).zfill(3) # Tmp file f_keys_temp = '{0}.tmp'.format(common.client_keys) copyfile(common.client_keys, f_keys_temp) # Generate key random_number = randrange(1, 999999) epoch_time = int(time()) str1 = "{0}{1}{2}{3}".format(epoch_time, name, random_number, platform()) random_number = randrange(1, 999999) str2 = "{0}{1}{2}".format(ip, last_id, random_number) hash1 = md5() hash1.update(str1.encode()) hash2 = md5() hash2.update(str2.encode()) new_key = hash1.hexdigest() + hash2.hexdigest() # Write key with open(f_keys_temp, 'a') as f_kt: f_kt.write('{0} {1} {2} {3}\n'.format(last_id, name, ip, new_key)) # Overwrite client.keys move(f_keys_temp, common.client_keys) root_uid = getpwnam("ossec").pw_uid ossec_gid = getgrnam("ossec").gr_gid chown(common.client_keys, root_uid, ossec_gid) chmod(common.client_keys, 0o640) self.id = last_id