PluginProbe
ManageWP Worker / 3.9.28
ManageWP Worker v3.9.28
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 / lib / PHPSecLib / Net / SSH1.php

SSH1.php in ManageWP Worker 3.9.28, at lib/PHPSecLib/Net/SSH1.php

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