PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / 3.1.13.4
JetBackup – Backup, Restore & Migrate v3.1.13.4
3.1.22.4 3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / src / JetBackup / 3rdparty / phpseclib3 / System / SSH / Agent.php
backup / src / JetBackup / 3rdparty / phpseclib3 / System / SSH Last commit date
Agent 9 months ago Common 9 months ago .htaccess 9 months ago Agent.php 9 months ago index.html 9 months ago web.config 9 months ago
Agent.php
280 lines
1 <?php
2
3 /**
4 * Pure-PHP ssh-agent client.
5 *
6 * {@internal See http://api.libssh.org/rfc/PROTOCOL.agent}
7 *
8 * PHP version 5
9 *
10 * Here are some examples of how to use this library:
11 * <code>
12 * <?php
13 * include 'vendor/autoload.php';
14 *
15 * $agent = new \phpseclib3\System\SSH\Agent();
16 *
17 * $ssh = new \phpseclib3\Net\SSH2('www.domain.tld');
18 * if (!$ssh->login('username', $agent)) {
19 * exit('Login Failed');
20 * }
21 *
22 * echo $ssh->exec('pwd');
23 * echo $ssh->exec('ls -la');
24 * ?>
25 * </code>
26 *
27 * @author Jim Wigginton <terrafrost@php.net>
28 * @copyright 2014 Jim Wigginton
29 * @license http://www.opensource.org/licenses/mit-license.html MIT License
30 * @link http://phpseclib.sourceforge.net
31 */
32
33 declare(strict_types=1);
34
35 namespace phpseclib3\System\SSH;
36
37 use phpseclib3\Common\Functions\Strings;
38 use phpseclib3\Crypt\PublicKeyLoader;
39 use phpseclib3\Exception\BadConfigurationException;
40 use phpseclib3\Exception\RuntimeException;
41 use phpseclib3\Net\SSH2;
42 use phpseclib3\System\SSH\Agent\Identity;
43
44 /**
45 * Pure-PHP ssh-agent client identity factory
46 *
47 * requestIdentities() method pumps out \phpseclib3\System\SSH\Agent\Identity objects
48 *
49 * @author Jim Wigginton <terrafrost@php.net>
50 */
51 class Agent
52 {
53 use Common\Traits\ReadBytes;
54
55 // Message numbers
56
57 // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
58 public const SSH_AGENTC_REQUEST_IDENTITIES = 11;
59 // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
60 public const SSH_AGENT_IDENTITIES_ANSWER = 12;
61 // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
62 public const SSH_AGENTC_SIGN_REQUEST = 13;
63 // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
64 public const SSH_AGENT_SIGN_RESPONSE = 14;
65
66 // Agent forwarding status
67
68 // no forwarding requested and not active
69 public const FORWARD_NONE = 0;
70 // request agent forwarding when opportune
71 public const FORWARD_REQUEST = 1;
72 // forwarding has been request and is active
73 public const FORWARD_ACTIVE = 2;
74
75 /**
76 * Unused
77 */
78 public const SSH_AGENT_FAILURE = 5;
79
80 /**
81 * Socket Resource
82 *
83 * @var resource
84 */
85 private $fsock;
86
87 /**
88 * Agent forwarding status
89 *
90 * @var int
91 */
92 private $forward_status = self::FORWARD_NONE;
93
94 /**
95 * Buffer for accumulating forwarded authentication
96 * agent data arriving on SSH data channel destined
97 * for agent unix socket
98 *
99 * @var string
100 */
101 private $socket_buffer = '';
102
103 /**
104 * Tracking the number of bytes we are expecting
105 * to arrive for the agent socket on the SSH data
106 * channel
107 *
108 * @var int
109 */
110 private $expected_bytes = 0;
111
112 /**
113 * Default Constructor
114 *
115 * @return Agent
116 * @throws BadConfigurationException if SSH_AUTH_SOCK cannot be found
117 * @throws RuntimeException on connection errors
118 */
119 public function __construct(?string $address = null)
120 {
121 if (!$address) {
122 switch (true) {
123 case isset($_SERVER['SSH_AUTH_SOCK']):
124 $address = $_SERVER['SSH_AUTH_SOCK'];
125 break;
126 case isset($_ENV['SSH_AUTH_SOCK']):
127 $address = $_ENV['SSH_AUTH_SOCK'];
128 break;
129 default:
130 throw new BadConfigurationException('SSH_AUTH_SOCK not found');
131 }
132 }
133
134 if (in_array('unix', stream_get_transports())) {
135 $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
136 if (!$this->fsock) {
137 throw new RuntimeException("Unable to connect to ssh-agent (Error $errno: $errstr)");
138 }
139 } else {
140 if (substr($address, 0, 9) != '\\\\.\\pipe\\' || str_contains(substr($address, 9), '\\')) {
141 throw new RuntimeException('Address is not formatted as a named pipe should be');
142 }
143
144 $this->fsock = fopen($address, 'r+b');
145 if (!$this->fsock) {
146 throw new RuntimeException('Unable to open address');
147 }
148 }
149 }
150
151 /**
152 * Request Identities
153 *
154 * See "2.5.2 Requesting a list of protocol 2 keys"
155 * Returns an array containing zero or more \phpseclib3\System\SSH\Agent\Identity objects
156 *
157 * @throws RuntimeException on receipt of unexpected packets
158 */
159 public function requestIdentities(): array
160 {
161 if (!$this->fsock) {
162 return [];
163 }
164
165 $packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
166 if (strlen($packet) != fwrite($this->fsock, $packet)) {
167 throw new RuntimeException('Connection closed while requesting identities');
168 }
169
170 $length = current(unpack('N', $this->readBytes(4)));
171 $packet = $this->readBytes($length);
172
173 [$type, $keyCount] = Strings::unpackSSH2('CN', $packet);
174 if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
175 throw new RuntimeException('Unable to request identities');
176 }
177
178 $identities = [];
179 for ($i = 0; $i < $keyCount; $i++) {
180 [$key_blob, $comment] = Strings::unpackSSH2('ss', $packet);
181 $temp = $key_blob;
182 [$key_type] = Strings::unpackSSH2('s', $temp);
183 switch ($key_type) {
184 case 'ssh-rsa':
185 case 'ssh-dss':
186 case 'ssh-ed25519':
187 case 'ecdsa-sha2-nistp256':
188 case 'ecdsa-sha2-nistp384':
189 case 'ecdsa-sha2-nistp521':
190 $key = PublicKeyLoader::load($key_type . ' ' . base64_encode($key_blob));
191 }
192 // resources are passed by reference by default
193 if (isset($key)) {
194 $identity = (new Identity($this->fsock))
195 ->withPublicKey($key)
196 ->withPublicKeyBlob($key_blob);
197 $identities[] = $identity;
198 unset($key);
199 }
200 }
201
202 return $identities;
203 }
204
205 /**
206 * Signal that agent forwarding should
207 * be requested when a channel is opened
208 */
209 public function startSSHForwarding(): void
210 {
211 if ($this->forward_status == self::FORWARD_NONE) {
212 $this->forward_status = self::FORWARD_REQUEST;
213 }
214 }
215
216 /**
217 * Request agent forwarding of remote server
218 */
219 private function request_forwarding(SSH2 $ssh)
220 {
221 if (!$ssh->requestAgentForwarding()) {
222 return false;
223 }
224
225 $this->forward_status = self::FORWARD_ACTIVE;
226
227 return true;
228 }
229
230 /**
231 * On successful channel open
232 *
233 * This method is called upon successful channel
234 * open to give the SSH Agent an opportunity
235 * to take further action. i.e. request agent forwarding
236 */
237 public function registerChannelOpen(SSH2 $ssh): void
238 {
239 if ($this->forward_status == self::FORWARD_REQUEST) {
240 $this->request_forwarding($ssh);
241 }
242 }
243
244 /**
245 * Forward data to SSH Agent and return data reply
246 *
247 * @return string Data from SSH Agent
248 * @throws RuntimeException on connection errors
249 */
250 public function forwardData(string $data)
251 {
252 if ($this->expected_bytes > 0) {
253 $this->socket_buffer .= $data;
254 $this->expected_bytes -= strlen($data);
255 } else {
256 $agent_data_bytes = current(unpack('N', $data));
257 $current_data_bytes = strlen($data);
258 $this->socket_buffer = $data;
259 if ($current_data_bytes != $agent_data_bytes + 4) {
260 $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
261 return false;
262 }
263 }
264
265 if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
266 throw new RuntimeException('Connection closed attempting to forward data to SSH agent');
267 }
268
269 $this->socket_buffer = '';
270 $this->expected_bytes = 0;
271
272 $agent_reply_bytes = current(unpack('N', $this->readBytes(4)));
273
274 $agent_reply_data = $this->readBytes($agent_reply_bytes);
275 $agent_reply_data = current(unpack('a*', $agent_reply_data));
276
277 return pack('Na*', $agent_reply_bytes, $agent_reply_data);
278 }
279 }
280