Service install: fix the bin-folder write grant (icacls) so it actually applies

The first icacls grant did not take (bin files stayed Users:RX), so a stopped service
still could not be updated without admin. Grant BUILTIN\Users (SID *S-1-5-32-545,
locale-independent) Modify with (OI)(CI)(M) and /T over existing contents, and log
icacls stderr on failure instead of swallowing it. Matching fix in the dev bootstrap
script.

Gate: 40/40.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ednunp
2026-07-17 15:17:40 +01:00
co-authored by Claude Opus 4.8
parent 5dfc4faec6
commit 4b2baa58b5
2 changed files with 44 additions and 3 deletions
+8 -3
View File
@@ -135,19 +135,24 @@ public static class ServiceControl
{
try
{
// *S-1-5-11 = Authenticated Users (locale-independent). (OI)(CI) = inherit to files+subfolders; M = Modify.
// *S-1-5-32-545 = BUILTIN\Users (locale-independent) — the group the interactive user is in.
// (OI)(CI) = inherit to files + subfolders; (M) = Modify. /T applies to the existing contents too
// (the bin was just populated), /C keeps going past any single-file error. Capture stderr so a
// real failure is logged rather than swallowed.
var psi = new ProcessStartInfo
{
FileName = "icacls.exe",
Arguments = $"\"{ServiceStore.BinDirectory}\" /grant \"*S-1-5-11:(OI)(CI)M\" /T /C /Q",
Arguments = $"\"{ServiceStore.BinDirectory}\" /grant \"*S-1-5-32-545:(OI)(CI)(M)\" /T /C",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
};
using var p = Process.Start(psi);
var err = p?.StandardError.ReadToEnd();
var outp = p?.StandardOutput.ReadToEnd();
p?.WaitForExit(20000);
if (p is { ExitCode: not 0 }) ServiceStore.AppendServiceEvent($"install: icacls grant-write on bin returned {p.ExitCode}");
if (p is { ExitCode: not 0 }) ServiceStore.AppendServiceEvent($"install: icacls grant-write on bin returned {p.ExitCode}: {err}{outp}");
}
catch (Exception ex) { ServiceStore.AppendServiceEvent($"install: grant-write on bin failed: {ex.GetType().Name}: {ex.Message}"); }
}