diff --git a/actor/macos/net.virtualcable.udsactor.server.plist b/actor/macos/net.virtualcable.udsactor.server.plist
new file mode 100644
index 000000000..e4c6c240a
--- /dev/null
+++ b/actor/macos/net.virtualcable.udsactor.server.plist
@@ -0,0 +1,33 @@
+
+
+
+
+ Label
+ net.virtualcable.udsactor.server
+
+ KeepAlive
+
+ SuccessfulExit
+
+
+
+ ProgramArguments
+
+ /Applications/UDSActor.app/Contents/MacOS/udsactor
+ start
+
+
+ RunAtLoad
+
+
+ StandardErrorPath
+ /var/log/udsactor.log
+
+ StandardOutPath
+ /var/log/nxserver.log
+
+ WorkingDirectory
+ /Applications/UDSActor.app/Contents/Resources/
+
+
+
diff --git a/actor/macos/notes.txt b/actor/macos/notes.txt
new file mode 100644
index 000000000..88a19be45
--- /dev/null
+++ b/actor/macos/notes.txt
@@ -0,0 +1 @@
+service file (net.virtualcable.udsactor.server.plist) goes in /Library/LaunchDaemons
diff --git a/actor/src/actor_config_unmanaged.py b/actor/src/actor_config_unmanaged.py
index 0f9866897..211ce674b 100755
--- a/actor/src/actor_config_unmanaged.py
+++ b/actor/src/actor_config_unmanaged.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2020 Virtual Cable S.L.
+# Copyright (c) 2020-2022 Virtual Cable S.L.U.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@@ -12,7 +12,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.
#
@@ -32,7 +32,7 @@
# pylint: disable=invalid-name
import sys
import os
-import pickle
+import pickle # nosec: B403
import logging
import typing
@@ -102,7 +102,7 @@ class UDSConfigDialog(QDialog):
self,
'UDS Test',
'Service token seems to be invalid . Please, check token validity.',
- QMessageBox.Ok,
+ QMessageBox.Ok, # type: ignore
)
else:
QMessageBox.information(
@@ -111,14 +111,14 @@ class UDSConfigDialog(QDialog):
'Configuration for {} seems to be correct.'.format(
self._config.host
),
- QMessageBox.Ok,
+ QMessageBox.Ok, # type: ignore
)
except Exception:
QMessageBox.information(
self,
'UDS Test',
'Configured host {} seems to be inaccesible.'.format(self._config.host),
- QMessageBox.Ok,
+ QMessageBox.Ok, # type: ignore
)
def saveConfig(self) -> None:
@@ -134,7 +134,7 @@ class UDSConfigDialog(QDialog):
self,
'Invalid subnet',
'Invalid subnet {}. Please, check it.'.format(restrictNet),
- QMessageBox.Ok,
+ QMessageBox.Ok, # type: ignore
)
return
@@ -153,12 +153,15 @@ class UDSConfigDialog(QDialog):
self.ui.testButton.setEnabled(True)
# Informs the user
QMessageBox.information(
- self, 'UDS Configuration', 'Configuration saved.', QMessageBox.Ok
+ self,
+ 'UDS Configuration',
+ 'Configuration saved.',
+ QMessageBox.Ok, # type: ignore
)
if __name__ == "__main__":
- # If to be run as "sudo" on linux, we will need this to avoid problems
+ # If run as "sudo" on linux, we will need this to avoid problems
if 'linux' in sys.platform:
os.environ['QT_X11_NO_MITSHM'] = '1'
@@ -171,16 +174,18 @@ if __name__ == "__main__":
if len(sys.argv) > 2:
if sys.argv[1] == 'export':
try:
- with open(sys.argv[2], 'wb') as f:
- pickle.dump(udsactor.platform.store.readConfig(), f, protocol=3)
+ with open(sys.argv[2], 'wb') as export_:
+ pickle.dump(
+ udsactor.platform.store.readConfig(), export_, protocol=3
+ )
except Exception as e:
print('Error exporting configuration file: {}'.format(e))
sys.exit(1)
sys.exit(0)
- if sys.argv[1] == 'import':
+ elif sys.argv[1] == 'import':
try:
- with open(sys.argv[2], 'rb') as f:
- config = pickle.load(f)
+ with open(sys.argv[2], 'rb') as import_:
+ config = pickle.load(import_) # nosec: B301: the file is provided by user, so it's not a security issue
udsactor.platform.store.writeConfig(config)
except Exception as e:
print('Error importing configuration file: {}'.format(e))
diff --git a/actor/src/udsactor/client.py b/actor/src/udsactor/client.py
index 2678a57bd..700bb99f1 100644
--- a/actor/src/udsactor/client.py
+++ b/actor/src/udsactor/client.py
@@ -235,7 +235,7 @@ class UDSActorClient(threading.Thread): # pylint: disable=too-many-instance-att
pixmap: 'QPixmap' = self._qApp.primaryScreen().grabWindow(0) # type: ignore
ba = QByteArray()
buffer = QBuffer(ba)
- buffer.open(QIODevice.WriteOnly)
+ buffer.open(QIODevice.WriteOnly) # type: ignore
pixmap.save(buffer, 'PNG')
buffer.close()
scrBase64 = bytes(ba.toBase64()).decode() # type: ignore # there are problems with Pylance and connects on PyQt5... :)
diff --git a/actor/src/udsactor/linux/daemon.py b/actor/src/udsactor/linux/daemon.py
index 2af430804..99569fa89 100644
--- a/actor/src/udsactor/linux/daemon.py
+++ b/actor/src/udsactor/linux/daemon.py
@@ -101,7 +101,7 @@ class Daemon:
def removePidFile(self) -> None:
try:
os.remove(self.pidfile)
- except Exception:
+ except Exception: # nosec: Not interested in exception
# Not found/not permissions or whatever, ignore it
pass
diff --git a/actor/src/udsactor/linux/log.py b/actor/src/udsactor/linux/log.py
index e70d3688b..e458b81c6 100644
--- a/actor/src/udsactor/linux/log.py
+++ b/actor/src/udsactor/linux/log.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2014-2019 Virtual Cable S.L.
+# Copyright (c) 2014-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.
#
@@ -35,8 +35,8 @@ import logging
import typing
class LocalLogger: # pylint: disable=too-few-public-methods
- linux = False
- windows = True
+ linux = True
+ windows = False
serviceLogger = False
logger: typing.Optional[logging.Logger]
@@ -59,7 +59,8 @@ class LocalLogger: # pylint: disable=too-few-public-methods
self.logger = logging.getLogger('udsactor')
os.chmod(fname, 0o0600)
return
- except Exception:
+ except Exception: # nosec: B110: we don't care about exceptions here
+ # Ignore and try next
pass
# Logger can't be set
diff --git a/actor/src/udsactor/linux/operations.py b/actor/src/udsactor/linux/operations.py
index c39d2b08b..a26d036f0 100644
--- a/actor/src/udsactor/linux/operations.py
+++ b/actor/src/udsactor/linux/operations.py
@@ -34,7 +34,7 @@ import platform
import socket
import fcntl # Only available on Linux. Expect complains if edited from windows
import os
-import subprocess
+import subprocess # nosec
import struct
import array
import typing
@@ -53,7 +53,9 @@ def _getMacAddr(ifname: str) -> typing.Optional[str]:
ifnameBytes = ifname.encode('utf-8')
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- info = bytearray(fcntl.ioctl(s.fileno(), 0x8927, struct.pack(str('256s'), ifnameBytes[:15])))
+ info = bytearray(
+ fcntl.ioctl(s.fileno(), 0x8927, struct.pack(str('256s'), ifnameBytes[:15]))
+ )
return str(''.join(['%02x:' % char for char in info[18:24]])[:-1]).upper()
except Exception:
return None
@@ -67,11 +69,15 @@ def _getIpAddr(ifname: str) -> typing.Optional[str]:
ifnameBytes = ifname.encode('utf-8')
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- return str(socket.inet_ntoa(fcntl.ioctl(
- s.fileno(),
- 0x8915, # SIOCGIFADDR
- struct.pack(str('256s'), ifnameBytes[:15])
- )[20:24]))
+ return str(
+ socket.inet_ntoa(
+ fcntl.ioctl(
+ s.fileno(),
+ 0x8915, # SIOCGIFADDR
+ struct.pack(str('256s'), ifnameBytes[:15]),
+ )[20:24]
+ )
+ )
except Exception:
return None
@@ -91,22 +97,32 @@ def _getInterfaces() -> typing.List[str]:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
names = array.array(str('B'), b'\0' * space)
- outbytes = struct.unpack('iL', fcntl.ioctl(
- s.fileno(),
- 0x8912, # SIOCGIFCONF
- struct.pack('iL', space, names.buffer_info()[0])
- ))[0]
+ outbytes = struct.unpack(
+ 'iL',
+ fcntl.ioctl(
+ s.fileno(),
+ 0x8912, # SIOCGIFCONF
+ struct.pack('iL', space, names.buffer_info()[0]),
+ ),
+ )[0]
namestr = names.tobytes()
# return namestr, outbytes
- return [namestr[i:i + offset].split(b'\0', 1)[0].decode('utf-8') for i in range(0, outbytes, length)]
+ return [
+ namestr[i : i + offset].split(b'\0', 1)[0].decode('utf-8')
+ for i in range(0, outbytes, length)
+ ]
-def _getIpAndMac(ifname: str) -> typing.Tuple[typing.Optional[str], typing.Optional[str]]:
+def _getIpAndMac(
+ ifname: str,
+) -> typing.Tuple[typing.Optional[str], typing.Optional[str]]:
ip, mac = _getIpAddr(ifname), _getMacAddr(ifname)
return (ip, mac)
+
def checkPermissions() -> bool:
- return os.getuid() == 0 # getuid only available on linux. Expect "complaioins" if edited from Windows
+ return os.getuid() == 0
+
def getComputerName() -> str:
'''
@@ -114,15 +130,23 @@ def getComputerName() -> str:
'''
return socket.gethostname().split('.')[0]
+
def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]:
for ifname in _getInterfaces():
ip, mac = _getIpAndMac(ifname)
- if mac != '00:00:00:00:00:00' and mac and ip and ip.startswith('169.254') is False: # Skips local interfaces & interfaces with no dhcp IPs
+ if (
+ mac != '00:00:00:00:00:00'
+ and mac
+ and ip
+ and ip.startswith('169.254') is False
+ ): # Skips local interfaces & interfaces with no dhcp IPs
yield types.InterfaceInfoType(name=ifname, mac=mac, ip=ip)
+
def getDomainName() -> str:
return ''
+
def getLinuxOs() -> str:
try:
with open('/etc/os-release', 'r') as f:
@@ -133,18 +157,19 @@ def getLinuxOs() -> str:
except Exception:
return 'unknown'
+
def reboot(flags: int = 0):
'''
Simple reboot using os command
'''
- subprocess.call(['/sbin/shutdown', 'now', '-r'])
+ subprocess.call(['/sbin/shutdown', 'now', '-r']) # nosec: Fine, all under control
def loggoff() -> None:
'''
Right now restarts the machine...
'''
- subprocess.call(['/usr/bin/pkill', '-u', os.environ['USER']])
+ subprocess.call(['/usr/bin/pkill', '-u', os.environ['USER']]) # nosec: Fine, all under control
# subprocess.call(['/sbin/shutdown', 'now', '-r'])
# subprocess.call(['/usr/bin/systemctl', 'reboot', '-i'])
@@ -158,7 +183,9 @@ def renameComputer(newName: str) -> bool:
return True # Always reboot right now. Not much slower but much more convenient
-def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False):
+def joinDomain(
+ domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False
+):
pass
@@ -166,7 +193,11 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
'''
Simple password change for user using command line
'''
- os.system('echo "{1}\n{1}" | /usr/bin/passwd {0} 2> /dev/null'.format(user, newPassword))
+
+ subprocess.run( # nosec: Fine, all under control
+ 'echo "{1}\n{1}" | /usr/bin/passwd {0} 2> /dev/null'.format(user, newPassword),
+ shell=True,
+ )
def initIdleDuration(atLeastSeconds: int) -> None:
@@ -183,14 +214,20 @@ def getCurrentUser() -> str:
'''
return os.environ['USER']
+
def getSessionType() -> str:
'''
- Known values:
- * Unknown -> No XDG_SESSION_TYPE environment variable
- * xrdp --> xrdp session
- * other types
+ Known values:
+ * Unknown -> No XDG_SESSION_TYPE environment variable
+ * xrdp --> xrdp session
+ * other types
'''
- return 'xrdp' if 'XRDP_SESSION' in os.environ else os.environ.get('XDG_SESSION_TYPE', 'unknown')
+ return (
+ 'xrdp'
+ if 'XRDP_SESSION' in os.environ
+ else os.environ.get('XDG_SESSION_TYPE', 'unknown')
+ )
+
def forceTimeSync() -> None:
return
diff --git a/actor/src/udsactor/linux/renamer/alt.py b/actor/src/udsactor/linux/renamer/alt.py
index 25f027578..fcd93a38d 100644
--- a/actor/src/udsactor/linux/renamer/alt.py
+++ b/actor/src/udsactor/linux/renamer/alt.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2014-2019 Virtual Cable S.L.
+# Copyright (c) 2014-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.
#
@@ -28,7 +28,7 @@
'''
@author: Alexey Shabalin, shaba at altlinux dot org
'''
-import os
+import subprocess # nosec
from .common import renamers
from ...log import logger
@@ -46,8 +46,8 @@ def rename(newName: str) -> bool:
hostname.write(newName)
# Force system new name
- os.system('/bin/hostname {}'.format(newName))
- os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
+ subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: subprocess
+ subprocess.run(['/bin/hostname', newName]) # nosec: subprocess
# add name to "hosts"
with open('/etc/hosts', 'r') as hosts:
diff --git a/actor/src/udsactor/linux/renamer/common.py b/actor/src/udsactor/linux/renamer/common.py
index cf8d44195..7d67beaac 100644
--- a/actor/src/udsactor/linux/renamer/common.py
+++ b/actor/src/udsactor/linux/renamer/common.py
@@ -29,9 +29,6 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
-import os
-import sys
-import pkgutil
import typing
from .. import operations
diff --git a/actor/src/udsactor/linux/renamer/debian.py b/actor/src/udsactor/linux/renamer/debian.py
index 7c198d03a..c88d54d18 100644
--- a/actor/src/udsactor/linux/renamer/debian.py
+++ b/actor/src/udsactor/linux/renamer/debian.py
@@ -29,7 +29,7 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
-import os
+import subprocess # nosec
from .common import renamers
from ...log import logger
@@ -45,8 +45,8 @@ def rename(newName: str) -> bool:
hostname.write(newName)
# Force system new name
- os.system('/bin/hostname {}'.format(newName))
- os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
+ subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
+ subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
# add name to "hosts"
with open('/etc/hosts', 'r') as hosts:
diff --git a/actor/src/udsactor/linux/renamer/opensuse.py b/actor/src/udsactor/linux/renamer/opensuse.py
index 63efd82da..9574abc91 100644
--- a/actor/src/udsactor/linux/renamer/opensuse.py
+++ b/actor/src/udsactor/linux/renamer/opensuse.py
@@ -28,7 +28,7 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
-import os
+import subprocess # nosec
from .common import renamers
from ...log import logger
@@ -46,8 +46,8 @@ def rename(newName: str) -> bool:
hostname.write(newName)
# Force system new name
- os.system('/bin/hostname {}'.format(newName))
- os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
+ subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
+ subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
# add name to "hosts"
with open('/etc/hosts', 'r') as hosts:
diff --git a/actor/src/udsactor/linux/renamer/redhat.py b/actor/src/udsactor/linux/renamer/redhat.py
index 3ad1ac810..73263aabe 100644
--- a/actor/src/udsactor/linux/renamer/redhat.py
+++ b/actor/src/udsactor/linux/renamer/redhat.py
@@ -28,7 +28,7 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
-import os
+import subprocess # nosec
from .common import renamers
from ...log import logger
@@ -46,8 +46,8 @@ def rename(newName: str) -> bool:
hostname.write(newName)
# Force system new name
- os.system('/bin/hostname {}'.format(newName))
- os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
+ subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
+ subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
# add name to "hosts"
with open('/etc/hosts', 'r') as hosts:
diff --git a/actor/src/udsactor/linux/service.py b/actor/src/udsactor/linux/service.py
index 835bfc942..2d345bba4 100644
--- a/actor/src/udsactor/linux/service.py
+++ b/actor/src/udsactor/linux/service.py
@@ -37,7 +37,7 @@ from ..log import logger
from ..service import CommonService
try:
- from prctl import set_proctitle # @UnresolvedImport
+ from prctl import set_proctitle # type: ignore
except ImportError: # Platform may not include prctl, so in case it's not available, we let the "name" as is
def set_proctitle(_):
pass
diff --git a/actor/src/udsactor/linux/store.py b/actor/src/udsactor/linux/store.py
index 869475e3f..43a6d89ff 100644
--- a/actor/src/udsactor/linux/store.py
+++ b/actor/src/udsactor/linux/store.py
@@ -32,12 +32,13 @@
import os
import configparser
import base64
-import pickle
+import pickle # nosec
from .. import types
CONFIGFILE = '/etc/udsactor/udsactor.cfg'
+
def readConfig() -> types.ActorConfigurationType:
try:
cfg = configparser.ConfigParser()
@@ -45,10 +46,22 @@ def readConfig() -> types.ActorConfigurationType:
uds: configparser.SectionProxy = cfg['uds']
# Extract data:
base64Config = uds.get('config', None)
- config = pickle.loads(base64.b64decode(base64Config.encode())) if base64Config else None
+ config = (
+ pickle.loads( # nosec: file is restricted
+ base64.b64decode(base64Config.encode())
+ )
+ if base64Config
+ else None
+ )
base64Data = uds.get('data', None)
- data = pickle.loads(base64.b64decode(base64Data.encode())) if base64Data else None
+ data = (
+ pickle.loads( # nosec: file is restricted
+ base64.b64decode(base64Data.encode())
+ )
+ if base64Data
+ else None
+ )
return types.ActorConfigurationType(
actorType=uds.get('type', types.MANAGED),
@@ -62,20 +75,23 @@ def readConfig() -> types.ActorConfigurationType:
post_command=uds.get('post_command', None),
log_level=int(uds.get('log_level', '2')),
config=config,
- data=data
+ data=data,
)
except Exception:
return types.ActorConfigurationType('', False)
+
def writeConfig(config: types.ActorConfigurationType) -> None:
cfg = configparser.ConfigParser()
cfg.add_section('uds')
uds: configparser.SectionProxy = cfg['uds']
uds['host'] = config.host
uds['validate'] = 'yes' if config.validateCertificate else 'no'
+
def writeIfValue(val, name):
if val:
uds[name] = val
+
writeIfValue(config.actorType, 'type')
writeIfValue(config.master_token, 'master_token')
writeIfValue(config.own_token, 'own_token')
@@ -93,15 +109,19 @@ def writeConfig(config: types.ActorConfigurationType) -> None:
# Ensures exists destination folder
dirname = os.path.dirname(CONFIGFILE)
if not os.path.exists(dirname):
- os.mkdir(dirname, mode=0o700) # Will create only if route to path already exists, for example, /etc (that must... :-))
+ os.mkdir(
+ dirname, mode=0o700
+ ) # Will create only if route to path already exists, for example, /etc (that must... :-))
with open(CONFIGFILE, 'w') as f:
cfg.write(f)
os.chmod(CONFIGFILE, 0o0600) # Ensure only readable by root
+
def useOldJoinSystem() -> bool:
return False
+
def invokeScriptOnLogin() -> str:
return ''
diff --git a/actor/src/udsactor/linux/xss.py b/actor/src/udsactor/linux/xss.py
index 9b97d8d2f..aba0f08c8 100644
--- a/actor/src/udsactor/linux/xss.py
+++ b/actor/src/udsactor/linux/xss.py
@@ -31,7 +31,7 @@
# pylint: disable=invalid-name
import ctypes
import ctypes.util
-import subprocess
+import subprocess # nosec
xlib = None
xss = None
@@ -39,17 +39,22 @@ display = None
xssInfo = None
initialized = False
+
class XScreenSaverInfo(ctypes.Structure): # pylint: disable=too-few-public-methods
- _fields_ = [('window', ctypes.c_long),
- ('state', ctypes.c_int),
- ('kind', ctypes.c_int),
- ('til_or_since', ctypes.c_ulong),
- ('idle', ctypes.c_ulong),
- ('eventMask', ctypes.c_ulong)]
+ _fields_ = [
+ ('window', ctypes.c_long),
+ ('state', ctypes.c_int),
+ ('kind', ctypes.c_int),
+ ('til_or_since', ctypes.c_ulong),
+ ('idle', ctypes.c_ulong),
+ ('eventMask', ctypes.c_ulong),
+ ]
+
class c_ptr(ctypes.c_void_p):
pass
+
def _ensureInitialized():
global xlib, xss, xssInfo, display, initialized # pylint: disable=global-statement
@@ -73,13 +78,15 @@ def _ensureInitialized():
xss.XScreenSaverQueryExtension.argtypes = [
ctypes.c_void_p,
ctypes.POINTER(ctypes.c_int),
- ctypes.POINTER(ctypes.c_int)
+ ctypes.POINTER(ctypes.c_int),
]
- xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure
+ xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(
+ XScreenSaverInfo
+ ) # Result in a XScreenSaverInfo structure
xss.XScreenSaverQueryInfo.argtypes = [
ctypes.c_void_p,
ctypes.c_void_p,
- ctypes.POINTER(XScreenSaverInfo)
+ ctypes.POINTER(XScreenSaverInfo),
]
xlib.XOpenDisplay.argtypes = [ctypes.c_char_p]
xlib.XOpenDisplay.restype = c_ptr
@@ -95,7 +102,9 @@ def _ensureInitialized():
event_base = ctypes.c_int()
error_base = ctypes.c_int()
- available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base))
+ available = xss.XScreenSaverQueryExtension(
+ display, ctypes.byref(event_base), ctypes.byref(error_base)
+ )
if available != 1:
raise Exception('ScreenSaver not available')
@@ -107,9 +116,11 @@ def _ensureInitialized():
def initIdleDuration(atLeastSeconds: int) -> None:
_ensureInitialized()
if atLeastSeconds:
- subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)])
+ subprocess.call( # nosec, controlled params
+ ['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)]
+ )
# And now reset it
- subprocess.call(['/usr/bin/xset', 's', 'reset'])
+ subprocess.call(['/usr/bin/xset', 's', 'reset']) # nosec: fixed command
def getIdleDuration() -> float:
@@ -122,7 +133,11 @@ def getIdleDuration() -> float:
xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), xssInfo)
# States: 0 = off, 1 = On, 2 = Cycle, 3 = Disabled, ...?
- if xssInfo.contents.state == 1: # state = 1 means "active", so idle is not a valid state
- return 3600 * 100 * 1000 # If screen saver is active, return a high enough value
+ if (
+ xssInfo.contents.state == 1
+ ): # state = 1 means "active", so idle is not a valid state
+ return (
+ 3600 * 100 * 1000
+ ) # If screen saver is active, return a high enough value
return xssInfo.contents.idle / 1000.0
diff --git a/actor/src/udsactor/log.py b/actor/src/udsactor/log.py
index 8073b2b81..4edc5fd41 100644
--- a/actor/src/udsactor/log.py
+++ b/actor/src/udsactor/log.py
@@ -35,6 +35,8 @@ import typing
if sys.platform == 'win32':
from .windows.log import LocalLogger
+elif sys.platform == 'darwin':
+ from .macos.log import LocalLogger
else:
from .linux.log import LocalLogger
@@ -55,7 +57,7 @@ class Logger:
self.logLevel = INFO
self.localLogger = LocalLogger()
self.remoteLogger = None
- self.own_token = ''
+ self.own_token = '' # nosec: This is no password at all
def setLevel(self, level: typing.Union[str, int]) -> None:
'''
diff --git a/actor/src/udsactor/macos/__init__.py b/actor/src/udsactor/macos/__init__.py
new file mode 100644
index 000000000..f29bc9971
--- /dev/null
+++ b/actor/src/udsactor/macos/__init__.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022 Virtual Cable S.L.U.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * 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.U. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# 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
+'''
diff --git a/actor/src/udsactor/macos/log.py b/actor/src/udsactor/macos/log.py
new file mode 100644
index 000000000..2a7ecaedc
--- /dev/null
+++ b/actor/src/udsactor/macos/log.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2014-2022 Virtual Cable S.L.U.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * 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.U. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# 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
+'''
+# pylint: disable=invalid-name
+import os
+import tempfile
+import logging
+import typing
+
+# Basically, same logger as in linux,
+class LocalLogger:
+ linux = False
+ windows = False
+ serviceLogger = False
+
+ 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
+ for logDir in ('/var/log', os.path.expanduser('~'), tempfile.gettempdir()):
+ try:
+ fname = os.path.join(logDir, 'udsactor.log')
+ logging.basicConfig(
+ filename=fname,
+ filemode='a',
+ format='%(levelname)s %(asctime)s %(message)s',
+ level=logging.DEBUG
+ )
+ self.logger = logging.getLogger('udsactor')
+ os.chmod(fname, 0o0600)
+ return
+ except Exception: # nosec: B110: we don't care about exceptions here
+ # ignore and try next one
+ pass
+
+ # Logger can't be set
+ self.logger = None
+
+ def log(self, level: int, message: str) -> None:
+ # Debug messages are logged to a file
+ # our loglevels are 0 (other), 10000 (debug), ....
+ # logging levels are 10 (debug), 20 (info)
+ # OTHER = logging.NOTSET
+ if self.logger:
+ self.logger.log(int(level / 1000), message)
diff --git a/actor/src/udsactor/macos/operations.py b/actor/src/udsactor/macos/operations.py
new file mode 100644
index 000000000..a6fc568b5
--- /dev/null
+++ b/actor/src/udsactor/macos/operations.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2014-2019 Virtual Cable S.L.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * 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
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# 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
+'''
+
+# Note. most methods are not implemented, as they are not needed for this platform (macos)
+# that only supports unmanaged machines
+
+import socket
+import os
+import re
+import subprocess # nosec
+import typing
+
+import psutil
+
+from .. import types
+
+MACVER_RE = re.compile(r"ProductVersion\s*(.*)", re.MULTILINE)
+MACVER_FILE = '/System/Library/CoreServices/SystemVersion.plist'
+
+def checkPermissions() -> bool:
+ return os.getuid() == 0
+
+def getComputerName() -> str:
+ '''
+ Returns computer name, with no domain
+ '''
+ return socket.gethostname().split('.')[0]
+
+def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]:
+ ifdata: typing.List['psutil._common.snicaddr']
+ for ifname, ifdata in psutil.net_if_addrs().items():
+ name, ip, mac = '', '', ''
+ # Get IP address, interface name and MAC address whenever possible
+ for row in ifdata:
+ if row.family == socket.AF_INET:
+ ip = row.address
+ name = ifname
+ elif row.family == socket.AF_LINK:
+ mac = row.address
+
+ # if all data is available, stop iterating
+ if ip and name and mac:
+ if mac != '00:00:00:00:00:00' and mac and ip and ip.startswith('169.254') is False: # Skips local interfaces & interfaces with no dhcp IPs
+ yield types.InterfaceInfoType(name=name, ip=ip, mac=mac)
+ break
+
+
+def getDomainName() -> str:
+ return ''
+
+def getMacOs() -> str:
+ try:
+ with open(MACVER_FILE, 'r') as f:
+ data = f.read()
+ m = MACVER_RE.search(data)
+ if m:
+ return m.group(1)
+ except Exception: # nosec: B110: ignore exception because we are not interested in it
+ pass
+
+ return 'unknown'
+
+def reboot(flags: int = 0):
+ '''
+ Simple reboot using os command
+ '''
+ subprocess.call(['/sbin/shutdown', '-r', 'now']) # nosec: Command line is fixed
+
+
+def loggoff() -> None:
+ '''
+ Right now restarts the machine...
+ '''
+ subprocess.run("/bin/launchctl bootout gui/$(id -u $USER)", shell=True) # nosec: Command line is fixed
+ # Ignores output, as it may fail if user is not logged in
+
+
+def renameComputer(newName: str) -> bool:
+ '''
+ Changes the computer name
+ Returns True if reboot needed
+ '''
+ return False
+
+
+def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False):
+ pass
+
+
+def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
+ pass
+
+
+def initIdleDuration(atLeastSeconds: int) -> None:
+ pass
+
+
+def getIdleDuration() -> float:
+ return 0
+
+
+def getCurrentUser() -> str:
+ '''
+ Returns current logged in user
+ '''
+ return os.environ['USER']
+
+def getSessionType() -> str:
+ '''
+ Known values:
+ * Unknown -> No XDG_SESSION_TYPE environment variable
+ * xrdp --> xrdp session
+ * other types
+ '''
+ return 'macos'
+
+def forceTimeSync() -> None:
+ return
diff --git a/actor/src/udsactor/macos/runner.py b/actor/src/udsactor/macos/runner.py
new file mode 100644
index 000000000..e201f4792
--- /dev/null
+++ b/actor/src/udsactor/macos/runner.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2014-2020 Virtual Cable S.L.U.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * 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
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# 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
+'''
+import sys
+
+from .. import rest
+from .. import platform
+from ..log import logger
+from .service import UDSActorSvc
+
+def usage():
+ sys.stderr.write('usage: udsactor start|login "username"|logout "username"\n')
+ sys.exit(2)
+
+def run() -> None:
+ logger.setLevel(20000)
+
+ if len(sys.argv) == 3 and sys.argv[1] in ('login', 'logout'):
+ logger.debug('Running client udsactor')
+ try:
+ client: rest.UDSClientApi = rest.UDSClientApi()
+ if sys.argv[1] == 'login':
+ r = client.login(sys.argv[2], platform.operations.getSessionType())
+ print('{},{},{},{}\n'.format(r.ip, r.hostname, r.max_idle, r.dead_line or ''))
+ elif sys.argv[1] == 'logout':
+ client.logout(sys.argv[2])
+ except Exception as e:
+ logger.exception()
+ logger.error('Got exception while processing command: %s', e)
+ sys.exit(0)
+ elif len(sys.argv) != 2:
+ usage()
+
+ daemonSvr = UDSActorSvc()
+ if len(sys.argv) == 2:
+ # Daemon mode...
+ if sys.argv[1] in ('start', 'start-foreground'):
+ daemonSvr.run() # execute in foreground
+ else:
+ usage()
+ sys.exit(0)
+ else:
+ usage()
diff --git a/actor/src/udsactor/macos/service.py b/actor/src/udsactor/macos/service.py
new file mode 100644
index 000000000..a8a816e1f
--- /dev/null
+++ b/actor/src/udsactor/macos/service.py
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022 Virtual Cable S.L.U.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * 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.U. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# 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
+'''
+import typing
+import signal
+
+from ..log import logger
+from ..service import CommonService
+
+
+class UDSActorSvc(CommonService):
+ def __init__(self) -> None:
+ CommonService.__init__(self)
+
+ # Captures signals so we can stop gracefully
+ signal.signal(signal.SIGINT, self.markForExit)
+ signal.signal(signal.SIGTERM, self.markForExit)
+
+ def markForExit(self, signum, frame) -> None: # pylint: disable=unused-argument
+ self._isAlive = False
+
+ def joinDomain( # pylint: disable=unused-argument, too-many-arguments
+ self,
+ name: str,
+ domain: str,
+ ou: str,
+ account: str,
+ password: str
+ ) -> None:
+ pass # Not implemented for unmanaged machines
+
+ def rename(
+ self,
+ name: str,
+ userName: typing.Optional[str] = None,
+ oldPassword: typing.Optional[str] = None,
+ newPassword: typing.Optional[str] = None,
+ ) -> None:
+ pass # Not implemented for unmanaged machines
+
+ def run(self) -> None:
+ logger.debug('Running Daemon: {}'.format(self._isAlive))
+
+ # Linux daemon will continue running unless something is requested to
+ # Unmanaged services does not initializes "on start", but rather when user logs in (because userservice does not exists "as such" before that)
+ if self.isManaged(): # Currently, managed is not implemented for UDS on M
+ logger.error('Managed machines not supported on MacOS')
+ # 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 # 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
+
+ # Start listening for petitions
+ self.startHttpServer()
+
+ # *********************
+ # * Main Service loop *
+ # *********************
+ # Counter used to check ip changes only once every 10 seconds, for
+ # example
+ counter = 0
+ while self._isAlive:
+ counter += 1
+ try:
+ if counter % 5 == 0:
+ self.loop()
+ except Exception as e:
+ logger.error('Got exception on main loop: %s', e)
+ # In milliseconds, will break
+ self.doWait(1000)
+
+ self.finish()
diff --git a/actor/src/udsactor/macos/store.py b/actor/src/udsactor/macos/store.py
new file mode 100644
index 000000000..e8290d6be
--- /dev/null
+++ b/actor/src/udsactor/macos/store.py
@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2014-2019 Virtual Cable S.L.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * 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
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# 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
+'''
+import os
+import configparser
+import base64
+import pickle # nosec
+
+from .. import types
+
+CONFIGFILE = '/etc/udsactor/udsactor.cfg'
+
+def readConfig() -> types.ActorConfigurationType:
+ try:
+ cfg = configparser.ConfigParser()
+ cfg.read(CONFIGFILE)
+ uds: configparser.SectionProxy = cfg['uds']
+ # Extract data:
+ base64Config = uds.get('config', None)
+ config = pickle.loads(base64.b64decode(base64Config.encode())) if base64Config else None # nosec: Read from root controled file, secure
+
+ base64Data = uds.get('data', None)
+ data = pickle.loads(base64.b64decode(base64Data.encode())) if base64Data else None # nosec: Read from root controled file, secure
+
+ return types.ActorConfigurationType(
+ actorType=uds.get('type', types.MANAGED),
+ host=uds.get('host', ''),
+ validateCertificate=uds.getboolean('validate', fallback=False),
+ master_token=uds.get('master_token', None),
+ own_token=uds.get('own_token', None),
+ restrict_net=uds.get('restrict_net', None),
+ pre_command=uds.get('pre_command', None),
+ runonce_command=uds.get('runonce_command', None),
+ post_command=uds.get('post_command', None),
+ log_level=int(uds.get('log_level', '2')),
+ config=config,
+ data=data
+ )
+ except Exception:
+ return types.ActorConfigurationType('', False)
+
+def writeConfig(config: types.ActorConfigurationType) -> None:
+ cfg = configparser.ConfigParser()
+ cfg.add_section('uds')
+ uds: configparser.SectionProxy = cfg['uds']
+ uds['host'] = config.host
+ uds['validate'] = 'yes' if config.validateCertificate else 'no'
+ def writeIfValue(val, name):
+ if val:
+ uds[name] = val
+ writeIfValue(config.actorType, 'type')
+ writeIfValue(config.master_token, 'master_token')
+ writeIfValue(config.own_token, 'own_token')
+ writeIfValue(config.restrict_net, 'restrict_net')
+ writeIfValue(config.pre_command, 'pre_command')
+ writeIfValue(config.post_command, 'post_command')
+ writeIfValue(config.runonce_command, 'runonce_command')
+ uds['log_level'] = str(config.log_level)
+ if config.config: # Special case, encoded & dumped
+ uds['config'] = base64.b64encode(pickle.dumps(config.config)).decode()
+
+ if config.data: # Special case, encoded & dumped
+ uds['data'] = base64.b64encode(pickle.dumps(config.data)).decode()
+
+ # Ensures exists destination folder
+ dirname = os.path.dirname(CONFIGFILE)
+ if not os.path.exists(dirname):
+ os.mkdir(dirname, mode=0o700) # Will create only if route to path already exists, for example, /etc (that must... :-))
+
+ with open(CONFIGFILE, 'w') as f:
+ cfg.write(f)
+
+ os.chmod(CONFIGFILE, 0o0600) # Ensure only readable by root
+
+def useOldJoinSystem() -> bool:
+ return False
+
+def invokeScriptOnLogin() -> str:
+ return ''
diff --git a/actor/src/udsactor/platform.py b/actor/src/udsactor/platform.py
index ebd3f5a71..2c8591bf8 100644
--- a/actor/src/udsactor/platform.py
+++ b/actor/src/udsactor/platform.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2014 Virtual Cable S.L.
+# Copyright (c) 2014-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.
#
@@ -32,6 +32,8 @@ import sys
name = sys.platform
if sys.platform == 'win32':
- from .windows import operations, store # pylint: disable=unused-import
+ from .windows import operations, store
+elif sys.platform == 'darwin':
+ from .macos import operations, store
else:
- from .linux import operations, store # pylint: disable=unused-import
+ from .linux import operations, store
diff --git a/actor/src/udsactor/rest.py b/actor/src/udsactor/rest.py
index 04abdb5f0..37e500764 100644
--- a/actor/src/udsactor/rest.py
+++ b/actor/src/udsactor/rest.py
@@ -103,7 +103,7 @@ class UDSApi: # pylint: disable=too-few-public-methods
logging.getLogger('urllib3').setLevel(logging.ERROR)
try:
warnings.simplefilter('ignore') # Disables all warnings
- except Exception:
+ except Exception: # nosec: not interested in exceptions
pass
@property
@@ -178,7 +178,7 @@ class UDSServerApi(UDSApi):
priority=v['priority'],
isCustom=v['isCustom'],
)
- except Exception:
+ except Exception: # nosec: not interested in exceptions
pass
def register( # pylint: disable=too-many-arguments, too-many-locals
@@ -329,7 +329,7 @@ class UDSServerApi(UDSApi):
) -> types.LoginResultInfoType:
if not token:
return types.LoginResultInfoType(
- ip='0.0.0.0', hostname=UNKNOWN, dead_line=None, max_idle=None
+ ip='0.0.0.0', hostname=UNKNOWN, dead_line=None, max_idle=None # nosec: this is not a binding
)
payload = {
'type': actor_type or types.MANAGED,
diff --git a/actor/src/udsactor/service.py b/actor/src/udsactor/service.py
index 71f884e21..11e93276b 100644
--- a/actor/src/udsactor/service.py
+++ b/actor/src/udsactor/service.py
@@ -101,7 +101,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
# 0 = OTHER, 10000 = DEBUG, 20000 = WARN, 30000 = INFO, 40000 = ERROR, 50000 = FATAL
# So this comes:
logger.setLevel([DEBUG, INFO, ERROR, FATAL][self._cfg.log_level])
- # If windows, enable service logger
+ # If windows, enable service logger FOR SERVICE only
logger.enableServiceLogger()
socket.setdefaulttimeout(20)
@@ -538,9 +538,9 @@ class CommonService: # pylint: disable=too-many-instance-attributes
if not self.isManaged():
self.uninitialize()
- # ****************************************
- # Methods that CAN BE overriden by actors
- # ****************************************
+ # ******************************************************
+ # Methods that CAN BE overriden by specific OS Actor
+ # ******************************************************
def doWait(self, miliseconds: int) -> None:
'''
Invoked to wait a bit
diff --git a/actor/src/udsactor/tools.py b/actor/src/udsactor/tools.py
index a39a39e75..18502d455 100644
--- a/actor/src/udsactor/tools.py
+++ b/actor/src/udsactor/tools.py
@@ -47,7 +47,7 @@ class ScriptExecutorThread(threading.Thread):
try:
logger.debug('Executing script: {}'.format(self.script))
- exec(self.script, globals(), None) # pylint: disable=exec-used
+ exec(self.script, globals(), None) # nosec: exec is fine, it's a "trusted" script
except Exception as e:
logger.error('Error executing script: {}'.format(e))
logger.exception()
diff --git a/actor/src/udsactor/windows/__init__.py b/actor/src/udsactor/windows/__init__.py
index 4db3bd57b..2a7d5e6c7 100644
--- a/actor/src/udsactor/windows/__init__.py
+++ b/actor/src/udsactor/windows/__init__.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2014-2019 Virtual Cable S.L.
+# Copyright (c) 2014-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.
#
diff --git a/actor/src/udsactor/windows/log.py b/actor/src/udsactor/windows/log.py
index 263fb985d..eb4db6690 100644
--- a/actor/src/udsactor/windows/log.py
+++ b/actor/src/udsactor/windows/log.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2014 Virtual Cable S.L.
+# Copyright (c) 2014-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.
#
diff --git a/actor/src/udsactor/windows/operations.py b/actor/src/udsactor/windows/operations.py
index 3b685d25d..9067ee0ae 100644
--- a/actor/src/udsactor/windows/operations.py
+++ b/actor/src/udsactor/windows/operations.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2014-2019 Virtual Cable S.L.
+# Copyright (c) 2014-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.
#
diff --git a/actor/src/udsactor/windows/runner.py b/actor/src/udsactor/windows/runner.py
index 6973b7842..a2aa85126 100644
--- a/actor/src/udsactor/windows/runner.py
+++ b/actor/src/udsactor/windows/runner.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (c) 2019 Virtual Cable S.L.
+# Copyright (c) 2019-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.
#