mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
5ca84589bd
Summary: Ref T4107. Ref T4189. This implements an SSH access log, similar to the HTTP access log. Test Plan: [Thu, 05 Dec 2013 13:45:41 -0800] 77841 orbital ::1 dweller epriestley epriestley git-receive-pack /diffusion/POEMS/ 0 324765 402 232 [Thu, 05 Dec 2013 13:45:48 -0800] 77860 orbital ::1 dweller epriestley epriestley git-receive-pack /diffusion/POEMS/ 0 325634 402 232 Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T4107, T4189 Differential Revision: https://secure.phabricator.com/D7719
151 lines
3.6 KiB
PHP
Executable file
151 lines
3.6 KiB
PHP
Executable file
#!/usr/bin/env php
|
|
<?php
|
|
|
|
$ssh_start_time = microtime(true);
|
|
|
|
$root = dirname(dirname(dirname(__FILE__)));
|
|
require_once $root.'/scripts/__init_script__.php';
|
|
|
|
$ssh_log = PhabricatorSSHLog::getLog();
|
|
|
|
// First, figure out the authenticated user.
|
|
$args = new PhutilArgumentParser($argv);
|
|
$args->setTagline('receive SSH requests');
|
|
$args->setSynopsis(<<<EOSYNOPSIS
|
|
**ssh-exec** --phabricator-ssh-user __user__ [--ssh-command __commmand__]
|
|
Receive SSH requests.
|
|
EOSYNOPSIS
|
|
);
|
|
|
|
$args->parse(
|
|
array(
|
|
array(
|
|
'name' => 'phabricator-ssh-user',
|
|
'param' => 'username',
|
|
),
|
|
array(
|
|
'name' => 'ssh-command',
|
|
'param' => 'command',
|
|
),
|
|
));
|
|
|
|
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.");
|
|
}
|
|
|
|
$ssh_log->setData(
|
|
array(
|
|
'u' => $user->getUsername(),
|
|
'P' => $user->getPHID(),
|
|
));
|
|
|
|
if (!$user->isUserActivated()) {
|
|
throw new Exception(pht("Your account is not activated."));
|
|
}
|
|
|
|
if ($args->getArg('ssh-command')) {
|
|
$original_command = $args->getArg('ssh-command');
|
|
} else {
|
|
$original_command = getenv('SSH_ORIGINAL_COMMAND');
|
|
}
|
|
|
|
// Now, rebuild the original command.
|
|
$original_argv = id(new PhutilShellLexer())
|
|
->splitArguments($original_command);
|
|
if (!$original_argv) {
|
|
throw new Exception("No interactive logins.");
|
|
}
|
|
|
|
$ssh_log->setData(
|
|
array(
|
|
'C' => $original_argv[0],
|
|
'U' => phutil_utf8_shorten(
|
|
implode(' ', array_slice($original_argv, 1)),
|
|
128),
|
|
));
|
|
|
|
$command = head($original_argv);
|
|
array_unshift($original_argv, 'phabricator-ssh-exec');
|
|
|
|
$original_args = new PhutilArgumentParser($original_argv);
|
|
|
|
$workflows = array(
|
|
new ConduitSSHWorkflow(),
|
|
new DiffusionSSHSubversionServeWorkflow(),
|
|
new DiffusionSSHMercurialServeWorkflow(),
|
|
new DiffusionSSHGitUploadPackWorkflow(),
|
|
new DiffusionSSHGitReceivePackWorkflow(),
|
|
);
|
|
|
|
$workflow_names = mpull($workflows, 'getName', 'getName');
|
|
if (empty($workflow_names[$command])) {
|
|
throw new Exception("Invalid command.");
|
|
}
|
|
|
|
$workflow = $original_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.");
|
|
}
|
|
|
|
$sock_stderr = fopen('php://stderr', 'w');
|
|
if (!$sock_stderr) {
|
|
throw new Exception("Unable to open stderr.");
|
|
}
|
|
|
|
$socket_channel = new PhutilSocketChannel(
|
|
$sock_stdin,
|
|
$sock_stdout);
|
|
$error_channel = new PhutilSocketChannel(null, $sock_stderr);
|
|
$metrics_channel = new PhutilMetricsChannel($socket_channel);
|
|
$workflow->setIOChannel($metrics_channel);
|
|
$workflow->setErrorChannel($error_channel);
|
|
|
|
$rethrow = null;
|
|
try {
|
|
$err = $workflow->execute($original_args);
|
|
|
|
$metrics_channel->flush();
|
|
$error_channel->flush();
|
|
} catch (Exception $ex) {
|
|
$rethrow = $ex;
|
|
}
|
|
|
|
// Always write this if we got as far as building a metrics channel.
|
|
$ssh_log->setData(
|
|
array(
|
|
'i' => $metrics_channel->getBytesRead(),
|
|
'o' => $metrics_channel->getBytesWritten(),
|
|
));
|
|
|
|
if ($rethrow) {
|
|
throw $ex;
|
|
}
|
|
} catch (Exception $ex) {
|
|
fwrite(STDERR, "phabricator-ssh-exec: ".$ex->getMessage()."\n");
|
|
$err = 1;
|
|
}
|
|
|
|
$ssh_log->setData(
|
|
array(
|
|
'c' => $err,
|
|
'T' => (int)(1000000 * (microtime(true) - $ssh_start_time)),
|
|
));
|
|
|
|
exit($err);
|