public void ActivateScreen() { var lockState = WorkstationHelper.GetCurrentSessionLockState(); if (lockState == WorkstationHelper.LockState.Locked || lockState == WorkstationHelper.LockState.Unknown) { try { // Should trigger activation of the screen in credential provider with zero impact on user //inputSimulator.Keyboard.KeyPress(WindowsInput.Native.VirtualKeyCode.F12); inputSimulator.Mouse.RightButtonClick(); // Windows 10 lockui ignores right mouse button for controls interaction } catch (Exception ex) { // The exception generated by library uses generic Exception class if (ex.Message.StartsWith("Some simulated input commands were not sent successfully")) { // This exception is thrown when the library could not successfully send simulated input // To the target window, usually due to User Interface Privacy Isolation (UIPI) _log.WriteLine("UIPI prevented simulated input", LogErrorSeverity.Warning); } else { throw; } } } }
public async Task Run() { #if !DEBUG if (WorkstationHelper.GetActiveSessionLockState() == WorkstationHelper.LockState.Unlocked) { try { SessionSwitchMonitor.SessionSwitch += SessionSwitchMonitor_SessionSwitch; _wcfLocker.LockWorkstation(); await Task.WhenAny(_tcs.Task, Task.Delay(_lockTimeout)); } finally { SessionSwitchMonitor.SessionSwitch -= SessionSwitchMonitor_SessionSwitch; } if (!_tcs.Task.IsCompleted && WorkstationHelper.GetActiveSessionLockState() == WorkstationHelper.LockState.Unlocked) { _wtsapiLocker.LockWorkstation(); } } #endif }
public SessionTimestampLogger(string timestampFilePath, SessionInfoProvider sessionInfoProvider, EventSaver eventSaver, ILog log) : base(nameof(SessionTimestampLogger), log) { _timestampFilePath = timestampFilePath; _sessionInfoProvider = sessionInfoProvider; _eventSaver = eventSaver; _timestampSaveTimer.Elapsed += TimestampSaveTimer_Elapsed; var savedTimestamp = GetSavedTimestamp(); if (savedTimestamp != null) { GenerateSessionEndEvent(savedTimestamp); ClearSavedTimestamp(); } SessionSwitchMonitor.SessionSwitch += SessionSwitchMonitor_SessionSwitch; var state = WorkstationHelper.GetSessionLockState(WorkstationHelper.GetSessionId()); if (state == WorkstationHelper.LockState.Unlocked) { SaveOrUpdateTimestamp(CreateNewTimestamp()); _timestampSaveTimer.Start(); } }
public void LockWorkstation() { var lockState = WorkstationHelper.GetActiveSessionLockState(); if (lockState == WorkstationHelper.LockState.Unlocked) { IntPtr ppSessionInfo = IntPtr.Zero; IntPtr userPtr = IntPtr.Zero; IntPtr domainPtr = IntPtr.Zero; Int32 count = 0; Int32 retval = WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref ppSessionInfo, ref count); Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO)); var currentSession = ppSessionInfo; uint bytes = 0; if (retval == 0) { return; } WriteLine("Query sessions"); for (int i = 0; i < count; i++) { WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)currentSession, typeof(WTS_SESSION_INFO)); currentSession += dataSize; WTSQuerySessionInformation(IntPtr.Zero, si.SessionID, WTS_INFO_CLASS.WTSUserName, out userPtr, out bytes); WTSQuerySessionInformation(IntPtr.Zero, si.SessionID, WTS_INFO_CLASS.WTSDomainName, out domainPtr, out bytes); var domain = Marshal.PtrToStringAnsi(domainPtr); var userName = Marshal.PtrToStringAnsi(userPtr); var sessionFullName = domain + "\\" + userName; WTSFreeMemory(userPtr); WTSFreeMemory(domainPtr); // Note: it might be a good idea to limit session disconnects only to those activated by triggered device //if (sessionFullName == sessionTolock) if (!string.IsNullOrWhiteSpace(domain) && !string.IsNullOrWhiteSpace(userName)) { if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive) { WriteLine($"Disconnecting session: {sessionFullName}"); bool disconnected = WTSDisconnectSession(IntPtr.Zero, si.SessionID, true); WriteLine($"Session disconnected: {disconnected}"); } else { WriteLine($"Session inactive: {sessionFullName}"); } } else { WriteLine($"Session skipped: {sessionFullName}"); } } WTSFreeMemory(ppSessionInfo); } }
void GenerateNewSessionId() { PreviousSession = CurrentSession; var virtualSessionId = Guid.NewGuid().ToString(); var sessionName = WorkstationHelper.GetSessionName(WorkstationHelper.GetSessionId()); CurrentSession = new SessionInfo(virtualSessionId, sessionName); WriteLine($"Generated new session id: (current: {CurrentSession?.SessionId}), (prev: {PreviousSession?.SessionId})"); }
void GenerateNewIdIfUnlocked() { var sid = WorkstationHelper.GetSessionId(); var state = WorkstationHelper.GetSessionLockState(sid); var name = WorkstationHelper.GetSessionName(sid); WriteLine($"Startup sid:{sid}, state:{state}, name:{name}"); if (state == WorkstationHelper.LockState.Unlocked && name != "SYSTEM") { GenerateNewSessionId(); } }
void ProximityMonitorManager_DeviceConnectionLost(object sender, IDevice device) { if (IsEnabled) { // Reconnect is performed only if manager is enabled and we are in unlocked windows session // Certain operations explicitly deny device reconnect and so CanReconnect will be FALSE during them if (!WorkstationHelper.IsActiveSessionLocked() && CanReconnect(device.SerialNo)) { Task.Run(() => Reconnect(device)); } else { SafeInvoke(DeviceDisconnected, device); } } }
void LockWorkstationAsync() { Task.Run(async() => { var lockState = WorkstationHelper.GetActiveSessionLockState(); if (lockState == WorkstationHelper.LockState.Unlocked) { try { await _messenger.Publish(new LockWorkstationMessage()); } catch (Exception ex) { WriteLine(ex); } } }); }
public void Start() { lock (_isRunningLock) { if (!_isRunning) { if (!WorkstationHelper.IsActiveSessionLocked()) { GenerateAndSaveUnlockToken(); } // Ensure that during the first launch on locked workstation unlock token is still generated if (_unlockTokenProvider.GetUnlockToken() == string.Empty) { GenerateAndSaveUnlockToken(); } _isRunning = true; WriteLine("Started"); } } }
/// <summary> /// Create and authorize remote device, then load credentials storage from this device /// </summary> /// <param name="authorizeDevice">If false, skip remote device authorization step. Default is true.</param> public async Task InitRemoteAndLoadStorageAsync(bool authorizeDevice = true) { if (Interlocked.CompareExchange(ref _interlockedRemote, 1, 0) == 0) { try { if (!IsCreatingRemoteDevice && !IsAuthorizingRemoteDevice && !IsLoadingStorage && WorkstationHelper.GetCurrentSessionLockState() == WorkstationHelper.LockState.Unlocked) { try { authCancellationTokenSource = new CancellationTokenSource(); var ct = authCancellationTokenSource.Token; remoteCancellationTokenSource = new CancellationTokenSource(); _infNid = Guid.NewGuid().ToString(); _errNid = Guid.NewGuid().ToString(); await CreateRemoteDeviceAsync(remoteCancellationTokenSource.Token); if (remoteCancellationTokenSource.IsCancellationRequested) { _log.WriteLine($"({SerialNo}) Remote vault creation cancelled"); return; } if (_remoteDevice != null) { _log.WriteLine($"({_remoteDevice.SerialNo}) Remote vault created"); await _remoteDevice.RefreshDeviceInfo(); if (_remoteDevice.AccessLevel != null) { _log.WriteLine($"({_remoteDevice.SerialNo}) access profile (allOk:{_remoteDevice.AccessLevel.IsAllOk}; " + $"pin:{_remoteDevice.AccessLevel.IsPinRequired}; " + $"newPin:{_remoteDevice.AccessLevel.IsNewPinRequired}; " + $"button:{_remoteDevice.AccessLevel.IsButtonRequired}; " + $"link:{_remoteDevice.AccessLevel.IsLinkRequired}; " + $"master:{_remoteDevice.AccessLevel.IsMasterKeyRequired}; " + $"locked:{_remoteDevice.AccessLevel.IsLocked})"); } else { _log.WriteLine($"({_remoteDevice.SerialNo}) access level is null"); } } if (_remoteDevice.IsLockedByCode) { throw new HideezException(HideezErrorCode.DeviceIsLocked); } else if (authorizeDevice && !IsAuthorized && _remoteDevice?.AccessLevel != null && !_remoteDevice.AccessLevel.IsAllOk) { await AuthorizeRemoteDevice(ct); } else if (!authorizeDevice && !IsAuthorized && _remoteDevice?.AccessLevel != null && _remoteDevice.AccessLevel.IsAllOk) { await AuthorizeRemoteDevice(ct); } else if (_remoteDevice?.AccessLevel != null && _remoteDevice.AccessLevel.IsLocked) { throw new HideezException(HideezErrorCode.DeviceIsLocked); } if (!ct.IsCancellationRequested && !IsStorageLoaded) { await LoadStorage(); } } catch (HideezException ex) when(ex.ErrorCode == HideezErrorCode.DeviceDisconnected) { _log.WriteLine("Remote vault creation aborted, vault disconnected", LogErrorSeverity.Warning); } catch (HideezException ex) when(ex.ErrorCode == HideezErrorCode.DeviceIsLocked) { if (_remoteDevice.IsLockedByCode) { await _metaMessenger.Publish(new ShowLockNotificationMessage(TranslationSource.Instance["Notification.DeviceLockedByCode.Message"], TranslationSource.Instance["Notification.DeviceLockedByCode.Caption"], new NotificationOptions() { CloseTimeout = NotificationOptions.LongTimeout }, Mac)); } else if (_remoteDevice.IsLockedByPin) { await _metaMessenger.Publish(new ShowLockNotificationMessage(TranslationSource.Instance["Notification.DeviceLockedByPin.Message"], TranslationSource.Instance["Notification.DeviceLockedByPin.Caption"], new NotificationOptions() { CloseTimeout = NotificationOptions.LongTimeout }, Mac)); } else { _log.WriteLine(ex); } } catch (HideezException ex) when(ex.ErrorCode == HideezErrorCode.DeviceIsLockedByPin) { } catch (HideezException ex) when(ex.ErrorCode == HideezErrorCode.DeviceIsLockedByCode) { } catch (Exception ex) { ShowError(ex.Message, _errNid); } finally { var tmp = authCancellationTokenSource; authCancellationTokenSource = null; tmp.Dispose(); tmp = remoteCancellationTokenSource; remoteCancellationTokenSource = null; tmp.Dispose(); } } } finally { Interlocked.Exchange(ref _interlockedRemote, 0); } } }
async Task MainWorkflow(string mac, bool rebondOnConnectionFail, bool tryUnlock, Action <WorkstationUnlockResult> onUnlockAttempt, CancellationToken ct) { // Ignore MainFlow requests for devices that are already connected // IsConnected-true indicates that device already finished main flow or is in progress var existingDevice = _deviceManager.Find(mac, (int)DefaultDeviceChannel.Main); if (existingDevice != null && existingDevice.IsConnected && !WorkstationHelper.IsActiveSessionLocked()) { return; } WriteLine($"Started main workflow ({mac})"); var flowId = Guid.NewGuid().ToString(); Started?.Invoke(this, flowId); bool workflowFinishedSuccessfully = false; bool deleteVaultBond = false; string errorMessage = null; IDevice device = null; try { await _ui.SendNotification(string.Empty, mac); _subp.PermissionsCheckProcessor.CheckPermissions(); // Start periodic screen activator to raise the "curtain" if (WorkstationHelper.IsActiveSessionLocked()) { _screenActivator?.ActivateScreen(); _screenActivator?.StartPeriodicScreenActivation(0); await new WaitWorkstationUnlockerConnectProc(_workstationUnlocker) .Run(SdkConfig.WorkstationUnlockerConnectTimeout, ct); } device = await _subp.VaultConnectionProcessor.ConnectVault(mac, rebondOnConnectionFail, ct); device.Disconnected += OnVaultDisconnectedDuringFlow; device.OperationCancelled += OnCancelledByVaultButton; await _subp.VaultConnectionProcessor.WaitVaultInitialization(mac, device, ct); if (device.IsBoot) { throw new WorkflowException(TranslationSource.Instance["ConnectionFlow.Error.VaultInBootloaderMode"]); } device.SetUserProperty(CustomProperties.HW_CONNECTION_STATE_PROP, HwVaultConnectionState.Initializing); HwVaultInfoFromHesDto vaultInfo = new HwVaultInfoFromHesDto(); // Initializes with default values for when HES is not connected if (_hesConnection.State == HesConnectionState.Connected) { vaultInfo = await _hesConnection.UpdateHwVaultProperties(new HwVaultInfoFromClientDto(device), true); } _subp.CacheVaultInfoProcessor.CacheAndUpdateVaultOwner(ref device, vaultInfo, ct); await _subp.LicensingProcessor.CheckLicense(device, vaultInfo, ct); vaultInfo = await _subp.StateUpdateProcessor.UpdateVaultStatus(device, vaultInfo, ct); vaultInfo = await _subp.ActivationProcessor.ActivateVault(device, vaultInfo, ct); await _subp.MasterkeyProcessor.AuthVault(device, ct); var osAccUpdateTask = _subp.AccountsUpdateProcessor.UpdateAccounts(device, vaultInfo, true); if (_workstationUnlocker.IsConnected && WorkstationHelper.IsActiveSessionLocked() && tryUnlock) { await Task.WhenAll(_subp.UserAuthorizationProcessor.AuthorizeUser(device, ct), osAccUpdateTask); _screenActivator?.StopPeriodicScreenActivation(); await _subp.UnlockProcessor.UnlockWorkstation(device, flowId, onUnlockAttempt, ct); } else { await osAccUpdateTask; } device.SetUserProperty(CustomProperties.HW_CONNECTION_STATE_PROP, HwVaultConnectionState.Finalizing); WriteLine($"Finalizing main workflow: ({device.Id})"); DeviceFinilizingMainFlow?.Invoke(this, device); await _subp.AccountsUpdateProcessor.UpdateAccounts(device, vaultInfo, false); device.SetUserProperty(CustomProperties.HW_CONNECTION_STATE_PROP, HwVaultConnectionState.Online); if (_hesConnection.State == HesConnectionState.Connected) { await _hesConnection.UpdateHwVaultProperties(new HwVaultInfoFromClientDto(device), false); } workflowFinishedSuccessfully = true; } catch (HideezException ex) { switch (ex.ErrorCode) { case HideezErrorCode.DeviceIsLocked: case HideezErrorCode.DeviceNotAssignedToUser: case HideezErrorCode.HesDeviceNotFound: case HideezErrorCode.HesDeviceCompromised: case HideezErrorCode.DeviceHasBeenWiped: // There errors require bond removal deleteVaultBond = true; errorMessage = HideezExceptionLocalization.GetErrorAsString(ex); break; case HideezErrorCode.ButtonConfirmationTimeout: case HideezErrorCode.GetPinTimeout: case HideezErrorCode.GetActivationCodeTimeout: // Silent handling WriteLine(ex); break; case HideezErrorCode.HesNotConnected: // We need to display an error message which is different from one that is usually shown for that error code. errorMessage = TranslationSource.Instance["ConnectionFlow.Error.UnexpectedlyLostNetworkConnection"]; break; default: errorMessage = HideezExceptionLocalization.GetErrorAsString(ex); break; } } catch (VaultFailedToAuthorizeException ex) { // User should never receive this error unless there is a bug in algorithm errorMessage = HideezExceptionLocalization.GetErrorAsString(ex); } catch (WorkstationUnlockFailedException ex) { // Silent handling of failed workstation unlock // The actual message will be displayed by credential provider WriteLine(ex); } catch (OperationCanceledException ex) { // Silent cancelation handling WriteLine(ex); } catch (TimeoutException ex) { // Silent timeout handling WriteLine(ex); } catch (WebSocketException ex) { // Retrieve the most inner WebSocketException to retrieve the error code if (ex.WebSocketErrorCode != 0) { errorMessage = string.Format(TranslationSource.Instance["ConnectionFlow.Error.UnexpectedNetworkError"], ex.WebSocketErrorCode); } else if (ex.ErrorCode != 0) { errorMessage = string.Format(TranslationSource.Instance["ConnectionFlow.Error.UnexpectedNetworkError"], ex.ErrorCode); } else if (ex.InnerException is Win32Exception) { errorMessage = string.Format(TranslationSource.Instance["ConnectionFlow.Error.UnexpectedNetworkError"], "native " + (ex.InnerException as Win32Exception).NativeErrorCode); } } catch (Exception ex) { errorMessage = HideezExceptionLocalization.GetErrorAsString(ex); } finally { if (device != null) { device.Disconnected -= OnVaultDisconnectedDuringFlow; device.OperationCancelled -= OnCancelledByVaultButton; } _screenActivator?.StopPeriodicScreenActivation(); } await WorkflowCleanup(errorMessage, mac, device, workflowFinishedSuccessfully, deleteVaultBond); Finished?.Invoke(this, flowId); WriteLine($"Main workflow end {mac}"); }