PluginProbe
ManageWP Worker / 4.9.25
ManageWP Worker v4.9.25
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / src / PHPSecLib / Net / SSH1.php

SSH1.php in ManageWP Worker 4.9.25, at src/PHPSecLib/Net/SSH1.php

1,705 lines 53.8 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 implementation of SSHv1.
5 *
6 * PHP versions 4 and 5
7 *
8 * Here's a short example of how to use this library:
9 * <code>
10 * <?php
11 * include 'Net/SSH1.php';
12 *
13 * $ssh = new Net_SSH1('www.domain.tld');
14 * if (!$ssh->login('username', 'password')) {
15 * exit('Login Failed');
16 * }
17 *
18 * echo $ssh->exec('ls -la');
19 * ?>
20 * </code>
21 *
22 * Here's another short example:
23 * <code>
24 * <?php
25 * include 'Net/SSH1.php';
26 *
27 * $ssh = new Net_SSH1('www.domain.tld');
28 * if (!$ssh->login('username', 'password')) {
29 * exit('Login Failed');
30 * }
31 *
32 * echo $ssh->read('username@username:~$');
33 * $ssh->write("ls -la\n");
34 * echo $ssh->read('username@username:~$');
35 * ?>
36 * </code>
37 *
38 * More information on the SSHv1 specification can be found by reading
39 * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
40 *
41 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
42 * of this software and associated documentation files (the "Software"), to deal
43 * in the Software without restriction, including without limitation the rights
44 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
45 * copies of the Software, and to permit persons to whom the Software is
46 * furnished to do so, subject to the following conditions:
47 *
48 * The above copyright notice and this permission notice shall be included in
49 * all copies or substantial portions of the Software.
50 *
51 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
54 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
57 * THE SOFTWARE.
58 *
59 * @category Net
60 * @package Net_SSH1
61 * @author Jim Wigginton <terrafrost@php.net>
62 * @copyright MMVII Jim Wigginton
63 * @license http://www.opensource.org/licenses/mit-license.html MIT License
64 * @link http://phpseclib.sourceforge.net
65 */
66
67 /**#@+
68 * Encryption Methods
69 *
70 * @see Net_SSH1::getSupportedCiphers()
71 * @access public
72 */
73 /**
74 * No encryption
75 *
76 * Not supported.
77 */
78 define('NET_SSH1_CIPHER_NONE', 0);
79 /**
80 * IDEA in CFB mode
81 *
82 * Not supported.
83 */
84 define('NET_SSH1_CIPHER_IDEA', 1);
85 /**
86 * DES in CBC mode
87 */
88 define('NET_SSH1_CIPHER_DES', 2);
89 /**
90 * Triple-DES in CBC mode
91 *
92 * All implementations are required to support this
93 */
94 define('NET_SSH1_CIPHER_3DES', 3);
95 /**
96 * TRI's Simple Stream encryption CBC
97 *
98 * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
99 * although it doesn't use it (see cipher.c)
100 */
101 define('NET_SSH1_CIPHER_BROKEN_TSS', 4);
102 /**
103 * RC4
104 *
105 * Not supported.
106 *
107 * @internal According to the SSH1 specs:
108 *
109 * "The first 16 bytes of the session key are used as the key for
110 * the server to client direction. The remaining 16 bytes are used
111 * as the key for the client to server direction. This gives
112 * independent 128-bit keys for each direction."
113 *
114 * This library currently only supports encryption when the same key is being used for both directions. This is
115 * because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
116 */
117 define('NET_SSH1_CIPHER_RC4', 5);
118 /**
119 * Blowfish
120 *
121 * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
122 * uses it (see cipher.c)
123 */
124 define('NET_SSH1_CIPHER_BLOWFISH', 6);
125 /**#@-*/
126
127 /**#@+
128 * Authentication Methods
129 *
130 * @see Net_SSH1::getSupportedAuthentications()
131 * @access public
132 */
133 /**
134 * .rhosts or /etc/hosts.equiv
135 */
136 define('NET_SSH1_AUTH_RHOSTS', 1);
137 /**
138 * pure RSA authentication
139 */
140 define('NET_SSH1_AUTH_RSA', 2);
141 /**
142 * password authentication
143 *
144 * This is the only method that is supported by this library.
145 */
146 define('NET_SSH1_AUTH_PASSWORD', 3);
147 /**
148 * .rhosts with RSA host authentication
149 */
150 define('NET_SSH1_AUTH_RHOSTS_RSA', 4);
151 /**#@-*/
152
153 /**#@+
154 * Terminal Modes
155 *
156 * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
157 * @access private
158 */
159 define('NET_SSH1_TTY_OP_END', 0);
160 /**#@-*/
161
162 /**
163 * The Response Type
164 *
165 * @see Net_SSH1::_get_binary_packet()
166 * @access private
167 */
168 define('NET_SSH1_RESPONSE_TYPE', 1);
169
170 /**
171 * The Response Data
172 *
173 * @see Net_SSH1::_get_binary_packet()
174 * @access private
175 */
176 define('NET_SSH1_RESPONSE_DATA', 2);
177
178 /**#@+
179 * Execution Bitmap Masks
180 *
181 * @see Net_SSH1::bitmap
182 * @access private
183 */
184 define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
185 define('NET_SSH1_MASK_CONNECTED', 0x00000002);
186 define('NET_SSH1_MASK_LOGIN', 0x00000004);
187 define('NET_SSH1_MASK_SHELL', 0x00000008);
188 /**#@-*/
189
190 /**#@+
191 * @access public
192 * @see Net_SSH1::getLog()
193 */
194 /**
195 * Returns the message numbers
196 */
197 define('NET_SSH1_LOG_SIMPLE', 1);
198 /**
199 * Returns the message content
200 */
201 define('NET_SSH1_LOG_COMPLEX', 2);
202 /**
203 * Outputs the content real-time
204 */
205 define('NET_SSH1_LOG_REALTIME', 3);
206 /**
207 * Dumps the content real-time to a file
208 */
209 define('NET_SSH1_LOG_REALTIME_FILE', 4);
210 /**#@-*/
211
212 /**#@+
213 * @access public
214 * @see Net_SSH1::read()
215 */
216 /**
217 * Returns when a string matching $expect exactly is found
218 */
219 define('NET_SSH1_READ_SIMPLE', 1);
220 /**
221 * Returns when a string matching the regular expression $expect is found
222 */
223 define('NET_SSH1_READ_REGEX', 2);
224 /**#@-*/
225
226 /**
227 * Pure-PHP implementation of SSHv1.
228 *
229 * @package Net_SSH1
230 * @author Jim Wigginton <terrafrost@php.net>
231 * @access public
232 */
233 class Net_SSH1
234 {
235 /**
236 * The SSH identifier
237 *
238 * @var String
239 * @access private
240 */
241 public $identifier = 'SSH-1.5-phpseclib';
242
243 /**
244 * The Socket Object
245 *
246 * @var Object
247 * @access private
248 */
249 public $fsock;
250
251 /**
252 * The cryptography object
253 *
254 * @var Object
255 * @access private
256 */
257 public $crypto = false;
258
259 /**
260 * Execution Bitmap
261 *
262 * The bits that are set represent functions that have been called already. This is used to determine
263 * if a requisite function has been successfully executed. If not, an error should be thrown.
264 *
265 * @var Integer
266 * @access private
267 */
268 public $bitmap = 0;
269
270 /**
271 * The Server Key Public Exponent
272 *
273 * Logged for debug purposes
274 *
275 * @see Net_SSH1::getServerKeyPublicExponent()
276 * @var String
277 * @access private
278 */
279 public $server_key_public_exponent;
280
281 /**
282 * The Server Key Public Modulus
283 *
284 * Logged for debug purposes
285 *
286 * @see Net_SSH1::getServerKeyPublicModulus()
287 * @var String
288 * @access private
289 */
290 public $server_key_public_modulus;
291
292 /**
293 * The Host Key Public Exponent
294 *
295 * Logged for debug purposes
296 *
297 * @see Net_SSH1::getHostKeyPublicExponent()
298 * @var String
299 * @access private
300 */
301 public $host_key_public_exponent;
302
303 /**
304 * The Host Key Public Modulus
305 *
306 * Logged for debug purposes
307 *
308 * @see Net_SSH1::getHostKeyPublicModulus()
309 * @var String
310 * @access private
311 */
312 public $host_key_public_modulus;
313
314 /**
315 * Supported Ciphers
316 *
317 * Logged for debug purposes
318 *
319 * @see Net_SSH1::getSupportedCiphers()
320 * @var Array
321 * @access private
322 */
323 var $supported_ciphers = array(
324 NET_SSH1_CIPHER_NONE => 'No encryption',
325 NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode',
326 NET_SSH1_CIPHER_DES => 'DES in CBC mode',
327 NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode',
328 NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
329 NET_SSH1_CIPHER_RC4 => 'RC4',
330 NET_SSH1_CIPHER_BLOWFISH => 'Blowfish',
331 );
332
333 /**
334 * Supported Authentications
335 *
336 * Logged for debug purposes
337 *
338 * @see Net_SSH1::getSupportedAuthentications()
339 * @var Array
340 * @access private
341 */
342 var $supported_authentications = array(
343 NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
344 NET_SSH1_AUTH_RSA => 'pure RSA authentication',
345 NET_SSH1_AUTH_PASSWORD => 'password authentication',
346 NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication',
347 );
348
349 /**
350 * Server Identification
351 *
352 * @see Net_SSH1::getServerIdentification()
353 * @var String
354 * @access private
355 */
356 public $server_identification = '';
357
358 /**
359 * Protocol Flags
360 *
361 * @see Net_SSH1::Net_SSH1()
362 * @var Array
363 * @access private
364 */
365 public $protocol_flags = array();
366
367 /**
368 * Protocol Flag Log
369 *
370 * @see Net_SSH1::getLog()
371 * @var Array
372 * @access private
373 */
374 public $protocol_flag_log = array();
375
376 /**
377 * Message Log
378 *
379 * @see Net_SSH1::getLog()
380 * @var Array
381 * @access private
382 */
383 public $message_log = array();
384
385 /**
386 * Real-time log file pointer
387 *
388 * @see Net_SSH1::_append_log()
389 * @var Resource
390 * @access private
391 */
392 public $realtime_log_file;
393
394 /**
395 * Real-time log file size
396 *
397 * @see Net_SSH1::_append_log()
398 * @var Integer
399 * @access private
400 */
401 public $realtime_log_size;
402
403 /**
404 * Real-time log file wrap boolean
405 *
406 * @see Net_SSH1::_append_log()
407 * @var Boolean
408 * @access private
409 */
410 public $realtime_log_wrap;
411
412 /**
413 * Interactive Buffer
414 *
415 * @see Net_SSH1::read()
416 * @var Array
417 * @access private
418 */
419 public $interactiveBuffer = '';
420
421 /**
422 * Timeout
423 *
424 * @see Net_SSH1::setTimeout()
425 * @access private
426 */
427 public $timeout;
428
429 /**
430 * Current Timeout
431 *
432 * @see Net_SSH1::_get_channel_packet()
433 * @access private
434 */
435 public $curTimeout;
436
437 /**
438 * Log Boundary
439 *
440 * @see Net_SSH1::_format_log
441 * @access private
442 */
443 public $log_boundary = ':';
444
445 /**
446 * Log Long Width
447 *
448 * @see Net_SSH1::_format_log
449 * @access private
450 */
451 public $log_long_width = 65;
452
453 /**
454 * Log Short Width
455 *
456 * @see Net_SSH1::_format_log
457 * @access private
458 */
459 public $log_short_width = 16;
460
461 /**
462 * Hostname
463 *
464 * @see Net_SSH1::Net_SSH1()
465 * @see Net_SSH1::_connect()
466 * @var String
467 * @access private
468 */
469 public $host;
470
471 /**
472 * Port Number
473 *
474 * @see Net_SSH1::Net_SSH1()
475 * @see Net_SSH1::_connect()
476 * @var Integer
477 * @access private
478 */
479 public $port;
480
481 /**
482 * Timeout for initial connection
483 *
484 * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like
485 * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor,
486 * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
487 * 10 seconds. It is used by fsockopen() in that function.
488 *
489 * @see Net_SSH1::Net_SSH1()
490 * @see Net_SSH1::_connect()
491 * @var Integer
492 * @access private
493 */
494 public $connectionTimeout;
495
496 /**
497 * Default cipher
498 *
499 * @see Net_SSH1::Net_SSH1()
500 * @see Net_SSH1::_connect()
501 * @var Integer
502 * @access private
503 */
504 public $cipher;
505
506 /**
507 * Default Constructor.
508 *
509 * Connects to an SSHv1 server
510 *
511 * @param String $host
512 * @param optional Integer $port
513 * @param optional Integer $timeout
514 * @param optional Integer $cipher
515 *
516 * @return Net_SSH1
517 * @access public
518 */
519 public function __construct($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
520 {
521 if (!class_exists('Math_BigInteger')) {
522 require_once dirname(__FILE__).'/../Math/BigInteger.php';
523 }
524
525 // Include Crypt_Random
526 // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
527 // will trigger a call to __autoload() if you're wanting to auto-load classes
528 // call function_exists() a second time to stop the require_once from being called outside
529 // of the auto loader
530 if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) {
531 require_once dirname(__FILE__).'/../Crypt/Random.php';
532 }
533
534 $this->protocol_flags = array(
535 1 => 'NET_SSH1_MSG_DISCONNECT',
536 2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
537 3 => 'NET_SSH1_CMSG_SESSION_KEY',
538 4 => 'NET_SSH1_CMSG_USER',
539 9 => 'NET_SSH1_CMSG_AUTH_PASSWORD',
540 10 => 'NET_SSH1_CMSG_REQUEST_PTY',
541 12 => 'NET_SSH1_CMSG_EXEC_SHELL',
542 13 => 'NET_SSH1_CMSG_EXEC_CMD',
543 14 => 'NET_SSH1_SMSG_SUCCESS',
544 15 => 'NET_SSH1_SMSG_FAILURE',
545 16 => 'NET_SSH1_CMSG_STDIN_DATA',
546 17 => 'NET_SSH1_SMSG_STDOUT_DATA',
547 18 => 'NET_SSH1_SMSG_STDERR_DATA',
548 19 => 'NET_SSH1_CMSG_EOF',
549 20 => 'NET_SSH1_SMSG_EXITSTATUS',
550 33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION',
551 );
552
553 $this->_define_array($this->protocol_flags);
554
555 $this->host = $host;
556 $this->port = $port;
557 $this->connectionTimeout = $timeout;
558 $this->cipher = $cipher;
559 }
560
561 /**
562 * Connect to an SSHv1 server
563 *
564 * @return Boolean
565 * @access private
566 */
567 public function _connect()
568 {
569 $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
570 if (!$this->fsock) {
571 user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
572
573 return false;
574 }
575
576 $this->server_identification = $init_line = fgets($this->fsock, 255);
577
578 if (defined('NET_SSH1_LOGGING')) {
579 $this->_append_log('<-', $this->server_identification);
580 $this->_append_log('->', $this->identifier."\r\n");
581 }
582
583 if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
584 user_error('Can only connect to SSH servers');
585
586 return false;
587 }
588 if ($parts[1][0] != 1) {
589 user_error("Cannot connect to SSH $parts[1] servers");
590
591 return false;
592 }
593
594 fputs($this->fsock, $this->identifier."\r\n");
595
596 $response = $this->_get_binary_packet();
597 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
598 user_error('Expected SSH_SMSG_PUBLIC_KEY');
599
600 return false;
601 }
602
603 $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
604
605 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
606
607 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
608 $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
609 $this->server_key_public_exponent = $server_key_public_exponent;
610
611 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
612 $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
613 $this->server_key_public_modulus = $server_key_public_modulus;
614
615 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
616
617 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
618 $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
619 $this->host_key_public_exponent = $host_key_public_exponent;
620
621 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
622 $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
623 $this->host_key_public_modulus = $host_key_public_modulus;
624
625 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
626
627 // get a list of the supported ciphers
628 extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
629 foreach ($this->supported_ciphers as $mask => $name) {
630 if (($supported_ciphers_mask & (1 << $mask)) == 0) {
631 unset($this->supported_ciphers[$mask]);
632 }
633 }
634
635 // get a list of the supported authentications
636 extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
637 foreach ($this->supported_authentications as $mask => $name) {
638 if (($supported_authentications_mask & (1 << $mask)) == 0) {
639 unset($this->supported_authentications[$mask]);
640 }
641 }
642
643 $session_id = pack('H*', md5($host_key_public_modulus->toBytes().$server_key_public_modulus->toBytes().$anti_spoofing_cookie));
644
645 $session_key = crypt_random_string(32);
646 $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
647
648 if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
649 $double_encrypted_session_key = $this->_rsa_crypt(
650 $double_encrypted_session_key,
651 array(
652 $server_key_public_exponent,
653 $server_key_public_modulus,
654 )
655 );
656 $double_encrypted_session_key = $this->_rsa_crypt(
657 $double_encrypted_session_key,
658 array(
659 $host_key_public_exponent,
660 $host_key_public_modulus,
661 )
662 );
663 } else {
664 $double_encrypted_session_key = $this->_rsa_crypt(
665 $double_encrypted_session_key,
666 array(
667 $host_key_public_exponent,
668 $host_key_public_modulus,
669 )
670 );
671 $double_encrypted_session_key = $this->_rsa_crypt(
672 $double_encrypted_session_key,
673 array(
674 $server_key_public_exponent,
675 $server_key_public_modulus,
676 )
677 );
678 }
679
680 $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : NET_SSH1_CIPHER_3DES;
681 $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
682
683 if (!$this->_send_binary_packet($data)) {
684 user_error('Error sending SSH_CMSG_SESSION_KEY');
685
686 return false;
687 }
688
689 switch ($cipher) {
690 //case NET_SSH1_CIPHER_NONE:
691 // $this->crypto = new Crypt_Null();
692 // break;
693 case NET_SSH1_CIPHER_DES:
694 if (!class_exists('Crypt_DES')) {
695 require_once dirname(__FILE__).'/../Crypt/DES.php';
696 }
697 $this->crypto = new Crypt_DES();
698 $this->crypto->disablePadding();
699 $this->crypto->enableContinuousBuffer();
700 $this->crypto->setKey(substr($session_key, 0, 8));
701 break;
702 case NET_SSH1_CIPHER_3DES:
703 if (!class_exists('Crypt_TripleDES')) {
704 require_once dirname(__FILE__).'/../Crypt/TripleDES.php';
705 }
706 $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
707 $this->crypto->disablePadding();
708 $this->crypto->enableContinuousBuffer();
709 $this->crypto->setKey(substr($session_key, 0, 24));
710 break;
711 //case NET_SSH1_CIPHER_RC4:
712 // if (!class_exists('Crypt_RC4')) {
713 // require_once 'Crypt/RC4.php';
714 // }
715 // $this->crypto = new Crypt_RC4();
716 // $this->crypto->enableContinuousBuffer();
717 // $this->crypto->setKey(substr($session_key, 0, 16));
718 // break;
719 }
720
721 $response = $this->_get_binary_packet();
722
723 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
724 user_error('Expected SSH_SMSG_SUCCESS');
725
726 return false;
727 }
728
729 $this->bitmap = NET_SSH1_MASK_CONNECTED;
730
731 return true;
732 }
733
734 /**
735 * Login
736 *
737 * @param String $username
738 * @param optional String $password
739 *
740 * @return Boolean
741 * @access public
742 */
743 public function login($username, $password = '')
744 {
745 if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) {
746 $this->bitmap |= NET_SSH1_MASK_CONSTRUCTOR;
747 if (!$this->_connect()) {
748 return false;
749 }
750 }
751
752 if (!($this->bitmap & NET_SSH1_MASK_CONNECTED)) {
753 return false;
754 }
755
756 $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
757
758 if (!$this->_send_binary_packet($data)) {
759 user_error('Error sending SSH_CMSG_USER');
760
761 return false;
762 }
763
764 $response = $this->_get_binary_packet();
765
766 if ($response === true) {
767 return false;
768 }
769 if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
770 $this->bitmap |= NET_SSH1_MASK_LOGIN;
771
772 return true;
773 } elseif ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
774 user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
775
776 return false;
777 }
778
779 $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
780
781 if (!$this->_send_binary_packet($data)) {
782 user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
783
784 return false;
785 }
786
787 // remove the username and password from the last logged packet
788 if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
789 $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
790 $this->message_log[count($this->message_log) - 1] = $data;
791 }
792
793 $response = $this->_get_binary_packet();
794
795 if ($response === true) {
796 return false;
797 }
798 if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
799 $this->bitmap |= NET_SSH1_MASK_LOGIN;
800
801 return true;
802 } elseif ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
803 return false;
804 } else {
805 user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
806
807 return false;
808 }
809 }
810
811 /**
812 * Set Timeout
813 *
814 * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely. setTimeout() makes it so it'll timeout.
815 * Setting $timeout to false or 0 will mean there is no timeout.
816 *
817 * @param Mixed $timeout
818 */
819 public function setTimeout($timeout)
820 {
821 $this->timeout = $this->curTimeout = $timeout;
822 }
823
824 /**
825 * Executes a command on a non-interactive shell, returns the output, and quits.
826 *
827 * An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
828 * servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
829 * shell with the -s option, as discussed in the following links:
830 *
831 * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
832 * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
833 *
834 * To execute further commands, a new Net_SSH1 object will need to be created.
835 *
836 * Returns false on failure and the output, otherwise.
837 *
838 * @see Net_SSH1::interactiveRead()
839 * @see Net_SSH1::interactiveWrite()
840 *
841 * @param String $cmd
842 *
843 * @return mixed
844 * @access public
845 */
846 public function exec($cmd, $block = true)
847 {
848 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
849 user_error('Operation disallowed prior to login()');
850
851 return false;
852 }
853
854 $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
855
856 if (!$this->_send_binary_packet($data)) {
857 user_error('Error sending SSH_CMSG_EXEC_CMD');
858
859 return false;
860 }
861
862 if (!$block) {
863 return true;
864 }
865
866 $output = '';
867 $response = $this->_get_binary_packet();
868
869 if ($response !== false) {
870 do {
871 $output .= substr($response[NET_SSH1_RESPONSE_DATA], 4);
872 $response = $this->_get_binary_packet();
873 } while (is_array($response) && $response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
874 }
875
876 $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
877
878 // i don't think it's really all that important if this packet gets sent or not.
879 $this->_send_binary_packet($data);
880
881 fclose($this->fsock);
882
883 // reset the execution bitmap - a new Net_SSH1 object needs to be created.
884 $this->bitmap = 0;
885
886 return $output;
887 }
888
889 /**
890 * Creates an interactive shell
891 *
892 * @see Net_SSH1::interactiveRead()
893 * @see Net_SSH1::interactiveWrite()
894 * @return Boolean
895 * @access private
896 */
897 public function _initShell()
898 {
899 // connect using the sample parameters in protocol-1.5.txt.
900 // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
901 // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
902 $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
903
904 if (!$this->_send_binary_packet($data)) {
905 user_error('Error sending SSH_CMSG_REQUEST_PTY');
906
907 return false;
908 }
909
910 $response = $this->_get_binary_packet();
911
912 if ($response === true) {
913 return false;
914 }
915 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
916 user_error('Expected SSH_SMSG_SUCCESS');
917
918 return false;
919 }
920
921 $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
922
923 if (!$this->_send_binary_packet($data)) {
924 user_error('Error sending SSH_CMSG_EXEC_SHELL');
925
926 return false;
927 }
928
929 $this->bitmap |= NET_SSH1_MASK_SHELL;
930
931 //stream_set_blocking($this->fsock, 0);
932
933 return true;
934 }
935
936 /**
937 * Inputs a command into an interactive shell.
938 *
939 * @see Net_SSH1::interactiveWrite()
940 *
941 * @param String $cmd
942 *
943 * @return Boolean
944 * @access public
945 */
946 public function write($cmd)
947 {
948 return $this->interactiveWrite($cmd);
949 }
950
951 /**
952 * Returns the output of an interactive shell when there's a match for $expect
953 *
954 * $expect can take the form of a string literal or, if $mode == NET_SSH1_READ_REGEX,
955 * a regular expression.
956 *
957 * @see Net_SSH1::write()
958 *
959 * @param String $expect
960 * @param Integer $mode
961 *
962 * @return Boolean
963 * @access public
964 */
965 public function read($expect, $mode = NET_SSH1_READ_SIMPLE)
966 {
967 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
968 user_error('Operation disallowed prior to login()');
969
970 return false;
971 }
972
973 if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
974 user_error('Unable to initiate an interactive shell session');
975
976 return false;
977 }
978
979 $match = $expect;
980 while (true) {
981 if ($mode == NET_SSH1_READ_REGEX) {
982 preg_match($expect, $this->interactiveBuffer, $matches);
983 $match = isset($matches[0]) ? $matches[0] : '';
984 }
985 $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
986 if ($pos !== false) {
987 return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
988 }
989 $response = $this->_get_binary_packet();
990
991 if ($response === true) {
992 return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
993 }
994 $this->interactiveBuffer .= substr($response[NET_SSH1_RESPONSE_DATA], 4);
995 }
996 }
997
998 /**
999 * Inputs a command into an interactive shell.
1000 *
1001 * @see Net_SSH1::interactiveRead()
1002 *
1003 * @param String $cmd
1004 *
1005 * @return Boolean
1006 * @access public
1007 */
1008 public function interactiveWrite($cmd)
1009 {
1010 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
1011 user_error('Operation disallowed prior to login()');
1012
1013 return false;
1014 }
1015
1016 if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
1017 user_error('Unable to initiate an interactive shell session');
1018
1019 return false;
1020 }
1021
1022 $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
1023
1024 if (!$this->_send_binary_packet($data)) {
1025 user_error('Error sending SSH_CMSG_STDIN');
1026
1027 return false;
1028 }
1029
1030 return true;
1031 }
1032
1033 /**
1034 * Returns the output of an interactive shell when no more output is available.
1035 *
1036 * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like
1037 * "^[[00m", you're seeing ANSI escape codes. According to
1038 * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
1039 * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
1040 * there's not going to be much recourse.
1041 *
1042 * @see Net_SSH1::interactiveRead()
1043 * @return String
1044 * @access public
1045 */
1046 public function interactiveRead()
1047 {
1048 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
1049 user_error('Operation disallowed prior to login()');
1050
1051 return false;
1052 }
1053
1054 if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
1055 user_error('Unable to initiate an interactive shell session');
1056
1057 return false;
1058 }
1059
1060 $read = array($this->fsock);
1061 $write = $except = null;
1062 if (stream_select($read, $write, $except, 0)) {
1063 $response = $this->_get_binary_packet();
1064
1065 return substr($response[NET_SSH1_RESPONSE_DATA], 4);
1066 } else {
1067 return '';
1068 }
1069 }
1070
1071 /**
1072 * Disconnect
1073 *
1074 * @access public
1075 */
1076 public function disconnect()
1077 {
1078 $this->_disconnect();
1079 }
1080
1081 /**
1082 * Destructor.
1083 *
1084 * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
1085 * disconnect().
1086 *
1087 * @access public
1088 */
1089 public function __destruct()
1090 {
1091 $this->_disconnect();
1092 }
1093
1094 /**
1095 * Disconnect
1096 *
1097 * @param String $msg
1098 *
1099 * @access private
1100 */
1101 public function _disconnect($msg = 'Client Quit')
1102 {
1103 if ($this->bitmap) {
1104 $data = pack('C', NET_SSH1_CMSG_EOF);
1105 $this->_send_binary_packet($data);
1106 /*
1107 $response = $this->_get_binary_packet();
1108 if ($response === true) {
1109 $response = array(NET_SSH1_RESPONSE_TYPE => -1);
1110 }
1111 switch ($response[NET_SSH1_RESPONSE_TYPE]) {
1112 case NET_SSH1_SMSG_EXITSTATUS:
1113 $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
1114 break;
1115 default:
1116 $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1117 }
1118 */
1119 $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1120
1121 $this->_send_binary_packet($data);
1122 fclose($this->fsock);
1123 $this->bitmap = 0;
1124 }
1125 }
1126
1127 /**
1128 * Gets Binary Packets
1129 *
1130 * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
1131 *
1132 * Also, this function could be improved upon by adding detection for the following exploit:
1133 * http://www.securiteam.com/securitynews/5LP042K3FY.html
1134 *
1135 * @see Net_SSH1::_send_binary_packet()
1136 * @return Array
1137 * @access private
1138 */
1139 public function _get_binary_packet()
1140 {
1141 if (feof($this->fsock)) {
1142 //user_error('connection closed prematurely');
1143 return false;
1144 }
1145
1146 if ($this->curTimeout) {
1147 $read = array($this->fsock);
1148 $write = $except = null;
1149
1150 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1151 $sec = floor($this->curTimeout);
1152 $usec = 1000000 * ($this->curTimeout - $sec);
1153 // on windows this returns a "Warning: Invalid CRT parameters detected" error
1154 if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
1155 //$this->_disconnect('Timeout');
1156 return true;
1157 }
1158 $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
1159 $this->curTimeout -= $elapsed;
1160 }
1161
1162 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1163 $temp = unpack('Nlength', fread($this->fsock, 4));
1164
1165 $padding_length = 8 - ($temp['length'] & 7);
1166 $length = $temp['length'] + $padding_length;
1167
1168 while ($length > 0) {
1169 $temp = fread($this->fsock, $length);
1170 $raw .= $temp;
1171 $length -= strlen($temp);
1172 }
1173 $stop = strtok(microtime(), ' ') + strtok('');
1174
1175 if (strlen($raw) && $this->crypto !== false) {
1176 $raw = $this->crypto->decrypt($raw);
1177 }
1178
1179 $padding = substr($raw, 0, $padding_length);
1180 $type = $raw[$padding_length];
1181 $data = substr($raw, $padding_length + 1, -4);
1182
1183 $temp = unpack('Ncrc', substr($raw, -4));
1184
1185 //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
1186 // user_error('Bad CRC in packet from server');
1187 // return false;
1188 //}
1189
1190 $type = ord($type);
1191
1192 if (defined('NET_SSH1_LOGGING')) {
1193 $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
1194 $temp = '<- '.$temp.
1195 ' ('.round($stop - $start, 4).'s)';
1196 $this->_append_log($temp, $data);
1197 }
1198
1199 return array(
1200 NET_SSH1_RESPONSE_TYPE => $type,
1201 NET_SSH1_RESPONSE_DATA => $data,
1202 );
1203 }
1204
1205 /**
1206 * Sends Binary Packets
1207 *
1208 * Returns true on success, false on failure.
1209 *
1210 * @see Net_SSH1::_get_binary_packet()
1211 *
1212 * @param String $data
1213 *
1214 * @return Boolean
1215 * @access private
1216 */
1217 public function _send_binary_packet($data)
1218 {
1219 if (feof($this->fsock)) {
1220 //user_error('connection closed prematurely');
1221 return false;
1222 }
1223
1224 $length = strlen($data) + 4;
1225
1226 $padding = crypt_random_string(8 - ($length & 7));
1227
1228 $orig = $data;
1229 $data = $padding.$data;
1230 $data .= pack('N', $this->_crc($data));
1231
1232 if ($this->crypto !== false) {
1233 $data = $this->crypto->encrypt($data);
1234 }
1235
1236 $packet = pack('Na*', $length, $data);
1237
1238 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1239 $result = strlen($packet) == fputs($this->fsock, $packet);
1240 $stop = strtok(microtime(), ' ') + strtok('');
1241
1242 if (defined('NET_SSH1_LOGGING')) {
1243 $temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
1244 $temp = '-> '.$temp.
1245 ' ('.round($stop - $start, 4).'s)';
1246 $this->_append_log($temp, $orig);
1247 }
1248
1249 return $result;
1250 }
1251
1252 /**
1253 * Cyclic Redundancy Check (CRC)
1254 *
1255 * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
1256 * we've reimplemented it. A more detailed discussion of the differences can be found after
1257 * $crc_lookup_table's initialization.
1258 *
1259 * @see Net_SSH1::_get_binary_packet()
1260 * @see Net_SSH1::_send_binary_packet()
1261 *
1262 * @param String $data
1263 *
1264 * @return Integer
1265 * @access private
1266 */
1267 public function _crc($data)
1268 {
1269 static $crc_lookup_table = array(
1270 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1271 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1272 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1273 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1274 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1275 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1276 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1277 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1278 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1279 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1280 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1281 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1282 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1283 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1284 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1285 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1286 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1287 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1288 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1289 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1290 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1291 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1292 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1293 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1294 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1295 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1296 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1297 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1298 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1299 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1300 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1301 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1302 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1303 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1304 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1305 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1306 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1307 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1308 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1309 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1310 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1311 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1312 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1313 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1314 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1315 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1316 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1317 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1318 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1319 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1320 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1321 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1322 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1323 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1324 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1325 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1326 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1327 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1328 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1329 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1330 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1331 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1332 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1333 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
1334 );
1335
1336 // For this function to yield the same output as PHP's crc32 function, $crc would have to be
1337 // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
1338 $crc = 0x00000000;
1339 $length = strlen($data);
1340
1341 for ($i = 0; $i < $length; $i++) {
1342 // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
1343 // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
1344 // yields 0xFF800000 - not 0x00800000. The following link elaborates:
1345 // http://www.php.net/manual/en/language.operators.bitwise.php#57281
1346 $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
1347 }
1348
1349 // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
1350 // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
1351 return $crc;
1352 }
1353
1354 /**
1355 * String Shift
1356 *
1357 * Inspired by array_shift
1358 *
1359 * @param String $string
1360 * @param optional Integer $index
1361 *
1362 * @return String
1363 * @access private
1364 */
1365 public function _string_shift(&$string, $index = 1)
1366 {
1367 $substr = substr($string, 0, $index);
1368 $string = substr($string, $index);
1369
1370 return $substr;
1371 }
1372
1373 /**
1374 * RSA Encrypt
1375 *
1376 * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
1377 * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
1378 * calls this call modexp, instead, but I think this makes things clearer, maybe...
1379 *
1380 * @see Net_SSH1::Net_SSH1()
1381 *
1382 * @param Math_BigInteger $m
1383 * @param Array $key
1384 *
1385 * @return Math_BigInteger
1386 * @access private
1387 */
1388 public function _rsa_crypt($m, $key)
1389 {
1390 /*
1391 if (!class_exists('Crypt_RSA')) {
1392 require_once 'Crypt/RSA.php';
1393 }
1394
1395 $rsa = new Crypt_RSA();
1396 $rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
1397 $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
1398 return $rsa->encrypt($m);
1399 */
1400
1401 // To quote from protocol-1.5.txt:
1402 // The most significant byte (which is only partial as the value must be
1403 // less than the public modulus, which is never a power of two) is zero.
1404 //
1405 // The next byte contains the value 2 (which stands for public-key
1406 // encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
1407 // zero random bytes to fill any unused space, a zero byte, and the data
1408 // to be encrypted in the least significant bytes, the last byte of the
1409 // data in the least significant byte.
1410
1411 // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
1412 // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
1413 // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
1414 $modulus = $key[1]->toBytes();
1415 $length = strlen($modulus) - strlen($m) - 3;
1416 $random = '';
1417 while (strlen($random) != $length) {
1418 $block = crypt_random_string($length - strlen($random));
1419 $block = str_replace("\x00", '', $block);
1420 $random .= $block;
1421 }
1422 $temp = chr(0).chr(2).$random.chr(0).$m;
1423
1424 $m = new Math_BigInteger($temp, 256);
1425 $m = $m->modPow($key[0], $key[1]);
1426
1427 return $m->toBytes();
1428 }
1429
1430 /**
1431 * Define Array
1432 *
1433 * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
1434 * named constants from it, using the value as the name of the constant and the index as the value of the constant.
1435 * If any of the constants that would be defined already exists, none of the constants will be defined.
1436 *
1437 * @param Array $array
1438 *
1439 * @access private
1440 */
1441 public function _define_array()
1442 {
1443 $args = func_get_args();
1444 foreach ($args as $arg) {
1445 foreach ($arg as $key => $value) {
1446 if (!defined($value)) {
1447 define($value, $key);
1448 } else {
1449 break 2;
1450 }
1451 }
1452 }
1453 }
1454
1455 /**
1456 * Returns a log of the packets that have been sent and received.
1457 *
1458 * Returns a string if NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX, an array if NET_SSH1_LOGGING == NET_SSH1_LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING')
1459 *
1460 * @access public
1461 * @return String or Array
1462 */
1463 public function getLog()
1464 {
1465 if (!defined('NET_SSH1_LOGGING')) {
1466 return false;
1467 }
1468
1469 switch (NET_SSH1_LOGGING) {
1470 case NET_SSH1_LOG_SIMPLE:
1471 return $this->message_number_log;
1472 break;
1473 case NET_SSH1_LOG_COMPLEX:
1474 return $this->_format_log($this->message_log, $this->protocol_flags_log);
1475 break;
1476 default:
1477 return false;
1478 }
1479 }
1480
1481 /**
1482 * Formats a log for printing
1483 *
1484 * @param Array $message_log
1485 * @param Array $message_number_log
1486 *
1487 * @access private
1488 * @return String
1489 */
1490 public function _format_log($message_log, $message_number_log)
1491 {
1492 $output = '';
1493 for ($i = 0; $i < count($message_log); $i++) {
1494 $output .= $message_number_log[$i]."\r\n";
1495 $current_log = $message_log[$i];
1496 $j = 0;
1497 do {
1498 if (strlen($current_log)) {
1499 $output .= str_pad(dechex($j), 7, '0', STR_PAD_LEFT).'0 ';
1500 }
1501 $fragment = $this->_string_shift($current_log, $this->log_short_width);
1502 $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
1503 // replace non ASCII printable characters with dots
1504 // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
1505 // also replace < with a . since < messes up the output on web browsers
1506 $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
1507 $output .= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ').$raw."\r\n";
1508 $j++;
1509 } while (strlen($current_log));
1510 $output .= "\r\n";
1511 }
1512
1513 return $output;
1514 }
1515
1516 /**
1517 * Helper function for _format_log
1518 *
1519 * For use with preg_replace_callback()
1520 *
1521 * @param Array $matches
1522 *
1523 * @access private
1524 * @return String
1525 */
1526 public function _format_log_helper($matches)
1527 {
1528 return $this->log_boundary.str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
1529 }
1530
1531 /**
1532 * Return the server key public exponent
1533 *
1534 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1535 * the raw bytes. This behavior is similar to PHP's md5() function.
1536 *
1537 * @param optional Boolean $raw_output
1538 *
1539 * @return String
1540 * @access public
1541 */
1542 public function getServerKeyPublicExponent($raw_output = false)
1543 {
1544 return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
1545 }
1546
1547 /**
1548 * Return the server key public modulus
1549 *
1550 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1551 * the raw bytes. This behavior is similar to PHP's md5() function.
1552 *
1553 * @param optional Boolean $raw_output
1554 *
1555 * @return String
1556 * @access public
1557 */
1558 public function getServerKeyPublicModulus($raw_output = false)
1559 {
1560 return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
1561 }
1562
1563 /**
1564 * Return the host key public exponent
1565 *
1566 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1567 * the raw bytes. This behavior is similar to PHP's md5() function.
1568 *
1569 * @param optional Boolean $raw_output
1570 *
1571 * @return String
1572 * @access public
1573 */
1574 public function getHostKeyPublicExponent($raw_output = false)
1575 {
1576 return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
1577 }
1578
1579 /**
1580 * Return the host key public modulus
1581 *
1582 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1583 * the raw bytes. This behavior is similar to PHP's md5() function.
1584 *
1585 * @param optional Boolean $raw_output
1586 *
1587 * @return String
1588 * @access public
1589 */
1590 public function getHostKeyPublicModulus($raw_output = false)
1591 {
1592 return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
1593 }
1594
1595 /**
1596 * Return a list of ciphers supported by SSH1 server.
1597 *
1598 * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1599 * is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
1600 * get array(NET_SSH1_CIPHER_3DES).
1601 *
1602 * @param optional Boolean $raw_output
1603 *
1604 * @return Array
1605 * @access public
1606 */
1607 public function getSupportedCiphers($raw_output = false)
1608 {
1609 return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
1610 }
1611
1612 /**
1613 * Return a list of authentications supported by SSH1 server.
1614 *
1615 * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1616 * is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
1617 * get array(NET_SSH1_AUTH_PASSWORD).
1618 *
1619 * @param optional Boolean $raw_output
1620 *
1621 * @return Array
1622 * @access public
1623 */
1624 public function getSupportedAuthentications($raw_output = false)
1625 {
1626 return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
1627 }
1628
1629 /**
1630 * Return the server identification.
1631 *
1632 * @return String
1633 * @access public
1634 */
1635 public function getServerIdentification()
1636 {
1637 return rtrim($this->server_identification);
1638 }
1639
1640 /**
1641 * Logs data packets
1642 *
1643 * Makes sure that only the last 1MB worth of packets will be logged
1644 *
1645 * @param String $data
1646 *
1647 * @access private
1648 */
1649 public function _append_log($protocol_flags, $message)
1650 {
1651 switch (NET_SSH1_LOGGING) {
1652 // useful for benchmarks
1653 case NET_SSH1_LOG_SIMPLE:
1654 $this->protocol_flags_log[] = $protocol_flags;
1655 break;
1656 // the most useful log for SSH1
1657 case NET_SSH1_LOG_COMPLEX:
1658 $this->protocol_flags_log[] = $protocol_flags;
1659 $this->_string_shift($message);
1660 $this->log_size += strlen($message);
1661 $this->message_log[] = $message;
1662 while ($this->log_size > NET_SSH1_LOG_MAX_SIZE) {
1663 $this->log_size -= strlen(array_shift($this->message_log));
1664 array_shift($this->protocol_flags_log);
1665 }
1666 break;
1667 // dump the output out realtime; packets may be interspersed with non packets,
1668 // passwords won't be filtered out and select other packets may not be correctly
1669 // identified
1670 case NET_SSH1_LOG_REALTIME:
1671 echo "<pre>\r\n".$this->_format_log(array($message), array($protocol_flags))."\r\n</pre>\r\n";
1672 @flush();
1673 @ob_flush();
1674 break;
1675 // basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE
1676 // needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE.
1677 // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
1678 // at the beginning of the file
1679 case NET_SSH1_LOG_REALTIME_FILE:
1680 if (!isset($this->realtime_log_file)) {
1681 // PHP doesn't seem to like using constants in fopen()
1682 $filename = NET_SSH1_LOG_REALTIME_FILE;
1683 $fp = fopen($filename, 'w');
1684 $this->realtime_log_file = $fp;
1685 }
1686 if (!is_resource($this->realtime_log_file)) {
1687 break;
1688 }
1689 $entry = $this->_format_log(array($message), array($protocol_flags));
1690 if ($this->realtime_log_wrap) {
1691 $temp = "<<< START >>>\r\n";
1692 $entry .= $temp;
1693 fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
1694 }
1695 $this->realtime_log_size += strlen($entry);
1696 if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) {
1697 fseek($this->realtime_log_file, 0);
1698 $this->realtime_log_size = strlen($entry);
1699 $this->realtime_log_wrap = true;
1700 }
1701 fputs($this->realtime_log_file, $entry);
1702 }
1703 }
1704 }
1705