1
0
Fork 0
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:
Fabian Stelzer 2014-12-23 08:11:44 -08:00 committed by epriestley
parent 6132d8012b
commit 2fedb6f941
7 changed files with 115 additions and 6 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_daemon.daemon_log
ADD runningAsUser VARCHAR(255) COLLATE {$COLLATE_TEXT};

View file

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

View file

@ -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'),

View file

@ -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'))

View file

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

View file

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

View file

@ -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',
),