From e48a7c5cf8eb3ed8f9d19218db02b868ca835a7c Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 12 May 2026 09:30:34 -0400 Subject: [PATCH] fix(occ): set GID before UID to ensure success The previous implementation attempted to set GID after dropping root UID, which would fail (silently) and made the posix_setgid() call effectively a no-op. This swaps the order to set the target GID first. Also refactored for clarity: - Renamed dropPrivileges to switchToConfigFileOwner for clearer intent - Update docblock to explicitly state best-effort limitations - Use more descriptive variable names - Re-organized for readability Signed-off-by: Josh --- occ | 51 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/occ b/occ index b7cfe961bde..99f11f147e0 100755 --- a/occ +++ b/occ @@ -8,26 +8,37 @@ declare(strict_types=1); * SPDX-License-Identifier: AGPL-3.0-or-later */ -/** - * Drop privileges when run as root - */ -function dropPrivileges(): void { - if (posix_getuid() !== 0) { - return; - } - - $configPath = __DIR__ . '/config/config.php'; - $uid = @fileowner($configPath); - if ($uid === false) { - return; - } - $info = posix_getpwuid($uid); - if ($info === false) { - return; - } - posix_setuid($uid); - posix_setgid($info['gid']); +if (posix_getuid() === 0) { + switchToConfigFileOwner(); } -dropPrivileges(); require_once __DIR__ . '/console.php'; + +/** + * Attempt to switch process identity to match the config file when run as root. + * + * This is a convenience for the operator to allow `occ` to run without manual + * user switching. It drops primary root privileges but is not a true sandbox. + * + * Note: Best-effort only. Will not change privileges if config file owner has + * no passwd entry. Does not clear environment variables nor supplementary groups. + * Failures are ignored here as downstream checks validate the final UID state. + */ +function switchToConfigFileOwner(): void { + $configPath = __DIR__ . '/config/config.php'; + $targetUid = @fileowner($configPath); + + if ($targetUid === false) { + return; + } + + $ownerInfo = posix_getpwuid($targetUid); + if ($ownerInfo === false) { + return; + } + + $targetGid = $ownerInfo['gid']; + + posix_setgid($targetGid); + posix_setuid($targetUid); +}