Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/scripts/ssh/ssh-auth.php
12241 views
1
#!/usr/bin/env php
2
<?php
3
4
$root = dirname(dirname(dirname(__FILE__)));
5
require_once $root.'/scripts/init/init-script.php';
6
7
$error_log = id(new PhutilErrorLog())
8
->setLogName(pht('SSH Error Log'))
9
->setLogPath(PhabricatorEnv::getEnvConfig('log.ssh-error.path'))
10
->activateLog();
11
12
// TODO: For now, this is using "parseParital()", not "parse()". This allows
13
// the script to accept (and ignore) additional arguments. This preserves
14
// backward compatibility until installs have time to migrate to the new
15
// syntax.
16
17
$args = id(new PhutilArgumentParser($argv))
18
->parsePartial(
19
array(
20
array(
21
'name' => 'sshd-key',
22
'param' => 'k',
23
'help' => pht(
24
'Accepts the "%%k" parameter from "AuthorizedKeysCommand".'),
25
),
26
));
27
28
$sshd_key = $args->getArg('sshd-key');
29
30
// NOTE: We are caching a datastructure rather than the flat key file because
31
// the path on disk to "ssh-exec" is arbitrarily mutable at runtime. See T12397.
32
33
$cache = PhabricatorCaches::getMutableCache();
34
$authstruct_key = PhabricatorAuthSSHKeyQuery::AUTHSTRUCT_CACHEKEY;
35
$authstruct_raw = $cache->getKey($authstruct_key);
36
37
$authstruct = null;
38
39
if ($authstruct_raw !== null && strlen($authstruct_raw)) {
40
try {
41
$authstruct = phutil_json_decode($authstruct_raw);
42
} catch (Exception $ex) {
43
// Ignore any issues with the cached data; we'll just rebuild the
44
// structure below.
45
}
46
}
47
48
if ($authstruct === null) {
49
$keys = id(new PhabricatorAuthSSHKeyQuery())
50
->setViewer(PhabricatorUser::getOmnipotentUser())
51
->withIsActive(true)
52
->execute();
53
54
if (!$keys) {
55
echo pht('No keys found.')."\n";
56
exit(1);
57
}
58
59
$key_list = array();
60
foreach ($keys as $ssh_key) {
61
$key_argv = array();
62
$object = $ssh_key->getObject();
63
if ($object instanceof PhabricatorUser) {
64
$key_argv[] = '--phabricator-ssh-user';
65
$key_argv[] = $object->getUsername();
66
} else if ($object instanceof AlmanacDevice) {
67
if (!$ssh_key->getIsTrusted()) {
68
// If this key is not a trusted device key, don't allow SSH
69
// authentication.
70
continue;
71
}
72
$key_argv[] = '--phabricator-ssh-device';
73
$key_argv[] = $object->getName();
74
} else {
75
// We don't know what sort of key this is; don't permit SSH auth.
76
continue;
77
}
78
79
$key_argv[] = '--phabricator-ssh-key';
80
$key_argv[] = $ssh_key->getID();
81
82
// Strip out newlines and other nonsense from the key type and key body.
83
$type = $ssh_key->getKeyType();
84
$type = preg_replace('@[\x00-\x20]+@', '', $type);
85
if (!strlen($type)) {
86
continue;
87
}
88
89
$key = $ssh_key->getKeyBody();
90
$key = preg_replace('@[\x00-\x20]+@', '', $key);
91
if (!strlen($key)) {
92
continue;
93
}
94
95
$key_list[] = array(
96
'argv' => $key_argv,
97
'type' => $type,
98
'key' => $key,
99
);
100
}
101
102
$authstruct = array(
103
'keys' => $key_list,
104
);
105
106
$authstruct_raw = phutil_json_encode($authstruct);
107
$ttl = phutil_units('24 hours in seconds');
108
$cache->setKey($authstruct_key, $authstruct_raw, $ttl);
109
}
110
111
// If we've received an "--sshd-key" argument and it matches some known key,
112
// only emit that key. (For now, if the key doesn't match, we'll fall back to
113
// emitting all keys.)
114
if ($sshd_key !== null) {
115
$matches = array();
116
foreach ($authstruct['keys'] as $key => $key_struct) {
117
if ($key_struct['key'] === $sshd_key) {
118
$matches[$key] = $key_struct;
119
}
120
}
121
122
if ($matches) {
123
$authstruct['keys'] = $matches;
124
}
125
}
126
127
$bin = $root.'/bin/ssh-exec';
128
$instance = PhabricatorEnv::getEnvConfig('cluster.instance');
129
130
$lines = array();
131
foreach ($authstruct['keys'] as $key_struct) {
132
$key_argv = $key_struct['argv'];
133
$key = $key_struct['key'];
134
$type = $key_struct['type'];
135
136
$cmd = csprintf('%s %Ls', $bin, $key_argv);
137
138
if ($instance !== null && strlen($instance)) {
139
$cmd = csprintf('PHABRICATOR_INSTANCE=%s %C', $instance, $cmd);
140
}
141
142
// This is additional escaping for the SSH 'command="..."' string.
143
$cmd = addcslashes($cmd, '"\\');
144
145
$options = array(
146
'command="'.$cmd.'"',
147
'no-port-forwarding',
148
'no-X11-forwarding',
149
'no-agent-forwarding',
150
'no-pty',
151
);
152
$options = implode(',', $options);
153
154
$lines[] = $options.' '.$type.' '.$key."\n";
155
}
156
157
$authfile = implode('', $lines);
158
159
echo $authfile;
160
161
exit(0);
162
163