mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-14 16:51:08 +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');
|
||||
}
|
||||
|
||||
$phd_user = PhabricatorEnv::getEnvConfig('phd.user');
|
||||
$environment_hash = PhabricatorEnv::calculateEnvironmentHash();
|
||||
$all_daemons = id(new PhabricatorDaemonLogQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
|
||||
->execute();
|
||||
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) {
|
||||
$doc_href = PhabricatorEnv::getDocLink(
|
||||
'Managing Daemons with phd');
|
||||
|
|
|
@ -163,6 +163,7 @@ final class PhabricatorDaemonLogViewController
|
|||
$view->addProperty(pht('Daemon Class'), $daemon->getDaemon());
|
||||
$view->addProperty(pht('Host'), $daemon->getHost());
|
||||
$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('Seen'),
|
||||
|
|
|
@ -34,11 +34,13 @@ final class PhabricatorDaemonEventListener extends PhabricatorEventListener {
|
|||
|
||||
private function handleLaunchEvent(PhutilEvent $event) {
|
||||
$id = $event->getValue('id');
|
||||
$current_user = posix_getpwuid(posix_geteuid());
|
||||
|
||||
$daemon = id(new PhabricatorDaemonLog())
|
||||
->setDaemon($event->getValue('daemonClass'))
|
||||
->setHost(php_uname('n'))
|
||||
->setPID(getmypid())
|
||||
->setRunningAsUser($current_user['name'])
|
||||
->setEnvHash(PhabricatorEnv::calculateEnvironmentHash())
|
||||
->setStatus(PhabricatorDaemonLog::STATUS_RUNNING)
|
||||
->setArgv($event->getValue('argv'))
|
||||
|
|
|
@ -21,11 +21,17 @@ final class PhabricatorDaemonManagementDebugWorkflow
|
|||
'name' => 'argv',
|
||||
'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) {
|
||||
$argv = $args->getArg('argv');
|
||||
$run_as_current_user = $args->getArg('as-current-user');
|
||||
|
||||
if (!$argv) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
|
@ -33,7 +39,11 @@ final class PhabricatorDaemonManagementDebugWorkflow
|
|||
}
|
||||
|
||||
$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
|
||||
extends PhabricatorManagementWorkflow {
|
||||
|
||||
private $runDaemonsAsUser = null;
|
||||
|
||||
protected final function loadAvailableDaemonClasses() {
|
||||
$loader = new PhutilSymbolLoader();
|
||||
return $loader
|
||||
|
@ -103,10 +105,37 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
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);
|
||||
$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 ($argv) {
|
||||
$console->writeOut(
|
||||
|
@ -187,13 +216,41 @@ abstract class PhabricatorDaemonManagementWorkflow
|
|||
|
||||
phutil_passthru('(cd %s && exec %C)', $daemon_script_dir, $command);
|
||||
} else {
|
||||
$future = new ExecFuture('exec %C', $command);
|
||||
// Play games to keep 'ps' looking reasonable.
|
||||
$future->setCWD($daemon_script_dir);
|
||||
$future->resolvex();
|
||||
try {
|
||||
$this->executeDaemonLaunchCommand(
|
||||
$command,
|
||||
$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) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ final class PhabricatorDaemonLog extends PhabricatorDaemonDAO
|
|||
protected $daemon;
|
||||
protected $host;
|
||||
protected $pid;
|
||||
protected $runningAsUser;
|
||||
protected $argv;
|
||||
protected $explicitArgv = array();
|
||||
protected $envHash;
|
||||
|
@ -28,6 +29,7 @@ final class PhabricatorDaemonLog extends PhabricatorDaemonDAO
|
|||
'daemon' => 'text255',
|
||||
'host' => 'text255',
|
||||
'pid' => 'uint32',
|
||||
'runningAsUser' => 'text255?',
|
||||
'envHash' => 'bytes40',
|
||||
'status' => 'text8',
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue