Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / scripts / ssh / ssh-connect.php
blobc128f3b32fd1e743eb815d4f245bc87d3d361fbb
1 #!/usr/bin/env php
2 <?php
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);
12 } else {
13 declare(ticks = 1);
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);
22 $args->parsePartial(
23 array(
24 array(
25 'name' => 'port',
26 'short' => 'p',
27 'param' => pht('port'),
28 'help' => pht('Port number to connect to.'),
30 array(
31 'name' => 'options',
32 'short' => 'o',
33 'param' => pht('options'),
34 'repeat' => true,
35 'help' => pht('SSH options.'),
37 ));
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.
48 exit(128 + $signo);
51 $pattern = array();
52 $arguments = array();
54 $pattern[] = 'ssh';
56 $pattern[] = '-o';
57 $pattern[] = 'StrictHostKeyChecking=no';
59 // This prevents "known host" failures, and covers for issues where HOME is set
60 // to something unusual.
61 $pattern[] = '-o';
62 $pattern[] = 'UserKnownHostsFile=/dev/null';
64 $as_device = getenv('PHABRICATOR_AS_DEVICE');
65 $credential_phid = getenv('PHABRICATOR_CREDENTIAL');
67 if ($as_device) {
68 $device = AlmanacKeys::getLiveDevice();
69 if (!$device) {
70 throw new Exception(
71 pht(
72 'Attempting to create an SSH connection that authenticates with '.
73 'the current device, but this host is not configured as a cluster '.
74 'device.'));
77 if ($credential_phid) {
78 throw new Exception(
79 pht(
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);
90 $pattern[] = '-l %P';
91 $arguments[] = $key->getUsernameEnvelope();
92 $pattern[] = '-i %P';
93 $arguments[] = $key->getKeyfileEnvelope();
96 if ($as_device) {
97 $pattern[] = '-l %R';
98 $arguments[] = AlmanacKeys::getClusterSSHUser();
99 $pattern[] = '-i %R';
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);
109 $host = $parts[0];
111 $port = $args->getArg('port');
113 if (!$port) {
114 if (count($parts) == 2) {
115 $port = $parts[1];
119 if ($port) {
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;
132 } else {
133 throw new Exception(
134 pht(
135 'Disallowed ssh option "%s" given with "-o". '.
136 'Allowed options are: %s.',
137 $option,
138 implode(', ', $allowed_ssh_options)));
143 $pattern[] = '--';
145 $pattern[] = '%s';
146 $arguments[] = $host;
148 foreach ($passthru_args as $passthru_arg) {
149 $pattern[] = '%s';
150 $arguments[] = $passthru_arg;
153 $pattern = implode(' ', $pattern);
154 array_unshift($arguments, $pattern);
156 $err = newv('PhutilExecPassthru', $arguments)
157 ->resolve();
159 exit($err);