JFIF$        dd7 

Viewing File: /opt/imunify360/venv/lib/python3.11/site-packages/defence360agent/subsys/svcctl.py

import asyncio
import logging
import os
import subprocess as su
from typing import Iterable, Union

from defence360agent.contracts.config import Core
from defence360agent.utils import check_run, CheckRunError, run, OsReleaseInfo

logger = logging.getLogger(__name__)

DOS_PROTECTOR_SERVICE_NAME = "imunify360-dos-protection"
UAL_SERVICE_NAME = "imunify360-unified-access-logger"
PAM_SERVICE_NAME = "imunify360-pam"
AUDITD_SERVICE_NAME = "imunify-auditd-log-reader"
SCANLOGD_SERVICE_NAME = "imunify360-scanlogd"
WAFD_SERVICE_NAME = "imunify360-wafd"
AGENT_SERVICE_NAME = "imunify360-agent"


def _apply_cmd(func):
    async def wrapper(*args, **kwargs):
        cmd = func(*args, **kwargs)
        logger.debug("check_call(%r)", cmd)
        await check_run(cmd)

    return wrapper


async def _reset_failed_state(
    services: Iterable[Union["_CentOs6", "_SystemctlBased"]]
):
    for s in services:
        try:
            await s.reset_failed()
            await s.restart()
        except CheckRunError as e:
            logger.warning(
                "Failed to reset failed state for service %s: %s", s, e
            )
            return
        for _ in range(10):
            if await s.is_active():
                break
            logger.warning(
                "Service %s is still not active, sleep for %s seconds", s, 1
            )
            await asyncio.sleep(1)


class _CentOs6:
    SVC_CTL_BIN = "/sbin/service"
    _CHKCONFIG = "/sbin/chkconfig"

    def __init__(self, service_name):
        self._service_name = service_name

    @_apply_cmd
    def start(self):
        return [self.SVC_CTL_BIN, self._service_name, "start"]

    @_apply_cmd
    def stop(self):
        return [self.SVC_CTL_BIN, self._service_name, "stop"]

    @_apply_cmd
    def restart(self):
        return [self.SVC_CTL_BIN, self._service_name, "restart"]

    async def reset_failed(self):
        """Not implemented for Centos6"""
        pass

    @_apply_cmd
    def enable(self, **kwargs):
        return [self._CHKCONFIG, "--add", self._service_name]

    async def is_enabled(self):
        cmd = [self._CHKCONFIG, "--list", self._service_name]
        proc = await asyncio.create_subprocess_exec(
            *cmd, stdout=su.PIPE, stderr=su.DEVNULL
        )
        out, _ = await proc.communicate()
        rc = await proc.wait()
        return rc == 0 and b":on" in out

    def is_enabled_sync(self):
        cmd = [self._CHKCONFIG, "--list", self._service_name]
        cp = su.run(cmd, stdout=su.PIPE, stderr=su.DEVNULL)
        return cp.returncode == 0 and b":on" in cp.stdout

    @_apply_cmd
    def disable(self):
        return [self._CHKCONFIG, "--del", self._service_name]

    mask = disable
    unmask = enable

    async def is_active(self):
        cmd = [self.SVC_CTL_BIN, self._service_name, "status"]
        exit_code, _, _ = await run(cmd)
        return exit_code == 0

    def unit_exists(self):
        cp = su.run(
            [self._CHKCONFIG, "--list", self._service_name],
            stdout=su.DEVNULL,
            stderr=su.DEVNULL,
        )
        return cp.returncode == 0


