Subversion Repositories cheapmusic

Rev

Details | Last modification | View Log | RSS feed

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