4 // This is a wrapper script for Git, Mercurial, and Subversion. It primarily
5 // serves to inject "-o StrictHostKeyChecking=no" into the SSH arguments.
7 // In some cases, Subversion sends us SIGTERM. If we don't catch the signal and
8 // react to it, we won't run object destructors by default and thus won't clean
9 // up temporary files. Declare ticks so we can install a signal handler.
10 if (function_exists('pcntl_async_signals')) {
11 pcntl_async_signals(true);
16 $root = dirname(dirname(dirname(__FILE__
)));
17 require_once $root.'/scripts/__init_script__.php';
19 // Contrary to the documentation, Git may pass a "-p" flag. If it does, respect
20 // it and move it before the "--" argument.
21 $args = new PhutilArgumentParser($argv);
27 'param' => pht('port'),
28 'help' => pht('Port number to connect to.'),
33 'param' => pht('options'),
35 'help' => pht('SSH options.'),
39 $unconsumed_argv = $args->getUnconsumedArgumentVector();
41 if (function_exists('pcntl_signal')) {
42 pcntl_signal(SIGTERM
, 'ssh_connect_signal');
45 function ssh_connect_signal($signo) {
46 // This is just letting destructors fire. In particular, we want to clean
47 // up any temporary files we wrote. See T10547.
57 $pattern[] = 'StrictHostKeyChecking=no';
59 // This prevents "known host" failures, and covers for issues where HOME is set
60 // to something unusual.
62 $pattern[] = 'UserKnownHostsFile=/dev/null';
64 $as_device = getenv('PHABRICATOR_AS_DEVICE');
65 $credential_phid = getenv('PHABRICATOR_CREDENTIAL');
68 $device = AlmanacKeys
::getLiveDevice();
72 'Attempting to create an SSH connection that authenticates with '.
73 'the current device, but this host is not configured as a cluster '.
77 if ($credential_phid) {
80 'Attempting to proxy an SSH connection that authenticates with '.
81 'both the current device and a specific credential. These options '.
82 'are mutually exclusive.'));
86 if ($credential_phid) {
87 $viewer = PhabricatorUser
::getOmnipotentUser();
88 $key = PassphraseSSHKey
::loadFromPHID($credential_phid, $viewer);
91 $arguments[] = $key->getUsernameEnvelope();
93 $arguments[] = $key->getKeyfileEnvelope();
98 $arguments[] = AlmanacKeys
::getClusterSSHUser();
100 $arguments[] = AlmanacKeys
::getKeyPath('device.key');
103 // Subversion passes us a host in the form "domain.com:port", which is not
104 // valid for normal SSH but which we can parse into a valid "-p" flag.
106 $passthru_args = $unconsumed_argv;
107 $host = array_shift($passthru_args);
108 $parts = explode(':', $host, 2);
111 $port = $args->getArg('port');
114 if (count($parts) == 2) {
120 $pattern[] = '-p %d';
121 $arguments[] = $port;
124 $options = $args->getArg('options');
125 $allowed_ssh_options = array('SendEnv=GIT_PROTOCOL');
127 if (!empty($options)) {
128 foreach ($options as $option) {
129 if (array_search($option, $allowed_ssh_options) !== false) {
130 $pattern[] = '-o %s';
131 $arguments[] = $option;
135 'Disallowed ssh option "%s" given with "-o". '.
136 'Allowed options are: %s.',
138 implode(', ', $allowed_ssh_options)));
146 $arguments[] = $host;
148 foreach ($passthru_args as $passthru_arg) {
150 $arguments[] = $passthru_arg;
153 $pattern = implode(' ', $pattern);
154 array_unshift($arguments, $pattern);
156 $err = newv('PhutilExecPassthru', $arguments)