4 * Pure-PHP implementation of SSHv1.
8 * Here's a short example of how to use this library:
11 * include 'Net/SSH1.php';
13 * $ssh = new Net_SSH1('www.domain.tld');
14 * if (!$ssh->login('username', 'password')) {
15 * exit('Login Failed');
18 * echo $ssh->exec('ls -la');
22 * Here's another short example:
25 * include 'Net/SSH1.php';
27 * $ssh = new Net_SSH1('www.domain.tld');
28 * if (!$ssh->login('username', 'password')) {
29 * exit('Login Failed');
32 * echo $ssh->read('username@username:~$');
33 * $ssh->write("ls -la\n");
34 * echo $ssh->read('username@username:~$');
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}.
41 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
42 * of this software and associated documentation files (the "Software"), to deal
43 * in the Software without restriction, including without limitation the rights
44 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
45 * copies of the Software, and to permit persons to whom the Software is
46 * furnished to do so, subject to the following conditions:
48 * The above copyright notice and this permission notice shall be included in
49 * all copies or substantial portions of the Software.
51 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
54 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
56 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61 * @author Jim Wigginton <terrafrost@php.net>
62 * @copyright 2007 Jim Wigginton
63 * @license http://www.opensource.org/licenses/mit-license.html MIT License
64 * @link http://phpseclib.sourceforge.net
70 * @see Net_SSH1::getSupportedCiphers()
78 define('NET_SSH1_CIPHER_NONE', 0);
84 define('NET_SSH1_CIPHER_IDEA', 1);
88 define('NET_SSH1_CIPHER_DES', 2);
90 * Triple-DES in CBC mode
92 * All implementations are required to support this
94 define('NET_SSH1_CIPHER_3DES', 3);
96 * TRI's Simple Stream encryption CBC
98 * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
99 * although it doesn't use it (see cipher.c)
101 define('NET_SSH1_CIPHER_BROKEN_TSS', 4);
107 * @internal According to the SSH1 specs:
109 * "The first 16 bytes of the session key are used as the key for
110 * the server to client direction. The remaining 16 bytes are used
111 * as the key for the client to server direction. This gives
112 * independent 128-bit keys for each direction."
114 * This library currently only supports encryption when the same key is being used for both directions. This is
115 * because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
117 define('NET_SSH1_CIPHER_RC4', 5);
121 * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
122 * uses it (see cipher.c)
124 define('NET_SSH1_CIPHER_BLOWFISH', 6);
128 * Authentication Methods
130 * @see Net_SSH1::getSupportedAuthentications()
134 * .rhosts or /etc/hosts.equiv
136 define('NET_SSH1_AUTH_RHOSTS', 1);
138 * pure RSA authentication
140 define('NET_SSH1_AUTH_RSA', 2);
142 * password authentication
144 * This is the only method that is supported by this library.
146 define('NET_SSH1_AUTH_PASSWORD', 3);
148 * .rhosts with RSA host authentication
150 define('NET_SSH1_AUTH_RHOSTS_RSA', 4);
156 * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
159 define('NET_SSH1_TTY_OP_END', 0);
165 * @see Net_SSH1::_get_binary_packet()
168 define('NET_SSH1_RESPONSE_TYPE', 1);
173 * @see Net_SSH1::_get_binary_packet()
176 define('NET_SSH1_RESPONSE_DATA', 2);
179 * Execution Bitmap Masks
181 * @see Net_SSH1::bitmap
184 define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
185 define('NET_SSH1_MASK_CONNECTED', 0x00000002);
186 define('NET_SSH1_MASK_LOGIN', 0x00000004);
187 define('NET_SSH1_MASK_SHELL', 0x00000008);
192 * @see Net_SSH1::getLog()
195 * Returns the message numbers
197 define('NET_SSH1_LOG_SIMPLE', 1);
199 * Returns the message content
201 define('NET_SSH1_LOG_COMPLEX', 2);
203 * Outputs the content real-time
205 define('NET_SSH1_LOG_REALTIME', 3);
207 * Dumps the content real-time to a file
209 define('NET_SSH1_LOG_REALTIME_FILE', 4);
214 * @see Net_SSH1::read()
217 * Returns when a string matching $expect exactly is found
219 define('NET_SSH1_READ_SIMPLE', 1);
221 * Returns when a string matching the regular expression $expect is found
223 define('NET_SSH1_READ_REGEX', 2);
227 * Pure-PHP implementation of SSHv1.
230 * @author Jim Wigginton <terrafrost@php.net>
241 var $identifier = 'SSH-1.5-phpseclib';
252 * The cryptography object
262 * The bits that are set represent functions that have been called already. This is used to determine
263 * if a requisite function has been successfully executed. If not, an error should be thrown.
271 * The Server Key Public Exponent
273 * Logged for debug purposes
275 * @see Net_SSH1::getServerKeyPublicExponent()
279 var $server_key_public_exponent;
282 * The Server Key Public Modulus
284 * Logged for debug purposes
286 * @see Net_SSH1::getServerKeyPublicModulus()
290 var $server_key_public_modulus;
293 * The Host Key Public Exponent
295 * Logged for debug purposes
297 * @see Net_SSH1::getHostKeyPublicExponent()
301 var $host_key_public_exponent;
304 * The Host Key Public Modulus
306 * Logged for debug purposes
308 * @see Net_SSH1::getHostKeyPublicModulus()
312 var $host_key_public_modulus;
317 * Logged for debug purposes
319 * @see Net_SSH1::getSupportedCiphers()
323 var $supported_ciphers = array(
324 NET_SSH1_CIPHER_NONE => 'No encryption',
325 NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode',
326 NET_SSH1_CIPHER_DES => 'DES in CBC mode',
327 NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode',
328 NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
329 NET_SSH1_CIPHER_RC4 => 'RC4',
330 NET_SSH1_CIPHER_BLOWFISH => 'Blowfish'
334 * Supported Authentications
336 * Logged for debug purposes
338 * @see Net_SSH1::getSupportedAuthentications()
342 var $supported_authentications = array(
343 NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
344 NET_SSH1_AUTH_RSA => 'pure RSA authentication',
345 NET_SSH1_AUTH_PASSWORD => 'password authentication',
346 NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
350 * Server Identification
352 * @see Net_SSH1::getServerIdentification()
356 var $server_identification = '';
361 * @see Net_SSH1::Net_SSH1()
365 var $protocol_flags = array();
370 * @see Net_SSH1::getLog()
374 var $protocol_flag_log = array();
379 * @see Net_SSH1::getLog()
383 var $message_log = array();
386 * Real-time log file pointer
388 * @see Net_SSH1::_append_log()
392 var $realtime_log_file;
395 * Real-time log file size
397 * @see Net_SSH1::_append_log()
401 var $realtime_log_size;
404 * Real-time log file wrap boolean
406 * @see Net_SSH1::_append_log()
410 var $realtime_log_wrap;
415 * @see Net_SSH1::read()
419 var $interactiveBuffer = '';
424 * @see Net_SSH1::setTimeout()
432 * @see Net_SSH1::_get_channel_packet()
440 * @see Net_SSH1::_format_log
443 var $log_boundary = ':';
448 * @see Net_SSH1::_format_log
451 var $log_long_width = 65;
456 * @see Net_SSH1::_format_log
459 var $log_short_width = 16;
464 * @see Net_SSH1::Net_SSH1()
465 * @see Net_SSH1::_connect()
474 * @see Net_SSH1::Net_SSH1()
475 * @see Net_SSH1::_connect()
482 * Timeout for initial connection
484 * Set by the constructor call. Calling setTimeout() is optional. If it's not called functions like
485 * exec() won't timeout unless some PHP setting forces it too. The timeout specified in the constructor,
486 * however, is non-optional. There will be a timeout, whether or not you set it. If you don't it'll be
487 * 10 seconds. It is used by fsockopen() in that function.
489 * @see Net_SSH1::Net_SSH1()
490 * @see Net_SSH1::_connect()
494 var $connectionTimeout;
499 * @see Net_SSH1::Net_SSH1()
500 * @see Net_SSH1::_connect()
507 * Default Constructor.
509 * Connects to an SSHv1 server
511 * @param String $host
512 * @param optional Integer $port
513 * @param optional Integer $timeout
514 * @param optional Integer $cipher
518 function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
520 if (!class_exists('Math_BigInteger')) {
521 include_once 'Math/BigInteger.php';
524 // Include Crypt_Random
525 // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
526 // will trigger a call to __autoload() if you're wanting to auto-load classes
527 // call function_exists() a second time to stop the include_once from being called outside
528 // of the auto loader
529 if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) {
530 include_once 'Crypt/Random.php';
533 $this->protocol_flags = array(
534 1 => 'NET_SSH1_MSG_DISCONNECT',
535 2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
536 3 => 'NET_SSH1_CMSG_SESSION_KEY',
537 4 => 'NET_SSH1_CMSG_USER',
538 9 => 'NET_SSH1_CMSG_AUTH_PASSWORD',
539 10 => 'NET_SSH1_CMSG_REQUEST_PTY',
540 12 => 'NET_SSH1_CMSG_EXEC_SHELL',
541 13 => 'NET_SSH1_CMSG_EXEC_CMD',
542 14 => 'NET_SSH1_SMSG_SUCCESS',
543 15 => 'NET_SSH1_SMSG_FAILURE',
544 16 => 'NET_SSH1_CMSG_STDIN_DATA',
545 17 => 'NET_SSH1_SMSG_STDOUT_DATA',
546 18 => 'NET_SSH1_SMSG_STDERR_DATA',
547 19 => 'NET_SSH1_CMSG_EOF',
548 20 => 'NET_SSH1_SMSG_EXITSTATUS',
549 33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION'
552 $this->_define_array($this->protocol_flags);
556 $this->connectionTimeout = $timeout;
557 $this->cipher = $cipher;
561 * Connect to an SSHv1 server
568 $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
570 user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
574 $this->server_identification = $init_line = fgets($this->fsock, 255);
576 if (defined('NET_SSH1_LOGGING')) {
577 $this->_append_log('<-', $this->server_identification);
578 $this->_append_log('->', $this->identifier . "\r\n");
581 if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
582 user_error('Can only connect to SSH servers');
585 if ($parts[1][0] != 1) {
586 user_error("Cannot connect to SSH $parts[1] servers");
590 fputs($this->fsock, $this->identifier."\r\n");
592 $response = $this->_get_binary_packet();
593 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
594 user_error('Expected SSH_SMSG_PUBLIC_KEY');
598 $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
600 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
602 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
603 $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
604 $this->server_key_public_exponent = $server_key_public_exponent;
606 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
607 $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
608 $this->server_key_public_modulus = $server_key_public_modulus;
610 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
612 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
613 $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
614 $this->host_key_public_exponent = $host_key_public_exponent;
616 $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
617 $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
618 $this->host_key_public_modulus = $host_key_public_modulus;
620 $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
622 // get a list of the supported ciphers
623 extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
624 foreach ($this->supported_ciphers as $mask=>$name) {
625 if (($supported_ciphers_mask & (1 << $mask)) == 0) {
626 unset($this->supported_ciphers[$mask]);
630 // get a list of the supported authentications
631 extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
632 foreach ($this->supported_authentications as $mask=>$name) {
633 if (($supported_authentications_mask & (1 << $mask)) == 0) {
634 unset($this->supported_authentications[$mask]);
638 $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
640 $session_key = crypt_random_string(32);
641 $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
643 if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
644 $double_encrypted_session_key = $this->_rsa_crypt(
645 $double_encrypted_session_key,
647 $server_key_public_exponent,
648 $server_key_public_modulus
651 $double_encrypted_session_key = $this->_rsa_crypt(
652 $double_encrypted_session_key,
654 $host_key_public_exponent,
655 $host_key_public_modulus
659 $double_encrypted_session_key = $this->_rsa_crypt(
660 $double_encrypted_session_key,
662 $host_key_public_exponent,
663 $host_key_public_modulus
666 $double_encrypted_session_key = $this->_rsa_crypt(
667 $double_encrypted_session_key,
669 $server_key_public_exponent,
670 $server_key_public_modulus
675 $cipher = isset($this->supported_ciphers[$this->cipher]) ? $this->cipher : NET_SSH1_CIPHER_3DES;
676 $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);
678 if (!$this->_send_binary_packet($data)) {
679 user_error('Error sending SSH_CMSG_SESSION_KEY');
684 //case NET_SSH1_CIPHER_NONE:
685 // $this->crypto = new Crypt_Null();
687 case NET_SSH1_CIPHER_DES:
688 if (!class_exists('Crypt_DES')) {
689 include_once 'Crypt/DES.php';
691 $this->crypto = new Crypt_DES();
692 $this->crypto->disablePadding();
693 $this->crypto->enableContinuousBuffer();
694 $this->crypto->setKey(substr($session_key, 0, 8));
696 case NET_SSH1_CIPHER_3DES:
697 if (!class_exists('Crypt_TripleDES')) {
698 include_once 'Crypt/TripleDES.php';
700 $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
701 $this->crypto->disablePadding();
702 $this->crypto->enableContinuousBuffer();
703 $this->crypto->setKey(substr($session_key, 0, 24));
705 //case NET_SSH1_CIPHER_RC4:
706 // if (!class_exists('Crypt_RC4')) {
707 // include_once 'Crypt/RC4.php';
709 // $this->crypto = new Crypt_RC4();
710 // $this->crypto->enableContinuousBuffer();
711 // $this->crypto->setKey(substr($session_key, 0, 16));
715 $response = $this->_get_binary_packet();
717 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
718 user_error('Expected SSH_SMSG_SUCCESS');
722 $this->bitmap = NET_SSH1_MASK_CONNECTED;
730 * @param String $username
731 * @param optional String $password
735 function login($username, $password = '')
737 if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) {
738 $this->bitmap |= NET_SSH1_MASK_CONSTRUCTOR;
739 if (!$this->_connect()) {
744 if (!($this->bitmap & NET_SSH1_MASK_CONNECTED)) {
748 $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
750 if (!$this->_send_binary_packet($data)) {
751 user_error('Error sending SSH_CMSG_USER');
755 $response = $this->_get_binary_packet();
757 if ($response === true) {
760 if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
761 $this->bitmap |= NET_SSH1_MASK_LOGIN;
763 } else if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
764 user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
768 $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
770 if (!$this->_send_binary_packet($data)) {
771 user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
775 // remove the username and password from the last logged packet
776 if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
777 $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
778 $this->message_log[count($this->message_log) - 1] = $data;
781 $response = $this->_get_binary_packet();
783 if ($response === true) {
786 if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
787 $this->bitmap |= NET_SSH1_MASK_LOGIN;
789 } else if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
792 user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
800 * $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.
801 * Setting $timeout to false or 0 will mean there is no timeout.
803 * @param Mixed $timeout
805 function setTimeout($timeout)
807 $this->timeout = $this->curTimeout = $timeout;
811 * Executes a command on a non-interactive shell, returns the output, and quits.
813 * An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
814 * servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
815 * shell with the -s option, as discussed in the following links:
817 * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
818 * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
820 * To execute further commands, a new Net_SSH1 object will need to be created.
822 * Returns false on failure and the output, otherwise.
824 * @see Net_SSH1::interactiveRead()
825 * @see Net_SSH1::interactiveWrite()
830 function exec($cmd, $block = true)
832 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
833 user_error('Operation disallowed prior to login()');
837 $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
839 if (!$this->_send_binary_packet($data)) {
840 user_error('Error sending SSH_CMSG_EXEC_CMD');
849 $response = $this->_get_binary_packet();
851 if ($response !== false) {
853 $output.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
854 $response = $this->_get_binary_packet();
855 } while (is_array($response) && $response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
858 $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
860 // i don't think it's really all that important if this packet gets sent or not.
861 $this->_send_binary_packet($data);
863 fclose($this->fsock);
865 // reset the execution bitmap - a new Net_SSH1 object needs to be created.
872 * Creates an interactive shell
874 * @see Net_SSH1::interactiveRead()
875 * @see Net_SSH1::interactiveWrite()
879 function _initShell()
881 // connect using the sample parameters in protocol-1.5.txt.
882 // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
883 // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
884 $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
886 if (!$this->_send_binary_packet($data)) {
887 user_error('Error sending SSH_CMSG_REQUEST_PTY');
891 $response = $this->_get_binary_packet();
893 if ($response === true) {
896 if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
897 user_error('Expected SSH_SMSG_SUCCESS');
901 $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
903 if (!$this->_send_binary_packet($data)) {
904 user_error('Error sending SSH_CMSG_EXEC_SHELL');
908 $this->bitmap |= NET_SSH1_MASK_SHELL;
910 //stream_set_blocking($this->fsock, 0);
916 * Inputs a command into an interactive shell.
918 * @see Net_SSH1::interactiveWrite()
925 return $this->interactiveWrite($cmd);
929 * Returns the output of an interactive shell when there's a match for $expect
931 * $expect can take the form of a string literal or, if $mode == NET_SSH1_READ_REGEX,
932 * a regular expression.
934 * @see Net_SSH1::write()
935 * @param String $expect
936 * @param Integer $mode
940 function read($expect, $mode = NET_SSH1_READ_SIMPLE)
942 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
943 user_error('Operation disallowed prior to login()');
947 if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
948 user_error('Unable to initiate an interactive shell session');
954 if ($mode == NET_SSH1_READ_REGEX) {
955 preg_match($expect, $this->interactiveBuffer, $matches);
956 $match = isset($matches[0]) ? $matches[0] : '';
958 $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
959 if ($pos !== false) {
960 return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
962 $response = $this->_get_binary_packet();
964 if ($response === true) {
965 return $this->_string_shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
967 $this->interactiveBuffer.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
972 * Inputs a command into an interactive shell.
974 * @see Net_SSH1::interactiveRead()
979 function interactiveWrite($cmd)
981 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
982 user_error('Operation disallowed prior to login()');
986 if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
987 user_error('Unable to initiate an interactive shell session');
991 $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
993 if (!$this->_send_binary_packet($data)) {
994 user_error('Error sending SSH_CMSG_STDIN');
1002 * Returns the output of an interactive shell when no more output is available.
1004 * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like
1005 * "^[[00m", you're seeing ANSI escape codes. According to
1006 * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
1007 * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
1008 * there's not going to be much recourse.
1010 * @see Net_SSH1::interactiveRead()
1014 function interactiveRead()
1016 if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
1017 user_error('Operation disallowed prior to login()');
1021 if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
1022 user_error('Unable to initiate an interactive shell session');
1026 $read = array($this->fsock);
1027 $write = $except = null;
1028 if (stream_select($read, $write, $except, 0)) {
1029 $response = $this->_get_binary_packet();
1030 return substr($response[NET_SSH1_RESPONSE_DATA], 4);
1041 function disconnect()
1043 $this->_disconnect();
1049 * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
1054 function __destruct()
1056 $this->_disconnect();
1062 * @param String $msg
1065 function _disconnect($msg = 'Client Quit')
1067 if ($this->bitmap) {
1068 $data = pack('C', NET_SSH1_CMSG_EOF);
1069 $this->_send_binary_packet($data);
1071 $response = $this->_get_binary_packet();
1072 if ($response === true) {
1073 $response = array(NET_SSH1_RESPONSE_TYPE => -1);
1075 switch ($response[NET_SSH1_RESPONSE_TYPE]) {
1076 case NET_SSH1_SMSG_EXITSTATUS:
1077 $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
1080 $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1083 $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
1085 $this->_send_binary_packet($data);
1086 fclose($this->fsock);
1092 * Gets Binary Packets
1094 * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
1096 * Also, this function could be improved upon by adding detection for the following exploit:
1097 * http://www.securiteam.com/securitynews/5LP042K3FY.html
1099 * @see Net_SSH1::_send_binary_packet()
1103 function _get_binary_packet()
1105 if (feof($this->fsock)) {
1106 //user_error('connection closed prematurely');
1110 if ($this->curTimeout) {
1111 $read = array($this->fsock);
1112 $write = $except = null;
1114 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1115 $sec = floor($this->curTimeout);
1116 $usec = 1000000 * ($this->curTimeout - $sec);
1117 // on windows this returns a "Warning: Invalid CRT parameters detected" error
1118 if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
1119 //$this->_disconnect('Timeout');
1122 $elapsed = strtok(microtime(), ' ') + strtok('') - $start;
1123 $this->curTimeout-= $elapsed;
1126 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1127 $temp = unpack('Nlength', fread($this->fsock, 4));
1129 $padding_length = 8 - ($temp['length'] & 7);
1130 $length = $temp['length'] + $padding_length;
1133 while ($length > 0) {
1134 $temp = fread($this->fsock, $length);
1136 $length-= strlen($temp);
1138 $stop = strtok(microtime(), ' ') + strtok('');
1140 if (strlen($raw) && $this->crypto !== false) {
1141 $raw = $this->crypto->decrypt($raw);
1144 $padding = substr($raw, 0, $padding_length);
1145 $type = $raw[$padding_length];
1146 $data = substr($raw, $padding_length + 1, -4);
1148 $temp = unpack('Ncrc', substr($raw, -4));
1150 //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
1151 // user_error('Bad CRC in packet from server');
1157 if (defined('NET_SSH1_LOGGING')) {
1158 $temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
1159 $temp = '<- ' . $temp .
1160 ' (' . round($stop - $start, 4) . 's)';
1161 $this->_append_log($temp, $data);
1165 NET_SSH1_RESPONSE_TYPE => $type,
1166 NET_SSH1_RESPONSE_DATA => $data
1171 * Sends Binary Packets
1173 * Returns true on success, false on failure.
1175 * @see Net_SSH1::_get_binary_packet()
1176 * @param String $data
1180 function _send_binary_packet($data)
1182 if (feof($this->fsock)) {
1183 //user_error('connection closed prematurely');
1187 $length = strlen($data) + 4;
1189 $padding = crypt_random_string(8 - ($length & 7));
1192 $data = $padding . $data;
1193 $data.= pack('N', $this->_crc($data));
1195 if ($this->crypto !== false) {
1196 $data = $this->crypto->encrypt($data);
1199 $packet = pack('Na*', $length, $data);
1201 $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
1202 $result = strlen($packet) == fputs($this->fsock, $packet);
1203 $stop = strtok(microtime(), ' ') + strtok('');
1205 if (defined('NET_SSH1_LOGGING')) {
1206 $temp = isset($this->protocol_flags[ord($orig[0])]) ? $this->protocol_flags[ord($orig[0])] : 'UNKNOWN';
1207 $temp = '-> ' . $temp .
1208 ' (' . round($stop - $start, 4) . 's)';
1209 $this->_append_log($temp, $orig);
1216 * Cyclic Redundancy Check (CRC)
1218 * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
1219 * we've reimplemented it. A more detailed discussion of the differences can be found after
1220 * $crc_lookup_table's initialization.
1222 * @see Net_SSH1::_get_binary_packet()
1223 * @see Net_SSH1::_send_binary_packet()
1224 * @param String $data
1228 function _crc($data)
1230 static $crc_lookup_table = array(
1231 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1232 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1233 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1234 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1235 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1236 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1237 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1238 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1239 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1240 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1241 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1242 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1243 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1244 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1245 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1246 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1247 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1248 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1249 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1250 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1251 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1252 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1253 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1254 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1255 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1256 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1257 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1258 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1259 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1260 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1261 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1262 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1263 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1264 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1265 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1266 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1267 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1268 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1269 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1270 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1271 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1272 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1273 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1274 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1275 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1276 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1277 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1278 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1279 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1280 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1281 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1282 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1283 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1284 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1285 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1286 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1287 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1288 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1289 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1290 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1291 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1292 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1293 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1294 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1297 // For this function to yield the same output as PHP's crc32 function, $crc would have to be
1298 // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
1300 $length = strlen($data);
1302 for ($i=0;$i<$length;$i++) {
1303 // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
1304 // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
1305 // yields 0xFF800000 - not 0x00800000. The following link elaborates:
1306 // http://www.php.net/manual/en/language.operators.bitwise.php#57281
1307 $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
1310 // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
1311 // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
1318 * Inspired by array_shift
1320 * @param String $string
1321 * @param optional Integer $index
1325 function _string_shift(&$string, $index = 1)
1327 $substr = substr($string, 0, $index);
1328 $string = substr($string, $index);
1335 * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
1336 * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
1337 * calls this call modexp, instead, but I think this makes things clearer, maybe...
1339 * @see Net_SSH1::Net_SSH1()
1340 * @param Math_BigInteger $m
1342 * @return Math_BigInteger
1345 function _rsa_crypt($m, $key)
1348 if (!class_exists('Crypt_RSA')) {
1349 include_once 'Crypt/RSA.php';
1352 $rsa = new Crypt_RSA();
1353 $rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
1354 $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
1355 return $rsa->encrypt($m);
1358 // To quote from protocol-1.5.txt:
1359 // The most significant byte (which is only partial as the value must be
1360 // less than the public modulus, which is never a power of two) is zero.
1362 // The next byte contains the value 2 (which stands for public-key
1363 // encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
1364 // zero random bytes to fill any unused space, a zero byte, and the data
1365 // to be encrypted in the least significant bytes, the last byte of the
1366 // data in the least significant byte.
1368 // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
1369 // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
1370 // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
1371 $modulus = $key[1]->toBytes();
1372 $length = strlen($modulus) - strlen($m) - 3;
1374 while (strlen($random) != $length) {
1375 $block = crypt_random_string($length - strlen($random));
1376 $block = str_replace("\x00", '', $block);
1379 $temp = chr(0) . chr(2) . $random . chr(0) . $m;
1381 $m = new Math_BigInteger($temp, 256);
1382 $m = $m->modPow($key[0], $key[1]);
1384 return $m->toBytes();
1390 * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
1391 * named constants from it, using the value as the name of the constant and the index as the value of the constant.
1392 * If any of the constants that would be defined already exists, none of the constants will be defined.
1394 * @param Array $array
1397 function _define_array()
1399 $args = func_get_args();
1400 foreach ($args as $arg) {
1401 foreach ($arg as $key=>$value) {
1402 if (!defined($value)) {
1403 define($value, $key);
1412 * Returns a log of the packets that have been sent and received.
1414 * Returns a string if NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX, an array if NET_SSH1_LOGGING == NET_SSH1_LOG_SIMPLE and false if !defined('NET_SSH1_LOGGING')
1417 * @return String or Array
1421 if (!defined('NET_SSH1_LOGGING')) {
1425 switch (NET_SSH1_LOGGING) {
1426 case NET_SSH1_LOG_SIMPLE:
1427 return $this->message_number_log;
1429 case NET_SSH1_LOG_COMPLEX:
1430 return $this->_format_log($this->message_log, $this->protocol_flags_log);
1438 * Formats a log for printing
1440 * @param Array $message_log
1441 * @param Array $message_number_log
1445 function _format_log($message_log, $message_number_log)
1448 for ($i = 0; $i < count($message_log); $i++) {
1449 $output.= $message_number_log[$i] . "\r\n";
1450 $current_log = $message_log[$i];
1453 if (strlen($current_log)) {
1454 $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
1456 $fragment = $this->_string_shift($current_log, $this->log_short_width);
1457 $hex = substr(preg_replace_callback('#.#s', array($this, '_format_log_helper'), $fragment), strlen($this->log_boundary));
1458 // replace non ASCII printable characters with dots
1459 // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
1460 // also replace < with a . since < messes up the output on web browsers
1461 $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
1462 $output.= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
1464 } while (strlen($current_log));
1472 * Helper function for _format_log
1474 * For use with preg_replace_callback()
1476 * @param Array $matches
1480 function _format_log_helper($matches)
1482 return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
1486 * Return the server key public exponent
1488 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1489 * the raw bytes. This behavior is similar to PHP's md5() function.
1491 * @param optional Boolean $raw_output
1495 function getServerKeyPublicExponent($raw_output = false)
1497 return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
1501 * Return the server key public modulus
1503 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1504 * the raw bytes. This behavior is similar to PHP's md5() function.
1506 * @param optional Boolean $raw_output
1510 function getServerKeyPublicModulus($raw_output = false)
1512 return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
1516 * Return the host key public exponent
1518 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1519 * the raw bytes. This behavior is similar to PHP's md5() function.
1521 * @param optional Boolean $raw_output
1525 function getHostKeyPublicExponent($raw_output = false)
1527 return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
1531 * Return the host key public modulus
1533 * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
1534 * the raw bytes. This behavior is similar to PHP's md5() function.
1536 * @param optional Boolean $raw_output
1540 function getHostKeyPublicModulus($raw_output = false)
1542 return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
1546 * Return a list of ciphers supported by SSH1 server.
1548 * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1549 * is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
1550 * get array(NET_SSH1_CIPHER_3DES).
1552 * @param optional Boolean $raw_output
1556 function getSupportedCiphers($raw_output = false)
1558 return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
1562 * Return a list of authentications supported by SSH1 server.
1564 * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
1565 * is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
1566 * get array(NET_SSH1_AUTH_PASSWORD).
1568 * @param optional Boolean $raw_output
1572 function getSupportedAuthentications($raw_output = false)
1574 return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
1578 * Return the server identification.
1583 function getServerIdentification()
1585 return rtrim($this->server_identification);
1591 * Makes sure that only the last 1MB worth of packets will be logged
1593 * @param String $data
1596 function _append_log($protocol_flags, $message)
1598 switch (NET_SSH1_LOGGING) {
1599 // useful for benchmarks
1600 case NET_SSH1_LOG_SIMPLE:
1601 $this->protocol_flags_log[] = $protocol_flags;
1603 // the most useful log for SSH1
1604 case NET_SSH1_LOG_COMPLEX:
1605 $this->protocol_flags_log[] = $protocol_flags;
1606 $this->_string_shift($message);
1607 $this->log_size+= strlen($message);
1608 $this->message_log[] = $message;
1609 while ($this->log_size > NET_SSH1_LOG_MAX_SIZE) {
1610 $this->log_size-= strlen(array_shift($this->message_log));
1611 array_shift($this->protocol_flags_log);
1614 // dump the output out realtime; packets may be interspersed with non packets,
1615 // passwords won't be filtered out and select other packets may not be correctly
1617 case NET_SSH1_LOG_REALTIME:
1618 echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
1622 // basically the same thing as NET_SSH1_LOG_REALTIME with the caveat that NET_SSH1_LOG_REALTIME_FILE
1623 // needs to be defined and that the resultant log file will be capped out at NET_SSH1_LOG_MAX_SIZE.
1624 // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
1625 // at the beginning of the file
1626 case NET_SSH1_LOG_REALTIME_FILE:
1627 if (!isset($this->realtime_log_file)) {
1628 // PHP doesn't seem to like using constants in fopen()
1629 $filename = NET_SSH1_LOG_REALTIME_FILE;
1630 $fp = fopen($filename, 'w');
1631 $this->realtime_log_file = $fp;
1633 if (!is_resource($this->realtime_log_file)) {
1636 $entry = $this->_format_log(array($message), array($protocol_flags));
1637 if ($this->realtime_log_wrap) {
1638 $temp = "<<< START >>>\r\n";
1640 fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
1642 $this->realtime_log_size+= strlen($entry);
1643 if ($this->realtime_log_size > NET_SSH1_LOG_MAX_SIZE) {
1644 fseek($this->realtime_log_file, 0);
1645 $this->realtime_log_size = strlen($entry);
1646 $this->realtime_log_wrap = true;
1648 fputs($this->realtime_log_file, $entry);