class _SystemctlBased:
    SVC_CTL_BIN = "systemctl"

    def __init__(self, service_name):
        self._service_name = service_name

    @_apply_cmd
    def start(self):
        return [self.SVC_CTL_BIN, "start", self._service_name]

    @_apply_cmd
    def stop(self):
        return [self.SVC_CTL_BIN, "stop", self._service_name]

    @_apply_cmd
    def restart(self):
        return [self.SVC_CTL_BIN, "restart", self._service_name]

    @_apply_cmd
    def _enable_now(self, *, now: bool):
        return [
            self.SVC_CTL_BIN,
            "enable",
            *(["--now"] if now else []),
            self._service_name,
        ]

    async def enable(self, *, now: bool):
        await self._enable_now(now=now)

        # WARN: Ubuntu 16.04 demonstrates very special behavior of the
        # `systemcl enable --now` command - if the unit is stopped it
        # wouldn't be started. We need to handle that case.
        # TODO: Remove this case on dropping support for Ubuntu 16.04.
        osinfo = {}
        try:
            OsReleaseInfo.dict_from_file(osinfo)
        except (FileNotFoundError, PermissionError):
            return
        if osinfo.get("ID", "").lower() != "ubuntu":
            return
        if osinfo.get("VERSION_ID", "") == "16.04":
            await self.restart()

    async def is_enabled(self):
        cmd = [self.SVC_CTL_BIN, "is-enabled", self._service_name]
        proc = await asyncio.create_subprocess_exec(
            *cmd, stdout=su.DEVNULL, stderr=su.DEVNULL
        )
        await proc.communicate()
        rc = await proc.wait()
        return rc == 0

    def is_enabled_sync(self):
        cmd = [self.SVC_CTL_BIN, "is-enabled", self._service_name]
        rc = su.call(cmd, stdout=su.DEVNULL, stderr=su.DEVNULL)
        return rc == 0

    @_apply_cmd
    def disable(self, *, now: bool):
        return [
            self.SVC_CTL_BIN,
            "disable",
            *(["--now"] if now else []),
            self._service_name,
        ]

    @_apply_cmd
    def reload(self):
        return [self.SVC_CTL_BIN, "reload", self._service_name]

    @_apply_cmd
    def mask(self):
        """
        It was created for imunify360-webshield which required masking as far
        This is no more relevant but let it stay
        is started by 'Wants=' in imunify360.service
        """
        return [self.SVC_CTL_BIN, "mask", self._service_name]

    @_apply_cmd
    def unmask(self):
        """
        It was created for imunify360-webshield which required masking as far
        This is no more relevant but let it stay
        is started by 'Wants=' in imunify360.service
        """
        return [self.SVC_CTL_BIN, "unmask", self._service_name]

    async def is_active(self):
        cmd = [self.SVC_CTL_BIN, "is-active", self._service_name]
        exit_code, _, _ = await run(cmd)
        return exit_code == 0

    @_apply_cmd
    def reset_failed(self):
        return [self.SVC_CTL_BIN, "reset-failed", self._service_name]

    def unit_exists(self):
        cp = su.run(
            [self.SVC_CTL_BIN, "cat", self._service_name],
            stdout=su.DEVNULL,
            stderr=su.DEVNULL,
        )
        return cp.returncode == 0


class _CentOs7(_SystemctlBased):
    SVC_CTL_BIN = "/usr/bin/systemctl"


class _DebianUbuntu(_SystemctlBased):
    SVC_CTL_BIN = "/bin/systemctl"


class MinidaemonService(_CentOs6):
    def __init__(self, service_name="minidaemon"):
        self._service_name = service_name

    @_apply_cmd
    def restart(self, service=None):
        cmd = [self.SVC_CTL_BIN, self._service_name, "restart"]  # restart all
        if service:
            cmd += [service]  # restart specific child process
        return cmd


def adaptor(service_name, *, include_centos6=True):
    for a in (
        _DebianUbuntu,
        _CentOs7,
        *((_CentOs6,) if include_centos6 else tuple()),
    ):
        if os.path.exists(a.SVC_CTL_BIN):
            return a(service_name)
    else:
        raise RuntimeError("Cannot instantiate appropriate adaptor.")


async def activate_socket_service(service_name):
    agent_service = adaptor(service_name)
    agent_service_socket = adaptor(f"{service_name}.socket")

    if (
        await agent_service_socket.is_enabled()
        and not await agent_service_socket.is_active()
    ):
        # reset the main service, which will trigger socket activation
        await agent_service_socket.reset_failed()
        await _reset_failed_state((agent_service,))

        # wait some times until socket activates
        for _ in range(5):
            await asyncio.sleep(1)
            if await agent_service_socket.is_active():
                return

        logger.error(
            f"Failed to await active {service_name}.socket after reseting"
            f" {service_name}"
        )


def imunify360_service():
    return adaptor(Core.SVC_NAME)


