diff --git a/CHANGELOG.md b/CHANGELOG.md
index 69d5d2551..9822f4294 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
### [2.4.2] 2022-09-14
+ * Fixed bash completion hanging when running as root without `COMPOSER_ALLOW_SUPERUSER` set (#11024)
+ * Fixed handling of plugin activation when running as root without `COMPOSER_ALLOW_SUPERUSER` set so it always happens after prompting, or does not happen if input is non-interactive
* Fixed package filter on `bump` command (#11053)
* Fixed handling of --ignore-platform-req with upper-bound ignores to not apply to conflict rules (#11037)
* Fixed handling of `COMPOSER_DISCARD_CHANGES` when set to `0`
diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php
index 5e4d84616..16302d424 100644
--- a/src/Composer/Console/Application.php
+++ b/src/Composer/Console/Application.php
@@ -205,6 +205,28 @@ class Application extends BaseApplication
}
}
+ $needsSudoCheck = !Platform::isWindows()
+ && function_exists('exec')
+ && !Platform::getEnv('COMPOSER_ALLOW_SUPERUSER')
+ && (ini_get('open_basedir') || !file_exists('/.dockerenv'));
+ $isNonAllowedRoot = false;
+
+ // Clobber sudo credentials if COMPOSER_ALLOW_SUPERUSER is not set before loading plugins
+ if ($needsSudoCheck) {
+ $isNonAllowedRoot = function_exists('posix_getuid') && posix_getuid() === 0;
+
+ if ($isNonAllowedRoot) {
+ if ($uid = (int) Platform::getEnv('SUDO_UID')) {
+ // Silently clobber any sudo credentials on the invoking user to avoid privilege escalations later on
+ // ref. https://github.com/composer/composer/issues/5119
+ Silencer::call('exec', "sudo -u \\#{$uid} sudo -K > /dev/null 2>&1");
+ }
+ }
+
+ // Silently clobber any remaining sudo leases on the current user as well to avoid privilege escalations
+ Silencer::call('exec', 'sudo -K > /dev/null 2>&1');
+ }
+
// avoid loading plugins/initializing the Composer instance earlier than necessary if no plugin command is needed
// if showing the version, we never need plugin commands
$mayNeedPluginCommand = false === $input->hasParameterOption(['--version', '-V'])
@@ -216,6 +238,21 @@ class Application extends BaseApplication
);
if ($mayNeedPluginCommand && !$this->disablePluginsByDefault && !$this->hasPluginCommands) {
+ // at this point plugins are needed, so if we are running as root and it is not allowed we need to prompt
+ // if interactive, and abort otherwise
+ if ($isNonAllowedRoot) {
+ $io->writeError('Do not run Composer as root/super user! See https://getcomposer.org/root for details');
+
+ if ($io->isInteractive() && $io->askConfirmation('Continue as root/super user [yes]? ')) {
+ // avoid a second prompt later
+ $isNonAllowedRoot = false;
+ } else {
+ $io->writeError('Aborting as no plugin should be loaded if running as super user is not explicitly allowed');
+
+ return 1;
+ }
+ }
+
try {
foreach ($this->getPluginCommands() as $command) {
if ($this->has($command->getName())) {
@@ -245,6 +282,10 @@ class Application extends BaseApplication
$this->hasPluginCommands = true;
}
+ if ($isNonAllowedRoot && !$io->isInteractive()) {
+ $this->disablePluginsByDefault = true;
+ }
+
// determine command name to be executed incl plugin commands, and check if it's a proxy command
$isProxyCommand = false;
if ($name = $this->getCommandName($input)) {
@@ -277,30 +318,16 @@ class Application extends BaseApplication
$io->writeError(sprintf('Warning: This development build of Composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.', $_SERVER['PHP_SELF']));
}
- if (
- !Platform::isWindows()
- && function_exists('exec')
- && !Platform::getEnv('COMPOSER_ALLOW_SUPERUSER')
- && (ini_get('open_basedir') || !file_exists('/.dockerenv'))
- ) {
- if (function_exists('posix_getuid') && posix_getuid() === 0) {
- if ($commandName !== 'self-update' && $commandName !== 'selfupdate') {
- $io->writeError('Do not run Composer as root/super user! See https://getcomposer.org/root for details');
+ if ($isNonAllowedRoot) {
+ if ($commandName !== 'self-update' && $commandName !== 'selfupdate' && $commandName !== '_complete') {
+ $io->writeError('Do not run Composer as root/super user! See https://getcomposer.org/root for details');
- if ($io->isInteractive()) {
- if (!$io->askConfirmation('Continue as root/super user [yes]? ')) {
- return 1;
- }
+ if ($io->isInteractive()) {
+ if (!$io->askConfirmation('Continue as root/super user [yes]? ')) {
+ return 1;
}
}
- if ($uid = (int) Platform::getEnv('SUDO_UID')) {
- // Silently clobber any sudo credentials on the invoking user to avoid privilege escalations later on
- // ref. https://github.com/composer/composer/issues/5119
- Silencer::call('exec', "sudo -u \\#{$uid} sudo -K > /dev/null 2>&1");
- }
}
- // Silently clobber any remaining sudo leases on the current user as well to avoid privilege escalations
- Silencer::call('exec', 'sudo -K > /dev/null 2>&1');
}
// Check system temp folder for usability as it can cause weird runtime issues otherwise