Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Main/Forms/Forms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1832,7 +1832,7 @@ PreferencesDialogBase::PreferencesDialogBase( wxWindow* parent, wxWindowID id, c
DismountOnScreenSaverCheckBox = new wxCheckBox( sbSizer13->GetStaticBox(), wxID_ANY, _("IDC_PREF_UNMOUNT_SCREENSAVER"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizer13->Add( DismountOnScreenSaverCheckBox, 0, wxALL, 5 );

DismountOnPowerSavingCheckBox = new wxCheckBox( sbSizer13->GetStaticBox(), wxID_ANY, _("LINUX_ENTERING_POVERSAWING"), wxDefaultPosition, wxDefaultSize, 0 );
DismountOnPowerSavingCheckBox = new wxCheckBox( sbSizer13->GetStaticBox(), wxID_ANY, _("LINUX_ENTERING_POWERSAVING"), wxDefaultPosition, wxDefaultSize, 0 );
sbSizer13->Add( DismountOnPowerSavingCheckBox, 0, wxALL, 5 );


Expand Down
8 changes: 6 additions & 2 deletions src/Main/Forms/PreferencesDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,16 @@ namespace VeraCrypt
CloseExplorerWindowsOnDismountCheckBox->Show (false);
#endif

#ifndef wxHAS_POWER_EVENTS
// On macOS, wxHAS_POWER_EVENTS is undefined but sleep is handled by a
// native observer (see MacOSXSleepLock), so keep the checkbox visible.
#if !defined(wxHAS_POWER_EVENTS) && !defined(TC_MACOSX)
DismountOnPowerSavingCheckBox->Show (false);
#endif

#ifdef TC_MACOSX
DismountOnScreenSaverCheckBox->Show (false);
// On macOS this checkbox drives dismount on screen lock (see
// MacOSXSleepLock), so relabel it accordingly.
DismountOnScreenSaverCheckBox->SetLabel (LangString["IDC_PREF_UNMOUNT_SESSION_LOCKED"]);
DismountOnLogOffCheckBox->SetLabel (LangString["LINUX_VC_QUITS"]);
Comment on lines +298 to 308

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please align the visible preference text with the macOS behavior. If this means screen lock, please use the existing IDC_PREF_UNMOUNT_SESSION_LOCKED label on macOS, or also handle the actual screen saver notification. Also, making the power saving checkbox visible exposes the existing LINUX_ENTERING_POVERSAWING typo, which should be fixed or avoided.

OpenExplorerWindowAfterMountCheckBox->SetLabel (LangString["LINUX_OPEN_FINDER"]);

Expand Down
2 changes: 1 addition & 1 deletion src/Main/Forms/TrueCrypt.fbp
Original file line number Diff line number Diff line change
Expand Up @@ -11134,7 +11134,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">LINUX_ENTERING_POVERSAWING</property>
<property name="label">LINUX_ENTERING_POWERSAVING</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
Expand Down
39 changes: 39 additions & 0 deletions src/Main/GraphicUserInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "FatalErrorHandler.h"
#ifdef TC_MACOSX
#include "MacOSXSecureTextFieldHotkeys.h"
#include "MacOSXSleepLock.h"
#endif
#include "Forms/DeviceSelectionDialog.h"
#include "Forms/KeyfileGeneratorDialog.h"
Expand Down Expand Up @@ -184,6 +185,7 @@ namespace VeraCrypt
{
#ifdef TC_MACOSX
UninstallMacOSXSecureTextFieldHotkeys();
UninstallMacOSXSleepLockHandler();
#endif
try
{
Expand Down Expand Up @@ -1038,6 +1040,38 @@ namespace VeraCrypt
}
}

#ifdef TC_MACOSX
// Called from MacOSXSleepLock.mm on the main thread when the system is about
// to sleep. wxWidgets does not deliver wxEVT_POWER_SUSPENDING on macOS
// (wxHAS_POWER_EVENTS is undefined there), so this observer fills that gap.
// AutoDismountVolumes is called with alwaysForce=false so that the
// ForceAutoDismount preference decides whether volumes with open files are
// detached, matching the Windows auto-dismount events (bForceAutoDismount).
void OnMacOSXSystemWillSleep ()
{
if (Gui && Gui->GetPreferences().BackgroundTaskEnabled && Gui->GetPreferences().DismountOnPowerSaving)
{
VolumeInfoList mountedVolumes = Core->GetMountedVolumes();
if (!mountedVolumes.empty())
Gui->AutoDismountVolumes (mountedVolumes, false);
}
}

// Called from MacOSXSleepLock.mm on the main thread when the user session
// has been verified as locked. macOS has no equivalent of the Windows
// screen-saver polling used by MainFrame::OnTimer, so screen-lock dismount
// is wired up here instead. Force semantics as above.
void OnMacOSXScreenLocked ()
{
if (Gui && Gui->GetPreferences().BackgroundTaskEnabled && Gui->GetPreferences().DismountOnScreenSaver)
{
VolumeInfoList mountedVolumes = Core->GetMountedVolumes();
if (!mountedVolumes.empty())
Gui->AutoDismountVolumes (mountedVolumes, false);
}
}
Comment on lines +1050 to +1072

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This calls OnAutoDismountAllEvent, which currently uses AutoDismountVolumes with alwaysForce=true. Please make that behavior explicit and intentional for macOS sleep and screen lock, or use a path that honors ForceAutoDismount. Screen lock can otherwise detach busy volumes.

#endif

bool GraphicUserInterface::OnInit ()
{
Gui = this;
Expand Down Expand Up @@ -1193,6 +1227,11 @@ namespace VeraCrypt
#ifdef wxHAS_POWER_EVENTS
Gui->Connect (wxEVT_POWER_SUSPENDING, wxPowerEventHandler (GraphicUserInterface::OnPowerSuspending));
#endif
#ifdef TC_MACOSX
// macOS lacks wxHAS_POWER_EVENTS; use native observers for sleep and
// screen lock so volumes can be auto-dismounted on those events.
InstallMacOSXSleepLockHandler();
#endif

mMainFrame = new MainFrame (nullptr);
#if defined(TC_UNIX)
Expand Down
28 changes: 28 additions & 0 deletions src/Main/MacOSXSleepLock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright (c) 2013-2026 AM Crypto. All rights reserved.

Governed by the Apache License 2.0 the full text of which is
contained in the file License.txt included in VeraCrypt binary and source
code distribution packages.
*/

#ifndef TC_HEADER_Main_MacOSXSleepLock
#define TC_HEADER_Main_MacOSXSleepLock

#ifdef TC_MACOSX
namespace VeraCrypt
{
// Register/unregister observers for system sleep and screen lock.
// Implemented in MacOSXSleepLock.mm.
void InstallMacOSXSleepLockHandler ();
void UninstallMacOSXSleepLockHandler ();

// Invoked by the observers above when the corresponding event occurs.
// Implemented on the C++ side (GraphicUserInterface.cpp) so that all
// wxWidgets / Core logic stays out of the Objective-C++ file.
void OnMacOSXSystemWillSleep ();
void OnMacOSXScreenLocked ();
}
#endif

#endif // TC_HEADER_Main_MacOSXSleepLock
133 changes: 133 additions & 0 deletions src/Main/MacOSXSleepLock.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
Copyright (c) 2013-2026 AM Crypto. All rights reserved.

Governed by the Apache License 2.0 the full text of which is
contained in the file License.txt included in VeraCrypt binary and source
code distribution packages.
*/

#include "System.h"
#include "MacOSXSleepLock.h"

#ifdef TC_MACOSX
#import <Cocoa/Cocoa.h>
#import <ApplicationServices/ApplicationServices.h>

// Queries the window server for the actual lock state of the current session.
// The com.apple.screenIsLocked distributed notification can be posted by any
// local process, so it is treated only as a hint and the dismount is performed
// only if the session really is locked.
static bool SessionIsLocked ()
{
bool locked = false;
CFDictionaryRef session = CGSessionCopyCurrentDictionary ();
if (session)
{
CFTypeRef value = CFDictionaryGetValue (session, CFSTR ("CGSSessionScreenIsLocked"));
locked = value && CFGetTypeID (value) == CFBooleanGetTypeID () && CFBooleanGetValue ((CFBooleanRef) value);
CFRelease (session);
}
return locked;
}

@interface VCSleepLockObserver : NSObject
- (void) systemWillSleep: (NSNotification *) notification;
- (void) screenLocked: (NSNotification *) notification;
- (void) dismountIfSessionLocked;
@end

@implementation VCSleepLockObserver

// The callbacks below are entered from AppKit notification dispatch; a C++
// exception must not unwind through those Objective-C frames, so every call
// into VeraCrypt code is guarded here. The dismount is best-effort: showing
// UI is not reliable while the session is locking or the system is going to
// sleep, so failures are ignored.

- (void) systemWillSleep: (NSNotification *) notification
{
(void) notification;
try
{
VeraCrypt::OnMacOSXSystemWillSleep ();
}
catch (...) { }
}

- (void) screenLocked: (NSNotification *) notification
{
(void) notification;
// The window server can update the session dictionary slightly after the
// notification is delivered, so if the session does not report itself as
// locked yet, re-check once after a short delay instead of giving up.
if (SessionIsLocked ())
{
[self dismountIfSessionLocked];
}
else
{
[NSObject cancelPreviousPerformRequestsWithTarget: self selector: @selector (dismountIfSessionLocked) object: nil];
[self performSelector: @selector (dismountIfSessionLocked) withObject: nil afterDelay: 1.0];
}
}

- (void) dismountIfSessionLocked
{
if (!SessionIsLocked ())
return;

try
{
VeraCrypt::OnMacOSXScreenLocked ();
}
catch (...) { }
}
Comment on lines +47 to +84

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an exception boundary before returning to Cocoa notification delivery. These callbacks enter the VeraCrypt dismount path, and GetMountedVolumes can still throw before or after DismountVolumes. Exceptions shouldn't escape through AppKit notification dispatch.


@end

namespace VeraCrypt
{
// Non-ARC build (see the .mm compile rule in Build/Include/Makefile.inc),
// so the observer is retained by alloc/init and released in Uninstall.
static VCSleepLockObserver *SleepLockObserver = nil;

void InstallMacOSXSleepLockHandler ()
{
if (SleepLockObserver)
return;

SleepLockObserver = [[VCSleepLockObserver alloc] init];

// System sleep (lid close, idle sleep, Apple menu > Sleep). Delivered on
// the main thread by NSWorkspace's own notification center, which only
// the system feeds (it is per-process, unlike the distributed center).
[[[NSWorkspace sharedWorkspace] notificationCenter]
addObserver: SleepLockObserver
selector: @selector (systemWillSleep:)
name: NSWorkspaceWillSleepNotification
object: nil];

// Screen lock. macOS exposes no public notification for this; the
// com.apple.screenIsLocked distributed notification is the long-standing
// de-facto mechanism used to detect it. It is untrusted input: the
// handler verifies the actual session lock state before dismounting.
[[NSDistributedNotificationCenter defaultCenter]
addObserver: SleepLockObserver
selector: @selector (screenLocked:)
name: @"com.apple.screenIsLocked"
object: nil];
}
Comment on lines +110 to +119

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please treat this distributed notification as untrusted and verify that the session is actually locked before dismounting. Otherwise another local process may be able to post the same notification and trigger VeraCrypt forced dismount.


void UninstallMacOSXSleepLockHandler ()
{
if (!SleepLockObserver)
return;

[NSObject cancelPreviousPerformRequestsWithTarget: SleepLockObserver];
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver: SleepLockObserver];
[[NSDistributedNotificationCenter defaultCenter] removeObserver: SleepLockObserver];
[SleepLockObserver release];
SleepLockObserver = nil;
}
}
#endif
1 change: 1 addition & 0 deletions src/Main/Main.make
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ OBJS += FatalErrorHandler.o
OBJS += GraphicUserInterface.o
ifeq "$(PLATFORM)" "MacOSX"
OBJS += MacOSXSecureTextFieldHotkeys.o
OBJS += MacOSXSleepLock.o
endif
OBJS += VolumeHistory.o
OBJS += Forms/AboutDialog.o
Expand Down
Loading