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'
def getVersion() -> str:
return 'Linux ' + getLinuxOs()
def reboot(flags: int = 0):
'''
Simple reboot using os command

View File

@ -27,5 +27,5 @@
# 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 -*-
#
# Copyright (c) 2014-2022 Virtual Cable S.L.U.
# Copyright (c) 2022 Virtual Cable S.L.U.
# All rights reserved.
#
# 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
# 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
import os
@ -43,8 +43,6 @@ class LocalLogger:
logger: typing.Optional[logging.Logger]
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
# 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

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014-2019 Virtual Cable S.L.
# Copyright (c) 2022 Virtual Cable S.L.U.
# All rights reserved.
#
# 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,
# this list of conditions and the following disclaimer in the documentation
# 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
# without specific prior written permission.
#
@ -26,7 +26,7 @@
# 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.
'''
@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)
@ -100,6 +100,10 @@ def getMacOs() -> str:
return 'unknown'
def getVersion() -> str:
return 'MacOS ' + getMacOs()
def reboot(flags: int = 0) -> None:
'''
Simple reboot using os command
@ -139,9 +143,10 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
def initIdleDuration(atLeastSeconds: int) -> None:
pass
# 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
@tools.cache(20)
@tools.cache(20)
def getIdleDuration() -> float:
# Execute:
try:

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014-2020 Virtual Cable S.L.U.
# Copyright (c) 2022 Virtual Cable S.L.U.
# All rights reserved.
#
# 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
# 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 typing

View File

@ -27,7 +27,7 @@
# 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 signal
@ -79,13 +79,12 @@ class UDSActorSvc(CommonService):
self.finish()
return # Stop daemon if initializes told to do so
else:
if not self.initializeUnmanaged():
# 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.
self.doWait(10000)
self.finish()
return
if not self.initializeUnmanaged():
# 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.
self.doWait(10000)
self.finish()
return
# Start listening for petitions
self.startHttpServer()

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014-2019 Virtual Cable S.L.
# Copyright (c) 2022 Virtual Cable S.L.U.
# All rights reserved.
#
# 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,
# this list of conditions and the following disclaimer in the documentation
# 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
# without specific prior written permission.
#
@ -26,7 +26,7 @@
# 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
Author: Adolfo Gómez, dkmaster at dkmon dot com
'''
import os
import configparser

View File

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

View File

@ -45,32 +45,46 @@ import win32con
from .. import types
from ..log import logger
def checkPermissions() -> bool:
return shell.IsUserAnAdmin()
def getErrorMessage(resultCode: int = 0) -> str:
# sys_fs_enc = sys.getfilesystemencoding() or 'mbcs'
msg = win32api.FormatMessage(resultCode)
return msg
def getComputerName() -> str:
return win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]:
obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
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:
for obj in adapters:
for ip in obj.IPAddress:
if ':' in ip: # Is IPV6, skip this
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
yield types.InterfaceInfoType(name=obj.Caption, mac=obj.MACAddress, ip=ip)
yield types.InterfaceInfoType(
name=obj.Caption, mac=obj.MACAddress, ip=ip
)
except Exception:
return
def getDomainName() -> str:
'''
Will return the domain name if we belong a domain, else None
@ -87,9 +101,19 @@ def getDomainName() -> str:
return domain
def getWindowsVersion() -> typing.Tuple[int, int, int, int, str]:
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_SHUTDOWN = 0x00000001
EWX_REBOOT = 0x00000002
@ -97,31 +121,53 @@ EWX_FORCE = 0x00000004
EWX_POWEROFF = 0x00000008
EWX_FORCEIFHUNG = 0x00000010
def reboot(flags: int = EWX_FORCEIFHUNG | EWX_REBOOT) -> None:
hproc = win32api.GetCurrentProcess()
htok = win32security.OpenProcessToken(hproc, win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY)
privs = ((win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME), win32security.SE_PRIVILEGE_ENABLED),)
htok = win32security.OpenProcessToken(
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)
win32api.ExitWindowsEx(flags, 0)
def loggoff() -> None:
win32api.ExitWindowsEx(EWX_LOGOFF)
def renameComputer(newName: str) -> bool:
'''
Changes the computer name
Returns True if reboot needed
'''
# 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.GetLastError -> returns error code
# (just put this comment here to remember to log this when logger is available)
error = getErrorMessage()
computerName = win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
raise Exception('Error renaming computer from {} to {}: {}'.format(computerName, newName, error))
computerName = win32api.GetComputerNameEx(
win32con.ComputerNamePhysicalDnsHostname
)
raise Exception(
'Error renaming computer from {} to {}: {}'.format(
computerName, newName, error
)
)
return True
NETSETUP_JOIN_DOMAIN = 0x00000001
NETSETUP_ACCT_CREATE = 0x00000002
NETSETUP_ACCT_DELETE = 0x00000004
@ -132,7 +178,10 @@ NETSETUP_MACHINE_PWD_PASSED = 0x00000080
NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400
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
:param domain: Domain to join to
@ -149,7 +198,9 @@ def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneSt
account = domain + '\\' + account
# 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:
flags |= NETSETUP_JOIN_WITH_NEW_NAME
@ -163,18 +214,31 @@ def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneSt
lpAccount = LPCWSTR(account)
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
if res == 2224:
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:
# Log the error
error = getErrorMessage(res)
if res == 1355:
error = "DC Is not reachable"
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:
# lpUser = LPCWSTR(user)
@ -188,7 +252,10 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
if res:
# Log the error, and raise exception to parent
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
_fields_ = [
@ -196,16 +263,20 @@ class LASTINPUTINFO(ctypes.Structure): # pylint: disable=too-few-public-methods
('dwTime', ctypes.c_uint),
]
def initIdleDuration(atLeastSeconds: int): # pylint: disable=unused-argument
'''
In windows, there is no need to set screensaver
'''
return
def getIdleDuration() -> float:
try:
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:
return 0
current = ctypes.c_uint(ctypes.windll.kernel32.GetTickCount()).value
@ -217,22 +288,27 @@ def getIdleDuration() -> float:
logger.error('Getting idle duration: {}'.format(e))
return 0
def getCurrentUser() -> str:
'''
Returns current logged in username
'''
return os.environ['USERNAME']
def getSessionType() -> str:
'''
Known values:
* Unknown -> No SESSIONNAME environment variable
* Console -> Local session
* RDP-Tcp#[0-9]+ -> RDP Session
Known values:
* Unknown -> No SESSIONNAME environment variable
* Console -> Local session
* RDP-Tcp#[0-9]+ -> RDP Session
'''
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]
try:
with open(pipeName, 'r+b', 0) as f:
@ -244,8 +320,11 @@ def writeToPipe(pipeName: str, bytesPayload: bytes, waitForResponse: bool) -> ty
except Exception:
return None
def forceTimeSync() -> None:
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:
logger.error('Error invoking time sync command: %s', e)