mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-15 01:01:09 +01:00
Start phd daemons as the correctly configured user and refuse otherwise
Summary: Fixes T5196 If no phd.user is configured the behaviour is unchanged besides printing a warning when run as root (Usually i would add an exit(1) here but that would break existing installs who do that). If phd.user is set and the current user is root it will run the daemon as: su USER -c "command" (I'm not sure if this works for every platform needed) Otherwise it will refuse to start if configured and current user mismatch. Test Plan: Stopped & Started phd daemon with various users and different phd.user settings including root Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: vinzent, epriestley Maniphest Tasks: T5196 Differential Revision: https://secure.phabricator.com/D11036
This commit is contained in:
parent
6132d8012b
commit
2fedb6f941
7 changed files with 115 additions and 6 deletions
2
resources/sql/autopatches/20141223.daemonloguser.sql
Normal file
2
resources/sql/autopatches/20141223.daemonloguser.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_daemon.daemon_log
|
||||||
|
ADD runningAsUser VARCHAR(255) COLLATE {$COLLATE_TEXT};
|
|
@ -43,12 +43,47 @@ final class PhabricatorSetupCheckDaemons extends PhabricatorSetupCheck {
|
||||||
->addCommand('phabricator/ $ ./bin/phd start');
|
->addCommand('phabricator/ $ ./bin/phd start');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$phd_user = PhabricatorEnv::getEnvConfig('phd.user');
|
||||||
$environment_hash = PhabricatorEnv::calculateEnvironmentHash();
|
$environment_hash = PhabricatorEnv::calculateEnvironmentHash();
|
||||||
$all_daemons = id(new PhabricatorDaemonLogQuery())
|
$all_daemons = id(new PhabricatorDaemonLogQuery())
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
|
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
|
||||||
->execute();
|
->execute();
|
||||||
foreach ($all_daemons as $daemon) {
|
foreach ($all_daemons as $daemon) {
|
||||||
|
|
||||||
|
if ($phd_user) {
|
||||||
|
if ($daemon->getRunningAsUser() != $phd_user) {
|
||||||
|
$doc_href = PhabricatorEnv::getDocLink(
|
||||||
|
'Managing Daemons with phd');
|
||||||
|
|
||||||
|
$summary = pht(
|
||||||
|
'At least one daemon is currently running as a different '.
|
||||||
|
'user than configured in the Phabricator phd.user setting');
|
||||||
|
|
||||||
|
$message = pht(
|
||||||
|
'A daemon is running as user %s while the Phabricator config '.
|
||||||
|
'specifies phd.user to be %s.'.
|
||||||
|
"\n\n".
|
||||||
|
'Either adjust phd.user to match %s or start '.
|
||||||
|
'the daemons as the correct user. '.
|
||||||
|
"\n\n".
|
||||||
|
'phd Daemons will try to '.
|
||||||
|
'use sudo to start as the configured user. '.
|
||||||
|
'Make sure that the user who starts phd has the correct '.
|
||||||
|
'sudo permissions to start phd daemons as %s',
|
||||||
|
phutil_tag('tt', array(), $daemon->getRunningAsUser()),
|
||||||
|
phutil_tag('tt', array(), $phd_user),
|
||||||
|
phutil_tag('tt', array(), $daemon->getRunningAsUser()),
|
||||||
|
phutil_tag('tt', array(), $phd_user));
|
||||||
|
|
||||||
|
$this->newIssue('daemons.run-as-different-user')
|
||||||
|
->setName(pht('Daemons are running as the wrong user'))
|
||||||
|
->setSummary($summary)
|
||||||
|
->setMessage($message)
|
||||||
|
->addCommand('phabricator/ $ ./bin/phd restart');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($daemon->getEnvHash() != $environment_hash) {
|
if ($daemon->getEnvHash() != $environment_hash) {
|
||||||
$doc_href = PhabricatorEnv::getDocLink(
|
$doc_href = PhabricatorEnv::getDocLink(
|
||||||
'Managing Daemons with phd');
|
'Managing Daemons with phd');
|
||||||
|
|
|
@ -163,6 +163,7 @@ final class PhabricatorDaemonLogViewController
|
||||||
$view->addProperty(pht('Daemon Class'), $daemon->getDaemon());
|
$view->addProperty(pht('Daemon Class'), $daemon->getDaemon());
|
||||||
$view->addProperty(pht('Host'), $daemon->getHost());
|
$view->addProperty(pht('Host'), $daemon->getHost());
|
||||||
$view->addProperty(pht('PID'), $daemon->getPID());
|
$view->addProperty(pht('PID'), $daemon->getPID());
|
||||||
|
$view->addProperty(pht('Running as'), $daemon->getRunningAsUser());
|
||||||
$view->addProperty(pht('Started'), phabricator_datetime($c_epoch, $viewer));
|
$view->addProperty(pht('Started'), phabricator_datetime($c_epoch, $viewer));
|
||||||
$view->addProperty(
|
$view->addProperty(
|
||||||
pht('Seen'),
|
pht('Seen'),
|
||||||
|
|
|
@ -34,11 +34,13 @@ final class PhabricatorDaemonEventListener extends PhabricatorEventListener {
|
||||||
|
|
||||||
private function handleLaunchEvent(PhutilEvent $event) {
|
private function handleLaunchEvent(PhutilEvent $event) {
|
||||||
$id = $event->getValue('id');
|
$id = $event->getValue('id');
|
||||||
|
$current_user = posix_getpwuid(posix_geteuid());
|
||||||
|
|
||||||
$daemon = id(new PhabricatorDaemonLog())
|
$daemon = id(new PhabricatorDaemonLog())
|
||||||
->setDaemon($event->getValue('daemonClass'))
|
->setDaemon($event->getValue('daemonClass'))
|
||||||
->setHost(php_uname('n'))
|
->setHost(php_uname('n'))
|
||||||
->setPID(getmypid())
|
->setPID(getmypid())
|
||||||
|
->setRunningAsUser($current_user['name'])
|
||||||
->setEnvHash(PhabricatorEnv::calculateEnvironmentHash())
|
->setEnvHash(PhabricatorEnv::calculateEnvironmentHash())
|
||||||
->setStatus(PhabricatorDaemonLog::STATUS_RUNNING)
|
->setStatus(PhabricatorDaemonLog::STATUS_RUNNING)
|
||||||
->setArgv($event->getValue('argv'))
|
->setArgv($event->getValue('argv'))
|
||||||
|
|
|
@ -21,11 +21,17 @@ final class PhabricatorDaemonManagementDebugWorkflow
|
||||||
'name' => 'argv',
|
'name' => 'argv',
|
||||||
'wildcard' => true,
|
'wildcard' => true,
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'as-current-user',
|
||||||
|
'help' => 'Run the daemon as the current user '.
|
||||||
|
'instead of the configured phd.user',
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(PhutilArgumentParser $args) {
|
public function execute(PhutilArgumentParser $args) {
|
||||||
$argv = $args->getArg('argv');
|
$argv = $args->getArg('argv');
|
||||||
|
$run_as_current_user = $args->getArg('as-current-user');
|
||||||
|
|
||||||
if (!$argv) {
|
if (!$argv) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
|
@ -33,7 +39,11 @@ final class PhabricatorDaemonManagementDebugWorkflow
|
||||||
}
|
}
|
||||||
|
|
||||||
$daemon_class = array_shift($argv);
|
$daemon_class = array_shift($argv);
|
||||||
return $this->launchDaemon($daemon_class, $argv, $is_debug = true);
|
return $this->launchDaemon(
|
||||||
|
$daemon_class,
|
||||||
|
$argv,
|
||||||
|
$is_debug = true,
|
||||||
|
$run_as_current_user);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
abstract class PhabricatorDaemonManagementWorkflow
|
abstract class PhabricatorDaemonManagementWorkflow
|
||||||
extends PhabricatorManagementWorkflow {
|
extends PhabricatorManagementWorkflow {
|
||||||
|
|
||||||
|
private $runDaemonsAsUser = null;
|
||||||
|
|
||||||
protected final function loadAvailableDaemonClasses() {
|
protected final function loadAvailableDaemonClasses() {
|
||||||
$loader = new PhutilSymbolLoader();
|
$loader = new PhutilSymbolLoader();
|
||||||
return $loader
|
return $loader
|
||||||
|
@ -103,10 +105,37 @@ abstract class PhabricatorDaemonManagementWorkflow
|
||||||
return head($match);
|
return head($match);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final function launchDaemon($class, array $argv, $debug) {
|
protected final function launchDaemon(
|
||||||
|
$class,
|
||||||
|
array $argv,
|
||||||
|
$debug,
|
||||||
|
$run_as_current_user = false) {
|
||||||
|
|
||||||
$daemon = $this->findDaemonClass($class);
|
$daemon = $this->findDaemonClass($class);
|
||||||
$console = PhutilConsole::getConsole();
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
|
if (!$run_as_current_user) {
|
||||||
|
// Check if the script is started as the correct user
|
||||||
|
$phd_user = PhabricatorEnv::getEnvConfig('phd.user');
|
||||||
|
$current_user = posix_getpwuid(posix_geteuid());
|
||||||
|
$current_user = $current_user['name'];
|
||||||
|
if ($phd_user && $phd_user != $current_user) {
|
||||||
|
if ($debug) {
|
||||||
|
throw new PhutilArgumentUsageException(pht(
|
||||||
|
'You are trying to run a daemon as a nonstandard user, '.
|
||||||
|
'and `phd` was not able to `sudo` to the correct user. '."\n".
|
||||||
|
'Phabricator is configured to run daemons as "%s", '.
|
||||||
|
'but the current user is "%s". '."\n".
|
||||||
|
'Use `sudo` to run as a different user, pass `--as-current-user` '.
|
||||||
|
'to ignore this warning, or edit `phd.user` '.
|
||||||
|
'to change the configuration.', $phd_user, $current_user));
|
||||||
|
} else {
|
||||||
|
$this->runDaemonsAsUser = $phd_user;
|
||||||
|
$console->writeOut(pht('Starting daemons as %s', $phd_user)."\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($debug) {
|
if ($debug) {
|
||||||
if ($argv) {
|
if ($argv) {
|
||||||
$console->writeOut(
|
$console->writeOut(
|
||||||
|
@ -187,13 +216,41 @@ abstract class PhabricatorDaemonManagementWorkflow
|
||||||
|
|
||||||
phutil_passthru('(cd %s && exec %C)', $daemon_script_dir, $command);
|
phutil_passthru('(cd %s && exec %C)', $daemon_script_dir, $command);
|
||||||
} else {
|
} else {
|
||||||
$future = new ExecFuture('exec %C', $command);
|
try {
|
||||||
// Play games to keep 'ps' looking reasonable.
|
$this->executeDaemonLaunchCommand(
|
||||||
$future->setCWD($daemon_script_dir);
|
$command,
|
||||||
$future->resolvex();
|
$daemon_script_dir,
|
||||||
|
$this->runDaemonsAsUser);
|
||||||
|
} catch (CommandException $e) {
|
||||||
|
// Retry without sudo
|
||||||
|
$console->writeOut(pht(
|
||||||
|
"sudo command failed. Starting daemon as current user\n"));
|
||||||
|
$this->executeDaemonLaunchCommand(
|
||||||
|
$command,
|
||||||
|
$daemon_script_dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function executeDaemonLaunchCommand(
|
||||||
|
$command,
|
||||||
|
$daemon_script_dir,
|
||||||
|
$run_as_user = null) {
|
||||||
|
|
||||||
|
if ($run_as_user) {
|
||||||
|
// If anything else besides sudo should be
|
||||||
|
// supported then insert it here (runuser, su, ...)
|
||||||
|
$command = csprintf(
|
||||||
|
'sudo -En -u %s -- %C',
|
||||||
|
$run_as_user,
|
||||||
|
$command);
|
||||||
|
}
|
||||||
|
$future = new ExecFuture('exec %C', $command);
|
||||||
|
// Play games to keep 'ps' looking reasonable.
|
||||||
|
$future->setCWD($daemon_script_dir);
|
||||||
|
$future->resolvex();
|
||||||
|
}
|
||||||
|
|
||||||
public static function ignoreSignal($signo) {
|
public static function ignoreSignal($signo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ final class PhabricatorDaemonLog extends PhabricatorDaemonDAO
|
||||||
protected $daemon;
|
protected $daemon;
|
||||||
protected $host;
|
protected $host;
|
||||||
protected $pid;
|
protected $pid;
|
||||||
|
protected $runningAsUser;
|
||||||
protected $argv;
|
protected $argv;
|
||||||
protected $explicitArgv = array();
|
protected $explicitArgv = array();
|
||||||
protected $envHash;
|
protected $envHash;
|
||||||
|
@ -28,6 +29,7 @@ final class PhabricatorDaemonLog extends PhabricatorDaemonDAO
|
||||||
'daemon' => 'text255',
|
'daemon' => 'text255',
|
||||||
'host' => 'text255',
|
'host' => 'text255',
|
||||||
'pid' => 'uint32',
|
'pid' => 'uint32',
|
||||||
|
'runningAsUser' => 'text255?',
|
||||||
'envHash' => 'bytes40',
|
'envHash' => 'bytes40',
|
||||||
'status' => 'text8',
|
'status' => 'text8',
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue