mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-03 01:17:56 +03:00
Moved "custom" parameters for osManager inside the "custom" dict
Also, kept "old" parematers for a while (a couple of versions), so old clients are compatible with UDS actor 4.0 at least (so we can upgrade server, keep running and eventually upgrade actors). Compatibility mast be kept for at lest a couple of minor releases, Al least, until UDS 4.5 will be kept this way
This commit is contained in:
parent
880aa24dbb
commit
c264ea9c13
@ -187,13 +187,16 @@ def renameComputer(newName: str) -> bool:
|
|||||||
rename(newName)
|
rename(newName)
|
||||||
return True # Always reboot right now. Not much slower but much more convenient
|
return True # Always reboot right now. Not much slower but much more convenient
|
||||||
|
|
||||||
def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False, custom: typing.Optional[typing.Mapping[str, typing.Any]] = None):
|
def joinDomain(name: str, custom: typing.Optional[typing.Mapping[str, typing.Any]] = None):
|
||||||
if not custom:
|
if not custom:
|
||||||
logger.error('Error joining domain: no custom data provided')
|
logger.error('Error joining domain: no custom data provided')
|
||||||
return
|
return
|
||||||
|
|
||||||
# Read parameters from custom data
|
# Read parameters from custom data
|
||||||
name: str = custom.get('name', '')
|
domain: str = custom.get('domain', '')
|
||||||
|
ou: str = custom.get('ou', '')
|
||||||
|
account: str = custom.get('account', '')
|
||||||
|
password: str = custom.get('password', '')
|
||||||
client_software: str = custom.get('client_software', '')
|
client_software: str = custom.get('client_software', '')
|
||||||
server_software: str = custom.get('server_software', '')
|
server_software: str = custom.get('server_software', '')
|
||||||
membership_software: str = custom.get('membership_software', '')
|
membership_software: str = custom.get('membership_software', '')
|
||||||
|
@ -64,20 +64,15 @@ class UDSActorSvc(daemon.Daemon, CommonService):
|
|||||||
return self._sensibleDataCleanable
|
return self._sensibleDataCleanable
|
||||||
|
|
||||||
def joinDomain( # pylint: disable=unused-argument, too-many-arguments
|
def joinDomain( # pylint: disable=unused-argument, too-many-arguments
|
||||||
self, name: str, domain: str, ou: str, account: str, password: str, custom: typing.Optional[typing.Mapping[str, typing.Any]] = None
|
self, name: str, custom: typing.Mapping[str, typing.Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
# Add name to custom data, needed by joinDomain on Linux
|
|
||||||
# First, Copy mapping to mutable dict so we can add name to it
|
self._sensibleDataCleanable = custom.get('isPersistent', False)
|
||||||
localCustom = {k: v for k, v in (custom.items() if custom is not None else [])}
|
|
||||||
localCustom['name'] = name
|
|
||||||
|
|
||||||
# If isPersistent is False, we need to keep sensible data, so it's not cleaned
|
|
||||||
self._sensibleDataCleanable = localCustom.get('isPersistent', False)
|
|
||||||
|
|
||||||
self.rename(name)
|
self.rename(name)
|
||||||
|
|
||||||
logger.debug(f'Starting joining domain {domain} with name {name}')
|
logger.debug('Starting joining domain %s with name %s', custom.get('domain', ''), name)
|
||||||
operations.joinDomain(domain, ou, account, password, custom=localCustom)
|
operations.joinDomain(name, custom)
|
||||||
|
|
||||||
def finish(self) -> None:
|
def finish(self) -> None:
|
||||||
try:
|
try:
|
||||||
@ -86,11 +81,11 @@ class UDSActorSvc(daemon.Daemon, CommonService):
|
|||||||
custom = self._cfg.config.os.custom
|
custom = self._cfg.config.os.custom
|
||||||
if osData.action == 'rename_ad' and custom.get('isPersistent', False):
|
if osData.action == 'rename_ad' and custom.get('isPersistent', False):
|
||||||
operations.leaveDomain(
|
operations.leaveDomain(
|
||||||
osData.ad or '',
|
custom.get('ad', ''),
|
||||||
osData.username or '',
|
custom.get('username', ''),
|
||||||
osData.password or '',
|
custom.get('password', ''),
|
||||||
custom['clientSoftware'] or '',
|
custom.get('clientSoftware', ''),
|
||||||
custom['serverSoftware'] or '',
|
custom.get('serverSoftware', ''),
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Got exception operating machine: {e}')
|
logger.error(f'Got exception operating machine: {e}')
|
||||||
|
@ -289,11 +289,6 @@ class UDSServerApi(UDSApi):
|
|||||||
os=types.ActorOsConfigurationType(
|
os=types.ActorOsConfigurationType(
|
||||||
action=os['action'],
|
action=os['action'],
|
||||||
name=os['name'],
|
name=os['name'],
|
||||||
username=os.get('username'),
|
|
||||||
password=os.get('password'),
|
|
||||||
new_password=os.get('new_password'),
|
|
||||||
ad=os.get('ad'),
|
|
||||||
ou=os.get('ou'),
|
|
||||||
custom=os.get('custom'),
|
custom=os.get('custom'),
|
||||||
)
|
)
|
||||||
if r['os']
|
if r['os']
|
||||||
|
@ -75,9 +75,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
logger.debug('Executing command on {}: {}'.format(section, cmdLine))
|
logger.debug('Executing command on {}: {}'.format(section, cmdLine))
|
||||||
res = subprocess.check_call(cmdLine, shell=True)
|
res = subprocess.check_call(cmdLine, shell=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(
|
logger.error('Got exception executing: {} - {} - {}'.format(section, cmdLine, e))
|
||||||
'Got exception executing: {} - {} - {}'.format(section, cmdLine, e)
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
logger.debug('Result of executing cmd for {} was {}'.format(section, res))
|
logger.debug('Result of executing cmd for {} was {}'.format(section, res))
|
||||||
return True
|
return True
|
||||||
@ -131,9 +129,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
) # Emty interfaces is like "no ip change" because cannot be notified
|
) # Emty interfaces is like "no ip change" because cannot be notified
|
||||||
if self._cfg.config and interfaces:
|
if self._cfg.config and interfaces:
|
||||||
try:
|
try:
|
||||||
return next(
|
return next(x for x in interfaces if x.mac.lower() == self._cfg.config.unique_id)
|
||||||
x for x in interfaces if x.mac.lower() == self._cfg.config.unique_id
|
|
||||||
)
|
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
return interfaces[0]
|
return interfaces[0]
|
||||||
|
|
||||||
@ -188,9 +184,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
# Success or any error that is not recoverable (retunerd by UDS). if Error, service will be cleaned in a while.
|
# Success or any error that is not recoverable (retunerd by UDS). if Error, service will be cleaned in a while.
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
logger.error(
|
logger.error('Could not locate IP address!!!. (Not registered with UDS)')
|
||||||
'Could not locate IP address!!!. (Not registered with UDS)'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Do not continue if not alive...
|
# Do not continue if not alive...
|
||||||
if not self._isAlive:
|
if not self._isAlive:
|
||||||
@ -199,9 +193,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
# Cleans sensible data
|
# Cleans sensible data
|
||||||
if self._cfg.config:
|
if self._cfg.config:
|
||||||
if self.canCleanSensibleData():
|
if self.canCleanSensibleData():
|
||||||
self._cfg = self._cfg._replace(
|
self._cfg = self._cfg._replace(config=self._cfg.config._replace(os=None), data=None)
|
||||||
config=self._cfg.config._replace(os=None), data=None
|
|
||||||
)
|
|
||||||
platform.store.writeConfig(self._cfg)
|
platform.store.writeConfig(self._cfg)
|
||||||
|
|
||||||
logger.info('Service ready')
|
logger.info('Service ready')
|
||||||
@ -232,22 +224,17 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
try:
|
try:
|
||||||
if self._cfg.config and self._cfg.config.os:
|
if self._cfg.config and self._cfg.config.os:
|
||||||
osData = self._cfg.config.os
|
osData = self._cfg.config.os
|
||||||
|
custom: typing.Mapping[str, typing.Any] = osData.custom or {}
|
||||||
|
# Needs UDS Server >= 4.0 to work
|
||||||
if osData.action == 'rename':
|
if osData.action == 'rename':
|
||||||
self.rename(
|
self.rename(
|
||||||
osData.name,
|
osData.name,
|
||||||
osData.username,
|
custom.get('username'),
|
||||||
osData.password,
|
custom.get('password'),
|
||||||
osData.new_password,
|
custom.get('new_password'),
|
||||||
)
|
)
|
||||||
elif osData.action == 'rename_ad':
|
elif osData.action == 'rename_ad':
|
||||||
self.joinDomain(
|
self.joinDomain(osData.name, custom)
|
||||||
osData.name,
|
|
||||||
osData.ad or '',
|
|
||||||
osData.ou or '',
|
|
||||||
osData.username or '',
|
|
||||||
osData.password or '',
|
|
||||||
osData.custom
|
|
||||||
)
|
|
||||||
|
|
||||||
if self._rebootRequested:
|
if self._rebootRequested:
|
||||||
try:
|
try:
|
||||||
@ -295,9 +282,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
self.doWait(5000)
|
self.doWait(5000)
|
||||||
|
|
||||||
def initialize(self) -> bool:
|
def initialize(self) -> bool:
|
||||||
if (
|
if self._initialized or not self._cfg.host or not self._isAlive: # Not configured or not running
|
||||||
self._initialized or not self._cfg.host or not self._isAlive
|
|
||||||
): # Not configured or not running
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
@ -319,18 +304,14 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
)
|
)
|
||||||
if not initResult.own_token: # Not managed
|
if not initResult.own_token: # Not managed
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'This host is not managed by UDS Broker (ids: {})'.format(
|
'This host is not managed by UDS Broker (ids: {})'.format(self._interfaces)
|
||||||
self._interfaces
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
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
|
# For unmanaged, if alias is present, replace master token with it
|
||||||
master_token = (
|
master_token = (
|
||||||
None
|
None if self.isManaged() else (initResult.alias_token or self._cfg.master_token)
|
||||||
if self.isManaged()
|
|
||||||
else (initResult.alias_token or self._cfg.master_token)
|
|
||||||
)
|
)
|
||||||
# Replace master token with alias token if present
|
# Replace master token with alias token if present
|
||||||
self._cfg = self._cfg._replace(
|
self._cfg = self._cfg._replace(
|
||||||
@ -352,16 +333,10 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
break # Initial configuration done..
|
break # Initial configuration done..
|
||||||
except rest.RESTConnectionError as e:
|
except rest.RESTConnectionError as e:
|
||||||
logger.info(
|
logger.info('Trying to inititialize connection with broker (last error: {})'.format(e))
|
||||||
'Trying to inititialize connection with broker (last error: {})'.format(
|
|
||||||
e
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.doWait(5000) # Wait a bit and retry
|
self.doWait(5000) # Wait a bit and retry
|
||||||
except rest.RESTError as e: # Invalid key?
|
except rest.RESTError as e: # Invalid key?
|
||||||
logger.error(
|
logger.error('Error validating with broker. (Invalid token?): {}'.format(e))
|
||||||
'Error validating with broker. (Invalid token?): {}'.format(e)
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception()
|
logger.exception()
|
||||||
@ -371,9 +346,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
def uninitialize(self):
|
def uninitialize(self):
|
||||||
self._initialized = False
|
self._initialized = False
|
||||||
self._cfg = self._cfg._replace(
|
self._cfg = self._cfg._replace(own_token=None) # Ensures assigned token is cleared
|
||||||
own_token=None
|
|
||||||
) # Ensures assigned token is cleared
|
|
||||||
|
|
||||||
def finish(self) -> None:
|
def finish(self) -> None:
|
||||||
if self._http:
|
if self._http:
|
||||||
@ -389,8 +362,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
self._cfg.actorType,
|
self._cfg.actorType,
|
||||||
self._cfg.own_token,
|
self._cfg.own_token,
|
||||||
'',
|
'',
|
||||||
client.session_id
|
client.session_id or 'stop', # If no session id, pass "stop"
|
||||||
or 'stop', # If no session id, pass "stop"
|
|
||||||
'',
|
'',
|
||||||
self._interfaces,
|
self._interfaces,
|
||||||
self._secret,
|
self._secret,
|
||||||
@ -405,11 +377,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
return # Unamanaged hosts does not changes ips. (The full initialize-login-logout process is done in a row, so at login the IP is correct)
|
return # Unamanaged hosts does not changes ips. (The full initialize-login-logout process is done in a row, so at login the IP is correct)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if (
|
if not self._cfg.own_token or not self._cfg.config or not self._cfg.config.unique_id:
|
||||||
not self._cfg.own_token
|
|
||||||
or not self._cfg.config
|
|
||||||
or not self._cfg.config.unique_id
|
|
||||||
):
|
|
||||||
# Not enouth data do check
|
# Not enouth data do check
|
||||||
return
|
return
|
||||||
currentInterfaces = tools.validNetworkCards(
|
currentInterfaces = tools.validNetworkCards(
|
||||||
@ -418,59 +386,20 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
old = self.serviceInterfaceInfo()
|
old = self.serviceInterfaceInfo()
|
||||||
new = self.serviceInterfaceInfo(currentInterfaces)
|
new = self.serviceInterfaceInfo(currentInterfaces)
|
||||||
if not new or not old:
|
if not new or not old:
|
||||||
raise Exception(
|
raise Exception('No ip currently available for {}'.format(self._cfg.config.unique_id))
|
||||||
'No ip currently available for {}'.format(
|
|
||||||
self._cfg.config.unique_id
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if old.ip != new.ip:
|
if old.ip != new.ip:
|
||||||
self._certificate = self._api.notifyIpChange(
|
self._certificate = self._api.notifyIpChange(
|
||||||
self._cfg.own_token, self._secret, new.ip, rest.LISTEN_PORT
|
self._cfg.own_token, self._secret, new.ip, rest.LISTEN_PORT
|
||||||
)
|
)
|
||||||
# Now store new addresses & interfaces...
|
# Now store new addresses & interfaces...
|
||||||
self._interfaces = currentInterfaces
|
self._interfaces = currentInterfaces
|
||||||
logger.info(
|
logger.info('Ip changed from {} to {}. Notified to UDS'.format(old.ip, new.ip))
|
||||||
'Ip changed from {} to {}. Notified to UDS'.format(old.ip, new.ip)
|
|
||||||
)
|
|
||||||
# Stop the running HTTP Thread and start a new one, with new generated cert
|
# Stop the running HTTP Thread and start a new one, with new generated cert
|
||||||
self.startHttpServer()
|
self.startHttpServer()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# No ip changed, log exception for info
|
# No ip changed, log exception for info
|
||||||
logger.warn('Checking ips failed: {}'.format(e))
|
logger.warn('Checking ips failed: {}'.format(e))
|
||||||
|
|
||||||
def rename(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
userName: typing.Optional[str] = None,
|
|
||||||
oldPassword: typing.Optional[str] = None,
|
|
||||||
newPassword: typing.Optional[str] = None,
|
|
||||||
) -> None:
|
|
||||||
'''
|
|
||||||
Invoked when broker requests a rename action
|
|
||||||
default does nothing
|
|
||||||
'''
|
|
||||||
hostName = platform.operations.getComputerName()
|
|
||||||
|
|
||||||
# Check for password change request for an user
|
|
||||||
if userName and newPassword:
|
|
||||||
logger.info('Setting password for configured user')
|
|
||||||
try:
|
|
||||||
platform.operations.changeUserPassword(
|
|
||||||
userName, oldPassword or '', newPassword
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
# Logs error, but continue renaming computer
|
|
||||||
logger.error(
|
|
||||||
'Could not change password for user {}: {}'.format(userName, e)
|
|
||||||
)
|
|
||||||
|
|
||||||
if hostName.lower() == name.lower():
|
|
||||||
logger.info('Computer name is already {}'.format(hostName))
|
|
||||||
return
|
|
||||||
|
|
||||||
if platform.operations.renameComputer(name):
|
|
||||||
self.reboot()
|
|
||||||
|
|
||||||
def loop(self):
|
def loop(self):
|
||||||
# Main common loop
|
# Main common loop
|
||||||
try:
|
try:
|
||||||
@ -487,22 +416,44 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
# ******************************************************
|
# ******************************************************
|
||||||
# Methods that can be overriden by linux & windows Actor
|
# Methods that can be overriden by linux & windows Actor
|
||||||
# ******************************************************
|
# ******************************************************
|
||||||
def joinDomain( # pylint: disable=unused-argument, too-many-arguments
|
def rename(
|
||||||
self, name: str, domain: str, ou: str, account: str, password: str, custom: typing.Optional[typing.Mapping[str, typing.Any]] = None
|
self,
|
||||||
|
name: str,
|
||||||
|
userName: typing.Optional[str] = None,
|
||||||
|
oldPassword: typing.Optional[str] = None,
|
||||||
|
newPassword: typing.Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
'''
|
||||||
|
Invoked when broker requests a rename action
|
||||||
|
'''
|
||||||
|
hostName = platform.operations.getComputerName()
|
||||||
|
|
||||||
|
# Check for password change request for an user
|
||||||
|
if userName and newPassword:
|
||||||
|
logger.info('Setting password for configured user')
|
||||||
|
try:
|
||||||
|
platform.operations.changeUserPassword(userName, oldPassword or '', newPassword)
|
||||||
|
except Exception as e:
|
||||||
|
# Logs error, but continue renaming computer
|
||||||
|
logger.error('Could not change password for user {}: {}'.format(userName, e))
|
||||||
|
|
||||||
|
if hostName.lower() == name.lower():
|
||||||
|
logger.info('Computer name is already {}'.format(hostName))
|
||||||
|
return
|
||||||
|
|
||||||
|
if platform.operations.renameComputer(name):
|
||||||
|
self.reboot()
|
||||||
|
|
||||||
|
def joinDomain(self, name: str, custom: typing.Mapping[str, typing.Any]) -> None:
|
||||||
'''
|
'''
|
||||||
Invoked when broker requests a "domain" action
|
Invoked when broker requests a "domain" action
|
||||||
default does nothing
|
default does nothing
|
||||||
'''
|
'''
|
||||||
logger.debug('Base join invoked: {} on {}, {}'.format(name, domain, ou))
|
logger.debug('Base join invoked: %s on %s, %s', name, custom)
|
||||||
|
|
||||||
# Client notifications
|
# Client notifications
|
||||||
def login(
|
def login(self, username: str, sessionType: typing.Optional[str] = None) -> types.LoginResultInfoType:
|
||||||
self, username: str, sessionType: typing.Optional[str] = None
|
result = types.LoginResultInfoType(ip='', hostname='', dead_line=None, max_idle=None, session_id=None)
|
||||||
) -> types.LoginResultInfoType:
|
|
||||||
result = types.LoginResultInfoType(
|
|
||||||
ip='', hostname='', dead_line=None, max_idle=None, session_id=None
|
|
||||||
)
|
|
||||||
master_token = None
|
master_token = None
|
||||||
secret = None
|
secret = None
|
||||||
# If unmanaged, do initialization now, because we don't know before this
|
# If unmanaged, do initialization now, because we don't know before this
|
||||||
@ -564,9 +515,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
)
|
)
|
||||||
!= 'ok' # Can return also "notified", that means the logout has not been processed by UDS
|
!= 'ok' # Can return also "notified", that means the logout has not been processed by UDS
|
||||||
):
|
):
|
||||||
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.onLogout(username, session_id or '')
|
||||||
@ -595,9 +544,7 @@ class CommonService: # pylint: disable=too-many-instance-attributes
|
|||||||
'''
|
'''
|
||||||
logger.info('Service stopped')
|
logger.info('Service stopped')
|
||||||
|
|
||||||
def preConnect(
|
def preConnect(self, userName: str, protocol: str, ip: str, hostname: str, udsUserName: str) -> str:
|
||||||
self, userName: str, protocol: str, ip: str, hostname: str, udsUserName: str
|
|
||||||
) -> str:
|
|
||||||
'''
|
'''
|
||||||
Invoked when received a PRE Connection request via REST
|
Invoked when received a PRE Connection request via REST
|
||||||
Base preconnect executes the preconnect command
|
Base preconnect executes the preconnect command
|
||||||
|
@ -19,11 +19,6 @@ class AuthenticatorType(typing.NamedTuple):
|
|||||||
class ActorOsConfigurationType(typing.NamedTuple):
|
class ActorOsConfigurationType(typing.NamedTuple):
|
||||||
action: str
|
action: str
|
||||||
name: str
|
name: str
|
||||||
username: typing.Optional[str] = None
|
|
||||||
password: typing.Optional[str] = None
|
|
||||||
new_password: typing.Optional[str] = None
|
|
||||||
ad: typing.Optional[str] = None
|
|
||||||
ou: typing.Optional[str] = None
|
|
||||||
custom: typing.Optional[typing.Mapping[str, typing.Any]] = None
|
custom: typing.Optional[typing.Mapping[str, typing.Any]] = None
|
||||||
|
|
||||||
class ActorDataConfigurationType(typing.NamedTuple):
|
class ActorDataConfigurationType(typing.NamedTuple):
|
||||||
|
@ -63,24 +63,17 @@ def getComputerName() -> str:
|
|||||||
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
|
ip is None or ip == '' or ip.startswith('169.254') or ip.startswith('0.')
|
||||||
or ip == ''
|
|
||||||
or ip.startswith('169.254')
|
|
||||||
or ip.startswith('0.')
|
|
||||||
): # If single link ip, or no ip
|
): # 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
|
||||||
|
|
||||||
@ -97,7 +90,7 @@ def getDomainName() -> str:
|
|||||||
# 3 = Domain
|
# 3 = Domain
|
||||||
domain, status = win32net.NetGetJoinInformation()
|
domain, status = win32net.NetGetJoinInformation()
|
||||||
if status != 3:
|
if status != 3:
|
||||||
domain = None
|
domain = ''
|
||||||
|
|
||||||
return domain
|
return domain
|
||||||
|
|
||||||
@ -109,9 +102,7 @@ def getWindowsVersion() -> typing.Tuple[int, int, int, int, str]:
|
|||||||
def getVersion() -> str:
|
def getVersion() -> str:
|
||||||
verinfo = getWindowsVersion()
|
verinfo = getWindowsVersion()
|
||||||
# Remove platform id i
|
# Remove platform id i
|
||||||
return 'Windows-{}.{} Build {} ({})'.format(
|
return 'Windows-{}.{} Build {} ({})'.format(verinfo[0], verinfo[1], verinfo[2], verinfo[4])
|
||||||
verinfo[0], verinfo[1], verinfo[2], verinfo[4]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
EWX_LOGOFF = 0x00000000
|
EWX_LOGOFF = 0x00000000
|
||||||
@ -129,11 +120,11 @@ def reboot(flags: int = EWX_FORCEIFHUNG | EWX_REBOOT) -> None:
|
|||||||
)
|
)
|
||||||
privs = (
|
privs = (
|
||||||
(
|
(
|
||||||
win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME),
|
win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME), # type: ignore
|
||||||
win32security.SE_PRIVILEGE_ENABLED,
|
win32security.SE_PRIVILEGE_ENABLED,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
win32security.AdjustTokenPrivileges(htok, 0, privs)
|
win32security.AdjustTokenPrivileges(htok, 0, privs) # type: ignore
|
||||||
win32api.ExitWindowsEx(flags, 0)
|
win32api.ExitWindowsEx(flags, 0)
|
||||||
|
|
||||||
|
|
||||||
@ -148,7 +139,7 @@ def renameComputer(newName: str) -> bool:
|
|||||||
'''
|
'''
|
||||||
# Needs admin privileges to work
|
# Needs admin privileges to work
|
||||||
if (
|
if (
|
||||||
ctypes.windll.kernel32.SetComputerNameExW(
|
ctypes.windll.kernel32.SetComputerNameExW( # type: ignore
|
||||||
DWORD(win32con.ComputerNamePhysicalDnsHostname), LPCWSTR(newName)
|
DWORD(win32con.ComputerNamePhysicalDnsHostname), LPCWSTR(newName)
|
||||||
)
|
)
|
||||||
== 0
|
== 0
|
||||||
@ -157,14 +148,8 @@ def renameComputer(newName: str) -> bool:
|
|||||||
# 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
|
||||||
|
|
||||||
|
|
||||||
@ -179,9 +164,7 @@ NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400
|
|||||||
NETSETUP_DEFER_SPN_SET = 0x1000000
|
NETSETUP_DEFER_SPN_SET = 0x1000000
|
||||||
|
|
||||||
|
|
||||||
def joinDomain(
|
def joinDomain(domain: str, ou: str, account: str, password: str, executeInOneStep: bool = False) -> None:
|
||||||
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 +181,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,13 +195,13 @@ def joinDomain(
|
|||||||
lpAccount = LPCWSTR(account)
|
lpAccount = LPCWSTR(account)
|
||||||
lpPassword = LPCWSTR(password)
|
lpPassword = LPCWSTR(password)
|
||||||
|
|
||||||
res = ctypes.windll.netapi32.NetJoinDomain(
|
res = ctypes.windll.netapi32.NetJoinDomain( # type: ignore
|
||||||
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( # type: ignore
|
||||||
None, lpDomain, None, lpAccount, lpPassword, flags
|
None, lpDomain, None, lpAccount, lpPassword, flags
|
||||||
)
|
)
|
||||||
if res:
|
if res:
|
||||||
@ -247,14 +228,12 @@ def changeUserPassword(user: str, oldPassword: str, newPassword: str) -> None:
|
|||||||
|
|
||||||
# res = ctypes.windll.netapi32.NetUserChangePassword(None, lpUser, lpOldPassword, lpNewPassword)
|
# res = ctypes.windll.netapi32.NetUserChangePassword(None, lpUser, lpOldPassword, lpNewPassword)
|
||||||
# Try to set new password "a las bravas", ignoring old one. This will not work with domain users
|
# Try to set new password "a las bravas", ignoring old one. This will not work with domain users
|
||||||
res = win32net.NetUserSetInfo(None, user, 1003, {'password': newPassword})
|
res = win32net.NetUserSetInfo(None, user, 1003, {'password': newPassword}) # type: ignore
|
||||||
|
|
||||||
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
|
||||||
@ -274,14 +253,14 @@ def initIdleDuration(atLeastSeconds: int): # pylint: disable=unused-argument
|
|||||||
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
|
if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo)) == 0: # type: ignore
|
||||||
) # pylint: disable=attribute-defined-outside-init
|
|
||||||
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 # type: ignore
|
||||||
if current < lastInputInfo.dwTime:
|
if current < lastInputInfo.dwTime:
|
||||||
current += 4294967296 # If current has "rolled" to zero, adjust it so it is greater than lastInputInfo
|
current += (
|
||||||
|
4294967296 # If current has "rolled" to zero, adjust it so it is greater than lastInputInfo
|
||||||
|
)
|
||||||
millis = current - lastInputInfo.dwTime # @UndefinedVariable
|
millis = current - lastInputInfo.dwTime # @UndefinedVariable
|
||||||
return millis / 1000.0
|
return millis / 1000.0
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -306,9 +285,7 @@ def getSessionType() -> str:
|
|||||||
return os.environ.get('SESSIONNAME', 'unknown')
|
return os.environ.get('SESSIONNAME', 'unknown')
|
||||||
|
|
||||||
|
|
||||||
def writeToPipe(
|
def writeToPipe(pipeName: str, bytesPayload: bytes, waitForResponse: bool) -> typing.Optional[bytes]:
|
||||||
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:
|
||||||
@ -323,8 +300,6 @@ def writeToPipe(
|
|||||||
|
|
||||||
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)
|
||||||
|
@ -49,11 +49,13 @@ from ..log import logger
|
|||||||
|
|
||||||
REMOTE_USERS_SID = 'S-1-5-32-555' # Well nown sid for remote desktop users
|
REMOTE_USERS_SID = 'S-1-5-32-555' # Well nown sid for remote desktop users
|
||||||
|
|
||||||
|
|
||||||
class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||||
'''
|
'''
|
||||||
This class represents a Windows Service for managing actor interactions
|
This class represents a Windows Service for managing actor interactions
|
||||||
with UDS Broker and Machine
|
with UDS Broker and Machine
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# ServiceeFramework related
|
# ServiceeFramework related
|
||||||
_svc_name_ = "UDSActorNG"
|
_svc_name_ = "UDSActorNG"
|
||||||
_svc_display_name_ = "UDS Actor Service"
|
_svc_display_name_ = "UDS Actor Service"
|
||||||
@ -78,7 +80,9 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
SvcShutdown = SvcStop
|
SvcShutdown = SvcStop
|
||||||
|
|
||||||
def notifyStop(self) -> None:
|
def notifyStop(self) -> None:
|
||||||
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STOPPED, (self._svc_name_, ''))
|
servicemanager.LogMsg(
|
||||||
|
servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STOPPED, (self._svc_name_, '')
|
||||||
|
)
|
||||||
super().notifyStop()
|
super().notifyStop()
|
||||||
|
|
||||||
def doWait(self, miliseconds: int) -> None:
|
def doWait(self, miliseconds: int) -> None:
|
||||||
@ -86,7 +90,9 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
# On windows, and while on tasks, ensure that our app processes waiting messages on "wait times"
|
# On windows, and while on tasks, ensure that our app processes waiting messages on "wait times"
|
||||||
pythoncom.PumpWaitingMessages() # pylint: disable=no-member
|
pythoncom.PumpWaitingMessages() # pylint: disable=no-member
|
||||||
|
|
||||||
def oneStepJoin(self, name: str, domain: str, ou: str, account: str, password: str) -> None: # pylint: disable=too-many-arguments
|
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
|
Ejecutes the join domain in exactly one step
|
||||||
'''
|
'''
|
||||||
@ -103,7 +109,9 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
logger.debug('Requested join domain {} without errors'.format(domain))
|
logger.debug('Requested join domain {} without errors'.format(domain))
|
||||||
self.reboot()
|
self.reboot()
|
||||||
|
|
||||||
def multiStepJoin(self, name: str, domain: str, ou: str, account: str, password: str) -> None: # pylint: disable=too-many-arguments
|
def multiStepJoin(
|
||||||
|
self, name: str, domain: str, ou: str, account: str, password: str
|
||||||
|
) -> None: # pylint: disable=too-many-arguments
|
||||||
currName = operations.getComputerName()
|
currName = operations.getComputerName()
|
||||||
if currName.lower() == name.lower():
|
if currName.lower() == name.lower():
|
||||||
currDomain = operations.getDomainName()
|
currDomain = operations.getDomainName()
|
||||||
@ -119,17 +127,21 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
logger.info('Rebooting computer for activating new name {}'.format(name))
|
logger.info('Rebooting computer for activating new name {}'.format(name))
|
||||||
self.reboot()
|
self.reboot()
|
||||||
|
|
||||||
def joinDomain( # pylint: disable=unused-argument, too-many-arguments
|
def joinDomain(self, name: str, custom: typing.Mapping[str, typing.Any]) -> None:
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
domain: str,
|
|
||||||
ou: str,
|
|
||||||
account: str,
|
|
||||||
password: str
|
|
||||||
) -> None:
|
|
||||||
versionData = operations.getWindowsVersion()
|
versionData = operations.getWindowsVersion()
|
||||||
versionInt = versionData[0] * 10 + versionData[1]
|
versionInt = versionData[0] * 10 + versionData[1]
|
||||||
logger.debug('Starting joining domain {} with name {} (detected operating version: {})'.format(domain, name, versionData))
|
|
||||||
|
# Extract custom data
|
||||||
|
domain = custom.get('domain', '')
|
||||||
|
ou = custom.get('ou', '')
|
||||||
|
account = custom.get('account', '')
|
||||||
|
password = custom.get('password', '')
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
'Starting joining domain {} with name {} (detected operating version: {})'.format(
|
||||||
|
domain, name, versionData
|
||||||
|
)
|
||||||
|
)
|
||||||
# Accepts one step joinDomain, also remember XP is no more supported by
|
# Accepts one step joinDomain, also remember XP is no more supported by
|
||||||
# microsoft, but this also must works with it because will do a "multi
|
# microsoft, but this also must works with it because will do a "multi
|
||||||
# step" join
|
# step" join
|
||||||
@ -139,17 +151,19 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
logger.info('Using multiple step join because configuration requests to do so')
|
logger.info('Using multiple step join because configuration requests to do so')
|
||||||
self.multiStepJoin(name, domain, ou, account, password)
|
self.multiStepJoin(name, domain, ou, account, password)
|
||||||
|
|
||||||
def preConnect(self, userName: str, protocol: str, ip: str, hostname: str, udsUserName: str) -> str:
|
def preConnect(self, userName: str, protocol: str, ip: str, hostname: str, udsUserName: str) -> str:
|
||||||
logger.debug('Pre connect invoked')
|
logger.debug('Pre connect invoked')
|
||||||
|
|
||||||
if protocol == 'rdp': # If connection is not using rdp, skip adding user
|
if protocol == 'rdp': # If connection is not using rdp, skip adding user
|
||||||
# Well known SSID for Remote Desktop Users
|
# Well known SSID for Remote Desktop Users
|
||||||
groupName = win32security.LookupAccountSid(None, win32security.GetBinarySid(REMOTE_USERS_SID))[0]
|
groupName = win32security.LookupAccountSid(None, win32security.GetBinarySid(REMOTE_USERS_SID))[0] # type: ignore
|
||||||
|
|
||||||
useraAlreadyInGroup = False
|
useraAlreadyInGroup = False
|
||||||
resumeHandle = 0
|
resumeHandle = 0
|
||||||
while True:
|
while True:
|
||||||
users, _, resumeHandle = win32net.NetLocalGroupGetMembers(None, groupName, 1, resumeHandle, 32768)
|
users, _, resumeHandle = win32net.NetLocalGroupGetMembers(
|
||||||
|
None, groupName, 1, resumeHandle, 32768 # type: ignore
|
||||||
|
)[:3]
|
||||||
if userName.lower() in [u['name'].lower() for u in users]:
|
if userName.lower() in [u['name'].lower() for u in users]:
|
||||||
useraAlreadyInGroup = True
|
useraAlreadyInGroup = True
|
||||||
break
|
break
|
||||||
@ -161,7 +175,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
self._user = userName
|
self._user = userName
|
||||||
try:
|
try:
|
||||||
userSSID = win32security.LookupAccountName(None, userName)[0]
|
userSSID = win32security.LookupAccountName(None, userName)[0]
|
||||||
win32net.NetLocalGroupAddMembers(None, groupName, 0, [{'sid': userSSID}])
|
win32net.NetLocalGroupAddMembers(None, groupName, 0, [{'sid': userSSID}]) # type: ignore
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Exception adding user to Remote Desktop Users: {}'.format(e))
|
logger.error('Exception adding user to Remote Desktop Users: {}'.format(e))
|
||||||
else:
|
else:
|
||||||
@ -178,7 +192,12 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
# Compose packet for ov
|
# Compose packet for ov
|
||||||
usernameBytes = username.encode()
|
usernameBytes = username.encode()
|
||||||
passwordBytes = password.encode()
|
passwordBytes = password.encode()
|
||||||
packet = struct.pack('!I', len(usernameBytes)) + usernameBytes + struct.pack('!I', len(passwordBytes)) + passwordBytes
|
packet = (
|
||||||
|
struct.pack('!I', len(usernameBytes))
|
||||||
|
+ usernameBytes
|
||||||
|
+ struct.pack('!I', len(passwordBytes))
|
||||||
|
+ passwordBytes
|
||||||
|
)
|
||||||
# Send packet with username/password to ov pipe
|
# Send packet with username/password to ov pipe
|
||||||
operations.writeToPipe("\\\\.\\pipe\\VDSMDPipe", packet, True)
|
operations.writeToPipe("\\\\.\\pipe\\VDSMDPipe", packet, True)
|
||||||
return 'done'
|
return 'done'
|
||||||
@ -187,14 +206,14 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
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)
|
||||||
groupName = win32security.LookupAccountSid(None, p)[0]
|
groupName = win32security.LookupAccountSid(None, p)[0] # type: ignore
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('Exception getting Windows Group')
|
logger.error('Exception getting Windows Group')
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._user:
|
if self._user:
|
||||||
try:
|
try:
|
||||||
win32net.NetLocalGroupDelMembers(None, groupName, [self._user])
|
win32net.NetLocalGroupDelMembers(None, groupName, [self._user]) # type: ignore
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error('Exception removing user from Remote Desktop Users: {}'.format(e))
|
logger.error('Exception removing user from Remote Desktop Users: {}'.format(e))
|
||||||
|
|
||||||
@ -203,18 +222,22 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
Detect if windows is installing anything, so we can delay the execution of Service
|
Detect if windows is installing anything, so we can delay the execution of Service
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
key = wreg.OpenKey(wreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\State')
|
key = wreg.OpenKey(wreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\State') # type: ignore
|
||||||
data, _ = wreg.QueryValueEx(key, 'ImageState')
|
data, _ = wreg.QueryValueEx(key, 'ImageState') # type: ignore
|
||||||
logger.debug('State: %s', data)
|
logger.debug('State: %s', data)
|
||||||
return data != 'IMAGE_STATE_COMPLETE' # If ImageState is different of ImageStateComplete, there is something running on installation
|
return (
|
||||||
except Exception: # If not found, means that no installation is running
|
data != 'IMAGE_STATE_COMPLETE'
|
||||||
|
) # If ImageState is different of ImageStateComplete, there is something running on installation
|
||||||
|
except Exception: # If not found, means that no installation is running
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def SvcDoRun(self) -> None: # pylint: disable=too-many-statements, too-many-branches
|
def SvcDoRun(self) -> None: # pylint: disable=too-many-statements, too-many-branches
|
||||||
'''
|
'''
|
||||||
Main service loop
|
Main service loop
|
||||||
'''
|
'''
|
||||||
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ''))
|
servicemanager.LogMsg(
|
||||||
|
servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, '')
|
||||||
|
)
|
||||||
|
|
||||||
# call the CoInitialize to allow the registration to run in an other
|
# call the CoInitialize to allow the registration to run in an other
|
||||||
# thread
|
# thread
|
||||||
@ -239,7 +262,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
|||||||
logger.info('Service stopped due to init')
|
logger.info('Service stopped due to init')
|
||||||
self.finish()
|
self.finish()
|
||||||
win32event.WaitForSingleObject(self._hWaitStop, 5000)
|
win32event.WaitForSingleObject(self._hWaitStop, 5000)
|
||||||
return # Stop daemon if initializes told to do so
|
return # Stop daemon if initializes told to do so
|
||||||
|
|
||||||
# Initialization is done, set machine to ready for UDS, communicate urls, etc...
|
# Initialization is done, set machine to ready for UDS, communicate urls, etc...
|
||||||
self.setReady()
|
self.setReady()
|
||||||
|
@ -185,12 +185,12 @@ class LinuxOsADManager(LinuxOsManager):
|
|||||||
return {
|
return {
|
||||||
'action': 'rename_ad',
|
'action': 'rename_ad',
|
||||||
'name': userService.getName(),
|
'name': userService.getName(),
|
||||||
'ad': self._domain,
|
|
||||||
'username': self._account,
|
|
||||||
'password': self._password,
|
|
||||||
'ou': self._ou,
|
|
||||||
'isPersistent': self.isPersistent(),
|
|
||||||
'custom': {
|
'custom': {
|
||||||
|
'domain': self._domain,
|
||||||
|
'username': self._account,
|
||||||
|
'password': self._password,
|
||||||
|
'ou': self._ou,
|
||||||
|
'isPersistent': self.isPersistent(),
|
||||||
'clientSoftware': self._clientSoftware,
|
'clientSoftware': self._clientSoftware,
|
||||||
'serverSoftware': self._serverSoftware,
|
'serverSoftware': self._serverSoftware,
|
||||||
'membershipSoftware': self._membershipSoftware,
|
'membershipSoftware': self._membershipSoftware,
|
||||||
|
@ -174,11 +174,11 @@ class LinuxOsFreeIPAManager(LinuxOsManager):
|
|||||||
return {
|
return {
|
||||||
'action': 'rename_ad',
|
'action': 'rename_ad',
|
||||||
'name': userService.getName(),
|
'name': userService.getName(),
|
||||||
'ad': self._domain,
|
|
||||||
'username': self._account,
|
|
||||||
'password': self._password,
|
|
||||||
'isPersistent': self.isPersistent(),
|
|
||||||
'custom': {
|
'custom': {
|
||||||
|
'domain': self._domain,
|
||||||
|
'username': self._account,
|
||||||
|
'password': self._password,
|
||||||
|
'isPersistent': self.isPersistent(),
|
||||||
'clientSoftware': self._clientSoftware,
|
'clientSoftware': self._clientSoftware,
|
||||||
'serverSoftware': self._serverSoftware,
|
'serverSoftware': self._serverSoftware,
|
||||||
'membershipSoftware': self._membershipSoftware,
|
'membershipSoftware': self._membershipSoftware,
|
||||||
|
@ -151,7 +151,7 @@ class LinuxOsManager(osmanagers.OSManager):
|
|||||||
def actorData(
|
def actorData(
|
||||||
self, userService: 'UserService'
|
self, userService: 'UserService'
|
||||||
) -> typing.MutableMapping[str, typing.Any]:
|
) -> typing.MutableMapping[str, typing.Any]:
|
||||||
return {'action': 'rename', 'name': userService.getName()}
|
return {'action': 'rename', 'name': userService.getName()} # No custom data
|
||||||
|
|
||||||
def processUnused(self, userService: 'UserService') -> None:
|
def processUnused(self, userService: 'UserService') -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -114,9 +114,18 @@ class LinuxRandomPassManager(LinuxOsManager):
|
|||||||
return {
|
return {
|
||||||
'action': 'rename',
|
'action': 'rename',
|
||||||
'name': userService.getName(),
|
'name': userService.getName(),
|
||||||
|
|
||||||
|
# Repeat data, to keep compat with old versions of Actor
|
||||||
|
# Will be removed in a couple of versions
|
||||||
'username': self._userAccount,
|
'username': self._userAccount,
|
||||||
'password': '', # On linux, user password is not needed so we provide an empty one
|
'password': '', # On linux, user password is not needed so we provide an empty one
|
||||||
'new_password': self.genPassword(userService),
|
'new_password': self.genPassword(userService),
|
||||||
|
|
||||||
|
'custom': {
|
||||||
|
'username': self._userAccount,
|
||||||
|
'password': '', # On linux, user password is not needed so we provide an empty one
|
||||||
|
'new_password': self.genPassword(userService),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def marshal(self) -> bytes:
|
def marshal(self) -> bytes:
|
||||||
|
@ -160,7 +160,7 @@ class WindowsOsManager(osmanagers.OSManager):
|
|||||||
def actorData(
|
def actorData(
|
||||||
self, userService: 'UserService'
|
self, userService: 'UserService'
|
||||||
) -> typing.MutableMapping[str, typing.Any]:
|
) -> typing.MutableMapping[str, typing.Any]:
|
||||||
return {'action': 'rename', 'name': userService.getName()}
|
return {'action': 'rename', 'name': userService.getName()} # No custom data
|
||||||
|
|
||||||
def processUserPassword(
|
def processUserPassword(
|
||||||
self, userService: 'UserService', username: str, password: str
|
self, userService: 'UserService', username: str, password: str
|
||||||
|
@ -440,10 +440,20 @@ class WinDomainOsManager(WindowsOsManager):
|
|||||||
return {
|
return {
|
||||||
'action': 'rename_ad',
|
'action': 'rename_ad',
|
||||||
'name': userService.getName(),
|
'name': userService.getName(),
|
||||||
|
|
||||||
|
# Repeat data, to keep compat with old versions of Actor
|
||||||
|
# Will be removed in a couple of versions
|
||||||
'ad': self._domain,
|
'ad': self._domain,
|
||||||
'ou': self._ou,
|
'ou': self._ou,
|
||||||
'username': self._account,
|
'username': self._account,
|
||||||
'password': self._password,
|
'password': self._password,
|
||||||
|
|
||||||
|
'custom': {
|
||||||
|
'domain': self._domain,
|
||||||
|
'ou': self._ou,
|
||||||
|
'username': self._account,
|
||||||
|
'password': self._password,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def marshal(self) -> bytes:
|
def marshal(self) -> bytes:
|
||||||
|
@ -127,9 +127,18 @@ class WinRandomPassManager(WindowsOsManager):
|
|||||||
return {
|
return {
|
||||||
'action': 'rename',
|
'action': 'rename',
|
||||||
'name': userService.getName(),
|
'name': userService.getName(),
|
||||||
|
|
||||||
|
# Repeat data, to keep compat with old versions of Actor
|
||||||
|
# Will be removed in a couple of versions
|
||||||
'username': self._userAccount,
|
'username': self._userAccount,
|
||||||
'password': self._password,
|
'password': self._password,
|
||||||
'new_password': self.genPassword(userService),
|
'new_password': self.genPassword(userService),
|
||||||
|
|
||||||
|
'custom': {
|
||||||
|
'username': self._userAccount,
|
||||||
|
'password': self._password,
|
||||||
|
'new_password': self.genPassword(userService),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def marshal(self) -> bytes:
|
def marshal(self) -> bytes:
|
||||||
|
Loading…
Reference in New Issue
Block a user