forked from shaba/openuds
Compare commits
No commits in common. "master" and "v3.5" have entirely different histories.
4
.gitignore
vendored
4
.gitignore
vendored
@ -64,6 +64,8 @@
|
|||||||
|
|
||||||
# /server/
|
# /server/
|
||||||
*_enterprise
|
*_enterprise
|
||||||
|
/server/openuds.sublime-project
|
||||||
|
/server/openuds.sublime-workspace
|
||||||
|
|
||||||
# /server/src/
|
# /server/src/
|
||||||
/server/src/taskmanager.pid
|
/server/src/taskmanager.pid
|
||||||
@ -86,6 +88,7 @@
|
|||||||
# /server/src/uds/
|
# /server/src/uds/
|
||||||
/server/src/uds/*_enterprise.py
|
/server/src/uds/*_enterprise.py
|
||||||
/server/src/uds/fixtures
|
/server/src/uds/fixtures
|
||||||
|
/server/src/uds/tests
|
||||||
|
|
||||||
# /server/src/uds/auths/
|
# /server/src/uds/auths/
|
||||||
/server/src/uds/auths/*-enterprise
|
/server/src/uds/auths/*-enterprise
|
||||||
@ -162,4 +165,3 @@
|
|||||||
|
|
||||||
.vscode
|
.vscode
|
||||||
.mypy_cache
|
.mypy_cache
|
||||||
.pytest_cache
|
|
||||||
|
29
LICENSE
29
LICENSE
@ -1,29 +0,0 @@
|
|||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. 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.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder 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.
|
|
@ -10,6 +10,6 @@ OpenUDS (Universal Desktop Services) is a multiplatform connection broker for:
|
|||||||
|
|
||||||
This is an Open Source Source project, initiated by Spanish Company Virtualcable and released Open Source with the help of several Spanish Universities.
|
This is an Open Source Source project, initiated by Spanish Company Virtualcable and released Open Source with the help of several Spanish Universities.
|
||||||
|
|
||||||
Please fell free to contribute to this project.
|
Any help provided will be welcome.
|
||||||
|
|
||||||
**Note: Master version is always under heavy development and it is not recommended for use, it will probably have unfixed bugs. Please use the latest stable branch.**
|
**Note: Master version is always under heavy development and it is not recommended for use, it will probably have unfixed bugs. Please use the latest stable branch.**
|
||||||
|
4
actor/deps.txt
Normal file
4
actor/deps.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Linux:
|
||||||
|
python3-prctl (recommended, but not required in fact)
|
||||||
|
python3-pyqt5
|
||||||
|
|
@ -11,9 +11,6 @@ dpkg-buildpackage -b
|
|||||||
cat udsactor-template.spec |
|
cat udsactor-template.spec |
|
||||||
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
||||||
sed -e s/"release 1"/"release ${RELEASE}"/g > udsactor-$VERSION.spec
|
sed -e s/"release 1"/"release ${RELEASE}"/g > udsactor-$VERSION.spec
|
||||||
cat udsactor-unmanaged-template.spec |
|
|
||||||
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
|
||||||
sed -e s/"release 1"/"release ${RELEASE}"/g > udsactor-unmanaged-$VERSION.spec
|
|
||||||
|
|
||||||
# Now fix dependencies for opensuse
|
# Now fix dependencies for opensuse
|
||||||
# Note that, although on opensuse the library is "libXss1" on newer,
|
# Note that, although on opensuse the library is "libXss1" on newer,
|
||||||
@ -25,7 +22,7 @@ cat udsactor-unmanaged-template.spec |
|
|||||||
# sed -e s/"libXScrnSaver"/"libXss1"/g > udsactor-opensuse-$VERSION.spec
|
# sed -e s/"libXScrnSaver"/"libXss1"/g > udsactor-opensuse-$VERSION.spec
|
||||||
|
|
||||||
#for pkg in udsactor-$VERSION.spec udsactor-opensuse-$VERSION.spec; do
|
#for pkg in udsactor-$VERSION.spec udsactor-opensuse-$VERSION.spec; do
|
||||||
for pkg in udsactor-*$VERSION.spec; do
|
for pkg in udsactor-$VERSION.spec; do
|
||||||
|
|
||||||
rm -rf rpm
|
rm -rf rpm
|
||||||
for folder in SOURCES BUILD RPMS SPECS SRPMS; do
|
for folder in SOURCES BUILD RPMS SPECS SRPMS; do
|
||||||
|
@ -1,15 +1,3 @@
|
|||||||
udsactor (4.0.0) stable; urgency=medium
|
|
||||||
|
|
||||||
* Upgraded to 4.0.0 release
|
|
||||||
|
|
||||||
-- Adolfo Gómez García <agomez@virtualcable.es> Fri, 1 Jul 2022 15:00:00 +0200
|
|
||||||
|
|
||||||
udsactor (3.6.0) stable; urgency=medium
|
|
||||||
|
|
||||||
* Upgraded to 3.6.0 release
|
|
||||||
|
|
||||||
-- Adolfo Gómez García <agomez@virtualcable.es> Fri, 1 Jul 2022 14:00:00 +0200
|
|
||||||
|
|
||||||
udsactor (3.5.0) stable; urgency=medium
|
udsactor (3.5.0) stable; urgency=medium
|
||||||
|
|
||||||
* Upgraded to 3.5.0 release
|
* Upgraded to 3.5.0 release
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
udsactor-unmanaged_3.6.0_all.deb admin optional
|
udsactor-unmanaged_3.5.0_all.deb admin optional
|
||||||
udsactor_3.6.0_all.deb admin optional
|
udsactor_3.5.0_all.deb admin optional
|
||||||
udsactor_3.6.0_amd64.buildinfo admin optional
|
udsactor_3.5.0_amd64.buildinfo admin optional
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
<?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 +0,0 @@
|
|||||||
service file (net.virtualcable.udsactor.server.plist) goes in /Library/LaunchDaemons
|
|
@ -29,32 +29,33 @@
|
|||||||
'''
|
'''
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
'''
|
'''
|
||||||
|
# pylint: disable=invalid-name
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import PyQt5 # noqa
|
import PyQt5 # pylint: disable=unused-import
|
||||||
from PyQt5.QtCore import QTimer
|
from PyQt5.QtCore import QTimer
|
||||||
from PyQt5.QtWidgets import QMainWindow
|
from PyQt5.QtWidgets import QMainWindow
|
||||||
|
|
||||||
from udsactor.log import logger, INFO
|
from udsactor.log import logger, INFO
|
||||||
from udsactor.client import UDSClientQApp
|
from udsactor.client import UDSClientQApp
|
||||||
from udsactor import platform
|
from udsactor.platform import operations
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logger.setLevel(INFO)
|
logger.setLevel(INFO)
|
||||||
|
|
||||||
# Ensure idle operations is initialized on start
|
# Ensure idle operations is initialized on start
|
||||||
platform.operations.initIdleDuration(0)
|
operations.initIdleDuration(0)
|
||||||
|
|
||||||
if platform.is_linux:
|
if 'linux' in sys.platform:
|
||||||
os.environ['QT_X11_NO_MITSHM'] = '1'
|
os.environ['QT_X11_NO_MITSHM'] = '1'
|
||||||
|
|
||||||
UDSClientQApp.setQuitOnLastWindowClosed(False)
|
UDSClientQApp.setQuitOnLastWindowClosed(False)
|
||||||
|
|
||||||
qApp = UDSClientQApp(sys.argv)
|
qApp = UDSClientQApp(sys.argv)
|
||||||
|
|
||||||
if platform.is_windows or platform.is_mac:
|
if 'linux' not in sys.platform:
|
||||||
# The "hidden window" is not needed on linux
|
# The "hidden window" is only needed to process events on Windows
|
||||||
# Not needed on Linux
|
# Not needed on Linux
|
||||||
mw = QMainWindow()
|
mw = QMainWindow()
|
||||||
mw.showMinimized() # Start minimized, will be hidden (not destroyed) as soon as qApp.init is invoked
|
mw.showMinimized() # Start minimized, will be hidden (not destroyed) as soon as qApp.init is invoked
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2020-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2020 Virtual Cable S.L.
|
||||||
# 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,
|
||||||
@ -35,7 +35,7 @@ import os
|
|||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import PyQt5 # Ensures PyQt is included in the package
|
import PyQt5 # pylint: disable=unused-import
|
||||||
from PyQt5.QtWidgets import QApplication, QDialog, QFileDialog, QMessageBox
|
from PyQt5.QtWidgets import QApplication, QDialog, QFileDialog, QMessageBox
|
||||||
|
|
||||||
import udsactor
|
import udsactor
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2020-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2020 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# 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 # nosec: B403
|
import pickle
|
||||||
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, # type: ignore
|
QMessageBox.Ok,
|
||||||
)
|
)
|
||||||
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, # type: ignore
|
QMessageBox.Ok,
|
||||||
)
|
)
|
||||||
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, # type: ignore
|
QMessageBox.Ok,
|
||||||
)
|
)
|
||||||
|
|
||||||
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, # type: ignore
|
QMessageBox.Ok,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -153,15 +153,12 @@ class UDSConfigDialog(QDialog):
|
|||||||
self.ui.testButton.setEnabled(True)
|
self.ui.testButton.setEnabled(True)
|
||||||
# Informs the user
|
# Informs the user
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
self,
|
self, 'UDS Configuration', 'Configuration saved.', QMessageBox.Ok
|
||||||
'UDS Configuration',
|
|
||||||
'Configuration saved.',
|
|
||||||
QMessageBox.Ok, # type: ignore
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# If run as "sudo" on linux, we will need this to avoid problems
|
# If to be 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'
|
||||||
|
|
||||||
@ -174,18 +171,16 @@ 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 export_:
|
with open(sys.argv[2], 'wb') as f:
|
||||||
pickle.dump(
|
pickle.dump(udsactor.platform.store.readConfig(), f, protocol=3)
|
||||||
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)
|
||||||
elif sys.argv[1] == 'import':
|
if sys.argv[1] == 'import':
|
||||||
try:
|
try:
|
||||||
with open(sys.argv[2], 'rb') as import_:
|
with open(sys.argv[2], 'rb') as f:
|
||||||
config = pickle.load(import_) # nosec: B301: the file is provided by user, so it's not a security issue
|
config = pickle.load(f)
|
||||||
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))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2020-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2020 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# may be used to endorse or promote products derived from this software
|
||||||
# without specific prior written permission.
|
# without specific prior written permission.
|
||||||
#
|
#
|
||||||
@ -29,8 +29,12 @@
|
|||||||
'''
|
'''
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
'''
|
'''
|
||||||
from udsactor import platform
|
import sys
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
from udsactor.windows import runner
|
||||||
|
else:
|
||||||
|
from udsactor.linux import runner
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
platform.runner.run()
|
runner.run()
|
||||||
|
@ -214,10 +214,10 @@
|
|||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLineEdit" name="serviceToken">
|
<widget class="QLineEdit" name="serviceToken">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>UDS Service Token</string>
|
<string>UDS user with administration rights (Will not be stored on template)</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="whatsThis">
|
<property name="whatsThis">
|
||||||
<string><html><head/><body><p>Token of the service on UDS platform</p><p>This token can be obtainend from the service configuration on UDS.</p></body></html></string>
|
<string><html><head/><body><p>Administrator user on UDS Server.</p><p>Note: This credential will not be stored on client. Will be used to obtain an unique token for this image.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -268,10 +268,10 @@
|
|||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLineEdit" name="restrictNet">
|
<widget class="QLineEdit" name="restrictNet">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Restrict valid detection of network interfaces to this network.</string>
|
<string>UDS user with administration rights (Will not be stored on template)</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="whatsThis">
|
<property name="whatsThis">
|
||||||
<string><html><head/><body><p>Restrics valid detection of network interfaces.</p><p>Note: Use this field only in case of several network interfaces, so UDS knows which one is the interface where the user will be connected..</p></body></html></string>
|
<string><html><head/><body><p>Administrator user on UDS Server.</p><p>Note: This credential will not be stored on client. Will be used to obtain an unique token for this image.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -35,4 +35,4 @@ from . import platform
|
|||||||
__title__ = 'udsactor'
|
__title__ = 'udsactor'
|
||||||
__author__ = 'Adolfo Gómez <dkmaster@dkmon.com>'
|
__author__ = 'Adolfo Gómez <dkmaster@dkmon.com>'
|
||||||
__license__ = "BSD 3-clause"
|
__license__ = "BSD 3-clause"
|
||||||
__copyright__ = "Copyright 2014-2022 VirtualCable S.L.U."
|
__copyright__ = "Copyright 2014-2020 VirtualCable S.L.U."
|
||||||
|
@ -196,7 +196,7 @@ class UDSActorClient(threading.Thread): # pylint: disable=too-many-instance-att
|
|||||||
self.checkIdle()
|
self.checkIdle()
|
||||||
self.checkDeadLine()
|
self.checkDeadLine()
|
||||||
|
|
||||||
time.sleep(1.22) # Sleeps between loop iterations
|
time.sleep(1.3) # Sleeps between loop iterations
|
||||||
|
|
||||||
self.api.logout(user + self._extraLogoff, sessionType)
|
self.api.logout(user + self._extraLogoff, sessionType)
|
||||||
logger.info('Notified logout for %s (%s)', user, sessionType) # Log logout
|
logger.info('Notified logout for %s (%s)', user, sessionType) # Log logout
|
||||||
@ -239,7 +239,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) # type: ignore
|
buffer.open(QIODevice.WriteOnly)
|
||||||
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... :)
|
||||||
|
@ -132,7 +132,7 @@ class HTTPServerThread(threading.Thread):
|
|||||||
self._app = app
|
self._app = app
|
||||||
|
|
||||||
self.port = -1
|
self.port = -1
|
||||||
self.id = secrets.token_urlsafe(24)
|
self.id = secrets.token_urlsafe(16)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self) -> str:
|
def url(self) -> str:
|
||||||
|
@ -33,8 +33,8 @@ import json
|
|||||||
import typing
|
import typing
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from udsactor import tools, types
|
|
||||||
from udsactor.log import logger
|
from ..log import logger
|
||||||
|
|
||||||
# For avoid proxy on localhost connections
|
# For avoid proxy on localhost connections
|
||||||
NO_PROXY = {
|
NO_PROXY = {
|
||||||
@ -42,108 +42,55 @@ NO_PROXY = {
|
|||||||
'https': None,
|
'https': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UDSActorClientPool:
|
||||||
class UDSActorClientPool(metaclass=tools.Singleton):
|
_clientUrl: typing.List[str]
|
||||||
_clients: typing.List[types.ClientInfo]
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._clients = []
|
self._clientUrl = []
|
||||||
|
|
||||||
def _post(
|
def _post(self, method: str, data: typing.MutableMapping[str, str], timeout=2) -> typing.List[requests.Response]:
|
||||||
self,
|
removables: typing.List[str] = []
|
||||||
session_id: typing.Optional[str],
|
result: typing.List[typing.Any] = []
|
||||||
method: str,
|
for clientUrl in self._clientUrl:
|
||||||
data: typing.MutableMapping[str, str],
|
|
||||||
timeout: int = 2,
|
|
||||||
) -> typing.List[
|
|
||||||
typing.Tuple[types.ClientInfo, typing.Optional[requests.Response]]
|
|
||||||
]:
|
|
||||||
result: typing.List[
|
|
||||||
typing.Tuple[types.ClientInfo, typing.Optional[requests.Response]]
|
|
||||||
] = []
|
|
||||||
for client in self._clients:
|
|
||||||
# Skip if session id is provided but does not match
|
|
||||||
if session_id and client.session_id != session_id:
|
|
||||||
continue
|
|
||||||
clientUrl = client.url
|
|
||||||
try:
|
try:
|
||||||
result.append(
|
result.append(requests.post(clientUrl + '/' + method, data=json.dumps(data), verify=False, timeout=timeout, proxies=NO_PROXY))
|
||||||
(
|
|
||||||
client,
|
|
||||||
requests.post(
|
|
||||||
clientUrl + '/' + method,
|
|
||||||
data=json.dumps(data),
|
|
||||||
verify=False,
|
|
||||||
timeout=timeout,
|
|
||||||
proxies=NO_PROXY, # type: ignore
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(
|
# If cannot request to a clientUrl, remove it from list
|
||||||
'Could not connect with client %s: %s. ',
|
logger.info('Could not connect with client %s: %s. Removed from registry.', e, clientUrl)
|
||||||
e,
|
removables.append(clientUrl)
|
||||||
clientUrl,
|
|
||||||
)
|
# Remove failed connections
|
||||||
result.append((client, None))
|
for clientUrl in removables:
|
||||||
|
self.unregister(clientUrl)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@property
|
def register(self, clientUrl: str) -> None:
|
||||||
def clients(self) -> typing.List[types.ClientInfo]:
|
|
||||||
return self._clients
|
|
||||||
|
|
||||||
def register(self, client_url: str) -> None:
|
|
||||||
# Remove first if exists, to avoid duplicates
|
# Remove first if exists, to avoid duplicates
|
||||||
self.unregister(client_url)
|
self.unregister(clientUrl)
|
||||||
# And add it again
|
# And add it again
|
||||||
self._clients.append(types.ClientInfo(client_url, ''))
|
self._clientUrl.append(clientUrl)
|
||||||
|
|
||||||
def set_session_id(self, client_url: str, session_id: typing.Optional[str]) -> None:
|
def unregister(self, clientUrl: str) -> None:
|
||||||
"""Set the session id for a client
|
self._clientUrl = list((i for i in self._clientUrl if i != clientUrl))
|
||||||
|
|
||||||
Args:
|
def executeScript(self, script: str) -> None:
|
||||||
clientUrl (str): _description_
|
self._post('script', {'script': script}, timeout=30)
|
||||||
session_id (str): _description_
|
|
||||||
"""
|
|
||||||
for client in self._clients:
|
|
||||||
if client.url == client_url:
|
|
||||||
# remove existing client from list, create a new one and insert it
|
|
||||||
self._clients.remove(client)
|
|
||||||
self._clients.append(types.ClientInfo(client_url, session_id or ''))
|
|
||||||
break
|
|
||||||
|
|
||||||
def unregister(self, client_url: str) -> None:
|
def logout(self) -> None:
|
||||||
# remove client url from array if found
|
self._post('logout', {})
|
||||||
for i, client in enumerate(self._clients):
|
|
||||||
if client.url == client_url:
|
|
||||||
self._clients.pop(i)
|
|
||||||
return
|
|
||||||
|
|
||||||
def executeScript(self, session_id: typing.Optional[str], script: str) -> None:
|
def message(self, message: str) -> None:
|
||||||
self._post(session_id, 'script', {'script': script}, timeout=30)
|
self._post('message', {'message': message})
|
||||||
|
|
||||||
def logout(self, session_id: typing.Optional[str]) -> None:
|
def ping(self) -> bool:
|
||||||
self._post(session_id, 'logout', {})
|
if not self._clientUrl:
|
||||||
|
return True # No clients, ping ok
|
||||||
|
self._post('ping', {}, timeout=1)
|
||||||
|
return bool(self._clientUrl) # There was clients, but they are now lost!!!
|
||||||
|
|
||||||
def message(self, session_id: typing.Optional[str], message: str) -> None:
|
def screenshot(self) -> typing.Optional[str]: # Screenshot are returned as base64
|
||||||
self._post(session_id, 'message', {'message': message})
|
for r in self._post('screenshot', {}, timeout=3):
|
||||||
|
|
||||||
def lost_clients(
|
|
||||||
self,
|
|
||||||
session_id: typing.Optional[str] = None,
|
|
||||||
) -> typing.Iterable[types.ClientInfo]: # returns the list of "lost" clients
|
|
||||||
# Port ping to every client
|
|
||||||
for i in self._post(session_id, 'ping', {}, timeout=1):
|
|
||||||
if i[1] is None:
|
|
||||||
yield i[0]
|
|
||||||
|
|
||||||
def screenshot(
|
|
||||||
self, session_id: typing.Optional[str]
|
|
||||||
) -> typing.Optional[str]: # Screenshot are returned as base64
|
|
||||||
for client, r in self._post(session_id, 'screenshot', {}, timeout=3):
|
|
||||||
if not r:
|
|
||||||
continue # Missing client, so we ignore it
|
|
||||||
try:
|
try:
|
||||||
return r.json()['result']
|
return r.json()['result']
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -30,23 +30,19 @@
|
|||||||
'''
|
'''
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from udsactor.http import handler, clients_pool
|
from . import handler
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from udsactor.service import CommonService
|
from ..service import CommonService
|
||||||
|
|
||||||
class LocalProvider(handler.Handler):
|
class LocalProvider(handler.Handler):
|
||||||
|
|
||||||
def post_login(self) -> typing.Any:
|
def post_login(self) -> typing.Any:
|
||||||
result = self._service.login(self._params['username'], self._params['session_type'])
|
result = self._service.login(self._params['username'], self._params['session_type'])
|
||||||
# if callback_url is provided, record it in the clients pool
|
|
||||||
if 'callback_url' in self._params and result.session_id:
|
|
||||||
# If no session id is returned, then no login is acounted for
|
|
||||||
clients_pool.UDSActorClientPool().set_session_id(self._params['callback_url'], result.session_id)
|
|
||||||
return result._asdict()
|
return result._asdict()
|
||||||
|
|
||||||
def post_logout(self) -> typing.Any:
|
def post_logout(self) -> typing.Any:
|
||||||
self._service.logout(self._params['username'], self._params['session_type'], self._params['session_id'])
|
self._service.logout(self._params['username'], self._params['session_type'])
|
||||||
return 'ok'
|
return 'ok'
|
||||||
|
|
||||||
def post_ping(self) -> typing.Any:
|
def post_ping(self) -> typing.Any:
|
||||||
|
@ -71,7 +71,7 @@ class HTTPServerHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
# Very simple path & params splitter
|
# Very simple path & params splitter
|
||||||
path = self.path.split('?')[0][1:].split('/')
|
path = self.path.split('?')[0][1:].split('/')
|
||||||
|
|
||||||
logger.debug('Path: %s, ip: %s, params: %s', path, self.client_address, params)
|
logger.debug('Path: %s, params: %s', path, params)
|
||||||
|
|
||||||
handlerType: typing.Optional[typing.Type['Handler']] = None
|
handlerType: typing.Optional[typing.Type['Handler']] = None
|
||||||
|
|
||||||
|
@ -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: # nosec: Not interested in exception
|
except 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-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# 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 = True
|
linux = False
|
||||||
windows = False
|
windows = True
|
||||||
serviceLogger = False
|
serviceLogger = False
|
||||||
|
|
||||||
logger: typing.Optional[logging.Logger]
|
logger: typing.Optional[logging.Logger]
|
||||||
@ -59,8 +59,7 @@ 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: # nosec: B110: we don't care about exceptions here
|
except Exception:
|
||||||
# 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 # nosec
|
import subprocess
|
||||||
import struct
|
import struct
|
||||||
import array
|
import array
|
||||||
import typing
|
import typing
|
||||||
@ -53,9 +53,7 @@ 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(
|
info = bytearray(fcntl.ioctl(s.fileno(), 0x8927, struct.pack(str('256s'), ifnameBytes[:15])))
|
||||||
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
|
||||||
@ -69,15 +67,11 @@ 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(
|
return str(socket.inet_ntoa(fcntl.ioctl(
|
||||||
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
|
||||||
|
|
||||||
@ -97,32 +91,22 @@ 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(
|
outbytes = struct.unpack('iL', fcntl.ioctl(
|
||||||
'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 [
|
return [namestr[i:i + offset].split(b'\0', 1)[0].decode('utf-8') for i in range(0, outbytes, length)]
|
||||||
namestr[i : i + offset].split(b'\0', 1)[0].decode('utf-8')
|
|
||||||
for i in range(0, outbytes, length)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def _getIpAndMac(
|
def _getIpAndMac(ifname: str) -> typing.Tuple[typing.Optional[str], typing.Optional[str]]:
|
||||||
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
|
return os.getuid() == 0 # getuid only available on linux. Expect "complaioins" if edited from Windows
|
||||||
|
|
||||||
|
|
||||||
def getComputerName() -> str:
|
def getComputerName() -> str:
|
||||||
'''
|
'''
|
||||||
@ -130,23 +114,15 @@ 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 (
|
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
|
||||||
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:
|
||||||
@ -157,22 +133,18 @@ def getLinuxOs() -> str:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return 'unknown'
|
return 'unknown'
|
||||||
|
|
||||||
|
|
||||||
def getVersion() -> str:
|
|
||||||
return 'Linux ' + getLinuxOs()
|
|
||||||
|
|
||||||
def reboot(flags: int = 0):
|
def reboot(flags: int = 0):
|
||||||
'''
|
'''
|
||||||
Simple reboot using os command
|
Simple reboot using os command
|
||||||
'''
|
'''
|
||||||
subprocess.call(['/sbin/shutdown', 'now', '-r']) # nosec: Fine, all under control
|
subprocess.call(['/sbin/shutdown', 'now', '-r'])
|
||||||
|
|
||||||
|
|
||||||
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']]) # nosec: Fine, all under control
|
subprocess.call(['/usr/bin/pkill', '-u', os.environ['USER']])
|
||||||
# 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'])
|
||||||
|
|
||||||
@ -186,9 +158,7 @@ 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(
|
def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False):
|
||||||
domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False
|
|
||||||
):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -196,11 +166,7 @@ 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:
|
||||||
@ -215,8 +181,7 @@ def getCurrentUser() -> str:
|
|||||||
'''
|
'''
|
||||||
Returns current logged in user
|
Returns current logged in user
|
||||||
'''
|
'''
|
||||||
return os.getlogin()
|
return os.environ['USER']
|
||||||
|
|
||||||
|
|
||||||
def getSessionType() -> str:
|
def getSessionType() -> str:
|
||||||
'''
|
'''
|
||||||
@ -225,12 +190,7 @@ def getSessionType() -> str:
|
|||||||
* xrdp --> xrdp session
|
* xrdp --> xrdp session
|
||||||
* other types
|
* other types
|
||||||
'''
|
'''
|
||||||
return (
|
return 'xrdp' if 'XRDP_SESSION' in os.environ else os.environ.get('XDG_SESSION_TYPE', 'unknown')
|
||||||
'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-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# 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 subprocess # nosec
|
import os
|
||||||
|
|
||||||
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
|
||||||
subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: subprocess
|
os.system('/bin/hostname {}'.format(newName))
|
||||||
subprocess.run(['/bin/hostname', newName]) # nosec: subprocess
|
os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
|
||||||
|
|
||||||
# add name to "hosts"
|
# add name to "hosts"
|
||||||
with open('/etc/hosts', 'r') as hosts:
|
with open('/etc/hosts', 'r') as hosts:
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
'''
|
'''
|
||||||
@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 subprocess # nosec
|
import os
|
||||||
|
|
||||||
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
|
||||||
subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
|
os.system('/bin/hostname {}'.format(newName))
|
||||||
subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
|
os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
|
||||||
|
|
||||||
# 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 subprocess # nosec
|
import os
|
||||||
|
|
||||||
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
|
||||||
subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
|
os.system('/bin/hostname {}'.format(newName))
|
||||||
subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
|
os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
|
||||||
|
|
||||||
# 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 subprocess # nosec
|
import os
|
||||||
|
|
||||||
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
|
||||||
subprocess.run(['hostnamectl', 'set-hostname', newName]) # nosec: ok, we are root
|
os.system('/bin/hostname {}'.format(newName))
|
||||||
subprocess.run(['/bin/hostname', newName]) # nosec: ok, we are root
|
os.system('/usr/bin/hostnamectl set-hostname {}'.format(newName))
|
||||||
|
|
||||||
# add name to "hosts"
|
# add name to "hosts"
|
||||||
with open('/etc/hosts', 'r') as hosts:
|
with open('/etc/hosts', 'r') as hosts:
|
||||||
|
@ -50,7 +50,7 @@ def run() -> None:
|
|||||||
r = client.login(sys.argv[2], platform.operations.getSessionType())
|
r = client.login(sys.argv[2], platform.operations.getSessionType())
|
||||||
print('{},{},{},{}\n'.format(r.ip, r.hostname, r.max_idle, r.dead_line or ''))
|
print('{},{},{},{}\n'.format(r.ip, r.hostname, r.max_idle, r.dead_line or ''))
|
||||||
elif sys.argv[1] == 'logout':
|
elif sys.argv[1] == 'logout':
|
||||||
client.logout(sys.argv[2], platform.operations.getSessionType())
|
client.logout(sys.argv[2])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception()
|
logger.exception()
|
||||||
logger.error('Got exception while processing command: %s', e)
|
logger.error('Got exception while processing command: %s', e)
|
||||||
|
@ -37,7 +37,7 @@ from ..log import logger
|
|||||||
from ..service import CommonService
|
from ..service import CommonService
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from prctl import set_proctitle # type: ignore
|
from prctl import set_proctitle # @UnresolvedImport
|
||||||
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,13 +32,12 @@
|
|||||||
import os
|
import os
|
||||||
import configparser
|
import configparser
|
||||||
import base64
|
import base64
|
||||||
import pickle # nosec
|
import pickle
|
||||||
|
|
||||||
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()
|
||||||
@ -46,22 +45,10 @@ 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 = (
|
config = pickle.loads(base64.b64decode(base64Config.encode())) if base64Config else None
|
||||||
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 = (
|
data = pickle.loads(base64.b64decode(base64Data.encode())) if base64Data else None
|
||||||
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),
|
||||||
@ -75,23 +62,20 @@ 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')
|
||||||
@ -109,19 +93,15 @@ 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(
|
os.mkdir(dirname, mode=0o700) # Will create only if route to path already exists, for example, /etc (that must... :-))
|
||||||
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 # nosec
|
import subprocess
|
||||||
|
|
||||||
xlib = None
|
xlib = None
|
||||||
xss = None
|
xss = None
|
||||||
@ -39,22 +39,17 @@ 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_ = [
|
_fields_ = [('window', ctypes.c_long),
|
||||||
('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
|
||||||
|
|
||||||
@ -78,15 +73,13 @@ 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(
|
xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure
|
||||||
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
|
||||||
@ -102,9 +95,7 @@ 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(
|
available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base))
|
||||||
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')
|
||||||
@ -116,11 +107,9 @@ def _ensureInitialized():
|
|||||||
def initIdleDuration(atLeastSeconds: int) -> None:
|
def initIdleDuration(atLeastSeconds: int) -> None:
|
||||||
_ensureInitialized()
|
_ensureInitialized()
|
||||||
if atLeastSeconds:
|
if atLeastSeconds:
|
||||||
subprocess.call( # nosec, controlled params
|
subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)])
|
||||||
['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)]
|
|
||||||
)
|
|
||||||
# And now reset it
|
# And now reset it
|
||||||
subprocess.call(['/usr/bin/xset', 's', 'reset']) # nosec: fixed command
|
subprocess.call(['/usr/bin/xset', 's', 'reset'])
|
||||||
|
|
||||||
|
|
||||||
def getIdleDuration() -> float:
|
def getIdleDuration() -> float:
|
||||||
@ -133,11 +122,7 @@ 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 (
|
if xssInfo.contents.state == 1: # state = 1 means "active", so idle is not a valid state
|
||||||
xssInfo.contents.state == 1
|
return 3600 * 100 * 1000 # If screen saver is active, return a high enough value
|
||||||
): # 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,8 +35,6 @@ 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
|
||||||
|
|
||||||
@ -57,7 +55,7 @@ class Logger:
|
|||||||
self.logLevel = INFO
|
self.logLevel = INFO
|
||||||
self.localLogger = LocalLogger()
|
self.localLogger = LocalLogger()
|
||||||
self.remoteLogger = None
|
self.remoteLogger = None
|
||||||
self.own_token = '' # nosec: This is no password at all
|
self.own_token = ''
|
||||||
|
|
||||||
def setLevel(self, level: typing.Union[str, int]) -> None:
|
def setLevel(self, level: typing.Union[str, int]) -> None:
|
||||||
'''
|
'''
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
# -*- 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
|
|
||||||
'''
|
|
@ -1,185 +0,0 @@
|
|||||||
# -*- 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
|
|
||||||
'''
|
|
||||||
|
|
||||||
# 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 udsactor import types, tools
|
|
||||||
|
|
||||||
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 getVersion() -> str:
|
|
||||||
return 'MacOS ' + getMacOs()
|
|
||||||
|
|
||||||
|
|
||||||
def reboot(flags: int = 0) -> None:
|
|
||||||
'''
|
|
||||||
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
|
|
||||||
Note: For macOS, no configuration is supported, only "unmanaged" actor
|
|
||||||
'''
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
# se we cache for 20 seconds the result, that is enough for our needs
|
|
||||||
# and we avoid calling a system command every time we need it
|
|
||||||
@tools.cache(20)
|
|
||||||
def getIdleDuration() -> float:
|
|
||||||
# Execute:
|
|
||||||
try:
|
|
||||||
return (
|
|
||||||
int(
|
|
||||||
next(
|
|
||||||
filter(
|
|
||||||
lambda x: b"HIDIdleTime" in x,
|
|
||||||
subprocess.check_output(
|
|
||||||
["/usr/sbin/ioreg", "-c", "IOHIDSystem"]
|
|
||||||
).split(b"\n"),
|
|
||||||
)
|
|
||||||
).split(b"=")[1]
|
|
||||||
)
|
|
||||||
/ 1000000000
|
|
||||||
) # nosec: Command line is fixed
|
|
||||||
except Exception: # nosec: B110: ignore exception because we are not interested in it
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def getCurrentUser() -> str:
|
|
||||||
'''
|
|
||||||
Returns current logged in user
|
|
||||||
'''
|
|
||||||
return os.getlogin()
|
|
||||||
|
|
||||||
|
|
||||||
def getSessionType() -> str:
|
|
||||||
'''
|
|
||||||
Returns the session type. Currently, only "macos" (console) is supported
|
|
||||||
'''
|
|
||||||
return 'macos'
|
|
||||||
|
|
||||||
|
|
||||||
def forceTimeSync() -> None:
|
|
||||||
return
|
|
@ -1,71 +0,0 @@
|
|||||||
# -*- 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. 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
|
|
||||||
import typing
|
|
||||||
|
|
||||||
from .. import rest
|
|
||||||
from .. import platform
|
|
||||||
from ..log import logger
|
|
||||||
from .service import UDSActorSvc
|
|
||||||
|
|
||||||
def usage() -> typing.NoReturn:
|
|
||||||
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], platform.operations.getSessionType())
|
|
||||||
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()
|
|
@ -1,108 +0,0 @@
|
|||||||
# -*- 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
|
|
||||||
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()
|
|
@ -1,106 +0,0 @@
|
|||||||
# -*- 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 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-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2014 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# may be used to endorse or promote products derived from this software
|
||||||
# without specific prior written permission.
|
# without specific prior written permission.
|
||||||
#
|
#
|
||||||
@ -31,15 +31,7 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
name = sys.platform
|
name = sys.platform
|
||||||
is_windows = is_linux = is_mac = False
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
from .windows import operations, store, runner
|
from .windows import operations, store # pylint: disable=unused-import
|
||||||
is_windows = True
|
|
||||||
elif sys.platform == 'darwin':
|
|
||||||
from .macos import operations, store, runner
|
|
||||||
is_mac = True
|
|
||||||
elif sys.platform == 'linux':
|
|
||||||
from .linux import operations, store, runner
|
|
||||||
is_linux = True
|
|
||||||
else:
|
else:
|
||||||
raise Exception('Unsupported platform: {0}'.format(sys.platform))
|
from .linux import operations, store # pylint: disable=unused-import
|
||||||
|
@ -36,8 +36,8 @@ import typing
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from udsactor import types, tools
|
from . import types
|
||||||
from udsactor.version import VERSION, BUILD
|
from .version import VERSION
|
||||||
|
|
||||||
# Default public listen port
|
# Default public listen port
|
||||||
LISTEN_PORT = 43910
|
LISTEN_PORT = 43910
|
||||||
@ -90,9 +90,9 @@ class UDSApi: # pylint: disable=too-few-public-methods
|
|||||||
Base for remote api accesses
|
Base for remote api accesses
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_host: str = ''
|
_host: str
|
||||||
_validateCert: bool = True
|
_validateCert: bool
|
||||||
_url: str = ''
|
_url: str
|
||||||
|
|
||||||
def __init__(self, host: str, validateCert: bool) -> None:
|
def __init__(self, host: str, validateCert: bool) -> None:
|
||||||
self._host = host
|
self._host = host
|
||||||
@ -103,17 +103,17 @@ 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: # nosec: not interested in exceptions
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _headers(self) -> typing.MutableMapping[str, str]:
|
def _headers(self) -> typing.MutableMapping[str, str]:
|
||||||
return {
|
return {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'User-Agent': 'UDS Actor v{}/{}'.format(VERSION, BUILD),
|
'User-Agent': 'UDS Actor v{}'.format(VERSION),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _api_url(self, method: str) -> str:
|
def _apiURL(self, method: str) -> str:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def _doPost(
|
def _doPost(
|
||||||
@ -126,7 +126,7 @@ class UDSApi: # pylint: disable=too-few-public-methods
|
|||||||
headers = headers or self._headers
|
headers = headers or self._headers
|
||||||
try:
|
try:
|
||||||
result = requests.post(
|
result = requests.post(
|
||||||
self._api_url(method),
|
self._apiURL(method),
|
||||||
data=json.dumps(payLoad),
|
data=json.dumps(payLoad),
|
||||||
headers=headers,
|
headers=headers,
|
||||||
verify=self._validateCert,
|
verify=self._validateCert,
|
||||||
@ -157,7 +157,7 @@ class UDSApi: # pylint: disable=too-few-public-methods
|
|||||||
# UDS Broker API access
|
# UDS Broker API access
|
||||||
#
|
#
|
||||||
class UDSServerApi(UDSApi):
|
class UDSServerApi(UDSApi):
|
||||||
def _api_url(self, method: str) -> str:
|
def _apiURL(self, method: str) -> str:
|
||||||
return self._url + 'actor/v3/' + method
|
return self._url + 'actor/v3/' + method
|
||||||
|
|
||||||
def enumerateAuthenticators(self) -> typing.Iterable[types.AuthenticatorType]:
|
def enumerateAuthenticators(self) -> typing.Iterable[types.AuthenticatorType]:
|
||||||
@ -178,10 +178,10 @@ class UDSServerApi(UDSApi):
|
|||||||
priority=v['priority'],
|
priority=v['priority'],
|
||||||
isCustom=v['isCustom'],
|
isCustom=v['isCustom'],
|
||||||
)
|
)
|
||||||
except Exception: # nosec: not interested in exceptions
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def register(
|
def register( # pylint: disable=too-many-arguments, too-many-locals
|
||||||
self,
|
self,
|
||||||
auth: str,
|
auth: str,
|
||||||
username: str,
|
username: str,
|
||||||
@ -225,7 +225,7 @@ class UDSServerApi(UDSApi):
|
|||||||
headers['X-Auth-Token'] = result.json()['token']
|
headers['X-Auth-Token'] = result.json()['token']
|
||||||
|
|
||||||
result = requests.post(
|
result = requests.post(
|
||||||
self._api_url('register'),
|
self._apiURL('register'),
|
||||||
data=json.dumps(data),
|
data=json.dumps(data),
|
||||||
headers=headers,
|
headers=headers,
|
||||||
verify=self._validateCert,
|
verify=self._validateCert,
|
||||||
@ -252,7 +252,6 @@ class UDSServerApi(UDSApi):
|
|||||||
'type': actor_type or types.MANAGED,
|
'type': actor_type or types.MANAGED,
|
||||||
'token': token,
|
'token': token,
|
||||||
'version': VERSION,
|
'version': VERSION,
|
||||||
'build': BUILD,
|
|
||||||
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces],
|
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces],
|
||||||
}
|
}
|
||||||
r = self._doPost('initialize', payload)
|
r = self._doPost('initialize', payload)
|
||||||
@ -271,7 +270,6 @@ class UDSServerApi(UDSApi):
|
|||||||
)
|
)
|
||||||
if r['os']
|
if r['os']
|
||||||
else None,
|
else None,
|
||||||
alias_token=r.get('alias_token'), # Possible alias for unmanaged
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def ready(
|
def ready(
|
||||||
@ -324,20 +322,20 @@ class UDSServerApi(UDSApi):
|
|||||||
actor_type: typing.Optional[str],
|
actor_type: typing.Optional[str],
|
||||||
token: str,
|
token: str,
|
||||||
username: str,
|
username: str,
|
||||||
session_type: str,
|
sessionType: str,
|
||||||
interfaces: typing.Iterable[types.InterfaceInfoType],
|
interfaces: typing.Iterable[types.InterfaceInfoType],
|
||||||
secret: typing.Optional[str],
|
secret: typing.Optional[str],
|
||||||
) -> 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, session_id=None
|
ip='0.0.0.0', hostname=UNKNOWN, dead_line=None, max_idle=None
|
||||||
)
|
)
|
||||||
payload = {
|
payload = {
|
||||||
'type': actor_type or types.MANAGED,
|
'type': actor_type or types.MANAGED,
|
||||||
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces],
|
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces],
|
||||||
'token': token,
|
'token': token,
|
||||||
'username': username,
|
'username': username,
|
||||||
'session_type': session_type,
|
'session_type': sessionType,
|
||||||
'secret': secret or '',
|
'secret': secret or '',
|
||||||
}
|
}
|
||||||
result = self._doPost('login', payload)
|
result = self._doPost('login', payload)
|
||||||
@ -346,7 +344,6 @@ class UDSServerApi(UDSApi):
|
|||||||
hostname=result['hostname'],
|
hostname=result['hostname'],
|
||||||
dead_line=result['dead_line'],
|
dead_line=result['dead_line'],
|
||||||
max_idle=result['max_idle'],
|
max_idle=result['max_idle'],
|
||||||
session_id=result.get('session_id', ''),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def logout(
|
def logout(
|
||||||
@ -354,8 +351,7 @@ class UDSServerApi(UDSApi):
|
|||||||
actor_type: typing.Optional[str],
|
actor_type: typing.Optional[str],
|
||||||
token: str,
|
token: str,
|
||||||
username: str,
|
username: str,
|
||||||
session_id: str,
|
sessionType: str,
|
||||||
session_type: str,
|
|
||||||
interfaces: typing.Iterable[types.InterfaceInfoType],
|
interfaces: typing.Iterable[types.InterfaceInfoType],
|
||||||
secret: typing.Optional[str],
|
secret: typing.Optional[str],
|
||||||
) -> typing.Optional[str]:
|
) -> typing.Optional[str]:
|
||||||
@ -366,8 +362,7 @@ class UDSServerApi(UDSApi):
|
|||||||
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces],
|
'id': [{'mac': i.mac, 'ip': i.ip} for i in interfaces],
|
||||||
'token': token,
|
'token': token,
|
||||||
'username': username,
|
'username': username,
|
||||||
'session_type': session_type,
|
'session_type': sessionType,
|
||||||
'session_id': session_id,
|
|
||||||
'secret': secret or '',
|
'secret': secret or '',
|
||||||
}
|
}
|
||||||
return self._doPost('logout', payload) # Can be 'ok' or 'notified'
|
return self._doPost('logout', payload) # Can be 'ok' or 'notified'
|
||||||
@ -386,17 +381,13 @@ class UDSServerApi(UDSApi):
|
|||||||
return self._doPost('test', payLoad) == 'ok'
|
return self._doPost('test', payLoad) == 'ok'
|
||||||
|
|
||||||
|
|
||||||
class UDSClientApi(UDSApi, metaclass=tools.Singleton):
|
class UDSClientApi(UDSApi):
|
||||||
_session_id: str = ''
|
|
||||||
_callback_url: str = ''
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__('127.0.0.1:{}'.format(LISTEN_PORT), False)
|
super().__init__('127.0.0.1:{}'.format(LISTEN_PORT), False)
|
||||||
|
# Override base url
|
||||||
# Replace base url
|
|
||||||
self._url = "https://{}/ui/".format(self._host)
|
self._url = "https://{}/ui/".format(self._host)
|
||||||
|
|
||||||
def _api_url(self, method: str) -> str:
|
def _apiURL(self, method: str) -> str:
|
||||||
return self._url + method
|
return self._url + method
|
||||||
|
|
||||||
def post(
|
def post(
|
||||||
@ -406,15 +397,13 @@ class UDSClientApi(UDSApi, metaclass=tools.Singleton):
|
|||||||
) -> typing.Any:
|
) -> typing.Any:
|
||||||
return self._doPost(method=method, payLoad=payLoad, disableProxy=True)
|
return self._doPost(method=method, payLoad=payLoad, disableProxy=True)
|
||||||
|
|
||||||
def register(self, callback_url: str) -> None:
|
def register(self, callbackUrl: str) -> None:
|
||||||
self._callback_url = callback_url
|
payLoad = {'callback_url': callbackUrl}
|
||||||
payLoad = {'callback_url': callback_url}
|
|
||||||
self.post('register', payLoad)
|
self.post('register', payLoad)
|
||||||
|
|
||||||
def unregister(self, callback_url: str) -> None:
|
def unregister(self, callbackUrl: str) -> None:
|
||||||
payLoad = {'callback_url': callback_url}
|
payLoad = {'callback_url': callbackUrl}
|
||||||
self.post('unregister', payLoad)
|
self.post('unregister', payLoad)
|
||||||
self._callback_url = ''
|
|
||||||
|
|
||||||
def login(
|
def login(
|
||||||
self, username: str, sessionType: typing.Optional[str] = None
|
self, username: str, sessionType: typing.Optional[str] = None
|
||||||
@ -422,26 +411,19 @@ class UDSClientApi(UDSApi, metaclass=tools.Singleton):
|
|||||||
payLoad = {
|
payLoad = {
|
||||||
'username': username,
|
'username': username,
|
||||||
'session_type': sessionType or UNKNOWN,
|
'session_type': sessionType or UNKNOWN,
|
||||||
'callback_url': self._callback_url, # So we identify ourselves
|
|
||||||
}
|
}
|
||||||
result = self.post('login', payLoad)
|
result = self.post('login', payLoad)
|
||||||
res = types.LoginResultInfoType(
|
return types.LoginResultInfoType(
|
||||||
ip=result['ip'],
|
ip=result['ip'],
|
||||||
hostname=result['hostname'],
|
hostname=result['hostname'],
|
||||||
dead_line=result['dead_line'],
|
dead_line=result['dead_line'],
|
||||||
max_idle=result['max_idle'],
|
max_idle=result['max_idle'],
|
||||||
session_id=result['session_id'],
|
|
||||||
)
|
)
|
||||||
# Store session id for future use
|
|
||||||
self._session_id = res.session_id or ''
|
|
||||||
return res
|
|
||||||
|
|
||||||
def logout(self, username: str, sessionType: typing.Optional[str]) -> None:
|
def logout(self, username: str, sessionType: typing.Optional[str]) -> None:
|
||||||
payLoad = {
|
payLoad = {
|
||||||
'username': username,
|
'username': username,
|
||||||
'session_type': sessionType or UNKNOWN,
|
'session_type': sessionType or UNKNOWN
|
||||||
'callback_url': self._callback_url, # So we identify ourselves
|
|
||||||
'session_id': self._session_id, # We now know the session id, provided on login
|
|
||||||
}
|
}
|
||||||
self.post('logout', payLoad)
|
self.post('logout', payLoad)
|
||||||
|
|
||||||
|
@ -36,13 +36,13 @@ import secrets
|
|||||||
import subprocess
|
import subprocess
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from udsactor import platform
|
from . import platform
|
||||||
from udsactor import rest
|
from . import rest
|
||||||
from udsactor import types
|
from . import types
|
||||||
from udsactor import tools
|
from . import tools
|
||||||
|
|
||||||
from udsactor.log import logger, DEBUG, INFO, ERROR, FATAL
|
from .log import logger, DEBUG, INFO, ERROR, FATAL
|
||||||
from udsactor.http import clients_pool, server, cert
|
from .http import clients_pool, server, cert
|
||||||
|
|
||||||
# def setup() -> None:
|
# def setup() -> None:
|
||||||
# cfg = platform.store.readConfig()
|
# cfg = platform.store.readConfig()
|
||||||
@ -60,12 +60,15 @@ from udsactor.http import clients_pool, server, cert
|
|||||||
class CommonService: # pylint: disable=too-many-instance-attributes
|
class CommonService: # pylint: disable=too-many-instance-attributes
|
||||||
_isAlive: bool = True
|
_isAlive: bool = True
|
||||||
_rebootRequested: bool = False
|
_rebootRequested: bool = False
|
||||||
|
_loggedIn: bool = False
|
||||||
_initialized: bool = False
|
_initialized: bool = False
|
||||||
|
|
||||||
_cfg: types.ActorConfigurationType
|
_cfg: types.ActorConfigurationType
|
||||||
_api: rest.UDSServerApi
|
_api: rest.UDSServerApi
|
||||||
_interfaces: typing.List[types.InterfaceInfoType]
|
_interfaces: typing.List[types.InterfaceInfoType]
|
||||||
_secret: str
|
_secret: str
|
||||||
_certificate: types.CertificateInfoType
|
_certificate: types.CertificateInfoType
|
||||||
|
_clientsPool: clients_pool.UDSActorClientPool
|
||||||
_http: typing.Optional[server.HTTPServerThread]
|
_http: typing.Optional[server.HTTPServerThread]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -98,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 FOR SERVICE only
|
# If windows, enable service logger
|
||||||
logger.enableServiceLogger()
|
logger.enableServiceLogger()
|
||||||
|
|
||||||
socket.setdefaulttimeout(20)
|
socket.setdefaulttimeout(20)
|
||||||
@ -320,13 +323,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Only removes master token for managed machines (will need it on next client execution)
|
# Only removes master token for managed machines (will need it on next client execution)
|
||||||
# For unmanaged, if alias is present, replace master token with it
|
master_token = None if self.isManaged() else self._cfg.master_token
|
||||||
master_token = (
|
|
||||||
None
|
|
||||||
if self.isManaged()
|
|
||||||
else (initResult.alias_token or self._cfg.master_token)
|
|
||||||
)
|
|
||||||
# Replace master token with alias token if present
|
|
||||||
self._cfg = self._cfg._replace(
|
self._cfg = self._cfg._replace(
|
||||||
master_token=master_token,
|
master_token=master_token,
|
||||||
own_token=initResult.own_token,
|
own_token=initResult.own_token,
|
||||||
@ -335,9 +332,8 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# On first successfull initialization request, master token will dissapear for managed hosts
|
# On first successfull initialization request, master token will dissapear for managed hosts so it will be no more available (not needed anyway)
|
||||||
# so it will be no more available (not needed anyway). For unmanaged, the master token will
|
if self.isManaged():
|
||||||
# be replaced with an alias token.
|
|
||||||
platform.store.writeConfig(self._cfg)
|
platform.store.writeConfig(self._cfg)
|
||||||
|
|
||||||
# Setup logger now
|
# Setup logger now
|
||||||
@ -374,17 +370,13 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
self._http.stop()
|
self._http.stop()
|
||||||
|
|
||||||
# If logged in, notify UDS of logout (daemon stoped = no control = logout)
|
# If logged in, notify UDS of logout (daemon stoped = no control = logout)
|
||||||
# For every connected client...
|
if self._loggedIn and self._cfg.own_token:
|
||||||
if self._cfg.own_token:
|
self._loggedIn = False
|
||||||
for client in clients_pool.UDSActorClientPool().clients:
|
|
||||||
if client.session_id:
|
|
||||||
try:
|
try:
|
||||||
self._api.logout(
|
self._api.logout(
|
||||||
self._cfg.actorType,
|
self._cfg.actorType,
|
||||||
self._cfg.own_token,
|
self._cfg.own_token,
|
||||||
'',
|
'',
|
||||||
client.session_id
|
|
||||||
or 'stop', # If no session id, pass "stop"
|
|
||||||
'',
|
'',
|
||||||
self._interfaces,
|
self._interfaces,
|
||||||
self._secret,
|
self._secret,
|
||||||
@ -472,9 +464,8 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
self.checkIpsChanged()
|
self.checkIpsChanged()
|
||||||
|
|
||||||
# Now check if every registered client is already there (if logged in OFC)
|
# Now check if every registered client is already there (if logged in OFC)
|
||||||
for lost_client in clients_pool.UDSActorClientPool().lost_clients():
|
if self._loggedIn and not self._clientsPool.ping():
|
||||||
logger.info('Lost client: {}'.format(lost_client))
|
self.logout('client_unavailable', '')
|
||||||
self.logout('client_unavailable', '', lost_client.session_id or '') # '' means "all clients"
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Exception on main service loop: %s', e)
|
logger.error('Exception on main service loop: %s', e)
|
||||||
|
|
||||||
@ -495,7 +486,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
self, username: str, sessionType: typing.Optional[str] = None
|
self, username: str, sessionType: typing.Optional[str] = None
|
||||||
) -> types.LoginResultInfoType:
|
) -> types.LoginResultInfoType:
|
||||||
result = types.LoginResultInfoType(
|
result = types.LoginResultInfoType(
|
||||||
ip='', hostname='', dead_line=None, max_idle=None, session_id=None
|
ip='', hostname='', dead_line=None, max_idle=None
|
||||||
)
|
)
|
||||||
master_token = None
|
master_token = None
|
||||||
secret = None
|
secret = None
|
||||||
@ -522,9 +513,9 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
secret,
|
secret,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if result.logged_in:
|
||||||
result.session_id
|
logger.debug('Login successful')
|
||||||
): # If logged in, process it. client_pool will take account of login response to client and session
|
self._loggedIn = True
|
||||||
script = platform.store.invokeScriptOnLogin()
|
script = platform.store.invokeScriptOnLogin()
|
||||||
if script:
|
if script:
|
||||||
logger.info('Executing script on login: {}'.format(script))
|
logger.info('Executing script on login: {}'.format(script))
|
||||||
@ -533,12 +524,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def logout(
|
def logout(self, username: str, sessionType: typing.Optional[str]) -> None:
|
||||||
self,
|
|
||||||
username: str,
|
|
||||||
session_type: typing.Optional[str],
|
|
||||||
session_id: typing.Optional[str],
|
|
||||||
) -> None:
|
|
||||||
master_token = self._cfg.master_token
|
master_token = self._cfg.master_token
|
||||||
|
|
||||||
# Own token will not be set if UDS did not assigned the initialized VM to an user
|
# Own token will not be set if UDS did not assigned the initialized VM to an user
|
||||||
@ -551,26 +537,24 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
self._cfg.actorType,
|
self._cfg.actorType,
|
||||||
token,
|
token,
|
||||||
username,
|
username,
|
||||||
session_id or '',
|
sessionType or '',
|
||||||
session_type or '',
|
|
||||||
self._interfaces,
|
self._interfaces,
|
||||||
self._secret,
|
self._secret,
|
||||||
)
|
)
|
||||||
!= 'ok' # Can return also "notified", that means the logout has not been processed by UDS
|
!= 'ok'
|
||||||
):
|
):
|
||||||
logger.info(
|
logger.info('Logout from %s ignored as required by uds broker', username)
|
||||||
'Logout from %s ignored as required by uds broker', username
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.onLogout(username, session_id or '')
|
self._loggedIn = False
|
||||||
|
self.onLogout(username)
|
||||||
|
|
||||||
if not self.isManaged():
|
if not self.isManaged():
|
||||||
self.uninitialize()
|
self.uninitialize()
|
||||||
|
|
||||||
# ******************************************************
|
# ****************************************
|
||||||
# Methods that CAN BE overriden by specific OS Actor
|
# Methods that CAN BE overriden by actors
|
||||||
# ******************************************************
|
# ****************************************
|
||||||
def doWait(self, miliseconds: int) -> None:
|
def doWait(self, miliseconds: int) -> None:
|
||||||
'''
|
'''
|
||||||
Invoked to wait a bit
|
Invoked to wait a bit
|
||||||
@ -611,5 +595,5 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
return 'ok'
|
return 'ok'
|
||||||
|
|
||||||
def onLogout(self, userName: str, session_id: str) -> None:
|
def onLogout(self, userName: str) -> None:
|
||||||
logger.debug('On logout invoked for {}'.format(userName))
|
logger.debug('On logout invoked for {}'.format(userName))
|
||||||
|
@ -30,43 +30,14 @@
|
|||||||
'''
|
'''
|
||||||
import threading
|
import threading
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import time
|
|
||||||
import typing
|
import typing
|
||||||
import functools
|
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from udsactor.types import InterfaceInfoType
|
from udsactor.types import InterfaceInfoType
|
||||||
|
|
||||||
# Simple cache for n seconds (default = 30) decorator
|
|
||||||
def cache(seconds: int = 30) -> typing.Callable:
|
|
||||||
'''
|
|
||||||
Simple cache for n seconds (default = 30) decorator
|
|
||||||
'''
|
|
||||||
def decorator(func) -> typing.Callable:
|
|
||||||
@functools.wraps(func)
|
|
||||||
def wrapper(*args, **kwargs) -> typing.Any:
|
|
||||||
if not hasattr(wrapper, 'cache'):
|
|
||||||
wrapper.cache = {} # type: ignore
|
|
||||||
cache = wrapper.cache # type: ignore
|
|
||||||
|
|
||||||
# Compose a key for the cache
|
|
||||||
key = '{}:{}'.format(args, kwargs)
|
|
||||||
if key in cache:
|
|
||||||
if time.time() - cache[key][0] < seconds:
|
|
||||||
return cache[key][1]
|
|
||||||
|
|
||||||
# Call the function
|
|
||||||
result = func(*args, **kwargs)
|
|
||||||
cache[key] = (time.time(), result)
|
|
||||||
return result
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
|
|
||||||
# Simple sub-script exectution thread
|
|
||||||
class ScriptExecutorThread(threading.Thread):
|
class ScriptExecutorThread(threading.Thread):
|
||||||
|
|
||||||
def __init__(self, script: str) -> None:
|
def __init__(self, script: str) -> None:
|
||||||
super(ScriptExecutorThread, self).__init__()
|
super(ScriptExecutorThread, self).__init__()
|
||||||
self.script = script
|
self.script = script
|
||||||
@ -76,40 +47,14 @@ class ScriptExecutorThread(threading.Thread):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
logger.debug('Executing script: {}'.format(self.script))
|
logger.debug('Executing script: {}'.format(self.script))
|
||||||
exec(
|
exec(self.script, globals(), None) # pylint: disable=exec-used
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
class Singleton(type):
|
|
||||||
'''
|
|
||||||
Metaclass for singleton pattern
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
class MyClass(metaclass=Singleton):
|
|
||||||
...
|
|
||||||
'''
|
|
||||||
|
|
||||||
_instance: typing.Optional[typing.Any]
|
|
||||||
|
|
||||||
# We use __init__ so we customise the created class from this metaclass
|
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
|
||||||
self._instance = None
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs) -> typing.Any:
|
|
||||||
if self._instance is None:
|
|
||||||
self._instance = super().__call__(*args, **kwargs)
|
|
||||||
return self._instance
|
|
||||||
|
|
||||||
|
|
||||||
# Convert "X.X.X.X/X" to ipaddress.IPv4Network
|
# Convert "X.X.X.X/X" to ipaddress.IPv4Network
|
||||||
def strToNoIPV4Network(
|
def strToNoIPV4Network(net: typing.Optional[str]) -> typing.Optional[ipaddress.IPv4Network]:
|
||||||
net: typing.Optional[str],
|
|
||||||
) -> typing.Optional[ipaddress.IPv4Network]:
|
|
||||||
if not net: # Empty or None
|
if not net: # Empty or None
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
|
@ -51,22 +51,16 @@ class InitializationResultType(typing.NamedTuple):
|
|||||||
own_token: typing.Optional[str] = None
|
own_token: typing.Optional[str] = None
|
||||||
unique_id: typing.Optional[str] = None
|
unique_id: typing.Optional[str] = None
|
||||||
os: typing.Optional[ActorOsConfigurationType] = None
|
os: typing.Optional[ActorOsConfigurationType] = None
|
||||||
alias_token: typing.Optional[str] = None
|
|
||||||
|
|
||||||
class LoginResultInfoType(typing.NamedTuple):
|
class LoginResultInfoType(typing.NamedTuple):
|
||||||
ip: str
|
ip: str
|
||||||
hostname: str
|
hostname: str
|
||||||
dead_line: typing.Optional[int]
|
dead_line: typing.Optional[int]
|
||||||
max_idle: typing.Optional[int]
|
max_idle: typing.Optional[int] # Not provided by broker
|
||||||
session_id: typing.Optional[str]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def logged_in(self) -> bool:
|
def logged_in(self) -> bool:
|
||||||
return bool(self.session_id)
|
return self.hostname != '' or self.ip != ''
|
||||||
|
|
||||||
class ClientInfo(typing.NamedTuple):
|
|
||||||
url: str
|
|
||||||
session_id: str
|
|
||||||
|
|
||||||
class CertificateInfoType(typing.NamedTuple):
|
class CertificateInfoType(typing.NamedTuple):
|
||||||
private_key: str
|
private_key: str
|
||||||
|
@ -1,2 +1 @@
|
|||||||
VERSION = '4.0.0'
|
VERSION = '3.5.0'
|
||||||
BUILD = '20220901'
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# 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-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2014 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# 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-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# may be used to endorse or promote products derived from this software
|
||||||
# without specific prior written permission.
|
# without specific prior written permission.
|
||||||
#
|
#
|
||||||
@ -45,46 +45,32 @@ import win32con
|
|||||||
from .. import types
|
from .. import types
|
||||||
from ..log import logger
|
from ..log import logger
|
||||||
|
|
||||||
|
|
||||||
def checkPermissions() -> bool:
|
def checkPermissions() -> bool:
|
||||||
return shell.IsUserAnAdmin()
|
return shell.IsUserAnAdmin()
|
||||||
|
|
||||||
|
|
||||||
def getErrorMessage(resultCode: int = 0) -> str:
|
def getErrorMessage(resultCode: int = 0) -> str:
|
||||||
# sys_fs_enc = sys.getfilesystemencoding() or 'mbcs'
|
# sys_fs_enc = sys.getfilesystemencoding() or 'mbcs'
|
||||||
msg = win32api.FormatMessage(resultCode)
|
msg = win32api.FormatMessage(resultCode)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
def getComputerName() -> str:
|
def getComputerName() -> str:
|
||||||
return win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
|
return win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
|
||||||
|
|
||||||
|
|
||||||
def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]:
|
def getNetworkInfo() -> typing.Iterator[types.InterfaceInfoType]:
|
||||||
obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
|
obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
|
||||||
wmobj = obj.ConnectServer("localhost", "root\\cimv2")
|
wmobj = obj.ConnectServer("localhost", "root\\cimv2")
|
||||||
adapters = wmobj.ExecQuery(
|
adapters = wmobj.ExecQuery("Select * from Win32_NetworkAdapterConfiguration where IpEnabled=True")
|
||||||
"Select * from Win32_NetworkAdapterConfiguration where IpEnabled=True"
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
for obj in adapters:
|
for obj in adapters:
|
||||||
for ip in obj.IPAddress:
|
for ip in obj.IPAddress:
|
||||||
if ':' in ip: # Is IPV6, skip this
|
if ':' in ip: # Is IPV6, skip this
|
||||||
continue
|
continue
|
||||||
if (
|
if ip is None or ip == '' or ip.startswith('169.254') or ip.startswith('0.'): # If single link ip, or no ip
|
||||||
ip is None
|
|
||||||
or ip == ''
|
|
||||||
or ip.startswith('169.254')
|
|
||||||
or ip.startswith('0.')
|
|
||||||
): # If single link ip, or no ip
|
|
||||||
continue
|
continue
|
||||||
yield types.InterfaceInfoType(
|
yield types.InterfaceInfoType(name=obj.Caption, mac=obj.MACAddress, ip=ip)
|
||||||
name=obj.Caption, mac=obj.MACAddress, ip=ip
|
|
||||||
)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def getDomainName() -> str:
|
def getDomainName() -> str:
|
||||||
'''
|
'''
|
||||||
Will return the domain name if we belong a domain, else None
|
Will return the domain name if we belong a domain, else None
|
||||||
@ -101,19 +87,9 @@ def getDomainName() -> str:
|
|||||||
|
|
||||||
return domain
|
return domain
|
||||||
|
|
||||||
|
|
||||||
def getWindowsVersion() -> typing.Tuple[int, int, int, int, str]:
|
def getWindowsVersion() -> typing.Tuple[int, int, int, int, str]:
|
||||||
return win32api.GetVersionEx()
|
return win32api.GetVersionEx()
|
||||||
|
|
||||||
|
|
||||||
def getVersion() -> str:
|
|
||||||
verinfo = getWindowsVersion()
|
|
||||||
# Remove platform id i
|
|
||||||
return 'Windows-{}.{} Build {} ({})'.format(
|
|
||||||
verinfo[0], verinfo[1], verinfo[2], verinfo[4]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
EWX_LOGOFF = 0x00000000
|
EWX_LOGOFF = 0x00000000
|
||||||
EWX_SHUTDOWN = 0x00000001
|
EWX_SHUTDOWN = 0x00000001
|
||||||
EWX_REBOOT = 0x00000002
|
EWX_REBOOT = 0x00000002
|
||||||
@ -121,53 +97,31 @@ EWX_FORCE = 0x00000004
|
|||||||
EWX_POWEROFF = 0x00000008
|
EWX_POWEROFF = 0x00000008
|
||||||
EWX_FORCEIFHUNG = 0x00000010
|
EWX_FORCEIFHUNG = 0x00000010
|
||||||
|
|
||||||
|
|
||||||
def reboot(flags: int = EWX_FORCEIFHUNG | EWX_REBOOT) -> None:
|
def reboot(flags: int = EWX_FORCEIFHUNG | EWX_REBOOT) -> None:
|
||||||
hproc = win32api.GetCurrentProcess()
|
hproc = win32api.GetCurrentProcess()
|
||||||
htok = win32security.OpenProcessToken(
|
htok = win32security.OpenProcessToken(hproc, win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY)
|
||||||
hproc, win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
|
privs = ((win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME), win32security.SE_PRIVILEGE_ENABLED),)
|
||||||
)
|
|
||||||
privs = (
|
|
||||||
(
|
|
||||||
win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME),
|
|
||||||
win32security.SE_PRIVILEGE_ENABLED,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
win32security.AdjustTokenPrivileges(htok, 0, privs)
|
win32security.AdjustTokenPrivileges(htok, 0, privs)
|
||||||
win32api.ExitWindowsEx(flags, 0)
|
win32api.ExitWindowsEx(flags, 0)
|
||||||
|
|
||||||
|
|
||||||
def loggoff() -> None:
|
def loggoff() -> None:
|
||||||
win32api.ExitWindowsEx(EWX_LOGOFF)
|
win32api.ExitWindowsEx(EWX_LOGOFF)
|
||||||
|
|
||||||
|
|
||||||
def renameComputer(newName: str) -> bool:
|
def renameComputer(newName: str) -> bool:
|
||||||
'''
|
'''
|
||||||
Changes the computer name
|
Changes the computer name
|
||||||
Returns True if reboot needed
|
Returns True if reboot needed
|
||||||
'''
|
'''
|
||||||
# Needs admin privileges to work
|
# Needs admin privileges to work
|
||||||
if (
|
if ctypes.windll.kernel32.SetComputerNameExW(DWORD(win32con.ComputerNamePhysicalDnsHostname), LPCWSTR(newName)) == 0: # @UndefinedVariable
|
||||||
ctypes.windll.kernel32.SetComputerNameExW(
|
|
||||||
DWORD(win32con.ComputerNamePhysicalDnsHostname), LPCWSTR(newName)
|
|
||||||
)
|
|
||||||
== 0
|
|
||||||
): # @UndefinedVariable
|
|
||||||
# win32api.FormatMessage -> returns error string
|
# win32api.FormatMessage -> returns error string
|
||||||
# win32api.GetLastError -> returns error code
|
# win32api.GetLastError -> returns error code
|
||||||
# (just put this comment here to remember to log this when logger is available)
|
# (just put this comment here to remember to log this when logger is available)
|
||||||
error = getErrorMessage()
|
error = getErrorMessage()
|
||||||
computerName = win32api.GetComputerNameEx(
|
computerName = win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
|
||||||
win32con.ComputerNamePhysicalDnsHostname
|
raise Exception('Error renaming computer from {} to {}: {}'.format(computerName, newName, error))
|
||||||
)
|
|
||||||
raise Exception(
|
|
||||||
'Error renaming computer from {} to {}: {}'.format(
|
|
||||||
computerName, newName, error
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
NETSETUP_JOIN_DOMAIN = 0x00000001
|
NETSETUP_JOIN_DOMAIN = 0x00000001
|
||||||
NETSETUP_ACCT_CREATE = 0x00000002
|
NETSETUP_ACCT_CREATE = 0x00000002
|
||||||
NETSETUP_ACCT_DELETE = 0x00000004
|
NETSETUP_ACCT_DELETE = 0x00000004
|
||||||
@ -178,10 +132,7 @@ NETSETUP_MACHINE_PWD_PASSED = 0x00000080
|
|||||||
NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400
|
NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400
|
||||||
NETSETUP_DEFER_SPN_SET = 0x1000000
|
NETSETUP_DEFER_SPN_SET = 0x1000000
|
||||||
|
|
||||||
|
def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False) -> None:
|
||||||
def joinDomain(
|
|
||||||
domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False
|
|
||||||
) -> None:
|
|
||||||
'''
|
'''
|
||||||
Joins machine to a windows domain
|
Joins machine to a windows domain
|
||||||
:param domain: Domain to join to
|
:param domain: Domain to join to
|
||||||
@ -198,9 +149,7 @@ def joinDomain(
|
|||||||
account = domain + '\\' + account
|
account = domain + '\\' + account
|
||||||
|
|
||||||
# Do log
|
# Do log
|
||||||
flags: typing.Any = (
|
flags: typing.Any = NETSETUP_ACCT_CREATE | NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN
|
||||||
NETSETUP_ACCT_CREATE | NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN
|
|
||||||
)
|
|
||||||
|
|
||||||
if executeInOneStep:
|
if executeInOneStep:
|
||||||
flags |= NETSETUP_JOIN_WITH_NEW_NAME
|
flags |= NETSETUP_JOIN_WITH_NEW_NAME
|
||||||
@ -214,31 +163,18 @@ def joinDomain(
|
|||||||
lpAccount = LPCWSTR(account)
|
lpAccount = LPCWSTR(account)
|
||||||
lpPassword = LPCWSTR(password)
|
lpPassword = LPCWSTR(password)
|
||||||
|
|
||||||
res = ctypes.windll.netapi32.NetJoinDomain(
|
res = ctypes.windll.netapi32.NetJoinDomain(None, lpDomain, lpOu, lpAccount, lpPassword, flags)
|
||||||
None, lpDomain, lpOu, lpAccount, lpPassword, flags
|
|
||||||
)
|
|
||||||
# Machine found in another ou, use it and warn this on log
|
# Machine found in another ou, use it and warn this on log
|
||||||
if res == 2224:
|
if res == 2224:
|
||||||
flags = DWORD(NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN)
|
flags = DWORD(NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN)
|
||||||
res = ctypes.windll.netapi32.NetJoinDomain(
|
res = ctypes.windll.netapi32.NetJoinDomain(None, lpDomain, None, lpAccount, lpPassword, flags)
|
||||||
None, lpDomain, None, lpAccount, lpPassword, flags
|
|
||||||
)
|
|
||||||
if res:
|
if res:
|
||||||
# Log the error
|
# Log the error
|
||||||
error = getErrorMessage(res)
|
error = getErrorMessage(res)
|
||||||
if res == 1355:
|
if res == 1355:
|
||||||
error = "DC Is not reachable"
|
error = "DC Is not reachable"
|
||||||
logger.error('Error joining domain: {}, {}'.format(error, res))
|
logger.error('Error joining domain: {}, {}'.format(error, res))
|
||||||
raise Exception(
|
raise Exception('Error joining domain {}, with credentials {}/*****{}: {}, {}'.format(domain, account, ', under OU {}'.format(ou) if ou is not None else '', res, error))
|
||||||
'Error joining domain {}, with credentials {}/*****{}: {}, {}'.format(
|
|
||||||
domain,
|
|
||||||
account,
|
|
||||||
', under OU {}'.format(ou) if ou is not None else '',
|
|
||||||
res,
|
|
||||||
error,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
|
def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
|
||||||
# lpUser = LPCWSTR(user)
|
# lpUser = LPCWSTR(user)
|
||||||
@ -252,10 +188,7 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
|
|||||||
if res:
|
if res:
|
||||||
# Log the error, and raise exception to parent
|
# Log the error, and raise exception to parent
|
||||||
error = getErrorMessage(res)
|
error = getErrorMessage(res)
|
||||||
raise Exception(
|
raise Exception('Error changing password for user {}: {} {}'.format(user, res, error))
|
||||||
'Error changing password for user {}: {} {}'.format(user, res, error)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class LASTINPUTINFO(ctypes.Structure): # pylint: disable=too-few-public-methods
|
class LASTINPUTINFO(ctypes.Structure): # pylint: disable=too-few-public-methods
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
@ -263,20 +196,16 @@ class LASTINPUTINFO(ctypes.Structure): # pylint: disable=too-few-public-methods
|
|||||||
('dwTime', ctypes.c_uint),
|
('dwTime', ctypes.c_uint),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def initIdleDuration(atLeastSeconds: int): # pylint: disable=unused-argument
|
def initIdleDuration(atLeastSeconds: int): # pylint: disable=unused-argument
|
||||||
'''
|
'''
|
||||||
In windows, there is no need to set screensaver
|
In windows, there is no need to set screensaver
|
||||||
'''
|
'''
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def getIdleDuration() -> float:
|
def getIdleDuration() -> float:
|
||||||
try:
|
try:
|
||||||
lastInputInfo = LASTINPUTINFO()
|
lastInputInfo = LASTINPUTINFO()
|
||||||
lastInputInfo.cbSize = ctypes.sizeof(
|
lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo) # pylint: disable=attribute-defined-outside-init
|
||||||
lastInputInfo
|
|
||||||
) # pylint: disable=attribute-defined-outside-init
|
|
||||||
if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo)) == 0:
|
if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo)) == 0:
|
||||||
return 0
|
return 0
|
||||||
current = ctypes.c_uint(ctypes.windll.kernel32.GetTickCount()).value
|
current = ctypes.c_uint(ctypes.windll.kernel32.GetTickCount()).value
|
||||||
@ -288,14 +217,12 @@ def getIdleDuration() -> float:
|
|||||||
logger.error('Getting idle duration: {}'.format(e))
|
logger.error('Getting idle duration: {}'.format(e))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def getCurrentUser() -> str:
|
def getCurrentUser() -> str:
|
||||||
'''
|
'''
|
||||||
Returns current logged in username
|
Returns current logged in username
|
||||||
'''
|
'''
|
||||||
return os.environ['USERNAME']
|
return os.environ['USERNAME']
|
||||||
|
|
||||||
|
|
||||||
def getSessionType() -> str:
|
def getSessionType() -> str:
|
||||||
'''
|
'''
|
||||||
Known values:
|
Known values:
|
||||||
@ -305,10 +232,7 @@ def getSessionType() -> str:
|
|||||||
'''
|
'''
|
||||||
return os.environ.get('SESSIONNAME', 'unknown')
|
return os.environ.get('SESSIONNAME', 'unknown')
|
||||||
|
|
||||||
|
def writeToPipe(pipeName: str, bytesPayload: bytes, waitForResponse: bool) -> typing.Optional[bytes]:
|
||||||
def writeToPipe(
|
|
||||||
pipeName: str, bytesPayload: bytes, waitForResponse: bool
|
|
||||||
) -> typing.Optional[bytes]:
|
|
||||||
# (str, bytes, bool) -> Optional[bytes]
|
# (str, bytes, bool) -> Optional[bytes]
|
||||||
try:
|
try:
|
||||||
with open(pipeName, 'r+b', 0) as f:
|
with open(pipeName, 'r+b', 0) as f:
|
||||||
@ -320,11 +244,8 @@ def writeToPipe(
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def forceTimeSync() -> None:
|
def forceTimeSync() -> None:
|
||||||
try:
|
try:
|
||||||
subprocess.call(
|
subprocess.call([r'c:\WINDOWS\System32\w32tm.exe', ' /resync']) # , '/rediscover'])
|
||||||
[r'c:\WINDOWS\System32\w32tm.exe', ' /resync']
|
|
||||||
) # , '/rediscover'])
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Error invoking time sync command: %s', e)
|
logger.error('Error invoking time sync command: %s', e)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2019-2022 Virtual Cable S.L.U.
|
# Copyright (c) 2019 Virtual Cable S.L.
|
||||||
# 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.U. nor the names of its contributors
|
# * 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
|
# may be used to endorse or promote products derived from this software
|
||||||
# without specific prior written permission.
|
# without specific prior written permission.
|
||||||
#
|
#
|
||||||
|
@ -183,7 +183,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
operations.writeToPipe("\\\\.\\pipe\\VDSMDPipe", packet, True)
|
operations.writeToPipe("\\\\.\\pipe\\VDSMDPipe", packet, True)
|
||||||
return 'done'
|
return 'done'
|
||||||
|
|
||||||
def onLogout(self, userName: str, session_id: str) -> None:
|
def onLogout(self, userName) -> None:
|
||||||
logger.debug('Windows onLogout invoked: {}, {}'.format(userName, self._user))
|
logger.debug('Windows onLogout invoked: {}, {}'.format(userName, self._user))
|
||||||
try:
|
try:
|
||||||
p = win32security.GetBinarySid(REMOTE_USERS_SID)
|
p = win32security.GetBinarySid(REMOTE_USERS_SID)
|
||||||
|
@ -146,7 +146,7 @@ class Ui_UdsActorSetupDialog(object):
|
|||||||
self.host.setToolTip(_translate("UdsActorSetupDialog", "Uds Broker Server Addres. Use IP or FQDN"))
|
self.host.setToolTip(_translate("UdsActorSetupDialog", "Uds Broker Server Addres. Use IP or FQDN"))
|
||||||
self.host.setWhatsThis(_translate("UdsActorSetupDialog", "Enter here the UDS Broker Addres using either its IP address or its FQDN address"))
|
self.host.setWhatsThis(_translate("UdsActorSetupDialog", "Enter here the UDS Broker Addres using either its IP address or its FQDN address"))
|
||||||
self.label_serviceToken.setText(_translate("UdsActorSetupDialog", "Service Token"))
|
self.label_serviceToken.setText(_translate("UdsActorSetupDialog", "Service Token"))
|
||||||
self.serviceToken.setToolTip(_translate("UdsActorSetupDialog", "UDS Service Token"))
|
self.serviceToken.setToolTip(_translate("UdsActorSetupDialog", "UDS user with administration rights (Will not be stored on template)"))
|
||||||
self.serviceToken.setWhatsThis(_translate("UdsActorSetupDialog", "<html><head/><body><p>Administrator user on UDS Server.</p><p>Note: This credential will not be stored on client. Will be used to obtain an unique token for this image.</p></body></html>"))
|
self.serviceToken.setWhatsThis(_translate("UdsActorSetupDialog", "<html><head/><body><p>Administrator user on UDS Server.</p><p>Note: This credential will not be stored on client. Will be used to obtain an unique token for this image.</p></body></html>"))
|
||||||
self.label_loglevel.setText(_translate("UdsActorSetupDialog", "Log Level"))
|
self.label_loglevel.setText(_translate("UdsActorSetupDialog", "Log Level"))
|
||||||
self.label_restrictNet.setText(_translate("UdsActorSetupDialog", "Restrict Net"))
|
self.label_restrictNet.setText(_translate("UdsActorSetupDialog", "Restrict Net"))
|
||||||
|
@ -1,15 +1,3 @@
|
|||||||
udsclient3 (4.0.0) stable; urgency=medium
|
|
||||||
|
|
||||||
* Upgraded to 4.0.0 release
|
|
||||||
|
|
||||||
-- Adolfo Gómez García <agomez@virtualcable.es> Fri, 1 Jul 2022 15:12:10 +0200
|
|
||||||
|
|
||||||
udsclient3 (4.0.0) stable; urgency=medium
|
|
||||||
|
|
||||||
* Upgraded to 3.6.0 release
|
|
||||||
|
|
||||||
-- Adolfo Gómez García <agomez@virtualcable.es> Fri, 1 Jul 2022 14:12:10 +0200
|
|
||||||
|
|
||||||
udsclient3 (3.5.0) stable; urgency=medium
|
udsclient3 (3.5.0) stable; urgency=medium
|
||||||
|
|
||||||
* Upgraded to 3.5.0 release
|
* Upgraded to 3.5.0 release
|
||||||
|
@ -1 +1 @@
|
|||||||
10
|
9
|
@ -1,2 +1,2 @@
|
|||||||
udsclient3_4.0.0_all.deb admin optional
|
udsclient3_3.5.0_all.deb admin optional
|
||||||
udsclient3_4.0.0_amd64.buildinfo admin optional
|
udsclient3_3.5.0_amd64.buildinfo admin optional
|
||||||
|
@ -38,7 +38,7 @@ import webbrowser
|
|||||||
import threading
|
import threading
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
from PyQt5 import QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import QSettings
|
from PyQt5.QtCore import QSettings
|
||||||
|
|
||||||
from uds.rest import RestApi, RetryException, InvalidVersion, UDSException
|
from uds.rest import RestApi, RetryException, InvalidVersion, UDSException
|
||||||
@ -79,10 +79,10 @@ class UDSClient(QtWidgets.QMainWindow):
|
|||||||
|
|
||||||
self.ui.info.setText('Initializing...')
|
self.ui.info.setText('Initializing...')
|
||||||
|
|
||||||
screen_geometry = QtGui.QGuiApplication.primaryScreen().geometry()
|
screen = QtWidgets.QDesktopWidget().screenGeometry()
|
||||||
mysize = self.geometry()
|
mysize = self.geometry()
|
||||||
hpos = (screen_geometry.width() - mysize.width()) // 2
|
hpos = (screen.width() - mysize.width()) // 2
|
||||||
vpos = (screen_geometry.height() - mysize.height() - mysize.height()) // 2
|
vpos = (screen.height() - mysize.height() - mysize.height()) // 2
|
||||||
self.move(hpos, vpos)
|
self.move(hpos, vpos)
|
||||||
|
|
||||||
self.animTimer = QtCore.QTimer()
|
self.animTimer = QtCore.QTimer()
|
||||||
|
@ -45,7 +45,7 @@ class UdsApplication(QtWidgets.QApplication):
|
|||||||
tunnel.kill()
|
tunnel.kill()
|
||||||
|
|
||||||
def event(self, evnt: QtCore.QEvent) -> bool:
|
def event(self, evnt: QtCore.QEvent) -> bool:
|
||||||
if evnt.type() == QtCore.QEvent.FileOpen: # type: ignore
|
if evnt.type() == QtCore.QEvent.FileOpen:
|
||||||
fe = typing.cast(QtGui.QFileOpenEvent, evnt)
|
fe = typing.cast(QtGui.QFileOpenEvent, evnt)
|
||||||
logger.debug('Got url: %s', fe.url().url())
|
logger.debug('Got url: %s', fe.url().url())
|
||||||
fe.accept()
|
fe.accept()
|
||||||
|
@ -29,11 +29,13 @@
|
|||||||
'''
|
'''
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
'''
|
'''
|
||||||
VERSION = '3.6.0'
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
VERSION = '3.5.0'
|
||||||
|
|
||||||
__title__ = 'udclient'
|
__title__ = 'udclient'
|
||||||
__version__ = VERSION
|
__version__ = VERSION
|
||||||
__build__ = 0x010712
|
__build__ = 0x010760
|
||||||
__author__ = 'Adolfo Gómez <dkmaster@dkmon.com>'
|
__author__ = 'Adolfo Gómez'
|
||||||
__license__ = "BSD 3-clause"
|
__license__ = "BSD 3-clause"
|
||||||
__copyright__ = "Copyright 2014-2022 VirtualCable S.L.U."
|
__copyright__ = "Copyright 2014-2017 VirtualCable S.L.U."
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2022 Virtual Cable S.L.U.
|
# Copyright (c) 2021 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,
|
||||||
|
10
legacy_actors/.gitignore
vendored
Normal file
10
legacy_actors/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
bin
|
||||||
|
*_enterprise*
|
||||||
|
udsactor*.deb
|
||||||
|
udsactor*.build
|
||||||
|
udsactor*.changes
|
||||||
|
/udsactor_*.dsc
|
||||||
|
/udsactor_*.tar.xz
|
||||||
|
/udsactor_*_amd64.buildinfo
|
||||||
|
/udsactor*.rpm
|
||||||
|
linux/debian/files
|
17
legacy_actors/.project
Normal file
17
legacy_actors/.project
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>actors</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.python.pydev.PyDevBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.python.pydev.pythonNature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
8
legacy_actors/.pydevproject
Normal file
8
legacy_actors/.pydevproject
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||||
|
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||||
|
<path>/${PROJECT_DIR_NAME}/src</path>
|
||||||
|
</pydev_pathproperty>
|
||||||
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
|
||||||
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||||
|
</pydev_project>
|
1
legacy_actors/linux/.gitignore
vendored
Normal file
1
legacy_actors/linux/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/udsactor-*[1-9].*.spec
|
98
legacy_actors/linux/Makefile
Normal file
98
legacy_actors/linux/Makefile
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
|
||||||
|
# Directories
|
||||||
|
SOURCEDIR := ../src
|
||||||
|
LIBDIR := $(DESTDIR)/usr/share/UDSActor
|
||||||
|
BINDIR := $(DESTDIR)/usr/bin
|
||||||
|
SBINDIR = $(DESTDIR)/usr/sbin
|
||||||
|
APPSDIR := $(DESTDIR)/usr/share/applications
|
||||||
|
CFGDIR := $(DESTDIR)/etc/udsactor
|
||||||
|
INITDIR := $(DESTDIR)/etc/init.d
|
||||||
|
POLKITDIR := $(DESTDIR)/usr/share/polkit-1/actions/
|
||||||
|
XDGAUTOSTARTDIR := $(DESTDIR)/etc/xdg/autostart
|
||||||
|
KDEAUTOSTARTDIR := $(DESTDIR)/usr/share/autostart
|
||||||
|
|
||||||
|
PYC := $(shell find $(SOURCEDIR) -name '*.py[co]')
|
||||||
|
CACHES := $(shell find $(SOURCEDIR) -name '__pycache__')
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(PYC) $(CACHES) $(DESTDIR)
|
||||||
|
install-udsactor-xrdp:
|
||||||
|
mkdir -p $(BINDIR)
|
||||||
|
cp scripts/uds-sesman.sh $(BINDIR)/uds-sesman
|
||||||
|
cp scripts/uds-wait-session.sh $(BINDIR)/uds-wait-session
|
||||||
|
|
||||||
|
chmod 0755 $(BINDIR)/uds-sesman
|
||||||
|
chmod 0755 $(BINDIR)/uds-wait-session
|
||||||
|
|
||||||
|
install-udsactor-nx:
|
||||||
|
mkdir -p $(BINDIR)
|
||||||
|
cp scripts/udsnxstart.sh $(BINDIR)/udsnxstart
|
||||||
|
cp scripts/udsnxstop.sh $(BINDIR)/udsnxstop
|
||||||
|
|
||||||
|
chmod 0755 $(BINDIR)/udsnxstart
|
||||||
|
chmod 0755 $(BINDIR)/udsnxstop
|
||||||
|
install-udsactor:
|
||||||
|
rm -rf $(DESTDIR)
|
||||||
|
mkdir -p $(LIBDIR)
|
||||||
|
mkdir -p $(BINDIR)
|
||||||
|
mkdir -p $(SBINDIR)
|
||||||
|
mkdir -p $(APPSDIR)
|
||||||
|
mkdir -p $(CFGDIR)
|
||||||
|
mkdir -p $(POLKITDIR)
|
||||||
|
mkdir -p $(XDGAUTOSTARTDIR)
|
||||||
|
mkdir -p $(KDEAUTOSTARTDIR)
|
||||||
|
|
||||||
|
mkdir $(LIBDIR)/img
|
||||||
|
|
||||||
|
# Cleans up .pyc and cache folders
|
||||||
|
rm -f $(PYC) $(CACHES)
|
||||||
|
|
||||||
|
cp -r $(SOURCEDIR)/udsactor $(LIBDIR)/udsactor
|
||||||
|
cp $(SOURCEDIR)/img/uds.png $(LIBDIR)/img
|
||||||
|
|
||||||
|
cp $(SOURCEDIR)/UDSActorConfig.py $(LIBDIR)
|
||||||
|
cp $(SOURCEDIR)/UDSActorUser.py $(LIBDIR)
|
||||||
|
# QT Dialogs & resources
|
||||||
|
cp $(SOURCEDIR)/*_ui.py $(LIBDIR)
|
||||||
|
cp $(SOURCEDIR)/UDSActor_rc.py $(LIBDIR)
|
||||||
|
|
||||||
|
# Menu GUI app
|
||||||
|
cp desktop/UDS_Actor_Configuration.desktop $(APPSDIR)
|
||||||
|
|
||||||
|
# Autostart elements for gnome/kde
|
||||||
|
cp desktop/UDSActorTool.desktop $(XDGAUTOSTARTDIR)
|
||||||
|
cp desktop/UDSActorTool.desktop $(KDEAUTOSTARTDIR)
|
||||||
|
|
||||||
|
# scripts
|
||||||
|
cp scripts/udsactor $(BINDIR)
|
||||||
|
cp scripts/UDSActorConfig-pkexec $(SBINDIR)
|
||||||
|
cp scripts/UDSActorTool-startup $(BINDIR)
|
||||||
|
cp scripts/udsvapp ${BINDIR}
|
||||||
|
|
||||||
|
# Policy to run as administrator
|
||||||
|
cp policy/org.openuds.pkexec.UDSActorConfig.policy $(POLKITDIR)
|
||||||
|
|
||||||
|
# Fix permissions
|
||||||
|
chmod 755 $(BINDIR)/udsactor
|
||||||
|
chmod 755 $(BINDIR)/udsvapp
|
||||||
|
chmod 755 $(BINDIR)/UDSActorTool-startup
|
||||||
|
chmod 755 $(SBINDIR)/UDSActorConfig-pkexec
|
||||||
|
chmod 755 $(LIBDIR)/UDSActorConfig.py
|
||||||
|
chmod 755 $(LIBDIR)/UDSActorUser.py
|
||||||
|
chmod 644 $(POLKITDIR)/org.openuds.pkexec.UDSActorConfig.policy
|
||||||
|
|
||||||
|
# If for red hat based, copy init.d
|
||||||
|
ifeq ($(DISTRO),rh)
|
||||||
|
mkdir -p $(INITDIR)
|
||||||
|
cp debian/udsactor.init $(INITDIR)/udsactor
|
||||||
|
ln -s /usr/share/UDSActor/UDSActorConfig.py $(SBINDIR)/UDSActorConfig
|
||||||
|
ln -s /usr/share/UDSActor/UDSActorUser.py $(BINDIR)/UDSActorTool
|
||||||
|
endif
|
||||||
|
|
||||||
|
# chmod 0755 $(BINDIR)/udsactor
|
||||||
|
uninstall:
|
||||||
|
rm -rf $(LIBDIR)
|
||||||
|
# rm -f $(BINDIR)/udsactor
|
||||||
|
rm -rf $(CFGDIR)
|
34
legacy_actors/linux/build-packages.sh
Executable file
34
legacy_actors/linux/build-packages.sh
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
VERSION=`cat ../../VERSION`
|
||||||
|
RELEASE=1
|
||||||
|
|
||||||
|
top=`pwd`
|
||||||
|
|
||||||
|
# Debian based
|
||||||
|
dpkg-buildpackage -b
|
||||||
|
|
||||||
|
cat udsactor-template.spec |
|
||||||
|
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
||||||
|
sed -e s/"release 1"/"release ${RELEASE}"/g > udsactor-$VERSION.spec
|
||||||
|
|
||||||
|
# Now fix dependencies for opensuse
|
||||||
|
cat udsactor-template.spec |
|
||||||
|
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
||||||
|
sed -e s/"name udsactor"/"name udsactor-opensuse"/g |
|
||||||
|
sed -e s/"PyQt4"/"python-qt4"/g |
|
||||||
|
sed -e s/"libXScrnSaver"/"libXss1"/g > udsactor-opensuse-$VERSION.spec
|
||||||
|
|
||||||
|
|
||||||
|
# Right now, udsactor-xrdp-1.7.0.spec is not needed
|
||||||
|
for pkg in udsactor-$VERSION.spec udsactor-opensuse-$VERSION.spec; do
|
||||||
|
|
||||||
|
rm -rf rpm
|
||||||
|
for folder in SOURCES BUILD RPMS SPECS SRPMS; do
|
||||||
|
mkdir -p rpm/$folder
|
||||||
|
done
|
||||||
|
|
||||||
|
rpmbuild -v -bb --clean --buildroot=$top/rpm/BUILD/$pkg-root --target noarch $pkg 2>&1
|
||||||
|
done
|
||||||
|
|
||||||
|
#rm udsactor-$VERSION
|
3
legacy_actors/linux/debian/.gitignore
vendored
Normal file
3
legacy_actors/linux/debian/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/udsactor/
|
||||||
|
/udsactor-xrdp/
|
||||||
|
/udsactor-nx/
|
53
legacy_actors/linux/debian/changelog
Normal file
53
legacy_actors/linux/debian/changelog
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
udsactor (3.0.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Upgraded to 3.0.0 release
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Wed, 10 Jul 2019 9:24:10 +0200
|
||||||
|
|
||||||
|
udsactor (2.2.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Upgraded to 2.2.1 release
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Thu, 2 Oct 2018 12:44:12 +0200
|
||||||
|
|
||||||
|
udsactor (2.2.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Upgraded to 2.2.0 release
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Thu, 19 Oct 2017 16:44:12 +0200
|
||||||
|
|
||||||
|
udsactor (2.1.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Fixes for 2.1.0 release
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 19 Jan 2017 08:00:22 +0200
|
||||||
|
|
||||||
|
udsactor (2.0.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Upgrade for 2.0.0
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 01 Mar 2016 03:39:21 +0100
|
||||||
|
|
||||||
|
udsactor (1.9.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Upgrade for 1.9.1
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 01 Mar 2016 03:19:21 +0100
|
||||||
|
|
||||||
|
udsactor (1.9.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Upgrade for 1.9.0 (fixed package version)
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 05 May 2015 07:10:27 +0200
|
||||||
|
|
||||||
|
udsactor (1.7.5) stable; urgency=medium
|
||||||
|
|
||||||
|
* Upgrade for 1.7.5
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Thu, 23 Apr 2015 06:08:53 +0200
|
||||||
|
|
||||||
|
udsactor (1.7.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Initial release.
|
||||||
|
|
||||||
|
-- Adolfo Gómez García <agomez@virtualcable.es> Mon, 17 Nov 2014 05:32:41 +0100
|
1
legacy_actors/linux/debian/compat
Normal file
1
legacy_actors/linux/debian/compat
Normal file
@ -0,0 +1 @@
|
|||||||
|
9
|
17
legacy_actors/linux/debian/control
Normal file
17
legacy_actors/linux/debian/control
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Source: udsactor
|
||||||
|
Section: admin
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: Adolfo Gómez García <agomez@virtualcable.es>
|
||||||
|
Build-Depends: debhelper (>= 7), po-debconf
|
||||||
|
Standards-Version: 3.9.2
|
||||||
|
Homepage: http://www.virtualcable.es
|
||||||
|
|
||||||
|
Package: udsactor
|
||||||
|
Section: admin
|
||||||
|
Priority: optional
|
||||||
|
Architecture: all
|
||||||
|
Depends: policykit-1(>=0.100), python3-requests (>=0.8.2), python3-pyqt4 (>=4.9), python3-six(>=1.1), python3 (>=3.4), libxss1, xscreensaver, ${misc:Depends}
|
||||||
|
Recommends: python3-prctl(>=1.1.1)
|
||||||
|
Description: Actor for Universal Desktop Services (UDS) Broker
|
||||||
|
This package provides the required components to allow this machine to work on an environment managed by UDS Broker.
|
||||||
|
|
26
legacy_actors/linux/debian/copyright
Normal file
26
legacy_actors/linux/debian/copyright
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
|
||||||
|
Name: udsactor
|
||||||
|
Maintainer: Adolfo Gómez García
|
||||||
|
Source: http://www.udsenterprise.com/
|
||||||
|
|
||||||
|
Copyright: 2014 Virtual Cable S.L.U.
|
||||||
|
License: BSD-3-clause
|
||||||
|
|
||||||
|
License: GPL-2+
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
.
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
.
|
||||||
|
On Debian systems, the full text of the GNU General Public
|
||||||
|
License version 2 can be found in the file
|
||||||
|
`/usr/share/common-licenses/GPL-2'.
|
1
legacy_actors/linux/debian/docs
Normal file
1
legacy_actors/linux/debian/docs
Normal file
@ -0,0 +1 @@
|
|||||||
|
readme.txt
|
46
legacy_actors/linux/debian/rules
Executable file
46
legacy_actors/linux/debian/rules
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
configure: configure-stamp
|
||||||
|
configure-stamp:
|
||||||
|
dh_testdir
|
||||||
|
touch configure-stamp
|
||||||
|
build: build-arch build-indep
|
||||||
|
build-arch: build-stamp
|
||||||
|
build-indep: build-stamp
|
||||||
|
build-stamp: configure-stamp
|
||||||
|
dh_testdir
|
||||||
|
$(MAKE)
|
||||||
|
touch $@
|
||||||
|
clean:
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
rm -f build-stamp configure-stamp
|
||||||
|
dh_clean
|
||||||
|
install: build
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_prep
|
||||||
|
dh_installdirs
|
||||||
|
$(MAKE) DESTDIR=$(CURDIR)/debian/udsactor install-udsactor
|
||||||
|
$(MAKE) DESTDIR=$(CURDIR)/debian/udsactor-xrdp install-udsactor-xrdp
|
||||||
|
$(MAKE) DESTDIR=$(CURDIR)/debian/udsactor-nx install-udsactor-nx
|
||||||
|
binary-arch: build install
|
||||||
|
# emptyness
|
||||||
|
binary-indep: build install
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_installchangelogs
|
||||||
|
dh_installdocs
|
||||||
|
dh_installdebconf
|
||||||
|
dh_installinit --no-start
|
||||||
|
dh_python2=python
|
||||||
|
dh_compress
|
||||||
|
dh_link
|
||||||
|
dh_fixperms
|
||||||
|
dh_installdeb
|
||||||
|
dh_shlibdeps
|
||||||
|
dh_gencontrol
|
||||||
|
dh_md5sums
|
||||||
|
dh_builddeb
|
||||||
|
binary: binary-indep
|
||||||
|
.PHONY: build clean binary-indep binary install configure
|
1
legacy_actors/linux/debian/source/format
Normal file
1
legacy_actors/linux/debian/source/format
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.0 (native)
|
37
legacy_actors/linux/debian/udsactor-nx.postinst
Normal file
37
legacy_actors/linux/debian/udsactor-nx.postinst
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
NXNODECFG=/usr/NX/etc/node.cfg
|
||||||
|
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
configure)
|
||||||
|
TMPFILE=$(mktemp /tmp/node.cfg.XXXXX)
|
||||||
|
trap "rm -f $TMPFILE" 0
|
||||||
|
cat $NXNODECFG | sed -e "s/.*udsnxst.*//; s/\(UserScriptAfterSessionStart *=.*\)/#\1/;s/\(UserScriptAfterSessionClose *=.*\)/#\1/" > $TMPFILE
|
||||||
|
echo >> $TMPFILE
|
||||||
|
echo "# Added by udsactor-nx (udsnxstart and udsnxstop)" >> $TMPFILE
|
||||||
|
echo UserScriptAfterSessionStart = \"/usr/bin/udsnxstart\" >> $TMPFILE
|
||||||
|
echo UserScriptAfterSessionClose = \"/usr/bin/udsnxstop\" >> $TMPFILE
|
||||||
|
cp $TMPFILE $NXNODECFG
|
||||||
|
invoke-rc.d nxserver restart
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade|abort-remove|abort-deconfigure)
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postinst called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
# Don't know why, but descriptors get "weird" when launched daemon, so we tell here to debconf to stop.
|
||||||
|
# Solved not starting the service right now, defered to next reboot
|
||||||
|
|
||||||
|
|
||||||
|
exit 0
|
30
legacy_actors/linux/debian/udsactor-nx.postrm
Normal file
30
legacy_actors/linux/debian/udsactor-nx.postrm
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
NXNODECFG=/usr/NX/etc/node.cfg
|
||||||
|
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
purge)
|
||||||
|
;;
|
||||||
|
remove)
|
||||||
|
if [ -f $NXNODECFG ]; then
|
||||||
|
TMPFILE=$(mktemp /tmp/node.cfg.XXXXX)
|
||||||
|
trap "rm -f $TMPFILE" 0
|
||||||
|
cat $NXNODECFG | sed -e "s/.*udsnxst.*//" > $TMPFILE
|
||||||
|
cp $TMPFILE $NXNODECFG
|
||||||
|
invoke-rc.d nxserver restart
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postrm called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
#DEBHELPER#
|
39
legacy_actors/linux/debian/udsactor-xrdp.postinst
Normal file
39
legacy_actors/linux/debian/udsactor-xrdp.postinst
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
SESMANFILE=/etc/pam.d/xrdp-sesman
|
||||||
|
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
configure)
|
||||||
|
trap "cp $SESMANFILE $SESMANFILE.uds.old" 0
|
||||||
|
|
||||||
|
TMPFILE=$(mktemp /tmp/sesman.XXXXX)
|
||||||
|
trap "rm -f $TMPFILE" 0
|
||||||
|
grep -v uds $SESMANFILE > $TMPFILE # Removes all UDS lines from sesman if they exists
|
||||||
|
|
||||||
|
echo >> $TMPFILE
|
||||||
|
echo "# Added by udsactor-xrdp" >> $TMPFILE
|
||||||
|
echo "session optional pam_exec.so /usr/bin/uds-sesman" >> $TMPFILE
|
||||||
|
cp $TMPFILE $SESMANFILE
|
||||||
|
trap "rm -f $TMPFILE" 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade|abort-remove|abort-deconfigure)
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postinst called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
# Don't know why, but descriptors get "weird" when launched daemon, so we tell here to debconf to stop.
|
||||||
|
# Solved not starting the service right now, defered to next reboot
|
||||||
|
|
||||||
|
|
||||||
|
exit 0
|
30
legacy_actors/linux/debian/udsactor-xrdp.postrm
Normal file
30
legacy_actors/linux/debian/udsactor-xrdp.postrm
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
SESMANFILE=/etc/pam.d/xrdp-sesman
|
||||||
|
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
purge)
|
||||||
|
;;
|
||||||
|
remove)
|
||||||
|
if [ -f $SESMANFILE ]; then
|
||||||
|
TMPFILE=$(mktemp /tmp/sesman.XXXXX)
|
||||||
|
trap "rm -f $TMPFILE" 0
|
||||||
|
grep -v uds $SESMANFILE > $TMPFILE # Removes all UDS lines from sesman if they exists
|
||||||
|
cp $TMPFILE $SESMANFILE
|
||||||
|
trap "rm -f $TMPFILE" 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postrm called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
#DEBHELPER#
|
45
legacy_actors/linux/debian/udsactor.config
Executable file
45
legacy_actors/linux/debian/udsactor.config
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
db_version 2.0
|
||||||
|
|
||||||
|
# This conf script is capable of backing up
|
||||||
|
db_capb backup
|
||||||
|
|
||||||
|
if [ -f /etc/udsactor/udsactor.cfg ] && [ "$1" != "reconfigure" ]; then
|
||||||
|
echo "/etc/udsactor/udsactor.cfg already exists, leaving untouched."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
STATE=1
|
||||||
|
while [ "$STATE" != 0 -a "$STATE" != 4 ]; do
|
||||||
|
case "$STATE" in
|
||||||
|
1)
|
||||||
|
db_input high udsactor/host || true
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
db_input high udsactor/secure || true
|
||||||
|
;;
|
||||||
|
3)
|
||||||
|
db_input high udsactor/masterKey || true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if db_go; then
|
||||||
|
STATE=$(($STATE + 1))
|
||||||
|
else
|
||||||
|
STATE=$(($STATE - 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
# If "cancelled", exit
|
||||||
|
if [ "$STATE" = 0 ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If using reconfigure, and already exists an configuration file, move it to a backup
|
||||||
|
if [ -f /etc/udsactor/udsactor.cfg ] && [ "$1" = "reconfigure" ]; then
|
||||||
|
echo "/etc/udsactor.cfg backup to /etc/udsactor.cfg.back"
|
||||||
|
mv /etc/udsactor/udsactor.cfg /etc/udsactor/udsactor.cfg.back
|
||||||
|
fi
|
23
legacy_actors/linux/debian/udsactor.init
Executable file
23
legacy_actors/linux/debian/udsactor.init
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: udsactor
|
||||||
|
# Required-Start: $local_fs $remote_fs $network $syslog $named
|
||||||
|
# Required-Stop: $local_fs $remote_fs $network $syslog $named
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: UDS Actor
|
||||||
|
### END INIT INFO
|
||||||
|
#
|
||||||
|
|
||||||
|
# . /lib/lsb/init-functions
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start|stop|restart)
|
||||||
|
/usr/bin/udsactor $1
|
||||||
|
;;
|
||||||
|
force-reload)
|
||||||
|
/usr/bin/udsactor restart
|
||||||
|
;;
|
||||||
|
*) echo "Usage: $0 {start|stop|restart|force-reload}" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
2
legacy_actors/linux/debian/udsactor.links
Normal file
2
legacy_actors/linux/debian/udsactor.links
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/usr/share/UDSActor/UDSActorConfig.py /usr/sbin/UDSActorConfig
|
||||||
|
/usr/share/UDSActor/UDSActorUser.py /usr/bin/UDSActorTool
|
54
legacy_actors/linux/debian/udsactor.postinst
Executable file
54
legacy_actors/linux/debian/udsactor.postinst
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
set -e
|
||||||
|
case "$1" in
|
||||||
|
configure)
|
||||||
|
/usr/bin/python3 -m compileall /usr/share/UDSActor > /dev/nul 2>&1
|
||||||
|
# If new "fresh" install or if configuration file has disappeared...
|
||||||
|
if [ "$2" = "" ] || [ ! -f /etc/udsactor/udsactor.cfg ]; then
|
||||||
|
db_get udsactor/host
|
||||||
|
host=$RET
|
||||||
|
db_get udsactor/secure
|
||||||
|
ssl=$RET
|
||||||
|
if [ "$ssl" = "true" ]; then
|
||||||
|
ssl=True;
|
||||||
|
else
|
||||||
|
ssl=False;
|
||||||
|
fi
|
||||||
|
db_get udsactor/masterKey
|
||||||
|
masterKey=$RET
|
||||||
|
|
||||||
|
# If already has a config file there
|
||||||
|
if [ -f /etc/udsactor/udsactor.cfg ]; then
|
||||||
|
cp /etc/udsactor/udsactor.cfg /etc/udsactor/udsactor.cfg.dpkg-old
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[uds]" > /etc/udsactor/udsactor.cfg
|
||||||
|
echo "host = $host" >> /etc/udsactor/udsactor.cfg
|
||||||
|
echo "logLevel = 30000" >> /etc/udsactor/udsactor.cfg
|
||||||
|
echo "ssl = $ssl" >> /etc/udsactor/udsactor.cfg
|
||||||
|
echo "masterKey = $masterKey" >> /etc/udsactor/udsactor.cfg
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fix perms so only root can access "masterKey"
|
||||||
|
chmod 0700 /etc/udsactor
|
||||||
|
chmod 0600 /etc/udsactor/udsactor.cfg
|
||||||
|
chown root:root /etc/udsactor
|
||||||
|
chown root:root /etc/udsactor/udsactor.cfg
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade|abort-remove|abort-deconfigure)
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postinst called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
exit 0
|
14
legacy_actors/linux/debian/udsactor.postrm
Executable file
14
legacy_actors/linux/debian/udsactor.postrm
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$1" = "purge" ] ; then
|
||||||
|
if [ -f /etc/udsactor/udsactor.cfg ]; then
|
||||||
|
mv /etc/udsactor/udsactor.cfg /etc/udsactor/udsactor.cfg.dpkg-backup
|
||||||
|
# Remove .pyc leaved behind
|
||||||
|
rm -rf /usr/share/UDSActor || true > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
1
legacy_actors/linux/debian/udsactor.prerm
Executable file
1
legacy_actors/linux/debian/udsactor.prerm
Executable file
@ -0,0 +1 @@
|
|||||||
|
#! /bin/bash -e
|
20
legacy_actors/linux/debian/udsactor.templates
Normal file
20
legacy_actors/linux/debian/udsactor.templates
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Template: udsactor/host
|
||||||
|
Type: string
|
||||||
|
Default:
|
||||||
|
Description: UDS Server address:
|
||||||
|
The actor needs the address of the server in order to communicate with it.
|
||||||
|
Provide here full address (or i) of the UDS server
|
||||||
|
|
||||||
|
Template: udsactor/secure
|
||||||
|
Type: boolean
|
||||||
|
Default: true
|
||||||
|
Description: Use secure (https) connection to communicate with UDS server?
|
||||||
|
If selected, the communication will be done using https.
|
||||||
|
If not selected, the communication will be done using http
|
||||||
|
|
||||||
|
Template: udsactor/masterKey
|
||||||
|
Type: string
|
||||||
|
Default:
|
||||||
|
Description: Master Key:
|
||||||
|
This key is available on UDS Administration interface.
|
||||||
|
Look for it under configuration, on Security tab.
|
12
legacy_actors/linux/desktop/UDSActorTool.desktop
Normal file
12
legacy_actors/linux/desktop/UDSActorTool.desktop
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=UDS Actor Tool
|
||||||
|
Comment=UDS Actor Userspace tools
|
||||||
|
Exec=/usr/bin/UDSActorTool-startup
|
||||||
|
Icon=/usr/share/UDSActor/img/uds.png
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
NoDisplay=true
|
||||||
|
X-KDE-autostart-after=panel
|
||||||
|
X-KDE-StartupNotify=false
|
||||||
|
X-DBUS-StartupType=None
|
||||||
|
X-KDE-UniqueApplet=false
|
11
legacy_actors/linux/desktop/UDS_Actor_Configuration.desktop
Normal file
11
legacy_actors/linux/desktop/UDS_Actor_Configuration.desktop
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Name=UDS Actor Configuration
|
||||||
|
Version=1.0
|
||||||
|
Exec=/usr/sbin/UDSActorConfig-pkexec
|
||||||
|
Comment=UDS Actor Configuration Application. (Must be executed as root)
|
||||||
|
Icon=/usr/share/UDSActor/img/uds.png
|
||||||
|
Type=Application
|
||||||
|
Terminal=false
|
||||||
|
StartupNotify=true
|
||||||
|
Encoding=UTF-8
|
||||||
|
Categories=Settings;System;
|
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE policyconfig PUBLIC
|
||||||
|
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
|
||||||
|
|
||||||
|
<policyconfig>
|
||||||
|
|
||||||
|
<action id="org.freedesktop.policykit.pkexec.run-UDSActorConfig">
|
||||||
|
<description>Run UDS Actor Configuration Program</description>
|
||||||
|
<message>Authentication is required to run UDS Actor Configuration</message>
|
||||||
|
<defaults>
|
||||||
|
<allow_any>no</allow_any>
|
||||||
|
<allow_inactive>no</allow_inactive>
|
||||||
|
<allow_active>auth_admin_keep</allow_active>
|
||||||
|
</defaults>
|
||||||
|
<annotate key="org.freedesktop.policykit.exec.path">/usr/sbin/UDSActorConfig</annotate>
|
||||||
|
<annotate key="org.freedesktop.policykit.exec.allow_gui">TRUE</annotate>
|
||||||
|
</action>
|
||||||
|
|
||||||
|
</policyconfig>
|
3
legacy_actors/linux/readme.txt
Normal file
3
legacy_actors/linux/readme.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
UDSActor is the client actor needed to get machines managed by UDS Broker.
|
||||||
|
|
||||||
|
Please, visit http://www.udsenterprise.com for more information
|
3
legacy_actors/linux/scripts/UDSActorConfig-pkexec
Normal file
3
legacy_actors/linux/scripts/UDSActorConfig-pkexec
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# pkexec env DISPLAY=$DISPLAY QT_X11_NO_MITSHM=1 "/usr/sbin/UDSActorConfig" "$@"
|
||||||
|
pkexec "/usr/sbin/UDSActorConfig" "$@"
|
10
legacy_actors/linux/scripts/UDSActorTool-startup
Normal file
10
legacy_actors/linux/scripts/UDSActorTool-startup
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Simple hack to wait for systray to be present
|
||||||
|
# Exec tool if not already runned by session manager
|
||||||
|
ps -ef | grep "$USER" | grep -v grep | grep -v UDSActorTool-startup | grep 'UDSActorTool' -q
|
||||||
|
# If not already running
|
||||||
|
if [ $? -eq 1 ]; then
|
||||||
|
sleep 5
|
||||||
|
exec /usr/bin/UDSActorTool
|
||||||
|
fi
|
13
legacy_actors/linux/scripts/uds-sesman.sh
Executable file
13
legacy_actors/linux/scripts/uds-sesman.sh
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
env > /tmp/env.txt
|
||||||
|
|
||||||
|
if [ "$PAM_TYPE" = "open_session" ]; then
|
||||||
|
nohup /usr/bin/udsactor login $PAM_USER &
|
||||||
|
# Wait in backgroud to TTY to close (close_session is not being invoked right now)
|
||||||
|
nohup /usr/bin/uds-wait-session &
|
||||||
|
elif [ "$PAM_TYPE" = "close_session" ]; then
|
||||||
|
nohup /usr/bin/udsactor logout $PAM_USER &
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
12
legacy_actors/linux/scripts/uds-wait-session.sh
Executable file
12
legacy_actors/linux/scripts/uds-wait-session.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
sleep 5 # Wait 5 seconds between checks
|
||||||
|
found=`ps -f -u$PAM_USER | grep -v grep | grep -v uds-wait-session | grep "$PAM_TTY" | wc -l`
|
||||||
|
|
||||||
|
if [ "$found" = "0" ]; then
|
||||||
|
/usr/bin/udsactor logout $PAM_USER
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
6
legacy_actors/linux/scripts/udsactor
Executable file
6
legacy_actors/linux/scripts/udsactor
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
FOLDER=/usr/share/UDSActor
|
||||||
|
|
||||||
|
cd $FOLDER
|
||||||
|
exec python3 -m udsactor.linux.UDSActorService $@
|
3
legacy_actors/linux/scripts/udsnxstart.sh
Normal file
3
legacy_actors/linux/scripts/udsnxstart.sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exec /usr/bin/udsactor login $2 &
|
3
legacy_actors/linux/scripts/udsnxstop.sh
Normal file
3
legacy_actors/linux/scripts/udsnxstop.sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exec /usr/bin/udsactor logout $2 &
|
5
legacy_actors/linux/scripts/udsvapp
Executable file
5
legacy_actors/linux/scripts/udsvapp
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
/usr/bin/udsactor login "$USER"
|
||||||
|
$@
|
||||||
|
/usr/bin/udsactor logout "$USER"
|
@ -1,5 +1,5 @@
|
|||||||
%define _topdir %(echo $PWD)/rpm
|
%define _topdir %(echo $PWD)/rpm
|
||||||
%define name udsactor-unmanaged
|
%define name udsactor
|
||||||
%define version 0.0.0
|
%define version 0.0.0
|
||||||
%define release 1
|
%define release 1
|
||||||
%define buildroot %{_topdir}/%{name}-%{version}-%{release}-root
|
%define buildroot %{_topdir}/%{name}-%{version}-%{release}-root
|
||||||
@ -11,7 +11,7 @@ Release: %{release}
|
|||||||
Summary: Actor for Universal Desktop Services (UDS) Broker
|
Summary: Actor for Universal Desktop Services (UDS) Broker
|
||||||
License: BSD3
|
License: BSD3
|
||||||
Group: Admin
|
Group: Admin
|
||||||
Requires: python3-six python3-requests python3-qt5 libXScrnSaver
|
Requires: python-six python-requests PyQt4 libXScrnSaver
|
||||||
Vendor: Virtual Cable S.L.U.
|
Vendor: Virtual Cable S.L.U.
|
||||||
URL: http://www.udsenterprise.com
|
URL: http://www.udsenterprise.com
|
||||||
Provides: udsactor
|
Provides: udsactor
|
||||||
@ -23,7 +23,7 @@ Provides: udsactor
|
|||||||
%install
|
%install
|
||||||
curdir=`pwd`
|
curdir=`pwd`
|
||||||
cd ../..
|
cd ../..
|
||||||
make DESTDIR=$RPM_BUILD_ROOT DISTRO=rh install-udsactor-unmanaged
|
make DESTDIR=$RPM_BUILD_ROOT DISTRO=rh install-udsactor
|
||||||
cd $curdir
|
cd $curdir
|
||||||
|
|
||||||
%clean
|
%clean
|
||||||
@ -51,13 +51,13 @@ fi
|
|||||||
rm -rf /usr/share/UDSActor > /dev/null 2>&1
|
rm -rf /usr/share/UDSActor > /dev/null 2>&1
|
||||||
|
|
||||||
%description
|
%description
|
||||||
This package provides the required components to allow this unmanaged machine to work on an environment managed by UDS Broker.
|
This package provides the required components to allow this machine to work on an environment managed by UDS Broker.
|
||||||
|
|
||||||
%files
|
%files
|
||||||
%defattr(-,root,root)
|
%defattr(-,root,root)
|
||||||
/etc/udsactor
|
/etc/udsactor
|
||||||
/etc/xdg/autostart/UDSActorTool.desktop
|
/etc/xdg/autostart/UDSActorTool.desktop
|
||||||
/etc/systemd/system/udsactor.service
|
/etc/init.d/udsactor
|
||||||
/usr/bin/UDSActorTool-startup
|
/usr/bin/UDSActorTool-startup
|
||||||
/usr/bin/udsactor
|
/usr/bin/udsactor
|
||||||
/usr/bin/udsvapp
|
/usr/bin/udsvapp
|
6
legacy_actors/src/.gitignore
vendored
Normal file
6
legacy_actors/src/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
build
|
||||||
|
dist
|
||||||
|
*.spec
|
||||||
|
.idea
|
||||||
|
*_enterprise*
|
||||||
|
/samples/
|
5
legacy_actors/src/UDSActor.qrc
Normal file
5
legacy_actors/src/UDSActor.qrc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="images">
|
||||||
|
<file>img/uds.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
17
legacy_actors/src/UDSActorConfig.manifest
Normal file
17
legacy_actors/src/UDSActorConfig.manifest
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="UDSActorConfig"
|
||||||
|
version="1.6.0.0"
|
||||||
|
processorArchitecture="x86"
|
||||||
|
/>
|
||||||
|
<description>Description</description>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
</assembly>
|
119
legacy_actors/src/UDSActorConfig.py
Normal file
119
legacy_actors/src/UDSActorConfig.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 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
|
||||||
|
'''
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from PyQt4 import QtCore, QtGui
|
||||||
|
import six
|
||||||
|
|
||||||
|
from udsactor import store
|
||||||
|
from udsactor import REST
|
||||||
|
from udsactor import utils
|
||||||
|
from udsactor.log import logger
|
||||||
|
|
||||||
|
from setup_dialog_ui import Ui_UdsActorSetupDialog
|
||||||
|
|
||||||
|
|
||||||
|
class UDSConfigDialog(QtGui.QDialog):
|
||||||
|
|
||||||
|
def __init__(self, data, parent=None):
|
||||||
|
QtGui.QDialog.__init__(self, parent)
|
||||||
|
self.ui = Ui_UdsActorSetupDialog()
|
||||||
|
self.ui.setupUi(self)
|
||||||
|
if data is not None:
|
||||||
|
self.ui.host.setText(data.get('host', ''))
|
||||||
|
self.ui.masterKey.setText(data.get('masterKey', ''))
|
||||||
|
self.ui.useSSl.setCurrentIndex(1 if data.get('ssl', False) is True else 0)
|
||||||
|
self.ui.logLevelComboBox.setCurrentIndex(int(data.get('logLevel', '10000')) / 10000 - 1)
|
||||||
|
|
||||||
|
def _getCfg(self):
|
||||||
|
return {
|
||||||
|
'host': six.text_type(self.ui.host.text()),
|
||||||
|
'masterKey': six.text_type(self.ui.masterKey.text()),
|
||||||
|
'ssl': self.ui.useSSl.currentIndex() == 1,
|
||||||
|
'logLevel': (self.ui.logLevelComboBox.currentIndex() + 1) * 10000
|
||||||
|
}
|
||||||
|
|
||||||
|
def textChanged(self):
|
||||||
|
enableButtons = self.ui.host.text() != '' and self.ui.masterKey.text() != ''
|
||||||
|
self.ui.testButton.setEnabled(enableButtons)
|
||||||
|
self.ui.saveButton.setEnabled(enableButtons)
|
||||||
|
|
||||||
|
def cancelAndDiscard(self):
|
||||||
|
logger.debug('Cancelling changes')
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def testParameters(self):
|
||||||
|
logger.debug('Testing connection')
|
||||||
|
try:
|
||||||
|
cfg = self._getCfg()
|
||||||
|
api = REST.Api(
|
||||||
|
cfg['host'], cfg['masterKey'], cfg['ssl'])
|
||||||
|
api.test()
|
||||||
|
QtGui.QMessageBox.information(
|
||||||
|
self, 'Test Passed', 'The test was executed successfully', QtGui.QMessageBox.Ok)
|
||||||
|
logger.info('Test was passed successfully')
|
||||||
|
except Exception as e:
|
||||||
|
logger.info('Test error: {}'.format(utils.exceptionToMessage(e)))
|
||||||
|
QtGui.QMessageBox.critical(self, 'Test Error', utils.exceptionToMessage(e), QtGui.QMessageBox.Ok)
|
||||||
|
|
||||||
|
def acceptAndSave(self):
|
||||||
|
cfg = self._getCfg()
|
||||||
|
store.writeConfig(cfg)
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
# If to be run as "sudo" on linux, we will need this to avoid problems
|
||||||
|
if 'linux' in sys.platform:
|
||||||
|
os.environ['QT_X11_NO_MITSHM'] = '1'
|
||||||
|
|
||||||
|
app = QtGui.QApplication(sys.argv)
|
||||||
|
|
||||||
|
if store.checkPermissions() is False:
|
||||||
|
QtGui.QMessageBox.critical(None, 'Notice', 'This Program must be executed as administrator', QtGui.QMessageBox.Ok)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Read configuration
|
||||||
|
cfg = store.readConfig()
|
||||||
|
|
||||||
|
if cfg is not None:
|
||||||
|
logger.setLevel(int(cfg.get('logLevel', 20000)))
|
||||||
|
else:
|
||||||
|
logger.setLevel(20000)
|
||||||
|
|
||||||
|
myapp = UDSConfigDialog(cfg)
|
||||||
|
myapp.show()
|
||||||
|
sys.exit(app.exec_())
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user