fixing up actor things

This commit is contained in:
Adolfo Gómez García 2022-10-13 00:04:26 +02:00
parent 2908b99435
commit 9deb2dcd74
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
9 changed files with 128 additions and 44 deletions

View File

@ -158,6 +158,9 @@ def getLinuxOs() -> str:
return 'unknown' return 'unknown'
def getVersion() -> str:
return 'Linux ' + getLinuxOs()
def reboot(flags: int = 0): def reboot(flags: int = 0):
''' '''
Simple reboot using os command Simple reboot using os command

View File

@ -27,5 +27,5 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''' '''
@author: Adolfo Gómez, dkmaster at dkmon dot com Author: Adolfo Gómez, dkmaster at dkmon dot com
''' '''

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2014-2022 Virtual Cable S.L.U. # Copyright (c) 2022 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -26,7 +26,7 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''' '''
@author: Adolfo Gómez, dkmaster at dkmon dot com Author: Adolfo Gómez, dkmaster at dkmon dot com
''' '''
# pylint: disable=invalid-name # pylint: disable=invalid-name
import os import os
@ -43,8 +43,6 @@ class LocalLogger:
logger: typing.Optional[logging.Logger] logger: typing.Optional[logging.Logger]
def __init__(self) -> None: def __init__(self) -> None:
# tempdir is different for "user application" and "service"
# service wil get c:\windows\temp, while user will get c:\users\XXX\temp
# Try to open logger at /var/log path # Try to open logger at /var/log path
# If it fails (access denied normally), will try to open one at user's home folder, and if # If it fails (access denied normally), will try to open one at user's home folder, and if
# agaim it fails, open it at the tmpPath # agaim it fails, open it at the tmpPath

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2014-2019 Virtual Cable S.L. # Copyright (c) 2022 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -11,7 +11,7 @@
# * Redistributions in binary form must reproduce the above copyright notice, # * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation # this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution. # and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors # * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
# may be used to endorse or promote products derived from this software # may be used to endorse or promote products derived from this software
# without specific prior written permission. # without specific prior written permission.
# #
@ -26,7 +26,7 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''' '''
@author: Adolfo Gómez, dkmaster at dkmon dot com Author: Adolfo Gómez, dkmaster at dkmon dot com
''' '''
# Note. most methods are not implemented, as they are not needed for this platform (macos) # Note. most methods are not implemented, as they are not needed for this platform (macos)
@ -100,6 +100,10 @@ def getMacOs() -> str:
return 'unknown' return 'unknown'
def getVersion() -> str:
return 'MacOS ' + getMacOs()
def reboot(flags: int = 0) -> None: def reboot(flags: int = 0) -> None:
''' '''
Simple reboot using os command Simple reboot using os command
@ -139,9 +143,10 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
def initIdleDuration(atLeastSeconds: int) -> None: def initIdleDuration(atLeastSeconds: int) -> None:
pass pass
# se we cache for 20 seconds the result, that is enough for our needs # se we cache for 20 seconds the result, that is enough for our needs
# and we avoid calling a system command every time we need it # and we avoid calling a system command every time we need it
@tools.cache(20) @tools.cache(20)
def getIdleDuration() -> float: def getIdleDuration() -> float:
# Execute: # Execute:
try: try:

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2014-2020 Virtual Cable S.L.U. # Copyright (c) 2022 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -26,7 +26,7 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''' '''
@author: Adolfo Gómez, dkmaster at dkmon dot com Author: Adolfo Gómez, dkmaster at dkmon dot com
''' '''
import sys import sys
import typing import typing

View File

@ -27,7 +27,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''' '''
@author: Adolfo Gómez, dkmaster at dkmon dot com Author: Adolfo Gómez, dkmaster at dkmon dot com
''' '''
import typing import typing
import signal import signal
@ -79,13 +79,12 @@ class UDSActorSvc(CommonService):
self.finish() self.finish()
return # Stop daemon if initializes told to do so return # Stop daemon if initializes told to do so
else: if not self.initializeUnmanaged():
if not self.initializeUnmanaged(): # Wait a bit, this is mac os and will be run by launchd
# Wait a bit, this is mac os and will be run by launchd # If the daemon shuts down too quickly, launchd may think it is a crash.
# If the daemon shuts down too quickly, launchd may think it is a crash. self.doWait(10000)
self.doWait(10000) self.finish()
self.finish() return
return
# Start listening for petitions # Start listening for petitions
self.startHttpServer() self.startHttpServer()

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2014-2019 Virtual Cable S.L. # Copyright (c) 2022 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -11,7 +11,7 @@
# * Redistributions in binary form must reproduce the above copyright notice, # * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation # this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution. # and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors # * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
# may be used to endorse or promote products derived from this software # may be used to endorse or promote products derived from this software
# without specific prior written permission. # without specific prior written permission.
# #
@ -26,7 +26,7 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''' '''
@author: Adolfo Gómez, dkmaster at dkmon dot com Author: Adolfo Gómez, dkmaster at dkmon dot com
''' '''
import os import os
import configparser import configparser

