2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
\r
5 * Pure-PHP implementation of SSHv1.
\r
7 * PHP versions 4 and 5
\r
9 * Here's a short example of how to use this library:
\r
12 * include('Net/SSH1.php');
\r
14 * $ssh = new Net_SSH1('www.domain.tld');
\r
15 * if (!$ssh->login('username', 'password')) {
\r
16 * exit('Login Failed');
\r
20 * echo $ssh->interactiveRead();
\r
22 * $read = array(STDIN);
\r
23 * $write = $except = NULL;
\r
24 * if (stream_select($read, $write, $except, 0)) {
\r
25 * $ssh->interactiveWrite(fread(STDIN, 1));
\r
31 * Here's another short example:
\r
34 * include('Net/SSH1.php');
\r
36 * $ssh = new Net_SSH1('www.domain.tld');
\r
37 * if (!$ssh->login('username', 'password')) {
\r
38 * exit('Login Failed');
\r
41 * echo $ssh->exec('ls -la');
\r
45 * More information on the SSHv1 specification can be found by reading
\r
46 * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
\r
48 * LICENSE: This library is free software; you can redistribute it and/or
\r
49 * modify it under the terms of the GNU Lesser General Public
\r
50 * License as published by the Free Software Foundation; either
\r
51 * version 2.1 of the License, or (at your option) any later version.
\r
53 * This library is distributed in the hope that it will be useful,
\r
54 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
55 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
56 * Lesser General Public License for more details.
\r
58 * You should have received a copy of the GNU Lesser General Public
\r
59 * License along with this library; if not, write to the Free Software
\r
60 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
\r
65 * @author Jim Wigginton <terrafrost@php.net>
\r
66 * @copyright MMVII Jim Wigginton
\r
67 * @license http://www.gnu.org/licenses/lgpl.txt
\r
68 * @version $Id: SSH1.php,v 1.15 2010/03/22 22:01:38 terrafrost Exp $
\r
69 * @link http://phpseclib.sourceforge.net
\r
73 * Include Math_BigInteger
\r
75 * Used to do RSA encryption.
\r
77 require_once('Math/BigInteger.php');
\r
80 * Include Crypt_Null
\r
82 //require_once('Crypt/Null.php');
\r
87 require_once('Crypt/DES.php');
\r
90 * Include Crypt_TripleDES
\r
92 require_once('Crypt/TripleDES.php');
\r
97 require_once('Crypt/RC4.php');
\r
100 * Include Crypt_Random
\r
102 require_once('Crypt/Random.php');
\r
109 define('NET_SSH1_MSG_DISCONNECT', 1);
\r
110 define('NET_SSH1_SMSG_PUBLIC_KEY', 2);
\r
111 define('NET_SSH1_CMSG_SESSION_KEY', 3);
\r
112 define('NET_SSH1_CMSG_USER', 4);
\r
113 define('NET_SSH1_CMSG_AUTH_PASSWORD', 9);
\r
114 define('NET_SSH1_CMSG_REQUEST_PTY', 10);
\r
115 define('NET_SSH1_CMSG_EXEC_SHELL', 12);
\r
116 define('NET_SSH1_CMSG_EXEC_CMD', 13);
\r
117 define('NET_SSH1_SMSG_SUCCESS', 14);
\r
118 define('NET_SSH1_SMSG_FAILURE', 15);
\r
119 define('NET_SSH1_CMSG_STDIN_DATA', 16);
\r
120 define('NET_SSH1_SMSG_STDOUT_DATA', 17);
\r
121 define('NET_SSH1_SMSG_STDERR_DATA', 18);
\r
122 define('NET_SSH1_SMSG_EXITSTATUS', 20);
\r
123 define('NET_SSH1_CMSG_EXIT_CONFIRMATION', 33);
\r
127 * Encryption Methods
\r
129 * @see Net_SSH1::getSupportedCiphers()
\r
137 define('NET_SSH1_CIPHER_NONE', 0);
\r
143 define('NET_SSH1_CIPHER_IDEA', 1);
\r
147 define('NET_SSH1_CIPHER_DES', 2);
\r
149 * Triple-DES in CBC mode
\r
151 * All implementations are required to support this
\r
153 define('NET_SSH1_CIPHER_3DES', 3);
\r
155 * TRI's Simple Stream encryption CBC
\r
157 * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
\r
158 * although it doesn't use it (see cipher.c)
\r
160 define('NET_SSH1_CIPHER_BROKEN_TSS', 4);
\r
166 * @internal According to the SSH1 specs:
\r
168 * "The first 16 bytes of the session key are used as the key for
\r
169 * the server to client direction. The remaining 16 bytes are used
\r
170 * as the key for the client to server direction. This gives
\r
171 * independent 128-bit keys for each direction."
\r
173 * This library currently only supports encryption when the same key is being used for both directions. This is
\r
174 * because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
\r
176 define('NET_SSH1_CIPHER_RC4', 5);
\r
180 * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
\r
181 * uses it (see cipher.c)
\r
183 define('NET_SSH1_CIPHER_BLOWFISH', 6);
\r
187 * Authentication Methods
\r
189 * @see Net_SSH1::getSupportedAuthentications()
\r
193 * .rhosts or /etc/hosts.equiv
\r
195 define('NET_SSH1_AUTH_RHOSTS', 1);
\r
197 * pure RSA authentication
\r
199 define('NET_SSH1_AUTH_RSA', 2);
\r
201 * password authentication
\r
203 * This is the only method that is supported by this library.
\r
205 define('NET_SSH1_AUTH_PASSWORD', 3);
\r
207 * .rhosts with RSA host authentication
\r
209 define('NET_SSH1_AUTH_RHOSTS_RSA', 4);
\r
215 * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
\r
218 define('NET_SSH1_TTY_OP_END', 0);
\r
222 * The Response Type
\r
224 * @see Net_SSH1::_get_binary_packet()
\r
227 define('NET_SSH1_RESPONSE_TYPE', 1);
\r
230 * The Response Data
\r
232 * @see Net_SSH1::_get_binary_packet()
\r
235 define('NET_SSH1_RESPONSE_DATA', 2);
\r
238 * Execution Bitmap Masks
\r
240 * @see Net_SSH1::bitmap
\r
243 define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
\r
244 define('NET_SSH1_MASK_LOGIN', 0x00000002);
\r
245 define('NET_SSH1_MASK_SHELL', 0x00000004);
\r
249 * Pure-PHP implementation of SSHv1.
\r
251 * @author Jim Wigginton <terrafrost@php.net>
\r
254 * @package Net_SSH1
\r
258 * The SSH identifier
\r
263 var $identifier = 'SSH-1.5-phpseclib';
\r
266 * The Socket Object
\r
274 * The cryptography object
\r
279 var $crypto = false;
\r
284 * The bits that are set reprsent functions that have been called already. This is used to determine
\r
285 * if a requisite function has been successfully executed. If not, an error should be thrown.
\r
293 * The Server Key Public Exponent
\r
295 * Logged for debug purposes
\r
297 * @see Net_SSH1::getServerKeyPublicExponent()
\r
301 var $server_key_public_exponent;
\r
304 * The Server Key Public Modulus
\r
306 * Logged for debug purposes
\r
308 * @see Net_SSH1::getServerKeyPublicModulus()
\r
312 var $server_key_public_modulus;
\r
315 * The Host Key Public Exponent
\r
317 * Logged for debug purposes
\r
319 * @see Net_SSH1::getHostKeyPublicExponent()
\r
323 var $host_key_public_exponent;
\r
326 * The Host Key Public Modulus
\r
328 * Logged for debug purposes
\r
330 * @see Net_SSH1::getHostKeyPublicModulus()
\r
334 var $host_key_public_modulus;
\r
337 * Supported Ciphers
\r
339 * Logged for debug purposes
\r
341 * @see Net_SSH1::getSupportedCiphers()
\r
345 var $supported_ciphers = array(
\r
346 NET_SSH1_CIPHER_NONE => 'No encryption',
\r
347 NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode',
\r
348 NET_SSH1_CIPHER_DES => 'DES in CBC mode',
\r
349 NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode',
\r
350 NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
\r
351 NET_SSH1_CIPHER_RC4 => 'RC4',
\r
352 NET_SSH1_CIPHER_BLOWFISH => 'Blowfish'
\r
356 * Supported Authentications
\r
358 * Logged for debug purposes
\r
360 * @see Net_SSH1::getSupportedAuthentications()
\r
364 var $supported_authentications = array(
\r
365 NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
\r
366 NET_SSH1_AUTH_RSA => 'pure RSA authentication',
\r
367 NET_SSH1_AUTH_PASSWORD => 'password authentication',
\r
368 NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
\r
372 * Server Identification
\r
374 * @see Net_SSH1::getServerIdentification()
\r
378 var $server_identification = '';
\r
381 * Default Constructor.
\r
383 * Connects to an SSHv1 server
\r
385 * @param String $host
\r
386 * @param optional Integer $port
\r
387 * @param optional Integer $timeout
\r
388 * @param optional Integer $cipher
\r
392 function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
\r
394 $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
\r
395 if (!$this->fsock) {
\r
396 user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
\r
400 $this->server_identification = $init_line = fgets($this->fsock, 255);
\r
401 if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
\r
402 user_error('Can only connect to SSH servers', E_USER_NOTICE);
\r
405 if ($parts[1][0] != 1) {
\r
406 user_error("Cannot connect to SSH $parts[1] servers", E_USER_NOTICE);
\r
410 fputs($this->fsock, $this->identifier."\r\n");
\r
412 $response = $this->_get_binary_packet();
\r
413 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
\r
414 user_error('Expected SSH_SMSG_PUBLIC_KEY', E_USER_NOTICE);
\r
418 $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
\r
420 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
\r
422 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
\r
423 $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
\r
424 $this->server_key_public_exponent = $server_key_public_exponent;
\r
426 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
\r
427 $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
\r
428 $this->server_key_public_modulus = $server_key_public_modulus;
\r
430 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
\r
432 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
\r
433 $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
\r
434 $this->host_key_public_exponent = $host_key_public_exponent;
\r
436 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
\r
437 $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
\r
438 $this->host_key_public_modulus = $host_key_public_modulus;
\r
440 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
\r
442 // get a list of the supported ciphers
\r
443 extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
\r
444 foreach ($this->supported_ciphers as $mask=>$name) {
\r
445 if (($supported_ciphers_mask & (1 << $mask)) == 0) {
\r
446 unset($this->supported_ciphers[$mask]);
\r
450 // get a list of the supported authentications
\r
451 extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
\r
452 foreach ($this->supported_authentications as $mask=>$name) {
\r
453 if (($supported_authentications_mask & (1 << $mask)) == 0) {
\r
454 unset($this->supported_authentications[$mask]);
\r
458 $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
\r
461 for ($i = 0; $i < 32; $i++) {
\r
462 $session_key.= chr(crypt_random(0, 255));
\r
464 $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
\r
466 if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
\r
467 $double_encrypted_session_key = $this->_rsa_crypt(
\r
468 $double_encrypted_session_key,
\r
470 $server_key_public_exponent,
\r
471 $server_key_public_modulus
\r
474 $double_encrypted_session_key = $this->_rsa_crypt(
\r
475 $double_encrypted_session_key,
\r
477 $host_key_public_exponent,
\r
478 $host_key_public_modulus
\r
482 $double_encrypted_session_key = $this->_rsa_crypt(
\r
483 $double_encrypted_session_key,
\r
485 $host_key_public_exponent,
\r
486 $host_key_public_modulus
\r
489 $double_encrypted_session_key = $this->_rsa_crypt(
\r
490 $double_encrypted_session_key,
\r
492 $server_key_public_exponent,
\r
493 $server_key_public_modulus
\r
498 $cipher = isset($this->supported_ciphers[$cipher]) ? $cipher : NET_SSH1_CIPHER_3DES;
\r
499 $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);
\r
501 if (!$this->_send_binary_packet($data)) {
\r
502 user_error('Error sending SSH_CMSG_SESSION_KEY', E_USER_NOTICE);
\r
507 //case NET_SSH1_CIPHER_NONE:
\r
508 // $this->crypto = new Crypt_Null();
\r
510 case NET_SSH1_CIPHER_DES:
\r
511 $this->crypto = new Crypt_DES();
\r
512 $this->crypto->disablePadding();
\r
513 $this->crypto->enableContinuousBuffer();
\r
514 $this->crypto->setKey(substr($session_key, 0, 8));
\r
516 case NET_SSH1_CIPHER_3DES:
\r
517 $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
\r
518 $this->crypto->disablePadding();
\r
519 $this->crypto->enableContinuousBuffer();
\r
520 $this->crypto->setKey(substr($session_key, 0, 24));
\r
522 //case NET_SSH1_CIPHER_RC4:
\r
523 // $this->crypto = new Crypt_RC4();
\r
524 // $this->crypto->enableContinuousBuffer();
\r
525 // $this->crypto->setKey(substr($session_key, 0, 16));
\r
529 $response = $this->_get_binary_packet();
\r
531 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
\r
532 user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
\r
536 $this->bitmap = NET_SSH1_MASK_CONSTRUCTOR;
\r
542 * @param String $username
\r
543 * @param optional String $password
\r
547 function login($username, $password = '')
\r
549 if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) {
\r
553 $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
\r
555 if (!$this->_send_binary_packet($data)) {
\r
556 user_error('Error sending SSH_CMSG_USER', E_USER_NOTICE);
\r
560 $response = $this->_get_binary_packet();
\r
562 if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
\r
563 $this->bitmap |= NET_SSH1_MASK_LOGIN;
\r
565 } else if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
\r
566 user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE);
\r
570 $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
\r
572 if (!$this->_send_binary_packet($data)) {
\r
573 user_error('Error sending SSH_CMSG_AUTH_PASSWORD', E_USER_NOTICE);
\r
577 $response = $this->_get_binary_packet();
\r
579 if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
\r
580 $this->bitmap |= NET_SSH1_MASK_LOGIN;
\r
582 } else if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
\r
585 user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE);
\r
591 * Executes a command on a non-interactive shell, returns the output, and quits.
\r
593 * An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
\r
594 * servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
\r
595 * shell with the -s option, as discussed in the following links:
\r
597 * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
\r
598 * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
\r
600 * To execute further commands, a new Net_SSH1 object will need to be created.
\r
602 * Returns false on failure and the output, otherwise.
\r
604 * @see Net_SSH1::interactiveRead()
\r
605 * @see Net_SSH1::interactiveWrite()
\r
606 * @param String $cmd
\r
610 function exec($cmd)
\r
612 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
\r
613 user_error('Operation disallowed prior to login()', E_USER_NOTICE);
\r
617 // connect using the sample parameters in protocol-1.5.txt.
\r
618 // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
\r
619 // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
\r
620 $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
\r
622 if (!$this->_send_binary_packet($data)) {
\r
623 user_error('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE);
\r
627 $response = $this->_get_binary_packet();
\r
629 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
\r
630 user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
\r
634 $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
\r
636 if (!$this->_send_binary_packet($data)) {
\r
637 user_error('Error sending SSH_CMSG_EXEC_CMD', E_USER_NOTICE);
\r
642 $response = $this->_get_binary_packet();
\r
645 $output.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
\r
646 $response = $this->_get_binary_packet();
\r
647 } while ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
\r
649 $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
\r
651 // i don't think it's really all that important if this packet gets sent or not.
\r
652 $this->_send_binary_packet($data);
\r
654 fclose($this->fsock);
\r
656 // reset the execution bitmap - a new Net_SSH1 object needs to be created.
\r
663 * Creates an interactive shell
\r
665 * @see Net_SSH1::interactiveRead()
\r
666 * @see Net_SSH1::interactiveWrite()
\r
670 function _initShell()
\r
672 $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
\r
674 if (!$this->_send_binary_packet($data)) {
\r
675 user_error('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE);
\r
679 $response = $this->_get_binary_packet();
\r
681 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
\r
682 user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
\r
686 $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
\r
688 if (!$this->_send_binary_packet($data)) {
\r
689 user_error('Error sending SSH_CMSG_EXEC_SHELL', E_USER_NOTICE);
\r
693 $this->bitmap |= NET_SSH1_MASK_SHELL;
\r
695 //stream_set_blocking($this->fsock, 0);
\r
701 * Inputs a command into an interactive shell.
\r
703 * @see Net_SSH1::interactiveRead()
\r
704 * @param String $cmd
\r
708 function interactiveWrite($cmd)
\r
710 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
\r
711 user_error('Operation disallowed prior to login()', E_USER_NOTICE);
\r
715 if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
\r
716 user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
\r
720 $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
\r
722 if (!$this->_send_binary_packet($data)) {
\r
723 user_error('Error sending SSH_CMSG_STDIN', E_USER_NOTICE);
\r
731 * Reads the output of an interactive shell.
\r
733 * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see crap,
\r
734 * you're seeing ANSI escape codes. According to
\r
735 * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
\r
736 * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
\r
737 * there's not going to be much recourse.
\r
739 * @see Net_SSH1::interactiveRead()
\r
743 function interactiveRead()
\r
745 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
\r
746 user_error('Operation disallowed prior to login()', E_USER_NOTICE);
\r
750 if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
\r
751 user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
\r
755 $read = array($this->fsock);
\r
756 $write = $except = null;
\r
757 if (stream_select($read, $write, $except, 0)) {
\r
758 $response = $this->_get_binary_packet();
\r
759 return substr($response[NET_SSH1_RESPONSE_DATA], 4);
\r
770 function disconnect()
\r
772 $this->_disconnect();
\r
778 * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
\r
783 function __destruct()
\r
785 $this->_disconnect();
\r
791 * @param String $msg
\r
794 function _disconnect($msg = 'Client Quit')
\r
796 if ($this->bitmap) {
\r
797 $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
\r
798 $this->_send_binary_packet($data);
\r
799 fclose($this->fsock);
\r
805 * Gets Binary Packets
\r
807 * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
\r
809 * Also, this function could be improved upon by adding detection for the following exploit:
\r
810 * http://www.securiteam.com/securitynews/5LP042K3FY.html
\r
812 * @see Net_SSH1::_send_binary_packet()
\r
816 function _get_binary_packet()
\r
818 if (feof($this->fsock)) {
\r
819 //user_error('connection closed prematurely', E_USER_NOTICE);
\r
823 $temp = unpack('Nlength', fread($this->fsock, 4));
\r
825 $padding_length = 8 - ($temp['length'] & 7);
\r
826 $length = $temp['length'] + $padding_length;
\r
828 $raw = fread($this->fsock, $length);
\r
830 if ($this->crypto !== false) {
\r
831 $raw = $this->crypto->decrypt($raw);
\r
834 $padding = substr($raw, 0, $padding_length);
\r
835 $type = $raw[$padding_length];
\r
836 $data = substr($raw, $padding_length + 1, -4);
\r
838 $temp = unpack('Ncrc', substr($raw, -4));
\r
840 //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
\r
841 // user_error('Bad CRC in packet from server', E_USER_NOTICE);
\r
846 NET_SSH1_RESPONSE_TYPE => ord($type),
\r
847 NET_SSH1_RESPONSE_DATA => $data
\r
852 * Sends Binary Packets
\r
854 * Returns true on success, false on failure.
\r
856 * @see Net_SSH1::_get_binary_packet()
\r
857 * @param String $data
\r
861 function _send_binary_packet($data) {
\r
862 if (feof($this->fsock)) {
\r
863 //user_error('connection closed prematurely', E_USER_NOTICE);
\r
867 $length = strlen($data) + 4;
\r
869 $padding_length = 8 - ($length & 7);
\r
871 for ($i = 0; $i < $padding_length; $i++) {
\r
872 $padding.= chr(crypt_random(0, 255));
\r
875 $data = $padding . $data;
\r
876 $data.= pack('N', $this->_crc($data));
\r
878 if ($this->crypto !== false) {
\r
879 $data = $this->crypto->encrypt($data);
\r
882 $packet = pack('Na*', $length, $data);
\r
884 return strlen($packet) == fputs($this->fsock, $packet);
\r
888 * Cyclic Redundancy Check (CRC)
\r
890 * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
\r
891 * we've reimplemented it. A more detailed discussion of the differences can be found after
\r
892 * $crc_lookup_table's initialization.
\r
894 * @see Net_SSH1::_get_binary_packet()
\r
895 * @see Net_SSH1::_send_binary_packet()
\r
896 * @param String $data
\r
900 function _crc($data)
\r
902 static $crc_lookup_table = array(
\r
903 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
\r
904 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
\r
905 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
\r
906 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
\r
907 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
\r
908 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
\r
909 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
\r
910 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
\r
911 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
\r
912 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
\r
913 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
\r
914 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
\r
915 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
\r
916 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
\r
917 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
\r
918 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
\r
919 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
\r
920 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
\r
921 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
\r
922 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
\r
923 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
\r
924 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
\r
925 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
\r
926 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
\r
927 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
\r
928 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
\r
929 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
\r
930 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
\r
931 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
\r
932 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
\r
933 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
\r
934 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
\r
935 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
\r
936 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
\r
937 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
\r
938 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
\r
939 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
\r
940 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
\r
941 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
\r
942 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
\r
943 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
\r
944 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
\r
945 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
\r
946 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
\r
947 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
\r
948 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
\r
949 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
\r
950 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
\r
951 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
\r
952 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
\r
953 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
\r
954 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
\r
955 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
\r
956 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
\r
957 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
\r
958 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
\r
959 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
\r
960 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
\r
961 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
\r
962 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
\r
963 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
\r
964 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
\r
965 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
\r
966 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
\r
969 // For this function to yield the same output as PHP's crc32 function, $crc would have to be
\r
970 // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
\r
972 $length = strlen($data);
\r
974 for ($i=0;$i<$length;$i++) {
\r
975 // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
\r
976 // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
\r
977 // yields 0xFF800000 - not 0x00800000. The following link elaborates:
\r
978 // http://www.php.net/manual/en/language.operators.bitwise.php#57281
\r
979 $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
\r
982 // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
\r
983 // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
\r
990 * Inspired by array_shift
\r
992 * @param String $string
\r
993 * @param optional Integer $index
\r
997 function _string_shift(&$string, $index = 1)
\r
999 $substr = substr($string, 0, $index);
\r
1000 $string = substr($string, $index);
\r
1007 * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
\r
1008 * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
\r
1009 * calls this call modexp, instead, but I think this makes things clearer, maybe...
\r
1011 * @see Net_SSH1::Net_SSH1()
\r
1012 * @param Math_BigInteger $m
\r
1013 * @param Array $key
\r
1014 * @return Math_BigInteger
\r
1017 function _rsa_crypt($m, $key)
\r
1020 if (!class_exists('Crypt_RSA')) {
\r
1021 require_once('Crypt/RSA.php');
\r
1024 $rsa = new Crypt_RSA();
\r
1025 $rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
\r
1026 $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
\r
1027 return $rsa->encrypt($m);
\r
1030 // To quote from protocol-1.5.txt:
\r
1031 // The most significant byte (which is only partial as the value must be
\r
1032 // less than the public modulus, which is never a power of two) is zero.
\r
1034 // The next byte contains the value 2 (which stands for public-key
\r
1035 // encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
\r
1036 // zero random bytes to fill any unused space, a zero byte, and the data
\r
1037 // to be encrypted in the least significant bytes, the last byte of the
\r
1038 // data in the least significant byte.
\r
1040 // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
\r
1041 // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
\r
1042 // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
\r
1043 $temp = chr(0) . chr(2);
\r
1044 $modulus = $key[1]->toBytes();
\r
1045 $length = strlen($modulus) - strlen($m) - 3;
\r
1046 for ($i = 0; $i < $length; $i++) {
\r
1047 $temp.= chr(crypt_random(1, 255));
\r
1049 $temp.= chr(0) . $m;
\r
1051 $m = new Math_BigInteger($temp, 256);
\r
1052 $m = $m->modPow($key[0], $key[1]);
\r
1054 return $m->toBytes();
\r
1058 * Return the server key public exponent
\r
1060 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
\r
1061 * the raw bytes. This behavior is similar to PHP's md5() function.
\r
1063 * @param optional Boolean $raw_output
\r
1067 function getServerKeyPublicExponent($raw_output = false)
\r
1069 return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
\r
1073 * Return the server key public modulus
\r
1075 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
\r
1076 * the raw bytes. This behavior is similar to PHP's md5() function.
\r
1078 * @param optional Boolean $raw_output
\r
1082 function getServerKeyPublicModulus($raw_output = false)
\r
1084 return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
\r
1088 * Return the host key public exponent
\r
1090 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
\r
1091 * the raw bytes. This behavior is similar to PHP's md5() function.
\r
1093 * @param optional Boolean $raw_output
\r
1097 function getHostKeyPublicExponent($raw_output = false)
\r
1099 return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
\r
1103 * Return the host key public modulus
\r
1105 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
\r
1106 * the raw bytes. This behavior is similar to PHP's md5() function.
\r
1108 * @param optional Boolean $raw_output
\r
1112 function getHostKeyPublicModulus($raw_output = false)
\r
1114 return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
\r
1118 * Return a list of ciphers supported by SSH1 server.
\r
1120 * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
\r
1121 * is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
\r
1122 * get array(NET_SSH1_CIPHER_3DES).
\r
1124 * @param optional Boolean $raw_output
\r
1128 function getSupportedCiphers($raw_output = false)
\r
1130 return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
\r
1134 * Return a list of authentications supported by SSH1 server.
\r
1136 * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
\r
1137 * is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
\r
1138 * get array(NET_SSH1_AUTH_PASSWORD).
\r
1140 * @param optional Boolean $raw_output
\r
1144 function getSupportedAuthentications($raw_output = false)
\r
1146 return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
\r
1150 * Return the server identification.
\r
1155 function getServerIdentification()
\r
1157 return rtrim($this->server_identification);
\r