Ejemplo n.º 1
0
    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 addressed 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, wazuh-remoted, wazuh-analysisd, wazuh-execd
        and wazuh-db
        """
        if self.f == wazuh.core.manager.status:
            return

        status = wazuh.core.manager.status()

        not_ready_daemons = {
            k: status[k]
            for k in self.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.WazuhError(1017, extra_message=extra_info)
Ejemplo n.º 2
0
    def get_connected_nodes(self, filter_node: str = None, offset: int = 0, limit: int = common.database_limit,
                            sort: Dict = None, search: Dict = None, select: Dict = None,
                            filter_type: str = 'all') -> Dict:
        """
        Return all connected nodes, including the master node
        :return: A dictionary containing data from each node
        """

        def return_node(node_info: Dict) -> bool:
            """
            Returns whether the node must be added to the result or not
            :param node_info: Node information
            :return: A boolean
            """
            return (filter_node is None or node_info['name'] in filter_node) and (
                        filter_type == 'all' or node_info['type'] == filter_type)

        default_fields = self.to_dict()['info'].keys()
        if select is None:
            select = default_fields
        else:
            if not set(select).issubset(default_fields):
                raise exception.WazuhError(code=1724, extra_message=', '.join(set(select) - default_fields),
                                           extra_remediation=', '.join(default_fields))

        if filter_type != 'all' and filter_type not in {'worker', 'master'}:
            raise exception.WazuhError(1728)

        if filter_node is not None:
            filter_node = set(filter_node) if isinstance(filter_node, list) else {filter_node}
            if not filter_node.issubset(set(itertools.chain(self.clients.keys(), [self.configuration['node_name']]))):
                raise exception.WazuhResourceNotFound(1730)

        res = [val.to_dict()['info'] for val in itertools.chain([self], self.clients.values())
               if return_node(val.to_dict()['info'])]

        return utils.process_array([{k: v[k] for k in select} for v in res],
                                   search_text=search['value'] if search is not None else None,
                                   complementary_search=search['negation'] if search is not None else False,
                                   sort_by=sort['fields'] if sort is not None else None,
                                   sort_ascending=False if sort is not None and sort['order'] == 'desc' else True,
                                   allowed_sort_fields=default_fields,
                                   offset=offset,
                                   limit=limit)
Ejemplo n.º 3
0
    async def distribute_function(self) -> [Dict, exception.WazuhException]:
        """
        Distribute an API call.

        Returns
        -------
        dict or WazuhException
            Dictionary with API response or WazuhException in case of error.
        """
        try:
            self.logger.debug("Receiving parameters {}".format(self.f_kwargs))
            is_dapi_enabled = self.cluster_items['distributed_api']['enabled']
            is_cluster_disabled = self.node == local_client and wazuh.core.cluster.cluster.check_cluster_status(
            )

            # If it is a cluster API request and the cluster is not enabled, raise an exception
            if is_cluster_disabled and self.cluster_required:
                raise exception.WazuhError(3013)

            # First case: execute the request locally.
            # If the distributed api is not enabled
            # If the cluster is disabled or the request type is local_any
            # if the request was made in the master node and the request type is local_master
            # if the request came forwarded from the master node and its type is distributed_master
            if not is_dapi_enabled or is_cluster_disabled or self.request_type == 'local_any' or \
                    (self.request_type == 'local_master' and self.node_info['type'] == 'master') or \
                    (self.request_type == 'distributed_master' and self.from_cluster):

                response = await self.execute_local_request()

            # Second case: forward the request
            # Only the master node will forward a request, and it will only be forwarded if its type is distributed_
            # master
            elif self.request_type == 'distributed_master' and self.node_info[
                    'type'] == 'master':
                response = await self.forward_request()

            # Last case: execute the request remotely.
            # A request will only be executed remotely if it was made in a worker node and its type isn't local_any
            else:
                response = await self.execute_remote_request()

            try:
                response = json.loads(response, object_hook=c_common.as_wazuh_object) \
                    if isinstance(response, str) else response
            except json.decoder.JSONDecodeError:
                response = {'message': response}

            return response if isinstance(response, (wresults.AbstractWazuhResult, exception.WazuhException)) \
                else wresults.WazuhResult(response)

        except exception.WazuhError as e:
            e.dapi_errors = self.get_error_info(e)
            return e
        except exception.WazuhInternalError as e:
            e.dapi_errors = self.get_error_info(e)
            if self.debug:
                raise
            self.logger.error(f'{e.message}', exc_info=True)
            return e
        except Exception as e:
            if self.debug:
                raise

            self.logger.error(f'Unhandled exception: {str(e)}', exc_info=True)
            return exception.WazuhInternalError(
                1000, dapi_errors=self.get_error_info(e))
Ejemplo n.º 4
0
    def get_connected_nodes(self,
                            filter_node: str = None,
                            offset: int = 0,
                            limit: int = common.database_limit,
                            sort: Dict = None,
                            search: Dict = None,
                            select: Dict = None,
                            filter_type: str = 'all') -> Dict:
        """Get all connected nodes, including the master node.

        Parameters
        ----------
        filter_node : str, list
            Node to return.
        offset : int
            First element to return.
        limit : int
            Maximum number of elements to return.
        sort : dict
            Sorts the collection by a field or fields.
        search : dict
            Looks for elements with the specified string.
        select : dict
            Select which fields to return (separated by comma).
        filter_type : str
            Type of node (worker/master).

        Returns
        -------
        dict
            Data from each node.
        """
        def return_node(node_info: Dict) -> bool:
            """Return whether the node must be added to the result or not.

            Parameters
            ----------
            node_info : dict
                Node information.

            Returns
            -------
            bool
                Whether the node must be added to the result or not.
            """
            return (filter_node is None or node_info['name']
                    in filter_node) and (filter_type == 'all'
                                         or node_info['type'] == filter_type)

        default_fields = self.to_dict()['info'].keys()
        if select is None:
            select = default_fields
        else:
            if not set(select).issubset(default_fields):
                raise exception.WazuhError(
                    code=1724,
                    extra_message=', '.join(set(select) - default_fields),
                    extra_remediation=', '.join(default_fields))

        if filter_type != 'all' and filter_type not in {'worker', 'master'}:
            raise exception.WazuhError(1728)

        if filter_node is not None:
            filter_node = set(filter_node) if isinstance(
                filter_node, list) else {filter_node}
            if not filter_node.issubset(
                    set(
                        itertools.chain(self.clients.keys(),
                                        [self.configuration['node_name']]))):
                raise exception.WazuhResourceNotFound(1730)

        res = [
            val.to_dict()['info']
            for val in itertools.chain([self], self.clients.values())
            if return_node(val.to_dict()['info'])
        ]

        return utils.process_array(
            [{k: v[k]
              for k in select} for v in res],
            search_text=search['value'] if search is not None else None,
            complementary_search=search['negation']
            if search is not None else False,
            sort_by=sort['fields'] if sort is not None else None,
            sort_ascending=False
            if sort is not None and sort['order'] == 'desc' else True,
            allowed_sort_fields=default_fields,
            offset=offset,
            limit=limit)