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