1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-05 09:17:54 +03:00

fixing client for windows

This commit is contained in:
Adolfo Gómez 2019-12-12 15:36:34 +01:00
parent 633671d12c
commit 0ac3fa1987
9 changed files with 50 additions and 44 deletions

View File

@ -34,13 +34,11 @@ import sys
import os
import PyQt5 # pylint: disable=unused-import
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QTimer
from udsactor.log import logger, DEBUG
from udsactor.client import UDSClientQApp
if __name__ == "__main__":
logger.setLevel(DEBUG)
@ -49,18 +47,21 @@ if __name__ == "__main__":
logger.info('Started UDS Client Actor')
QApplication.setQuitOnLastWindowClosed(False)
# QApplication.setQuitOnLastWindowClosed(False)
qApp = UDSClientQApp(sys.argv)
qApp.init()
# Crate a timer, so we can check signals from time to time by executing python interpreter
# Note: Signals are only checked on python code execution, so we create a
timer = QTimer(qApp)
timer.start(1000)
timer.timeout.connect(lambda *a: None)
qApp.init()
qApp.exec_()
# On windows, this point will never be reached :)
qApp.end()
logger.debug('Exiting...')

View File

@ -28,10 +28,11 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=invalid-name
import threading
import time
import typing
import signal
import typing
from PyQt5.QtWidgets import QApplication, QMessageBox
from PyQt5.QtCore import QByteArray, QBuffer, QIODevice, pyqtSignal
@ -49,6 +50,7 @@ if typing.TYPE_CHECKING:
from . import types
from PyQt5.QtGui import QPixmap
class UDSClientQApp(QApplication):
_app: 'UDSActorClient'
_initialized: bool
@ -60,6 +62,9 @@ class UDSClientQApp(QApplication):
# This will be invoked on session close
self.commitDataRequest.connect(self.end) # Will be invoked on session close, to gracely close app
self.aboutToQuit.connect(self.end)
self.message.connect(self.showMessage)
# Execute backgroup thread for actions
@ -69,9 +74,13 @@ class UDSClientQApp(QApplication):
# Notify loging and mark it
logger.debug('Starting APP')
self._app.start()
self.aboutToQuit.connect(lambda: logger.debug('About to quit'))
self._initialized = True
def end(self, sessionManager=None) -> None:
logger.debug('Stopping App')
if not self._initialized:
return
@ -120,12 +129,14 @@ class UDSActorClient(threading.Thread):
try:
# Notify loging and mark it
self.api.login(platform.operations.getCurrentUser())
if platform.name != 'win32': # On win32, SENS will send login/logouts
self.api.login(platform.operations.getCurrentUser())
while self._running:
time.sleep(1.1) # Sleeps between loop iterations
self.api.logout(platform.operations.getCurrentUser())
if platform.name != 'win32': # On win32, SENS will send login/logouts
self.api.logout(platform.operations.getCurrentUser())
except Exception as e:
logger.error('Error on client loop: %s', e)
@ -154,7 +165,11 @@ class UDSActorClient(threading.Thread):
return 'ok'
def screenshot(self) -> typing.Any:
pixmap: QPixmap = self._qApp.primaryScreen().grabWindow(0)
'''
On windows, an RDP session with minimized screen will render "black screen"
So only when user is using RDP connection will return an "actual" screenshot
'''
pixmap: 'QPixmap' = self._qApp.primaryScreen().grabWindow(0)
ba = QByteArray()
buffer = QBuffer(ba)
buffer.open(QIODevice.WriteOnly)

View File

@ -28,6 +28,7 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=invalid-name
import threading
import http.server
import secrets
@ -81,7 +82,8 @@ class HTTPServerHandler(http.server.BaseHTTPRequestHandler):
try:
result = getattr(self, 'method_' + path[1])(params) # last part of path is method
except AttributeError:
except AttributeError as e:
logger.error('Invoked invalid method: %s: %s', path[1], e)
self.sendJsonResponse(error='Invalid request', code=400)
return
except Exception as e:

View File

@ -28,6 +28,7 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=invalid-name
import json
import typing

View File