def imunify360_dos_protector_service():
    try:
        return adaptor(DOS_PROTECTOR_SERVICE_NAME, include_centos6=False)
    except RuntimeError:
        logger.info("DOS Protector service is not available on this system")
        return None


def imunify360_ual_service():
    return adaptor(UAL_SERVICE_NAME)


def imunify360_pam_service():
    return adaptor(PAM_SERVICE_NAME)


def imunify360_scanlogd_service():
    return adaptor(SCANLOGD_SERVICE_NAME)


def imunify360_wafd_service():
    return adaptor(WAFD_SERVICE_NAME)


def imunify360_agent_service():
    return adaptor(AGENT_SERVICE_NAME)


def imunify360_auditd_service():
    unit = adaptor(AUDITD_SERVICE_NAME)
    if unit.unit_exists():
        return adaptor(AUDITD_SERVICE_NAME)
    logger.info("Auditd-log-reader service is not available on this system")
    return None
Back to Directory  nL+D550H?Mx ,D"v]qv;6*Zqn)ZP0!1 A "#a$2Qr D8 a Ri[f\mIykIw0cuFcRı?lO7к_f˓[C$殷WF<_W ԣsKcëIzyQy/_LKℂ;C",pFA:/]=H  ~,ls/9ć:[=/#f;)x{ٛEQ )~ =𘙲r*2~ a _V=' kumFD}KYYC)({ *g&f`툪ry`=^cJ.I](*`wq1dđ#̩͑0;H]u搂@:~וKL Nsh}OIR*8:2 !lDJVo(3=M(zȰ+i*NAr6KnSl)!JJӁ* %݉?|D}d5:eP0R;{$X'xF@.ÊB {,WJuQɲRI;9QE琯62fT.DUJ;*cP A\ILNj!J۱+O\͔]ޒS߼Jȧc%ANolՎprULZԛerE2=XDXgVQeӓk yP7U*omQIs,K`)6\G3t?pgjrmۛجwluGtfh9uyP0D;Uڽ"OXlif$)&|ML0Zrm1[HXPlPR0'G=i2N+0e2]]9VTPO׮7h(F*癈'=QVZDF,d߬~TX G[`le69CR(!S2!P <0x<!1AQ "Raq02Br#SCTb ?Ζ"]mH5WR7k.ۛ!}Q~+yԏz|@T20S~Kek *zFf^2X*(@8r?CIuI|֓>^ExLgNUY+{.RѪ τV׸YTD I62'8Y27'\TP.6d&˦@Vqi|8-OΕ]ʔ U=TL8=;6c| !qfF3aů&~$l}'NWUs$Uk^SV:U# 6w++s&r+nڐ{@29 gL u"TÙM=6(^"7r}=6YݾlCuhquympǦ GjhsǜNlɻ}o7#S6aw4!OSrD57%|?x>L |/nD6?/8w#[)L7+6〼T ATg!%5MmZ/c-{1_Je"|^$'O&ޱմTrb$w)R$& N1EtdU3Uȉ1pM"N*(DNyd96.(jQ)X 5cQɎMyW?Q*!R>6=7)Xj5`J]e8%t!+'!1Q5 !1 AQaqё#2"0BRb?Gt^## .llQT $v,,m㵜5ubV =sY+@d{N! dnO<.-B;_wJt6;QJd.Qc%p{ 1,sNDdFHI0ГoXшe黅XۢF:)[FGXƹ/w_cMeD,ʡcc.WDtA$j@:) -# u c1<@ۗ9F)KJ-hpP]_x[qBlbpʖw q"LFGdƶ*s+ډ_Zc"?%t[IP 6J]#=ɺVvvCGsGh1 >)6|ey?Lӣm,4GWUi`]uJVoVDG< SB6ϏQ@ TiUlyOU0kfV~~}SZ@*WUUi##; s/[=!7}"WN]'(L! ~y5g9T̅JkbM' +s:S +B)v@Mj e Cf jE 0Y\QnzG1д~Wo{T9?`Rmyhsy3!HAD]mc1~2LSu7xT;j$`}4->L#vzŏILS ֭T{rjGKC;bpU=-`BsK.SFw4Mq]ZdHS0)tLg