1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 14:00:56 +01:00
phorge-phorge/scripts/ssh/ssh-exec.php
epriestley 6dd0169873 Fix various issues with SSH receivers
Summary:
  - Original command is in SSH_ORIGINAL_COMMAND, not normal argv.
  - Use PhutilShellLexer to parse it.
  - Fix a protocol encoding issue with ConduitSSHWorkflow. I think I'm going to make this protocol accept multiple commands anyway because SSH pipes are crazy expensive to build (even locally, they're ~300ms).

Test Plan: With other changes, successfully executed "arc list --conduit-uri=ssh://localhost:2222".

Reviewers: btrahan, vrana

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T550

Differential Revision: https://secure.phabricator.com/D4232
2012-12-19 11:11:32 -08:00

91 lines
2.4 KiB
PHP
Executable file

#!/usr/bin/env php
<?php
$root = dirname(dirname(dirname(__FILE__)));
require_once $root.'/scripts/__init_script__.php';
$original_command = getenv('SSH_ORIGINAL_COMMAND');
$original_argv = id(new PhutilShellLexer())->splitArguments($original_command);
$argv = array_merge($argv, $original_argv);
$args = new PhutilArgumentParser($argv);
$args->setTagline('receive SSH requests');
$args->setSynopsis(<<<EOSYNOPSIS
**ssh-exec** --phabricator-ssh-user __user__ __commmand__ [__options__]
Receive SSH requests.
EOSYNOPSIS
);
// NOTE: Do NOT parse standard arguments. Arguments are coming from a remote
// client over SSH, and they should not be able to execute "--xprofile",
// "--recon", etc.
$args->parsePartial(
array(
array(
'name' => 'phabricator-ssh-user',
'param' => 'username',
),
));
try {
$user_name = $args->getArg('phabricator-ssh-user');
if (!strlen($user_name)) {
throw new Exception("No username.");
}
$user = id(new PhabricatorUser())->loadOneWhere(
'userName = %s',
$user_name);
if (!$user) {
throw new Exception("Invalid username.");
}
if ($user->getIsDisabled()) {
throw new Exception("You have been exiled.");
}
$workflows = array(
new ConduitSSHWorkflow(),
);
// This duplicates logic in parseWorkflows(), but allows us to raise more
// concise/relevant exceptions when the client is a remote SSH.
$remain = $args->getUnconsumedArgumentVector();
if (empty($remain)) {
throw new Exception("No interactive logins.");
} else {
$command = head($remain);
$workflow_names = mpull($workflows, 'getName', 'getName');
if (empty($workflow_names[$command])) {
throw new Exception("Invalid command.");
}
}
$workflow = $args->parseWorkflows($workflows);
$workflow->setUser($user);
$sock_stdin = fopen('php://stdin', 'r');
if (!$sock_stdin) {
throw new Exception("Unable to open stdin.");
}
$sock_stdout = fopen('php://stdout', 'w');
if (!$sock_stdout) {
throw new Exception("Unable to open stdout.");
}
$socket_channel = new PhutilSocketChannel(
$sock_stdin,
$sock_stdout);
$metrics_channel = new PhutilMetricsChannel($socket_channel);
$workflow->setIOChannel($metrics_channel);
$err = $workflow->execute($args);
$metrics_channel->flush();
} catch (Exception $ex) {
echo "phabricator-ssh-exec: ".$ex->getMessage()."\n";
exit(1);
}