@ -30,6 +30,7 @@
'''
import sys
name = sys.platform
if sys.platform == 'win32':
from .windows import operations, store # pylint: disable=unused-import
else:

View File

@ -353,6 +353,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
self._loggedIn = False
if self._cfg.own_token:
self._api.logout(self._cfg.own_token, username)
self.onLogout(username)
# ****************************************
# Methods that CAN BE overriden by actors

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014 Virtual Cable S.L.
# Copyright (c) 2014-2019 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@ -29,15 +29,12 @@
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
# _*_ coding: iso-8859-1 _*_
from __future__ import unicode_literals
import typing
import win32com.client # @UnresolvedImport, pylint: disable=import-error
import win32com.server.policy # @UnresolvedImport, pylint: disable=import-error
import os
from udsactor.log import logger
from ..log import logger
# based on python SENS example from
# http://timgolden.me.uk/python/win32_how_do_i/track-session-events.html
@ -52,6 +49,9 @@ PROGID_EventSubscription = "EventSystem.EventSubscription"
IID_ISensLogon = "{d597bab3-5b9f-11d1-8dd2-00aa004abd5e}"
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from ..service import CommonService
class SensLogon(win32com.server.policy.DesignatedWrapPolicy):
_com_interfaces_ = [IID_ISensLogon]
@ -65,38 +65,19 @@ class SensLogon(win32com.server.policy.DesignatedWrapPolicy):
'StopScreenSaver'
]
def __init__(self, service):
_service: 'CommonService'
def __init__(self, service: 'CommonService'): # pylint: disable=super-init-not-called
self._wrap_(self)
self.service = service
self._service = service
def Logon(self, *args):
logger.debug('Logon event: {}'.format(args))
if self.service.api is not None and self.service.api.isConnected:
try:
data = self.service.api.login(args[0])
logger.debug('Data received for login: {}'.format(data))
data = data.split('\t')
if len(data) >= 2:
logger.debug('Data is valid: {}'.format(data))
windir = os.environ['windir']
with open(os.path.join(windir, 'remoteip.txt'), 'w') as f:
f.write(data[0])
with open(os.path.join(windir, 'remoteh.txt'), 'w') as f:
f.write(data[1])
except Exception as e:
logger.fatal('Error notifying logon to server: {}'.format(e))
self._service.login(args[0] or '')
def Logoff(self, *args):
logger.debug('Logoff event: arguments: {}'.format(args))
if self.service is not None and self.service.api is not None and self.service.api.isConnected:
try:
self.service.api.logout(args[0])
except Exception as e:
logger.fatal('Error notifying logoff to server: {}'.format(e))
logger.debug('Invoking onLogout: {}'.format(self.service))
self.service.onLogout(args[0])
logger.debug('Invoked!!')
self._service.logout(args[0] or '')
def StartShell(self, *args):
# logevent('StartShell : %s' % [args])

View File

@ -32,6 +32,7 @@
import logging
import os
import tempfile
import typing
import servicemanager # @UnresolvedImport, pylint: disable=import-error
@ -42,6 +43,8 @@ class LocalLogger: # pylint: disable=too-few-public-methods
linux = False
windows = True
logger: typing.Optional[logging.Logger]
def __init__(self):
# tempdir is different for "user application" and "service"
# service wil get c:\windows\temp, while user will get c:\users\XXX\temp
@ -50,7 +53,7 @@ class LocalLogger: # pylint: disable=too-few-public-methods
filename=os.path.join(tempfile.gettempdir(), 'udsactor.log'),
filemode='a',
format='%(levelname)s %(asctime)s %(message)s',
level=logging.INFO
level=logging.DEBUG
)
except Exception:
logging.basicConfig() # basic init
@ -63,7 +66,8 @@ class LocalLogger: # pylint: disable=too-few-public-methods
# our loglevels are 10000 (other), 20000 (debug), ....
# logging levels are 10 (debug), 20 (info)
# OTHER = logging.NOTSET
self.logger.log(level // 1000 - 10, message)
if self.logger:
self.logger.log(int(level / 1000) - 10, message)
if level < INFO or self.serviceLogger is False: # Only information and above will be on event log
return

View File

@ -92,7 +92,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
def doWait(self, miliseconds: int) -> None:
win32event.WaitForSingleObject(self._hWaitStop, miliseconds)
def oneStepJoin(self, name: str, domain: str, ou: str, account: str, password: str) -> None:
def oneStepJoin(self, name: str, domain: str, ou: str, account: str, password: str) -> None: # pylint: disable=too-many-arguments
'''
Ejecutes the join domain in exactly one step
'''
@ -109,7 +109,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
logger.debug('Requested join domain {} without errors'.format(domain))
self.reboot()
def multiStepJoin(self, name: str, domain: str, ou: str, account: str, password: str) -> None:
def multiStepJoin(self, name: str, domain: str, ou: str, account: str, password: str) -> None: # pylint: disable=too-many-arguments
currName = operations.getComputerName()
if currName.lower() == name.lower():
currDomain = operations.getDomainName()