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 <josh.t.richards@gmail.com>
This commit is contained in:
Josh 2026-05-12 09:30:34 -04:00 committed by GitHub
parent b438b345b5
commit e48a7c5cf8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

51
occ
View file

@ -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);
}