From 732d0bf5aeb9a7caf508af366f5def45a290aea5 Mon Sep 17 00:00:00 2001 From: ospab Date: Tue, 11 Aug 2026 23:28:36 +0300 Subject: [PATCH] fix(installer): grant users permission to start the helper task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The task was registered correctly and pointed at the right binary — the app's own log confirmed the match — but starting it failed: run: schtasks /Run failed (Some(1)): ERROR: Access is denied. falling back to a direct elevated launch — this is the consent prompt Registering a task and being allowed to start one are separate things, and I had conflated them. The principal (BUILTIN\Users by SID, HighestAvailable) decides who the task runs AS. Who may START it comes from the task's security descriptor, and a task created by an elevated installer defaults to granting execution to Administrators only. So the unprivileged GUI was refused and fell back to prompting on every connect, exactly as before the installer existed. This also explains why manual testing said the opposite: running the task by hand happened from an elevated console, where it works, which pointed suspicion at the app for several rounds. Register-ScheduledTask cannot set a descriptor, so the hook now follows the registration with a SetSecurityDescriptor call through the Task Scheduler COM object: GA for Administrators and SYSTEM, GR+GX for BUILTIN\Users. A failure there is reported on its own rather than being folded into the success message, since the task would otherwise look registered while remaining unusable. --- ostp-gui/src-tauri/windows/hooks.nsh | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/ostp-gui/src-tauri/windows/hooks.nsh b/ostp-gui/src-tauri/windows/hooks.nsh index 99ea14a..427feaa 100644 --- a/ostp-gui/src-tauri/windows/hooks.nsh +++ b/ostp-gui/src-tauri/windows/hooks.nsh @@ -49,7 +49,29 @@ Pop $R0 ${If} $R0 == 0 - DetailPrint "Helper task registered; connecting will not ask for consent." + ; Registering the task is not enough to make it usable. The principal above + ; decides WHO THE TASK RUNS AS; the task's security descriptor decides who + ; is allowed to START it, and they are not the same thing. A task created by + ; an elevated installer defaults to a DACL granting execution to + ; Administrators only, so the unprivileged GUI got + ; schtasks /Run -> ERROR: Access is denied + ; and fell back to prompting on every single connect. Running it by hand + ; from an elevated console worked, which is what made this look for a while + ; like the app was at fault. + ; + ; Register-ScheduledTask cannot set a descriptor, so this goes through the + ; Task Scheduler COM object. GA for Administrators and SYSTEM, GR+GX — + ; read and execute — for BUILTIN\Users (BU), which is what lets a normal + ; user start it without being elevated. + DetailPrint "Granting users permission to start the task..." + nsExec::ExecToLog `powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "$$svc = New-Object -ComObject Schedule.Service; $$svc.Connect(); $$t = $$svc.GetFolder('\').GetTask('OSTP TUN Helper'); $$t.SetSecurityDescriptor('D:(A;;GA;;;BA)(A;;GA;;;SY)(A;;GRGX;;;BU)', 0)"` + Pop $R1 + ${If} $R1 == 0 + DetailPrint "Helper task registered; connecting will not ask for consent." + ${Else} + DetailPrint "Task registered but its permissions could not be set (exit $R1)." + DetailPrint "Every connect will ask for consent." + ${EndIf} ${Else} ; Not fatal: the app still works, it just falls back to an elevated launch ; that asks for consent on each connect.