forked from shaba/openuds
Started MacOS Unmanaged Support
This commit is contained in:
parent
552ba3796b
commit
ff25b4945a
33
actor/macos/net.virtualcable.udsactor.server.plist
Normal file
33
actor/macos/net.virtualcable.udsactor.server.plist
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>net.virtualcable.udsactor.server</string>
|
||||||
|
|
||||||
|
<key>KeepAlive</key>
|
||||||
|
<dict>
|
||||||
|
<key>SuccessfulExit</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>/Applications/UDSActor.app/Contents/MacOS/udsactor</string>
|
||||||
|
<string>start</string>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
|
||||||
|
<key>StandardErrorPath</key>
|
||||||
|
<string>/var/log/udsactor.log</string>
|
||||||
|
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>/var/log/nxserver.log</string>
|
||||||
|
|
||||||
|
<key>WorkingDirectory</key>
|
||||||
|
<string>/Applications/UDSActor.app/Contents/Resources/</string>
|
||||||
|
|
||||||
|
</dict>
|
||||||
|
</plist>
|
1
actor/macos/notes.txt
Normal file
1
actor/macos/notes.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
service file (net.virtualcable.udsactor.server.plist) goes in /Library/LaunchDaemons
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2020 Virtual Cable S.L.
|
# Copyright (c) 2020-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,
|
||||||
@ -12,7 +12,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.
|
||||||
#
|
#
|
||||||
@ -32,7 +32,7 @@
|
|||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import pickle
|
import pickle # nosec: B403
|
||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ class UDSConfigDialog(QDialog):
|
|||||||
self,
|
self,
|
||||||
'UDS Test',
|
'UDS Test',
|
||||||
'Service token seems to be invalid . Please, check token validity.',
|
'Service token seems to be invalid . Please, check token validity.',
|
||||||
QMessageBox.Ok,
|
QMessageBox.Ok, # type: ignore
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
@ -111,14 +111,14 @@ class UDSConfigDialog(QDialog):
|
|||||||
'Configuration for {} seems to be correct.'.format(
|
'Configuration for {} seems to be correct.'.format(
|
||||||
self._config.host
|
self._config.host
|
||||||
),
|
),
|
||||||
QMessageBox.Ok,
|
QMessageBox.Ok, # type: ignore
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
self,
|
self,
|
||||||
'UDS Test',
|
'UDS Test',
|
||||||
'Configured host {} seems to be inaccesible.'.format(self._config.host),
|
'Configured host {} seems to be inaccesible.'.format(self._config.host),
|
||||||
QMessageBox.Ok,
|
QMessageBox.Ok, # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
def saveConfig(self) -> None:
|
def saveConfig(self) -> None:
|
||||||
@ -134,7 +134,7 @@ class UDSConfigDialog(QDialog):
|
|||||||
self,
|
self,
|
||||||
'Invalid subnet',
|
'Invalid subnet',
|
||||||
'Invalid subnet {}. Please, check it.'.format(restrictNet),
|
'Invalid subnet {}. Please, check it.'.format(restrictNet),
|
||||||
QMessageBox.Ok,
|
QMessageBox.Ok, # type: ignore
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -153,12 +153,15 @@ class UDSConfigDialog(QDialog):
|
|||||||
self.ui.testButton.setEnabled(True)
|
self.ui.testButton.setEnabled(True)
|
||||||
# Informs the user
|
# Informs the user
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
self, 'UDS Configuration', 'Configuration saved.', QMessageBox.Ok
|
self,
|
||||||
|
'UDS Configuration',
|
||||||
|
'Configuration saved.',
|
||||||
|
QMessageBox.Ok, # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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:
|
if 'linux' in sys.platform:
|
||||||
os.environ['QT_X11_NO_MITSHM'] = '1'
|
os.environ['QT_X11_NO_MITSHM'] = '1'
|
||||||
|
|
||||||
@ -171,16 +174,18 @@ if __name__ == "__main__":
|
|||||||
if len(sys.argv) > 2:
|
if len(sys.argv) > 2:
|
||||||
if sys.argv[1] == 'export':
|
if sys.argv[1] == 'export':
|
||||||
try:
|
try:
|
||||||
with open(sys.argv[2], 'wb') as f:
|
with open(sys.argv[2], 'wb') as export_:
|
||||||
pickle.dump(udsactor.platform.store.readConfig(), f, protocol=3)
|
pickle.dump(
|
||||||
|
udsactor.platform.store.readConfig(), export_, protocol=3
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Error exporting configuration file: {}'.format(e))
|
print('Error exporting configuration file: {}'.format(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
if sys.argv[1] == 'import':
|
elif sys.argv[1] == 'import':
|
||||||
try:
|
try:
|
||||||
with open(sys.argv[2], 'rb') as f:
|
with open(sys.argv[2], 'rb') as import_:
|
||||||
config = pickle.load(f)
|
config = pickle.load(import_) # nosec: B301: the file is provided by user, so it's not a security issue
|
||||||
udsactor.platform.store.writeConfig(config)
|
udsactor.platform.store.writeConfig(config)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Error importing configuration file: {}'.format(e))
|
print('Error importing configuration file: {}'.format(e))
|
||||||
|
@ -235,7 +235,7 @@ class UDSActorClient(threading.Thread): # pylint: disable=too-many-instance-att
|
|||||||
pixmap: 'QPixmap' = self._qApp.primaryScreen().grabWindow(0) # type: ignore
|
pixmap: 'QPixmap' = self._qApp.primaryScreen().grabWindow(0) # type: ignore
|
||||||
ba = QByteArray()
|
ba = QByteArray()
|
||||||
buffer = QBuffer(ba)
|
buffer = QBuffer(ba)
|
||||||
buffer.open(QIODevice.WriteOnly)
|
buffer.open(QIODevice.WriteOnly) # type: ignore
|
||||||
pixmap.save(buffer, 'PNG')
|
pixmap.save(buffer, 'PNG')
|
||||||
buffer.close()
|
buffer.close()
|
||||||
scrBase64 = bytes(ba.toBase64()).decode() # type: ignore # there are problems with Pylance and connects on PyQt5... :)
|
scrBase64 = bytes(ba.toBase64()).decode() # type: ignore # there are problems with Pylance and connects on PyQt5... :)
|
||||||
|
@ -101,7 +101,7 @@ class Daemon:
|
|||||||
def removePidFile(self) -> None:
|
def removePidFile(self) -> None:
|
||||||
try:
|
try:
|
||||||
os.remove(self.pidfile)
|
os.remove(self.pidfile)
|
||||||
except Exception:
|
except Exception: # nosec: Not interested in exception
|
||||||
# Not found/not permissions or whatever, ignore it
|
# Not found/not permissions or whatever, ignore it
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
# Copyright (c) 2014-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.
|
||||||
#
|
#
|
||||||
@ -35,8 +35,8 @@ import logging
|
|||||||
import typing
|
import typing
|
||||||
|
|
||||||
class LocalLogger: # pylint: disable=too-few-public-methods
|
class LocalLogger: # pylint: disable=too-few-public-methods
|
||||||
linux = False
|
linux = True
|
||||||
windows = True
|
windows = False
|
||||||
serviceLogger = False
|
serviceLogger = False
|
||||||
|
|
||||||
logger: typing.Optional[logging.Logger]
|
logger: typing.Optional[logging.Logger]
|
||||||
@ -59,7 +59,8 @@ class LocalLogger: # pylint: disable=too-few-public-methods
|
|||||||
self.logger = logging.getLogger('udsactor')
|
self.logger = logging.getLogger('udsactor')
|
||||||
os.chmod(fname, 0o0600)
|
os.chmod(fname, 0o0600)
|
||||||
return
|
return
|
||||||
except Exception:
|
except Exception: # nosec: B110: we don't care about exceptions here
|
||||||
|
# Ignore and try next
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Logger can't be set
|
# Logger can't be set
|
||||||
|
@ -34,7 +34,7 @@ import platform
|
|||||||
import socket
|
import socket
|
||||||
import fcntl # Only available on Linux. Expect complains if edited from windows
|
import fcntl # Only available on Linux. Expect complains if edited from windows
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess # nosec
|
||||||
import struct
|
import struct
|
||||||
import array
|
import array
|
||||||
import typing
|
import typing
|
||||||
@ -53,7 +53,9 @@ def _getMacAddr(ifname: str) -> typing.Optional[str]:
|
|||||||
ifnameBytes = ifname.encode('utf-8')
|
ifnameBytes = ifname.encode('utf-8')
|
||||||
try:
|
try:
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
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()
|
return str(''.join(['%02x:' % char for char in info[18:24]])[:-1]).upper()
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
@ -67,11 +69,15 @@ def _getIpAddr(ifname: str) -> typing.Optional[str]:
|
|||||||
ifnameBytes = ifname.encode('utf-8')
|
ifnameBytes = ifname.encode('utf-8')
|
||||||
try:
|
try:
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
return str(socket.inet_ntoa(fcntl.ioctl(
|
return str(
|
||||||
|
socket.inet_ntoa(
|
||||||
|
fcntl.ioctl(
|
||||||
s.fileno(),
|
s.fileno(),
|
||||||
0x8915, # SIOCGIFADDR
|
0x8915, # SIOCGIFADDR
|
||||||
struct.pack(str('256s'), ifnameBytes[:15])
|
struct.pack(str('256s'), ifnameBytes[:15]),
|
||||||
)[20:24]))
|
)[20:24]
|
||||||
|
)
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -91,22 +97,32 @@ def _getInterfaces() -> typing.List[str]:
|
|||||||
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
names = array.array(str('B'), b'\0' * space)
|
names = array.array(str('B'), b'\0' * space)
|
||||||
outbytes = struct.unpack('iL', fcntl.ioctl(
|
outbytes = struct.unpack(
|
||||||
|
'iL',
|
||||||
|
fcntl.ioctl(
|
||||||
s.fileno(),
|
s.fileno(),
|
||||||
0x8912, # SIOCGIFCONF
|
0x8912, # SIOCGIFCONF
|
||||||
struct.pack('iL', space, names.buffer_info()[0])
|
struct.pack('iL', space, names.buffer_info()[0]),
|
||||||
))[0]
|
),
|
||||||
|
)[0]
|
||||||
namestr = names.tobytes()
|
namestr = names.tobytes()
|
||||||
# return namestr, outbytes
|
# 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)
|
ip, mac = _getIpAddr(ifname), _getMacAddr(ifname)
|
||||||
return (ip, mac)
|
return (ip, mac)
|
||||||
|
|
||||||
|
|
||||||
def checkPermissions() -> bool:
|
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:
|
def getComputerName() -> str:
|
||||||
'''
|
'''
|
||||||
@ -114,15 +130,23 @@ def getComputerName() -> str:
|
|||||||
'''
|
'''
|
||||||
return socket.gethostname().split('.')[0]
|
return socket.gethostname().split('.')[0]
|
||||||
|
|
||||||
|
|
||||||
def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]:
|
def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]:
|
||||||
for ifname in _getInterfaces():
|
for ifname in _getInterfaces():
|
||||||
ip, mac = _getIpAndMac(ifname)
|
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)
|
yield types.InterfaceInfoType(name=ifname, mac=mac, ip=ip)
|
||||||
|
|
||||||
|
|
||||||
def getDomainName() -> str:
|
def getDomainName() -> str:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
def getLinuxOs() -> str:
|
def getLinuxOs() -> str:
|
||||||
try:
|
try:
|
||||||
with open('/etc/os-release', 'r') as f:
|
with open('/etc/os-release', 'r') as f:
|
||||||
@ -133,18 +157,19 @@ def getLinuxOs() -> str:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return 'unknown'
|
return 'unknown'
|
||||||
|
|
||||||
|
|
||||||
def reboot(flags: int = 0):
|
def reboot(flags: int = 0):
|
||||||
'''
|
'''
|
||||||
Simple reboot using os command
|
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:
|
def loggoff() -> None:
|
||||||
'''
|
'''
|
||||||
Right now restarts the machine...
|
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(['/sbin/shutdown', 'now', '-r'])
|
||||||
# subprocess.call(['/usr/bin/systemctl', 'reboot', '-i'])
|
# 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
|
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
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -166,7 +193,11 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
|
|||||||
'''
|
'''
|
||||||
Simple password change for user using command line
|
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:
|
def initIdleDuration(atLeastSeconds: int) -> None:
|
||||||
@ -183,6 +214,7 @@ def getCurrentUser() -> str:
|
|||||||
'''
|
'''
|
||||||
return os.environ['USER']
|
return os.environ['USER']
|
||||||
|
|
||||||
|
|
||||||
def getSessionType() -> str:
|
def getSessionType() -> str:
|
||||||
'''
|
'''
|
||||||
Known values:
|
Known values:
|
||||||
@ -190,7 +222,12 @@ def getSessionType() -> str:
|
|||||||
* xrdp --> xrdp session
|
* xrdp --> xrdp session
|
||||||
* other types
|
* 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:
|
def forceTimeSync() -> None:
|
||||||
return
|
return
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
# Copyright (c) 2014-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.
|
||||||
#
|
#
|
||||||
@ -28,7 +28,7 @@
|
|||||||
'''
|
'''
|
||||||
@author: Alexey Shabalin, shaba at altlinux dot org
|
@author: Alexey Shabalin, shaba at altlinux dot org
|
||||||
'''
|
'''
|
||||||
import os
|
import subprocess # nosec
|
||||||
|
|
||||||
from .common import renamers
|
from .common import renamers
|
||||||
from ...log import logger
|
from ...log import logger
|
||||||
@ -46,8 +46,8 @@ def rename(newName: str) -> bool:
|
|||||||
hostname.write(newName)
|
hostname.write(newName)
|
||||||
|
|
||||||
# Force system new name
|
# Force system new name
|
||||||
os.system('/bin/hostname {}'.format(newName))
|
subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: subprocess
|
||||||
os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
|
subprocess.run(['/bin/hostname', newName]) # nosec: subprocess
|
||||||
|
|
||||||
# add name to "hosts"
|
# add name to "hosts"
|
||||||
with open('/etc/hosts', 'r') as hosts:
|
with open('/etc/hosts', 'r') as hosts:
|
||||||
|
@ -29,9 +29,6 @@
|
|||||||
'''
|
'''
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
'''
|
'''
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import pkgutil
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from .. import operations
|
from .. import operations
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
'''
|
'''
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
'''
|
'''
|
||||||
import os
|
import subprocess # nosec
|
||||||
|
|
||||||
from .common import renamers
|
from .common import renamers
|
||||||
from ...log import logger
|
from ...log import logger
|
||||||
@ -45,8 +45,8 @@ def rename(newName: str) -> bool:
|
|||||||
hostname.write(newName)
|
hostname.write(newName)
|
||||||
|
|
||||||
# Force system new name
|
# Force system new name
|
||||||
os.system('/bin/hostname {}'.format(newName))
|
subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
|
||||||
os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
|
subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
|
||||||
|
|
||||||
# add name to "hosts"
|
# add name to "hosts"
|
||||||
with open('/etc/hosts', 'r') as hosts:
|
with open('/etc/hosts', 'r') as hosts:
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
'''
|
'''
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
'''
|
'''
|
||||||
import os
|
import subprocess # nosec
|
||||||
|
|
||||||
from .common import renamers
|
from .common import renamers
|
||||||
from ...log import logger
|
from ...log import logger
|
||||||
@ -46,8 +46,8 @@ def rename(newName: str) -> bool:
|
|||||||
hostname.write(newName)
|
hostname.write(newName)
|
||||||
|
|
||||||
# Force system new name
|
# Force system new name
|
||||||
os.system('/bin/hostname {}'.format(newName))
|
subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
|
||||||
os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
|
subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
|
||||||
|
|
||||||
# add name to "hosts"
|
# add name to "hosts"
|
||||||
with open('/etc/hosts', 'r') as hosts:
|
with open('/etc/hosts', 'r') as hosts:
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
'''
|
'''
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
'''
|
'''
|
||||||
import os
|
import subprocess # nosec
|
||||||
|
|
||||||
from .common import renamers
|
from .common import renamers
|
||||||
from ...log import logger
|
from ...log import logger
|
||||||
@ -46,8 +46,8 @@ def rename(newName: str) -> bool:
|
|||||||
hostname.write(newName)
|
hostname.write(newName)
|
||||||
|
|
||||||
# Force system new name
|
# Force system new name
|
||||||
os.system('/bin/hostname {}'.format(newName))
|
subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
|
||||||
os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
|
subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
|
||||||
|
|
||||||
# add name to "hosts"
|
# add name to "hosts"
|
||||||
with open('/etc/hosts', 'r') as hosts:
|
with open('/etc/hosts', 'r') as hosts:
|
||||||
|
@ -37,7 +37,7 @@ from ..log import logger
|
|||||||
from ..service import CommonService
|
from ..service import CommonService
|
||||||
|
|
||||||
try:
|
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
|
except ImportError: # Platform may not include prctl, so in case it's not available, we let the "name" as is
|
||||||
def set_proctitle(_):
|
def set_proctitle(_):
|
||||||
pass
|
pass
|
||||||
|
@ -32,12 +32,13 @@
|
|||||||
import os
|
import os
|
||||||
import configparser
|
import configparser
|
||||||
import base64
|
import base64
|
||||||
import pickle
|
import pickle # nosec
|
||||||
|
|
||||||
from .. import types
|
from .. import types
|
||||||
|
|
||||||
CONFIGFILE = '/etc/udsactor/udsactor.cfg'
|
CONFIGFILE = '/etc/udsactor/udsactor.cfg'
|
||||||
|
|
||||||
|
|
||||||
def readConfig() -> types.ActorConfigurationType:
|
def readConfig() -> types.ActorConfigurationType:
|
||||||
try:
|
try:
|
||||||
cfg = configparser.ConfigParser()
|
cfg = configparser.ConfigParser()
|
||||||
@ -45,10 +46,22 @@ def readConfig() -> types.ActorConfigurationType:
|
|||||||
uds: configparser.SectionProxy = cfg['uds']
|
uds: configparser.SectionProxy = cfg['uds']
|
||||||
# Extract data:
|
# Extract data:
|
||||||
base64Config = uds.get('config', None)
|
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)
|
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(
|
return types.ActorConfigurationType(
|
||||||
actorType=uds.get('type', types.MANAGED),
|
actorType=uds.get('type', types.MANAGED),
|
||||||
@ -62,20 +75,23 @@ def readConfig() -> types.ActorConfigurationType:
|
|||||||
post_command=uds.get('post_command', None),
|
post_command=uds.get('post_command', None),
|
||||||
log_level=int(uds.get('log_level', '2')),
|
log_level=int(uds.get('log_level', '2')),
|
||||||
config=config,
|
config=config,
|
||||||
data=data
|
data=data,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
return types.ActorConfigurationType('', False)
|
return types.ActorConfigurationType('', False)
|
||||||
|
|
||||||
|
|
||||||
def writeConfig(config: types.ActorConfigurationType) -> None:
|
def writeConfig(config: types.ActorConfigurationType) -> None:
|
||||||
cfg = configparser.ConfigParser()
|
cfg = configparser.ConfigParser()
|
||||||
cfg.add_section('uds')
|
cfg.add_section('uds')
|
||||||
uds: configparser.SectionProxy = cfg['uds']
|
uds: configparser.SectionProxy = cfg['uds']
|
||||||
uds['host'] = config.host
|
uds['host'] = config.host
|
||||||
uds['validate'] = 'yes' if config.validateCertificate else 'no'
|
uds['validate'] = 'yes' if config.validateCertificate else 'no'
|
||||||
|
|
||||||
def writeIfValue(val, name):
|
def writeIfValue(val, name):
|
||||||
if val:
|
if val:
|
||||||
uds[name] = val
|
uds[name] = val
|
||||||
|
|
||||||
writeIfValue(config.actorType, 'type')
|
writeIfValue(config.actorType, 'type')
|
||||||
writeIfValue(config.master_token, 'master_token')
|
writeIfValue(config.master_token, 'master_token')
|
||||||
writeIfValue(config.own_token, 'own_token')
|
writeIfValue(config.own_token, 'own_token')
|
||||||
@ -93,15 +109,19 @@ def writeConfig(config: types.ActorConfigurationType) -> None:
|
|||||||
# Ensures exists destination folder
|
# Ensures exists destination folder
|
||||||
dirname = os.path.dirname(CONFIGFILE)
|
dirname = os.path.dirname(CONFIGFILE)
|
||||||
if not os.path.exists(dirname):
|
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:
|
with open(CONFIGFILE, 'w') as f:
|
||||||
cfg.write(f)
|
cfg.write(f)
|
||||||
|
|
||||||
os.chmod(CONFIGFILE, 0o0600) # Ensure only readable by root
|
os.chmod(CONFIGFILE, 0o0600) # Ensure only readable by root
|
||||||
|
|
||||||
|
|
||||||
def useOldJoinSystem() -> bool:
|
def useOldJoinSystem() -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def invokeScriptOnLogin() -> str:
|
def invokeScriptOnLogin() -> str:
|
||||||
return ''
|
return ''
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
import ctypes
|
import ctypes
|
||||||
import ctypes.util
|
import ctypes.util
|
||||||
import subprocess
|
import subprocess # nosec
|
||||||
|
|
||||||
xlib = None
|
xlib = None
|
||||||
xss = None
|
xss = None
|
||||||
@ -39,17 +39,22 @@ display = None
|
|||||||
xssInfo = None
|
xssInfo = None
|
||||||
initialized = False
|
initialized = False
|
||||||
|
|
||||||
|
|
||||||
class XScreenSaverInfo(ctypes.Structure): # pylint: disable=too-few-public-methods
|
class XScreenSaverInfo(ctypes.Structure): # pylint: disable=too-few-public-methods
|
||||||
_fields_ = [('window', ctypes.c_long),
|
_fields_ = [
|
||||||
|
('window', ctypes.c_long),
|
||||||
('state', ctypes.c_int),
|
('state', ctypes.c_int),
|
||||||
('kind', ctypes.c_int),
|
('kind', ctypes.c_int),
|
||||||
('til_or_since', ctypes.c_ulong),
|
('til_or_since', ctypes.c_ulong),
|
||||||
('idle', ctypes.c_ulong),
|
('idle', ctypes.c_ulong),
|
||||||
('eventMask', ctypes.c_ulong)]
|
('eventMask', ctypes.c_ulong),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class c_ptr(ctypes.c_void_p):
|
class c_ptr(ctypes.c_void_p):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _ensureInitialized():
|
def _ensureInitialized():
|
||||||
global xlib, xss, xssInfo, display, initialized # pylint: disable=global-statement
|
global xlib, xss, xssInfo, display, initialized # pylint: disable=global-statement
|
||||||
|
|
||||||
@ -73,13 +78,15 @@ def _ensureInitialized():
|
|||||||
xss.XScreenSaverQueryExtension.argtypes = [
|
xss.XScreenSaverQueryExtension.argtypes = [
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
ctypes.POINTER(ctypes.c_int),
|
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 = [
|
xss.XScreenSaverQueryInfo.argtypes = [
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
ctypes.c_void_p,
|
ctypes.c_void_p,
|
||||||
ctypes.POINTER(XScreenSaverInfo)
|
ctypes.POINTER(XScreenSaverInfo),
|
||||||
]
|
]
|
||||||
xlib.XOpenDisplay.argtypes = [ctypes.c_char_p]
|
xlib.XOpenDisplay.argtypes = [ctypes.c_char_p]
|
||||||
xlib.XOpenDisplay.restype = c_ptr
|
xlib.XOpenDisplay.restype = c_ptr
|
||||||
@ -95,7 +102,9 @@ def _ensureInitialized():
|
|||||||
event_base = ctypes.c_int()
|
event_base = ctypes.c_int()
|
||||||
error_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:
|
if available != 1:
|
||||||
raise Exception('ScreenSaver not available')
|
raise Exception('ScreenSaver not available')
|
||||||
@ -107,9 +116,11 @@ def _ensureInitialized():
|
|||||||
def initIdleDuration(atLeastSeconds: int) -> None:
|
def initIdleDuration(atLeastSeconds: int) -> None:
|
||||||
_ensureInitialized()
|
_ensureInitialized()
|
||||||
if atLeastSeconds:
|
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
|
# And now reset it
|
||||||
subprocess.call(['/usr/bin/xset', 's', 'reset'])
|
subprocess.call(['/usr/bin/xset', 's', 'reset']) # nosec: fixed command
|
||||||
|
|
||||||
|
|
||||||
def getIdleDuration() -> float:
|
def getIdleDuration() -> float:
|
||||||
@ -122,7 +133,11 @@ def getIdleDuration() -> float:
|
|||||||
xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), xssInfo)
|
xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), xssInfo)
|
||||||
|
|
||||||
# States: 0 = off, 1 = On, 2 = Cycle, 3 = Disabled, ...?
|
# 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
|
if (
|
||||||
return 3600 * 100 * 1000 # If screen saver is active, return a high enough value
|
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
|
return xssInfo.contents.idle / 1000.0
|
||||||
|
@ -35,6 +35,8 @@ import typing
|
|||||||
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
from .windows.log import LocalLogger
|
from .windows.log import LocalLogger
|
||||||
|
elif sys.platform == 'darwin':
|
||||||
|
from .macos.log import LocalLogger
|
||||||
else:
|
else:
|
||||||
from .linux.log import LocalLogger
|
from .linux.log import LocalLogger
|
||||||
|
|
||||||
@ -55,7 +57,7 @@ class Logger:
|
|||||||
self.logLevel = INFO
|
self.logLevel = INFO
|
||||||
self.localLogger = LocalLogger()
|
self.localLogger = LocalLogger()
|
||||||
self.remoteLogger = None
|
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:
|
def setLevel(self, level: typing.Union[str, int]) -> None:
|
||||||
'''
|
'''
|
||||||
|
31
actor/src/udsactor/macos/__init__.py
Normal file
31
actor/src/udsactor/macos/__init__.py
Normal file
@ -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
|
||||||
|
'''
|
76
actor/src/udsactor/macos/log.py
Normal file
76
actor/src/udsactor/macos/log.py
Normal file
@ -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)
|
146
actor/src/udsactor/macos/operations.py
Normal file
146
actor/src/udsactor/macos/operations.py
Normal file
@ -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"<key>ProductVersion</key>\s*<string>(.*)</string>", 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
|
70
actor/src/udsactor/macos/runner.py
Normal file
70
actor/src/udsactor/macos/runner.py
Normal file
@ -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()
|
109
actor/src/udsactor/macos/service.py
Normal file
109
actor/src/udsactor/macos/service.py
Normal file
@ -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()
|
106
actor/src/udsactor/macos/store.py
Normal file
106
actor/src/udsactor/macos/store.py
Normal file
@ -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 ''
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014 Virtual Cable S.L.
|
# Copyright (c) 2014-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.
|
||||||
#
|
#
|
||||||
@ -32,6 +32,8 @@ import sys
|
|||||||
|
|
||||||
name = sys.platform
|
name = sys.platform
|
||||||
if sys.platform == 'win32':
|
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:
|
else:
|
||||||
from .linux import operations, store # pylint: disable=unused-import
|
from .linux import operations, store
|
||||||
|
@ -103,7 +103,7 @@ class UDSApi: # pylint: disable=too-few-public-methods
|
|||||||
logging.getLogger('urllib3').setLevel(logging.ERROR)
|
logging.getLogger('urllib3').setLevel(logging.ERROR)
|
||||||
try:
|
try:
|
||||||
warnings.simplefilter('ignore') # Disables all warnings
|
warnings.simplefilter('ignore') # Disables all warnings
|
||||||
except Exception:
|
except Exception: # nosec: not interested in exceptions
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -178,7 +178,7 @@ class UDSServerApi(UDSApi):
|
|||||||
priority=v['priority'],
|
priority=v['priority'],
|
||||||
isCustom=v['isCustom'],
|
isCustom=v['isCustom'],
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception: # nosec: not interested in exceptions
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def register( # pylint: disable=too-many-arguments, too-many-locals
|
def register( # pylint: disable=too-many-arguments, too-many-locals
|
||||||
@ -329,7 +329,7 @@ class UDSServerApi(UDSApi):
|
|||||||
) -> types.LoginResultInfoType:
|
) -> types.LoginResultInfoType:
|
||||||
if not token:
|
if not token:
|
||||||
return types.LoginResultInfoType(
|
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 = {
|
payload = {
|
||||||
'type': actor_type or types.MANAGED,
|
'type': actor_type or types.MANAGED,
|
||||||
|
@ -101,7 +101,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
# 0 = OTHER, 10000 = DEBUG, 20000 = WARN, 30000 = INFO, 40000 = ERROR, 50000 = FATAL
|
# 0 = OTHER, 10000 = DEBUG, 20000 = WARN, 30000 = INFO, 40000 = ERROR, 50000 = FATAL
|
||||||
# So this comes:
|
# So this comes:
|
||||||
logger.setLevel([DEBUG, INFO, ERROR, FATAL][self._cfg.log_level])
|
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()
|
logger.enableServiceLogger()
|
||||||
|
|
||||||
socket.setdefaulttimeout(20)
|
socket.setdefaulttimeout(20)
|
||||||
@ -538,9 +538,9 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
if not self.isManaged():
|
if not self.isManaged():
|
||||||
self.uninitialize()
|
self.uninitialize()
|
||||||
|
|
||||||
# ****************************************
|
# ******************************************************
|
||||||
# Methods that CAN BE overriden by actors
|
# Methods that CAN BE overriden by specific OS Actor
|
||||||
# ****************************************
|
# ******************************************************
|
||||||
def doWait(self, miliseconds: int) -> None:
|
def doWait(self, miliseconds: int) -> None:
|
||||||
'''
|
'''
|
||||||
Invoked to wait a bit
|
Invoked to wait a bit
|
||||||
|
@ -47,7 +47,7 @@ class ScriptExecutorThread(threading.Thread):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
logger.debug('Executing script: {}'.format(self.script))
|
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:
|
except Exception as e:
|
||||||
logger.error('Error executing script: {}'.format(e))
|
logger.error('Error executing script: {}'.format(e))
|
||||||
logger.exception()
|
logger.exception()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
# Copyright (c) 2014-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.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014 Virtual Cable S.L.
|
# Copyright (c) 2014-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.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
# Copyright (c) 2014-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.
|
||||||
#
|
#
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2019 Virtual Cable S.L.
|
# Copyright (c) 2019-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.
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user