Page MenuHomePhabricator

D7719.diff

diff --git a/scripts/ssh/ssh-exec.php b/scripts/ssh/ssh-exec.php
--- a/scripts/ssh/ssh-exec.php
+++ b/scripts/ssh/ssh-exec.php
@@ -1,9 +1,13 @@
#!/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');
@@ -38,6 +42,12 @@
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."));
}
@@ -54,6 +64,15 @@
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');
@@ -98,12 +117,35 @@
$workflow->setIOChannel($metrics_channel);
$workflow->setErrorChannel($error_channel);
- $err = $workflow->execute($original_args);
+ $rethrow = null;
+ try {
+ $err = $workflow->execute($original_args);
+ $metrics_channel->flush();
+ $error_channel->flush();
+ } catch (Exception $ex) {
+ $rethrow = $ex;
+ }
- $metrics_channel->flush();
- $error_channel->flush();
+ // 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");
- exit(1);
+ $err = 1;
}
+
+$ssh_log->setData(
+ array(
+ 'c' => $err,
+ 'T' => (int)(1000000 * (microtime(true) - $ssh_start_time)),
+ ));
+
+exit($err);
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -996,7 +996,7 @@
'Phabricator404Controller' => 'applications/base/controller/Phabricator404Controller.php',
'PhabricatorAWSConfigOptions' => 'applications/config/option/PhabricatorAWSConfigOptions.php',
'PhabricatorAccessControlTestCase' => 'applications/base/controller/__tests__/PhabricatorAccessControlTestCase.php',
- 'PhabricatorAccessLog' => 'infrastructure/PhabricatorAccessLog.php',
+ 'PhabricatorAccessLog' => 'infrastructure/log/PhabricatorAccessLog.php',
'PhabricatorAccessLogConfigOptions' => 'applications/config/option/PhabricatorAccessLogConfigOptions.php',
'PhabricatorActionHeaderExample' => 'applications/uiexample/examples/PhabricatorActionHeaderExample.php',
'PhabricatorActionHeaderView' => 'view/layout/PhabricatorActionHeaderView.php',
@@ -1811,6 +1811,7 @@
'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php',
'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php',
'PhabricatorSQLPatchList' => 'infrastructure/storage/patch/PhabricatorSQLPatchList.php',
+ 'PhabricatorSSHLog' => 'infrastructure/log/PhabricatorSSHLog.php',
'PhabricatorSSHPassthruCommand' => 'infrastructure/ssh/PhabricatorSSHPassthruCommand.php',
'PhabricatorSSHWorkflow' => 'infrastructure/ssh/PhabricatorSSHWorkflow.php',
'PhabricatorSavedQuery' => 'applications/search/storage/PhabricatorSavedQuery.php',
@@ -4337,6 +4338,7 @@
'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO',
'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine',
+ 'PhabricatorSSHLog' => 'Phobject',
'PhabricatorSSHPassthruCommand' => 'Phobject',
'PhabricatorSSHWorkflow' => 'PhutilArgumentWorkflow',
'PhabricatorSavedQuery' =>
diff --git a/src/applications/config/option/PhabricatorAccessLogConfigOptions.php b/src/applications/config/option/PhabricatorAccessLogConfigOptions.php
--- a/src/applications/config/option/PhabricatorAccessLogConfigOptions.php
+++ b/src/applications/config/option/PhabricatorAccessLogConfigOptions.php
@@ -4,48 +4,56 @@
extends PhabricatorApplicationConfigOptions {
public function getName() {
- return pht("Access Log");
+ return pht("Access Logs");
}
public function getDescription() {
- return pht("Configure the access log, which logs all requests.");
+ return pht("Configure the access logs, which log HTTP/SSH requests.");
}
public function getOptions() {
- $map = array(
- 'c' => pht("The HTTP response code."),
- 'C' => pht("The controller which handled the request."),
+ $common_map = array(
+ 'C' => pht("The controller or workflow which handled the request."),
+ 'c' => pht("The HTTP response code or process exit code."),
'D' => pht("The request date."),
'e' => pht("Epoch timestamp."),
'h' => pht("The webserver's host name."),
'p' => pht("The PID of the server process."),
- 'R' => pht("The HTTP referrer."),
'r' => pht("The remote IP."),
'T' => pht("The request duration, in microseconds."),
- 'U' => pht("The request path."),
+ 'U' => pht("The request path, or request target."),
+ 'm' => pht("For conduit, the Conduit method which was invoked."),
'u' => pht("The logged-in username, if one is logged in."),
'P' => pht("The logged-in user PHID, if one is logged in."),
+ 'i' => pht("Request input, in bytes."),
+ 'o' => pht("Request output, in bytes."),
+ );
+
+ $http_map = $common_map + array(
+ 'R' => pht("The HTTP referrer."),
'M' => pht("The HTTP method."),
- 'm' => pht("For conduit, the Conduit method which was invoked."),
);
- $fdesc = pht("Format for the access log. Available variables are:");
- $fdesc .= "\n\n";
- foreach ($map as $key => $desc) {
- $fdesc .= " - %".$key." ".$desc."\n";
- }
- $fdesc .= "\n";
- $fdesc .= pht(
- "If a variable isn't available (for example, %%m appears in the file ".
- "format but the request is not a Conduit request), it will be rendered ".
- "as '-'");
- $fdesc .= "\n\n";
- $fdesc .= pht(
- "Note that the default format is subject to change in the future, so ".
- "if you rely on the log's format, specify it explicitly.");
+ $ssh_map = $common_map + array(
+ 's' => pht("The system user."),
+ 'S' => pht("The system sudo user."),
+ );
+
+ $http_desc = pht(
+ "Format for the HTTP access log. Use {{log.access.path}} to set the ".
+ "path. Available variables are:");
+ $http_desc .= "\n\n";
+ $http_desc .= $this->renderMapHelp($http_map);
+
+ $ssh_desc = pht(
+ "Format for the SSH access log. Use {{log.ssh.path}} to set the ".
+ "path. Available variables are:");
+ $ssh_desc .= "\n\n";
+ $ssh_desc .= $this->renderMapHelp($ssh_map);
return array(
$this->newOption('log.access.path', 'string', null)
+ ->setLocked(true)
->setSummary(pht("Access log location."))
->setDescription(
pht(
@@ -57,19 +65,61 @@
"If not set, no log will be written."))
->addExample(
null,
- pht('Disable access log'))
+ pht('Disable access log.'))
->addExample(
'/var/log/phabricator/access.log',
- pht('Write access log here')),
+ pht('Write access log here.')),
$this->newOption(
'log.access.format',
// NOTE: This is 'wild' intead of 'string' so "\t" and such can be
// specified.
'wild',
"[%D]\t%p\t%h\t%r\t%u\t%C\t%m\t%U\t%R\t%c\t%T")
+ ->setLocked(true)
->setSummary(pht("Access log format."))
- ->setDescription($fdesc),
+ ->setDescription($http_desc),
+ $this->newOption('log.ssh.path', 'string', null)
+ ->setLocked(true)
+ ->setSummary(pht("SSH log location."))
+ ->setDescription(
+ pht(
+ "To enable the Phabricator SSH log, specify a path. The ".
+ "access log can provide more detailed information about SSH ".
+ "access than a normal SSH log (for instance, it can show ".
+ "logged-in users, commands, and other application data).\n\n".
+ "If not set, no log will be written."))
+ ->addExample(
+ null,
+ pht('Disable SSH log.'))
+ ->addExample(
+ '/var/log/phabricator/ssh.log',
+ pht('Write SSH log here.')),
+ $this->newOption(
+ 'log.ssh.format',
+ 'wild',
+ "[%D]\t%p\t%h\t%r\t%s\t%S\t%u\t%C\t%U\t%c\t%T\t%i\t%o")
+ ->setLocked(true)
+ ->setSummary(pht("SSH log format."))
+ ->setDescription($ssh_desc),
);
}
+ private function renderMapHelp(array $map) {
+ $desc = '';
+ foreach ($map as $key => $kdesc) {
+ $desc .= " - `%".$key."` ".$kdesc."\n";
+ }
+ $desc .= "\n";
+ $desc .= pht(
+ "If a variable isn't available (for example, %%m appears in the file ".
+ "format but the request is not a Conduit request), it will be rendered ".
+ "as '-'");
+ $desc .= "\n\n";
+ $desc .= pht(
+ "Note that the default format is subject to change in the future, so ".
+ "if you rely on the log's format, specify it explicitly.");
+
+ return $desc;
+ }
+
}
diff --git a/src/infrastructure/PhabricatorAccessLog.php b/src/infrastructure/log/PhabricatorAccessLog.php
rename from src/infrastructure/PhabricatorAccessLog.php
rename to src/infrastructure/log/PhabricatorAccessLog.php
diff --git a/src/infrastructure/log/PhabricatorSSHLog.php b/src/infrastructure/log/PhabricatorSSHLog.php
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/log/PhabricatorSSHLog.php
@@ -0,0 +1,52 @@
+<?php
+
+final class PhabricatorSSHLog extends Phobject {
+
+ static $log;
+
+ public static function getLog() {
+ if (!self::$log) {
+ $path = PhabricatorEnv::getEnvConfig('log.ssh.path');
+ $format = PhabricatorEnv::getEnvConfig('log.ssh.format');
+ $format = nonempty(
+ $format,
+ "[%D]\t%p\t%h\t%r\t%s\t%S\t%u\t%C\t%U\t%c\t%T\t%i\t%o");
+
+ // NOTE: Path may be null. We still create the log, it just won't write
+ // anywhere.
+
+ $data = array(
+ 'D' => date('r'),
+ 'h' => php_uname('n'),
+ 'p' => getmypid(),
+ 'e' => time(),
+ );
+
+ $sudo_user = PhabricatorEnv::getEnvConfig('phd.user');
+ if (strlen($sudo_user)) {
+ $data['S'] = $sudo_user;
+ }
+
+ if (function_exists('posix_geteuid')) {
+ $system_uid = posix_geteuid();
+ $system_info = posix_getpwuid($system_uid);
+ $data['s'] = idx($system_info, 'name');
+ }
+
+ $client = getenv('SSH_CLIENT');
+ if (strlen($client)) {
+ $remote_address = head(explode(' ', $client));
+ $data['r'] = $remote_address;
+ }
+
+ $log = id(new PhutilDeferredLog($path, $format))
+ ->setFailQuietly(true)
+ ->setData($data);
+
+ self::$log = $log;
+ }
+
+ return self::$log;
+ }
+
+}

File Metadata

Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/km/7b/vjyrb6bjbpvgjex5
Default Alt Text
D7719.diff (11 KB)

Event Timeline