View File

@ -181,7 +181,7 @@ class UDSServerApi(UDSApi):
except Exception: # nosec: not interested in exceptions except Exception: # nosec: not interested in exceptions
pass pass
def register( # pylint: disable=too-many-arguments, too-many-locals def register(
self, self,
auth: str, auth: str,
username: str, username: str,

View File

@ -45,32 +45,46 @@ import win32con
from .. import types from .. import types
from ..log import logger from ..log import logger
def checkPermissions() -> bool: def checkPermissions() -> bool:
return shell.IsUserAnAdmin() return shell.IsUserAnAdmin()
def getErrorMessage(resultCode: int = 0) -> str: def getErrorMessage(resultCode: int = 0) -> str:
# sys_fs_enc = sys.getfilesystemencoding() or 'mbcs' # sys_fs_enc = sys.getfilesystemencoding() or 'mbcs'
msg = win32api.FormatMessage(resultCode) msg = win32api.FormatMessage(resultCode)
return msg return msg
def getComputerName() -> str: def getComputerName() -> str:
return win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname) return win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]: def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]:
obj = win32com.client.Dispatch("WbemScripting.SWbemLocator") obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
wmobj = obj.ConnectServer("localhost", "root\\cimv2") wmobj = obj.ConnectServer("localhost", "root\\cimv2")
adapters = wmobj.ExecQuery("Select * from Win32_NetworkAdapterConfiguration where IpEnabled=True") adapters = wmobj.ExecQuery(
"Select * from Win32_NetworkAdapterConfiguration where IpEnabled=True"
)
try: try:
for obj in adapters: for obj in adapters:
for ip in obj.IPAddress: for ip in obj.IPAddress:
if ':' in ip: # Is IPV6, skip this if ':' in ip: # Is IPV6, skip this
continue continue
if ip is None or ip == '' or ip.startswith('169.254') or ip.startswith('0.'): # If single link ip, or no ip if (
ip is None
or ip == ''
or ip.startswith('169.254')
or ip.startswith('0.')
): # If single link ip, or no ip
continue continue
yield types.InterfaceInfoType(name=obj.Caption, mac=obj.MACAddress, ip=ip) yield types.InterfaceInfoType(
name=obj.Caption, mac=obj.MACAddress, ip=ip
)
except Exception: except Exception:
return return
def getDomainName() -> str: def getDomainName() -> str:
''' '''
Will return the domain name if we belong a domain, else None Will return the domain name if we belong a domain, else None
@ -87,9 +101,19 @@ def getDomainName() -> str:
return domain return domain
def getWindowsVersion() -> typing.Tuple[int, int, int, int, str]: def getWindowsVersion() -> typing.Tuple[int, int, int, int, str]:
return win32api.GetVersionEx() return win32api.GetVersionEx()
def getVersion() -> str:
verinfo = getWindowsVersion()
# Remove platform id i
return 'Windows-{}.{} Build {} ({})'.format(
verinfo[0], verinfo[1], verinfo[2], verinfo[4]
)
EWX_LOGOFF = 0x00000000 EWX_LOGOFF = 0x00000000
EWX_SHUTDOWN = 0x00000001 EWX_SHUTDOWN = 0x00000001
EWX_REBOOT = 0x00000002 EWX_REBOOT = 0x00000002
@ -97,31 +121,53 @@ EWX_FORCE = 0x00000004
EWX_POWEROFF = 0x00000008 EWX_POWEROFF = 0x00000008
EWX_FORCEIFHUNG = 0x00000010 EWX_FORCEIFHUNG = 0x00000010
def reboot(flags: int = EWX_FORCEIFHUNG | EWX_REBOOT) -> None: def reboot(flags: int = EWX_FORCEIFHUNG | EWX_REBOOT) -> None:
hproc = win32api.GetCurrentProcess() hproc = win32api.GetCurrentProcess()
htok = win32security.OpenProcessToken(hproc, win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY) htok = win32security.OpenProcessToken(
privs = ((win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME), win32security.SE_PRIVILEGE_ENABLED),) hproc, win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
)
privs = (
(
win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME),
win32security.SE_PRIVILEGE_ENABLED,
),
)
win32security.AdjustTokenPrivileges(htok, 0, privs) win32security.AdjustTokenPrivileges(htok, 0, privs)
win32api.ExitWindowsEx(flags, 0) win32api.ExitWindowsEx(flags, 0)
def loggoff() -> None: def loggoff() -> None:
win32api.ExitWindowsEx(EWX_LOGOFF) win32api.ExitWindowsEx(EWX_LOGOFF)
def renameComputer(newName: str) -> bool: def renameComputer(newName: str) -> bool:
''' '''
Changes the computer name Changes the computer name
Returns True if reboot needed Returns True if reboot needed
''' '''
# Needs admin privileges to work # Needs admin privileges to work
if ctypes.windll.kernel32.SetComputerNameExW(DWORD(win32con.ComputerNamePhysicalDnsHostname), LPCWSTR(newName)) == 0: # @UndefinedVariable if (
ctypes.windll.kernel32.SetComputerNameExW(
DWORD(win32con.ComputerNamePhysicalDnsHostname), LPCWSTR(newName)
)
== 0
): # @UndefinedVariable
# win32api.FormatMessage -> returns error string # win32api.FormatMessage -> returns error string
# win32api.GetLastError -> returns error code # win32api.GetLastError -> returns error code
# (just put this comment here to remember to log this when logger is available) # (just put this comment here to remember to log this when logger is available)
error = getErrorMessage() error = getErrorMessage()
computerName = win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname) computerName = win32api.GetComputerNameEx(
raise Exception('Error renaming computer from {} to {}: {}'.format(computerName, newName, error)) win32con.ComputerNamePhysicalDnsHostname
)
raise Exception(
'Error renaming computer from {} to {}: {}'.format(
computerName, newName, error
)
)
return True return True
NETSETUP_JOIN_DOMAIN = 0x00000001 NETSETUP_JOIN_DOMAIN = 0x00000001
NETSETUP_ACCT_CREATE = 0x00000002 NETSETUP_ACCT_CREATE = 0x00000002
NETSETUP_ACCT_DELETE = 0x00000004 NETSETUP_ACCT_DELETE = 0x00000004
@ -132,7 +178,10 @@ NETSETUP_MACHINE_PWD_PASSED = 0x00000080
NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400 NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400
NETSETUP_DEFER_SPN_SET = 0x1000000 NETSETUP_DEFER_SPN_SET = 0x1000000
def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False) -> None:
def joinDomain(
domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False
) -> None:
''' '''
Joins machine to a windows domain Joins machine to a windows domain
:param domain: Domain to join to :param domain: Domain to join to
@ -149,7 +198,9 @@ def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneSt
account = domain + '\\' + account account = domain + '\\' + account
# Do log # Do log
flags: typing.Any = NETSETUP_ACCT_CREATE | NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN flags: typing.Any = (
NETSETUP_ACCT_CREATE | NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN
)
if executeInOneStep: if executeInOneStep:
flags |= NETSETUP_JOIN_WITH_NEW_NAME flags |= NETSETUP_JOIN_WITH_NEW_NAME
@ -163,18 +214,31 @@ def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneSt
lpAccount = LPCWSTR(account) lpAccount = LPCWSTR(account)
lpPassword = LPCWSTR(password) lpPassword = LPCWSTR(password)
res = ctypes.windll.netapi32.NetJoinDomain(None, lpDomain, lpOu, lpAccount, lpPassword, flags) res = ctypes.windll.netapi32.NetJoinDomain(
None, lpDomain, lpOu, lpAccount, lpPassword, flags
)
# Machine found in another ou, use it and warn this on log # Machine found in another ou, use it and warn this on log
if res == 2224: if res == 2224:
flags = DWORD(NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN) flags = DWORD(NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN)
res = ctypes.windll.netapi32.NetJoinDomain(None, lpDomain, None, lpAccount, lpPassword, flags) res = ctypes.windll.netapi32.NetJoinDomain(
None, lpDomain, None, lpAccount, lpPassword, flags
)
if res: if res:
# Log the error # Log the error
error = getErrorMessage(res) error = getErrorMessage(res)
if res == 1355: if res == 1355:
error = "DC Is not reachable" error = "DC Is not reachable"
logger.error('Error joining domain: {}, {}'.format(error, res)) logger.error('Error joining domain: {}, {}'.format(error, res))
raise Exception('Error joining domain {}, with credentials {}/*****{}: {}, {}'.format(domain, account, ', under OU {}'.format(ou) if ou is not None else '', res, error)) raise Exception(
'Error joining domain {}, with credentials {}/*****{}: {}, {}'.format(
domain,
account,
', under OU {}'.format(ou) if ou is not None else '',
res,
error,
)
)
def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None: def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
# lpUser = LPCWSTR(user) # lpUser = LPCWSTR(user)
@ -188,7 +252,10 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
if res: if res:
# Log the error, and raise exception to parent # Log the error, and raise exception to parent
error = getErrorMessage(res) error = getErrorMessage(res)
raise Exception('Error changing password for user {}: {} {}'.format(user, res, error)) raise Exception(
'Error changing password for user {}: {} {}'.format(user, res, error)
)
class LASTINPUTINFO(ctypes.Structure): # pylint: disable=too-few-public-methods class LASTINPUTINFO(ctypes.Structure): # pylint: disable=too-few-public-methods
_fields_ = [ _fields_ = [
@ -196,16 +263,20 @@ class LASTINPUTINFO(ctypes.Structure): # pylint: disable=too-few-public-methods
('dwTime', ctypes.c_uint), ('dwTime', ctypes.c_uint),
] ]
def initIdleDuration(atLeastSeconds: int): # pylint: disable=unused-argument def initIdleDuration(atLeastSeconds: int): # pylint: disable=unused-argument
''' '''
In windows, there is no need to set screensaver In windows, there is no need to set screensaver
''' '''
return return
def getIdleDuration() -> float: def getIdleDuration() -> float:
try: try:
lastInputInfo = LASTINPUTINFO() lastInputInfo = LASTINPUTINFO()
lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo) # pylint: disable=attribute-defined-outside-init lastInputInfo.cbSize = ctypes.sizeof(
lastInputInfo
) # pylint: disable=attribute-defined-outside-init
if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo)) == 0: if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo)) == 0:
return 0 return 0
current = ctypes.c_uint(ctypes.windll.kernel32.GetTickCount()).value current = ctypes.c_uint(ctypes.windll.kernel32.GetTickCount()).value
@ -217,22 +288,27 @@ def getIdleDuration() -> float:
logger.error('Getting idle duration: {}'.format(e)) logger.error('Getting idle duration: {}'.format(e))
return 0 return 0
def getCurrentUser() -> str: def getCurrentUser() -> str:
''' '''
Returns current logged in username Returns current logged in username
''' '''
return os.environ['USERNAME'] return os.environ['USERNAME']
def getSessionType() -> str: def getSessionType() -> str:
''' '''
Known values: Known values:
* Unknown -> No SESSIONNAME environment variable * Unknown -> No SESSIONNAME environment variable
* Console -> Local session * Console -> Local session
* RDP-Tcp#[0-9]+ -> RDP Session * RDP-Tcp#[0-9]+ -> RDP Session
''' '''
return os.environ.get('SESSIONNAME', 'unknown') return os.environ.get('SESSIONNAME', 'unknown')
def writeToPipe(pipeName: str, bytesPayload: bytes, waitForResponse: bool) -> typing.Optional[bytes]:
def writeToPipe(
pipeName: str, bytesPayload: bytes, waitForResponse: bool
) -> typing.Optional[bytes]:
# (str, bytes, bool) -> Optional[bytes] # (str, bytes, bool) -> Optional[bytes]
try: try:
with open(pipeName, 'r+b', 0) as f: with open(pipeName, 'r+b', 0) as f:
@ -244,8 +320,11 @@ def writeToPipe(pipeName: str, bytesPayload: bytes, waitForResponse: bool) -> ty
except Exception: except Exception:
return None return None
def forceTimeSync() -> None: def forceTimeSync() -> None:
try: try:
subprocess.call([r'c:\WINDOWS\System32\w32tm.exe', ' /resync']) # , '/rediscover']) subprocess.call(
[r'c:\WINDOWS\System32\w32tm.exe', ' /resync']
) # , '/rediscover'])
except Exception as e: except Exception as e:
logger.error('Error invoking time sync command: %s', e) logger.error('Error invoking time sync command: %s', e)