PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.22
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.22
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / phpseclib / phpseclib / phpseclib / System / SSH / Agent.php

Agent.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.2.22, at vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php

613 lines 17.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Pure-PHP ssh-agent client.
5 *
6 * PHP versions 4 and 5
7 *
8 * Here are some examples of how to use this library:
9 * <code>
10 * <?php
11 * include 'System/SSH/Agent.php';
12 * include 'Net/SSH2.php';
13 *
14 * $agent = new System_SSH_Agent();
15 *
16 * $ssh = new Net_SSH2('www.domain.tld');
17 * if (!$ssh->login('username', $agent)) {
18 * exit('Login Failed');
19 * }
20 *
21 * echo $ssh->exec('pwd');
22 * echo $ssh->exec('ls -la');
23 * ?>
24 * </code>
25 *
26 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
27 * of this software and associated documentation files (the "Software"), to deal
28 * in the Software without restriction, including without limitation the rights
29 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30 * copies of the Software, and to permit persons to whom the Software is
31 * furnished to do so, subject to the following conditions:
32 *
33 * The above copyright notice and this permission notice shall be included in
34 * all copies or substantial portions of the Software.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42 * THE SOFTWARE.
43 *
44 * @category System
45 * @package System_SSH_Agent
46 * @author Jim Wigginton <[email protected]>
47 * @copyright 2014 Jim Wigginton
48 * @license http://www.opensource.org/licenses/mit-license.html MIT License
49 * @link http://phpseclib.sourceforge.net
50 * @internal See http://api.libssh.org/rfc/PROTOCOL.agent
51 */
52
53 /**#@+
54 * Message numbers
55 *
56 * @access private
57 */
58 // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
59 define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11);
60 // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
61 define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12);
62 define('SYSTEM_SSH_AGENT_FAILURE', 5);
63 // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
64 define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13);
65 // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
66 define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14);
67 /**#@-*/
68
69 /**@+
70 * Agent forwarding status
71 *
72 * @access private
73 */
74 // no forwarding requested and not active
75 define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0);
76 // request agent forwarding when opportune
77 define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1);
78 // forwarding has been request and is active
79 define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2);
80 /**#@-*/
81
82 /**@+
83 * Signature Flags
84 *
85 * See https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3
86 *
87 * @access private
88 */
89 define('SYSTEM_SSH_AGENT_RSA2_256', 2);
90 define('SYSTEM_SSH_AGENT_RSA2_512', 4);
91 /**#@-*/
92
93 /**
94 * Pure-PHP ssh-agent client identity object
95 *
96 * Instantiation should only be performed by System_SSH_Agent class.
97 * This could be thought of as implementing an interface that Crypt_RSA
98 * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
99 * The methods in this interface would be getPublicKey, setSignatureMode
100 * and sign since those are the methods phpseclib looks for to perform
101 * public key authentication.
102 *
103 * @package System_SSH_Agent
104 * @author Jim Wigginton <[email protected]>
105 * @access internal
106 */
107 class System_SSH_Agent_Identity
108 {
109 /**
110 * Key Object
111 *
112 * @var Crypt_RSA
113 * @access private
114 * @see self::getPublicKey()
115 */
116 var $key;
117
118 /**
119 * Key Blob
120 *
121 * @var string
122 * @access private
123 * @see self::sign()
124 */
125 var $key_blob;
126
127 /**
128 * Socket Resource
129 *
130 * @var resource
131 * @access private
132 * @see self::sign()
133 */
134 var $fsock;
135
136 /**
137 * Signature flags
138 *
139 * @var int
140 * @access private
141 * @see self::sign()
142 * @see self::setHash()
143 */
144 var $flags = 0;
145
146 /**
147 * Default Constructor.
148 *
149 * @param resource $fsock
150 * @return System_SSH_Agent_Identity
151 * @access private
152 */
153 function __construct($fsock)
154 {
155 $this->fsock = $fsock;
156 }
157
158 /**
159 * PHP4 compatible Default Constructor.
160 *
161 * @see self::__construct()
162 * @param resource $fsock
163 * @access public
164 */
165 function System_SSH_Agent_Identity($fsock)
166 {
167 $this->__construct($fsock);
168 }
169
170 /**
171 * Set Public Key
172 *
173 * Called by System_SSH_Agent::requestIdentities()
174 *
175 * @param Crypt_RSA $key
176 * @access private
177 */
178 function setPublicKey($key)
179 {
180 $this->key = $key;
181 $this->key->setPublicKey();
182 }
183
184 /**
185 * Set Public Key
186 *
187 * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key
188 * but this saves a small amount of computation.
189 *
190 * @param string $key_blob
191 * @access private
192 */
193 function setPublicKeyBlob($key_blob)
194 {
195 $this->key_blob = $key_blob;
196 }
197
198 /**
199 * Get Public Key
200 *
201 * Wrapper for $this->key->getPublicKey()
202 *
203 * @param int $format optional
204 * @return mixed
205 * @access public
206 */
207 function getPublicKey($format = null)
208 {
209 return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
210 }
211
212 /**
213 * Set Signature Mode
214 *
215 * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
216 * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1
217 *
218 * @param int $mode
219 * @access public
220 */
221 function setSignatureMode($mode)
222 {
223 }
224
225 /**
226 * Set Hash
227 *
228 * ssh-agent doesn't support using hashes for RSA other than SHA1
229 *
230 * @param string $hash
231 * @access public
232 */
233 function setHash($hash)
234 {
235 $this->flags = 0;
236 switch ($hash) {
237 case 'sha1':
238 break;
239 case 'sha256':
240 $this->flags = SYSTEM_SSH_AGENT_RSA2_256;
241 break;
242 case 'sha512':
243 $this->flags = SYSTEM_SSH_AGENT_RSA2_512;
244 break;
245 default:
246 user_error('The only supported hashes for RSA are sha1, sha256 and sha512');
247 }
248 }
249
250 /**
251 * Create a signature
252 *
253 * See "2.6.2 Protocol 2 private key signature request"
254 *
255 * @param string $message
256 * @return string
257 * @access public
258 */
259 function sign($message)
260 {
261 // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
262 $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, $this->flags);
263 $packet = pack('Na*', strlen($packet), $packet);
264 if (strlen($packet) != fputs($this->fsock, $packet)) {
265 user_error('Connection closed during signing');
266 return false;
267 }
268
269 $temp = fread($this->fsock, 4);
270 if (strlen($temp) != 4) {
271 user_error('Connection closed during signing');
272 return false;
273 }
274 $length = current(unpack('N', $temp));
275 $type = ord(fread($this->fsock, 1));
276 if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) {
277 user_error('Unable to retreive signature');
278 return false;
279 }
280
281 $signature_blob = fread($this->fsock, $length - 1);
282 if (strlen($signature_blob) != $length - 1) {
283 user_error('Connection closed during signing');
284 return false;
285 }
286 $length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
287 if ($length != strlen($signature_blob)) {
288 user_error('Malformed signature blob');
289 return false;
290 }
291 $length = current(unpack('N', $this->_string_shift($signature_blob, 4)));
292 if ($length > strlen($signature_blob) + 4) {
293 user_error('Malformed signature blob');
294 return false;
295 }
296 $type = $this->_string_shift($signature_blob, $length);
297 $this->_string_shift($signature_blob, 4);
298
299 return $signature_blob;
300 }
301
302 /**
303 * String Shift
304 *
305 * Inspired by array_shift
306 *
307 * @param string $string
308 * @param int $index
309 * @return string
310 * @access private
311 */
312 function _string_shift(&$string, $index = 1)
313 {
314 $substr = substr($string, 0, $index);
315 $string = substr($string, $index);
316 return $substr;
317 }
318 }
319
320 /**
321 * Pure-PHP ssh-agent client identity factory
322 *
323 * requestIdentities() method pumps out System_SSH_Agent_Identity objects
324 *
325 * @package System_SSH_Agent
326 * @author Jim Wigginton <[email protected]>
327 * @access public
328 */
329 class System_SSH_Agent
330 {
331 /**
332 * Socket Resource
333 *
334 * @var resource
335 * @access private
336 */
337 var $fsock;
338
339 /**
340 * Agent forwarding status
341 *
342 * @access private
343 */
344 var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE;
345
346 /**
347 * Buffer for accumulating forwarded authentication
348 * agent data arriving on SSH data channel destined
349 * for agent unix socket
350 *
351 * @access private
352 */
353 var $socket_buffer = '';
354
355 /**
356 * Tracking the number of bytes we are expecting
357 * to arrive for the agent socket on the SSH data
358 * channel
359 */
360 var $expected_bytes = 0;
361
362 /**
363 * Default Constructor
364 *
365 * @return System_SSH_Agent
366 * @access public
367 */
368 function __construct($address = null)
369 {
370 if (!$address) {
371 switch (true) {
372 case isset($_SERVER['SSH_AUTH_SOCK']):
373 $address = $_SERVER['SSH_AUTH_SOCK'];
374 break;
375 case isset($_ENV['SSH_AUTH_SOCK']):
376 $address = $_ENV['SSH_AUTH_SOCK'];
377 break;
378 default:
379 user_error('SSH_AUTH_SOCK not found');
380 return false;
381 }
382 }
383
384 $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
385 if (!$this->fsock) {
386 user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
387 }
388 }
389
390 /**
391 * PHP4 compatible Default Constructor.
392 *
393 * @see self::__construct()
394 * @access public
395 */
396 function System_SSH_Agent($address = null)
397 {
398 $this->__construct($address);
399 }
400
401 /**
402 * Request Identities
403 *
404 * See "2.5.2 Requesting a list of protocol 2 keys"
405 * Returns an array containing zero or more System_SSH_Agent_Identity objects
406 *
407 * @return array
408 * @access public
409 */
410 function requestIdentities()
411 {
412 if (!$this->fsock) {
413 return array();
414 }
415
416 $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES);
417 if (strlen($packet) != fputs($this->fsock, $packet)) {
418 user_error('Connection closed while requesting identities');
419 return array();
420 }
421
422 $temp = fread($this->fsock, 4);
423 if (strlen($temp) != 4) {
424 user_error('Connection closed while requesting identities');
425 return array();
426 }
427 $length = current(unpack('N', $temp));
428 $type = ord(fread($this->fsock, 1));
429 if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) {
430 user_error('Unable to request identities');
431 return array();
432 }
433
434 $identities = array();
435 $temp = fread($this->fsock, 4);
436 if (strlen($temp) != 4) {
437 user_error('Connection closed while requesting identities');
438 return array();
439 }
440 $keyCount = current(unpack('N', $temp));
441 for ($i = 0; $i < $keyCount; $i++) {
442 $temp = fread($this->fsock, 4);
443 if (strlen($temp) != 4) {
444 user_error('Connection closed while requesting identities');
445 return array();
446 }
447 $length = current(unpack('N', $temp));
448 $key_blob = fread($this->fsock, $length);
449 if (strlen($key_blob) != $length) {
450 user_error('Connection closed while requesting identities');
451 return array();
452 }
453 $key_str = 'ssh-rsa ' . base64_encode($key_blob);
454 $temp = fread($this->fsock, 4);
455 if (strlen($temp) != 4) {
456 user_error('Connection closed while requesting identities');
457 return array();
458 }
459 $length = current(unpack('N', $temp));
460 if ($length) {
461 $temp = fread($this->fsock, $length);
462 if (strlen($temp) != $length) {
463 user_error('Connection closed while requesting identities');
464 return array();
465 }
466 $key_str.= ' ' . $temp;
467 }
468 $length = current(unpack('N', substr($key_blob, 0, 4)));
469 $key_type = substr($key_blob, 4, $length);
470 switch ($key_type) {
471 case 'ssh-rsa':
472 if (!class_exists('Crypt_RSA')) {
473 include_once 'Crypt/RSA.php';
474 }
475 $key = new Crypt_RSA();
476 $key->loadKey($key_str);
477 break;
478 case 'ssh-dss':
479 // not currently supported
480 break;
481 }
482 // resources are passed by reference by default
483 if (isset($key)) {
484 $identity = new System_SSH_Agent_Identity($this->fsock);
485 $identity->setPublicKey($key);
486 $identity->setPublicKeyBlob($key_blob);
487 $identities[] = $identity;
488 unset($key);
489 }
490 }
491
492 return $identities;
493 }
494
495 /**
496 * Signal that agent forwarding should
497 * be requested when a channel is opened
498 *
499 * @return bool
500 * @access public
501 */
502 function startSSHForwarding()
503 {
504 if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) {
505 $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST;
506 }
507 }
508
509 /**
510 * Request agent forwarding of remote server
511 *
512 * @param Net_SSH2 $ssh
513 * @return bool
514 * @access private
515 */
516 function _request_forwarding($ssh)
517 {
518 $request_channel = $ssh->_get_open_channel();
519 if ($request_channel === false) {
520 return false;
521 }
522
523 $packet = pack(
524 'CNNa*C',
525 NET_SSH2_MSG_CHANNEL_REQUEST,
526 $ssh->server_channels[$request_channel],
527 strlen('[email protected]'),
528 '[email protected]',
529 1
530 );
531
532 $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;
533
534 if (!$ssh->_send_binary_packet($packet)) {
535 return false;
536 }
537
538 $response = $ssh->_get_channel_packet($request_channel);
539 if ($response === false) {
540 return false;
541 }
542
543 $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;
544 $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE;
545
546 return true;
547 }
548
549 /**
550 * On successful channel open
551 *
552 * This method is called upon successful channel
553 * open to give the SSH Agent an opportunity
554 * to take further action. i.e. request agent forwarding
555 *
556 * @param Net_SSH2 $ssh
557 * @access private
558 */
559 function _on_channel_open($ssh)
560 {
561 if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) {
562 $this->_request_forwarding($ssh);
563 }
564 }
565
566 /**
567 * Forward data to SSH Agent and return data reply
568 *
569 * @param string $data
570 * @return data from SSH Agent
571 * @access private
572 */
573 function _forward_data($data)
574 {
575 if ($this->expected_bytes > 0) {
576 $this->socket_buffer.= $data;
577 $this->expected_bytes -= strlen($data);
578 } else {
579 $agent_data_bytes = current(unpack('N', $data));
580 $current_data_bytes = strlen($data);
581 $this->socket_buffer = $data;
582 if ($current_data_bytes != $agent_data_bytes + 4) {
583 $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
584 return false;
585 }
586 }
587
588 if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
589 user_error('Connection closed attempting to forward data to SSH agent');
590 return false;
591 }
592
593 $this->socket_buffer = '';
594 $this->expected_bytes = 0;
595
596 $temp = fread($this->fsock, 4);
597 if (strlen($temp) != 4) {
598 user_error('Connection closed while reading data response');
599 return false;
600 }
601 $agent_reply_bytes = current(unpack('N', $temp));
602
603 $agent_reply_data = fread($this->fsock, $agent_reply_bytes);
604 if (strlen($agent_reply_data) != $agent_reply_bytes) {
605 user_error('Connection closed while reading data response');
606 return false;
607 }
608 $agent_reply_data = current(unpack('a*', $agent_reply_data));
609
610 return pack('Na*', $agent_reply_bytes, $agent_reply_data);
611 }
612 }
613