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