PageRenderTime 127ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/fuelphp/fuel/core/vendor/phpseclib/Net/SSH2.php

http://github.com/eryx/php-framework-benchmark
PHP | 2633 lines | 1405 code | 317 blank | 911 comment | 227 complexity | 8cdc353c64ec6d08b66ce1b284d72410 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, Apache-2.0, LGPL-2.1, LGPL-3.0, BSD-2-Clause

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. namespace PHPSecLib;
  4. /**
  5. * Pure-PHP implementation of SSHv2.
  6. *
  7. * PHP versions 4 and 5
  8. *
  9. * Here are some examples of how to use this library:
  10. * <code>
  11. * <?php
  12. * include('Net/SSH2.php');
  13. *
  14. * $ssh = new Net_SSH2('www.domain.tld');
  15. * if (!$ssh->login('username', 'password')) {
  16. * exit('Login Failed');
  17. * }
  18. *
  19. * echo $ssh->exec('pwd');
  20. * echo $ssh->exec('ls -la');
  21. * ?>
  22. * </code>
  23. *
  24. * <code>
  25. * <?php
  26. * include('Crypt/RSA.php');
  27. * include('Net/SSH2.php');
  28. *
  29. * $key = new Crypt_RSA();
  30. * //$key->setPassword('whatever');
  31. * $key->loadKey(file_get_contents('privatekey'));
  32. *
  33. * $ssh = new Net_SSH2('www.domain.tld');
  34. * if (!$ssh->login('username', $key)) {
  35. * exit('Login Failed');
  36. * }
  37. *
  38. * echo $ssh->read('username@username:~$');
  39. * $ssh->write("ls -la\n");
  40. * echo $ssh->read('username@username:~$');
  41. * ?>
  42. * </code>
  43. *
  44. * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
  45. * of this software and associated documentation files (the "Software"), to deal
  46. * in the Software without restriction, including without limitation the rights
  47. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  48. * copies of the Software, and to permit persons to whom the Software is
  49. * furnished to do so, subject to the following conditions:
  50. *
  51. * The above copyright notice and this permission notice shall be included in
  52. * all copies or substantial portions of the Software.
  53. *
  54. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  55. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  56. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  57. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  58. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  59. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  60. * THE SOFTWARE.
  61. *
  62. * @category Net
  63. * @package Net_SSH2
  64. * @author Jim Wigginton <terrafrost@php.net>
  65. * @copyright MMVII Jim Wigginton
  66. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  67. * @version $Id: SSH2.php,v 1.53 2010-10-24 01:24:30 terrafrost Exp $
  68. * @link http://phpseclib.sourceforge.net
  69. */
  70. /**#@+
  71. * Crypt random global function
  72. *
  73. * @see Crypt/Random.php
  74. */
  75. require_once (__DIR__.DS.'../Crypt/Random.php');
  76. /**#@+
  77. * Execution Bitmap Masks
  78. *
  79. * @see Net_SSH2::bitmap
  80. * @access private
  81. */
  82. define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001);
  83. define('NET_SSH2_MASK_LOGIN', 0x00000002);
  84. define('NET_SSH2_MASK_SHELL', 0x00000004);
  85. /**#@-*/
  86. /**#@+
  87. * Channel constants
  88. *
  89. * RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer
  90. * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with
  91. * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a
  92. * recepient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel
  93. * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snipet:
  94. * The 'recipient channel' is the channel number given in the original
  95. * open request, and 'sender channel' is the channel number allocated by
  96. * the other side.
  97. *
  98. * @see Net_SSH2::_send_channel_packet()
  99. * @see Net_SSH2::_get_channel_packet()
  100. * @access private
  101. */
  102. define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100
  103. define('NET_SSH2_CHANNEL_SHELL',1);
  104. /**#@-*/
  105. /**#@+
  106. * @access public
  107. * @see Net_SSH2::getLog()
  108. */
  109. /**
  110. * Returns the message numbers
  111. */
  112. define('NET_SSH2_LOG_SIMPLE', 1);
  113. /**
  114. * Returns the message content
  115. */
  116. define('NET_SSH2_LOG_COMPLEX', 2);
  117. /**#@-*/
  118. /**#@+
  119. * @access public
  120. * @see Net_SSH2::read()
  121. */
  122. /**
  123. * Returns when a string matching $expect exactly is found
  124. */
  125. define('NET_SSH2_READ_SIMPLE', 1);
  126. /**
  127. * Returns when a string matching the regular expression $expect is found
  128. */
  129. define('NET_SSH2_READ_REGEX', 2);
  130. /**#@-*/
  131. /**
  132. * Pure-PHP implementation of SSHv2.
  133. *
  134. * @author Jim Wigginton <terrafrost@php.net>
  135. * @version 0.1.0
  136. * @access public
  137. * @package Net_SSH2
  138. */
  139. class Net_SSH2 {
  140. /**
  141. * The SSH identifier
  142. *
  143. * @var String
  144. * @access private
  145. */
  146. var $identifier = 'SSH-2.0-phpseclib_0.2';
  147. /**
  148. * The Socket Object
  149. *
  150. * @var Object
  151. * @access private
  152. */
  153. var $fsock;
  154. /**
  155. * Execution Bitmap
  156. *
  157. * The bits that are set reprsent functions that have been called already. This is used to determine
  158. * if a requisite function has been successfully executed. If not, an error should be thrown.
  159. *
  160. * @var Integer
  161. * @access private
  162. */
  163. var $bitmap = 0;
  164. /**
  165. * Error information
  166. *
  167. * @see Net_SSH2::getErrors()
  168. * @see Net_SSH2::getLastError()
  169. * @var String
  170. * @access private
  171. */
  172. var $errors = array();
  173. /**
  174. * Server Identifier
  175. *
  176. * @see Net_SSH2::getServerIdentification()
  177. * @var String
  178. * @access private
  179. */
  180. var $server_identifier = '';
  181. /**
  182. * Key Exchange Algorithms
  183. *
  184. * @see Net_SSH2::getKexAlgorithims()
  185. * @var Array
  186. * @access private
  187. */
  188. var $kex_algorithms;
  189. /**
  190. * Server Host Key Algorithms
  191. *
  192. * @see Net_SSH2::getServerHostKeyAlgorithms()
  193. * @var Array
  194. * @access private
  195. */
  196. var $server_host_key_algorithms;
  197. /**
  198. * Encryption Algorithms: Client to Server
  199. *
  200. * @see Net_SSH2::getEncryptionAlgorithmsClient2Server()
  201. * @var Array
  202. * @access private
  203. */
  204. var $encryption_algorithms_client_to_server;
  205. /**
  206. * Encryption Algorithms: Server to Client
  207. *
  208. * @see Net_SSH2::getEncryptionAlgorithmsServer2Client()
  209. * @var Array
  210. * @access private
  211. */
  212. var $encryption_algorithms_server_to_client;
  213. /**
  214. * MAC Algorithms: Client to Server
  215. *
  216. * @see Net_SSH2::getMACAlgorithmsClient2Server()
  217. * @var Array
  218. * @access private
  219. */
  220. var $mac_algorithms_client_to_server;
  221. /**
  222. * MAC Algorithms: Server to Client
  223. *
  224. * @see Net_SSH2::getMACAlgorithmsServer2Client()
  225. * @var Array
  226. * @access private
  227. */
  228. var $mac_algorithms_server_to_client;
  229. /**
  230. * Compression Algorithms: Client to Server
  231. *
  232. * @see Net_SSH2::getCompressionAlgorithmsClient2Server()
  233. * @var Array
  234. * @access private
  235. */
  236. var $compression_algorithms_client_to_server;
  237. /**
  238. * Compression Algorithms: Server to Client
  239. *
  240. * @see Net_SSH2::getCompressionAlgorithmsServer2Client()
  241. * @var Array
  242. * @access private
  243. */
  244. var $compression_algorithms_server_to_client;
  245. /**
  246. * Languages: Server to Client
  247. *
  248. * @see Net_SSH2::getLanguagesServer2Client()
  249. * @var Array
  250. * @access private
  251. */
  252. var $languages_server_to_client;
  253. /**
  254. * Languages: Client to Server
  255. *
  256. * @see Net_SSH2::getLanguagesClient2Server()
  257. * @var Array
  258. * @access private
  259. */
  260. var $languages_client_to_server;
  261. /**
  262. * Block Size for Server to Client Encryption
  263. *
  264. * "Note that the length of the concatenation of 'packet_length',
  265. * 'padding_length', 'payload', and 'random padding' MUST be a multiple
  266. * of the cipher block size or 8, whichever is larger. This constraint
  267. * MUST be enforced, even when using stream ciphers."
  268. *
  269. * -- http://tools.ietf.org/html/rfc4253#section-6
  270. *
  271. * @see Net_SSH2::Net_SSH2()
  272. * @see Net_SSH2::_send_binary_packet()
  273. * @var Integer
  274. * @access private
  275. */
  276. var $encrypt_block_size = 8;
  277. /**
  278. * Block Size for Client to Server Encryption
  279. *
  280. * @see Net_SSH2::Net_SSH2()
  281. * @see Net_SSH2::_get_binary_packet()
  282. * @var Integer
  283. * @access private
  284. */
  285. var $decrypt_block_size = 8;
  286. /**
  287. * Server to Client Encryption Object
  288. *
  289. * @see Net_SSH2::_get_binary_packet()
  290. * @var Object
  291. * @access private
  292. */
  293. var $decrypt = false;
  294. /**
  295. * Client to Server Encryption Object
  296. *
  297. * @see Net_SSH2::_send_binary_packet()
  298. * @var Object
  299. * @access private
  300. */
  301. var $encrypt = false;
  302. /**
  303. * Client to Server HMAC Object
  304. *
  305. * @see Net_SSH2::_send_binary_packet()
  306. * @var Object
  307. * @access private
  308. */
  309. var $hmac_create = false;
  310. /**
  311. * Server to Client HMAC Object
  312. *
  313. * @see Net_SSH2::_get_binary_packet()
  314. * @var Object
  315. * @access private
  316. */
  317. var $hmac_check = false;
  318. /**
  319. * Size of server to client HMAC
  320. *
  321. * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read.
  322. * For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is
  323. * append it.
  324. *
  325. * @see Net_SSH2::_get_binary_packet()
  326. * @var Integer
  327. * @access private
  328. */
  329. var $hmac_size = false;
  330. /**
  331. * Server Public Host Key
  332. *
  333. * @see Net_SSH2::getServerPublicHostKey()
  334. * @var String
  335. * @access private
  336. */
  337. var $server_public_host_key;
  338. /**
  339. * Session identifer
  340. *
  341. * "The exchange hash H from the first key exchange is additionally
  342. * used as the session identifier, which is a unique identifier for
  343. * this connection."
  344. *
  345. * -- http://tools.ietf.org/html/rfc4253#section-7.2
  346. *
  347. * @see Net_SSH2::_key_exchange()
  348. * @var String
  349. * @access private
  350. */
  351. var $session_id = false;
  352. /**
  353. * Exchange hash
  354. *
  355. * The current exchange hash
  356. *
  357. * @see Net_SSH2::_key_exchange()
  358. * @var String
  359. * @access private
  360. */
  361. var $exchange_hash = false;
  362. /**
  363. * Message Numbers
  364. *
  365. * @see Net_SSH2::Net_SSH2()
  366. * @var Array
  367. * @access private
  368. */
  369. var $message_numbers = array();
  370. /**
  371. * Disconnection Message 'reason codes' defined in RFC4253
  372. *
  373. * @see Net_SSH2::Net_SSH2()
  374. * @var Array
  375. * @access private
  376. */
  377. var $disconnect_reasons = array();
  378. /**
  379. * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
  380. *
  381. * @see Net_SSH2::Net_SSH2()
  382. * @var Array
  383. * @access private
  384. */
  385. var $channel_open_failure_reasons = array();
  386. /**
  387. * Terminal Modes
  388. *
  389. * @link http://tools.ietf.org/html/rfc4254#section-8
  390. * @see Net_SSH2::Net_SSH2()
  391. * @var Array
  392. * @access private
  393. */
  394. var $terminal_modes = array();
  395. /**
  396. * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
  397. *
  398. * @link http://tools.ietf.org/html/rfc4254#section-5.2
  399. * @see Net_SSH2::Net_SSH2()
  400. * @var Array
  401. * @access private
  402. */
  403. var $channel_extended_data_type_codes = array();
  404. /**
  405. * Send Sequence Number
  406. *
  407. * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
  408. *
  409. * @see Net_SSH2::_send_binary_packet()
  410. * @var Integer
  411. * @access private
  412. */
  413. var $send_seq_no = 0;
  414. /**
  415. * Get Sequence Number
  416. *
  417. * See 'Section 6.4. Data Integrity' of rfc4253 for more info.
  418. *
  419. * @see Net_SSH2::_get_binary_packet()
  420. * @var Integer
  421. * @access private
  422. */
  423. var $get_seq_no = 0;
  424. /**
  425. * Server Channels
  426. *
  427. * Maps client channels to server channels
  428. *
  429. * @see Net_SSH2::_get_channel_packet()
  430. * @see Net_SSH2::exec()
  431. * @var Array
  432. * @access private
  433. */
  434. var $server_channels = array();
  435. /**
  436. * Channel Buffers
  437. *
  438. * If a client requests a packet from one channel but receives two packets from another those packets should
  439. * be placed in a buffer
  440. *
  441. * @see Net_SSH2::_get_channel_packet()
  442. * @see Net_SSH2::exec()
  443. * @var Array
  444. * @access private
  445. */
  446. var $channel_buffers = array();
  447. /**
  448. * Channel Status
  449. *
  450. * Contains the type of the last sent message
  451. *
  452. * @see Net_SSH2::_get_channel_packet()
  453. * @var Array
  454. * @access private
  455. */
  456. var $channel_status = array();
  457. /**
  458. * Packet Size
  459. *
  460. * Maximum packet size indexed by channel
  461. *
  462. * @see Net_SSH2::_send_channel_packet()
  463. * @var Array
  464. * @access private
  465. */
  466. var $packet_size_client_to_server = array();
  467. /**
  468. * Message Number Log
  469. *
  470. * @see Net_SSH2::getLog()
  471. * @var Array
  472. * @access private
  473. */
  474. var $message_number_log = array();
  475. /**
  476. * Message Log
  477. *
  478. * @see Net_SSH2::getLog()
  479. * @var Array
  480. * @access private
  481. */
  482. var $message_log = array();
  483. /**
  484. * The Window Size
  485. *
  486. * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 4GB)
  487. *
  488. * @var Integer
  489. * @see Net_SSH2::_send_channel_packet()
  490. * @see Net_SSH2::exec()
  491. * @access private
  492. */
  493. var $window_size = 0x7FFFFFFF;
  494. /**
  495. * Window size
  496. *
  497. * Window size indexed by channel
  498. *
  499. * @see Net_SSH2::_send_channel_packet()
  500. * @var Array
  501. * @access private
  502. */
  503. var $window_size_client_to_server = array();
  504. /**
  505. * Server signature
  506. *
  507. * Verified against $this->session_id
  508. *
  509. * @see Net_SSH2::getServerPublicHostKey()
  510. * @var String
  511. * @access private
  512. */
  513. var $signature = '';
  514. /**
  515. * Server signature format
  516. *
  517. * ssh-rsa or ssh-dss.
  518. *
  519. * @see Net_SSH2::getServerPublicHostKey()
  520. * @var String
  521. * @access private
  522. */
  523. var $signature_format = '';
  524. /**
  525. * Interactive Buffer
  526. *
  527. * @see Net_SSH2::read()
  528. * @var Array
  529. * @access private
  530. */
  531. var $interactiveBuffer = '';
  532. /**
  533. * Default Constructor.
  534. *
  535. * Connects to an SSHv2 server
  536. *
  537. * @param String $host
  538. * @param optional Integer $port
  539. * @param optional Integer $timeout
  540. * @return Net_SSH2
  541. * @access public
  542. */
  543. function __construct($host, $port = 22, $timeout = 10)
  544. {
  545. $this->message_numbers = array(
  546. 1 => 'NET_SSH2_MSG_DISCONNECT',
  547. 2 => 'NET_SSH2_MSG_IGNORE',
  548. 3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
  549. 4 => 'NET_SSH2_MSG_DEBUG',
  550. 5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
  551. 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
  552. 20 => 'NET_SSH2_MSG_KEXINIT',
  553. 21 => 'NET_SSH2_MSG_NEWKEYS',
  554. 30 => 'NET_SSH2_MSG_KEXDH_INIT',
  555. 31 => 'NET_SSH2_MSG_KEXDH_REPLY',
  556. 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
  557. 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
  558. 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
  559. 53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
  560. 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
  561. 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
  562. 82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
  563. 90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
  564. 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
  565. 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
  566. 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
  567. 94 => 'NET_SSH2_MSG_CHANNEL_DATA',
  568. 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
  569. 96 => 'NET_SSH2_MSG_CHANNEL_EOF',
  570. 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
  571. 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
  572. 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
  573. 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
  574. );
  575. $this->disconnect_reasons = array(
  576. 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
  577. 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
  578. 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
  579. 4 => 'NET_SSH2_DISCONNECT_RESERVED',
  580. 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
  581. 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
  582. 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
  583. 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
  584. 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
  585. 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
  586. 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
  587. 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
  588. 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
  589. 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
  590. 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
  591. );
  592. $this->channel_open_failure_reasons = array(
  593. 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
  594. );
  595. $this->terminal_modes = array(
  596. 0 => 'NET_SSH2_TTY_OP_END'
  597. );
  598. $this->channel_extended_data_type_codes = array(
  599. 1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
  600. );
  601. $this->_define_array(
  602. $this->message_numbers,
  603. $this->disconnect_reasons,
  604. $this->channel_open_failure_reasons,
  605. $this->terminal_modes,
  606. $this->channel_extended_data_type_codes,
  607. array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
  608. array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'),
  609. array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
  610. 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE')
  611. );
  612. $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
  613. if (!$this->fsock) {
  614. user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
  615. return;
  616. }
  617. /* According to the SSH2 specs,
  618. "The server MAY send other lines of data before sending the version
  619. string. Each line SHOULD be terminated by a Carriage Return and Line
  620. Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
  621. in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
  622. MUST be able to process such lines." */
  623. $temp = '';
  624. $extra = '';
  625. while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
  626. if (substr($temp, -2) == "\r\n") {
  627. $extra.= $temp;
  628. $temp = '';
  629. }
  630. $temp.= fgets($this->fsock, 255);
  631. }
  632. if (feof($this->fsock)) {
  633. user_error('Connection closed by server', E_USER_NOTICE);
  634. return false;
  635. }
  636. $ext = array();
  637. if (extension_loaded('mcrypt')) {
  638. $ext[] = 'mcrypt';
  639. }
  640. if (extension_loaded('gmp')) {
  641. $ext[] = 'gmp';
  642. } else if (extension_loaded('bcmath')) {
  643. $ext[] = 'bcmath';
  644. }
  645. if (!empty($ext)) {
  646. $this->identifier.= ' (' . implode(', ', $ext) . ')';
  647. }
  648. if (defined('NET_SSH2_LOGGING')) {
  649. $this->message_number_log[] = '<-';
  650. $this->message_number_log[] = '->';
  651. if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
  652. $this->message_log[] = $temp;
  653. $this->message_log[] = $this->identifier . "\r\n";
  654. }
  655. }
  656. $this->server_identifier = trim($temp, "\r\n");
  657. if (!empty($extra)) {
  658. $this->errors[] = utf8_decode($extra);
  659. }
  660. if ($matches[1] != '1.99' && $matches[1] != '2.0') {
  661. user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE);
  662. return;
  663. }
  664. fputs($this->fsock, $this->identifier . "\r\n");
  665. $response = $this->_get_binary_packet();
  666. if ($response === false) {
  667. user_error('Connection closed by server', E_USER_NOTICE);
  668. return;
  669. }
  670. if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
  671. user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE);
  672. return;
  673. }
  674. if (!$this->_key_exchange($response)) {
  675. return;
  676. }
  677. $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR;
  678. }
  679. /**
  680. * Key Exchange
  681. *
  682. * @param String $kexinit_payload_server
  683. * @access private
  684. */
  685. function _key_exchange($kexinit_payload_server)
  686. {
  687. static $kex_algorithms = array(
  688. 'diffie-hellman-group1-sha1', // REQUIRED
  689. 'diffie-hellman-group14-sha1' // REQUIRED
  690. );
  691. static $server_host_key_algorithms = array(
  692. 'ssh-rsa', // RECOMMENDED sign Raw RSA Key
  693. 'ssh-dss' // REQUIRED sign Raw DSS Key
  694. );
  695. static $encryption_algorithms = array(
  696. // from <http://tools.ietf.org/html/rfc4345#section-4>:
  697. 'arcfour256',
  698. 'arcfour128',
  699. 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
  700. 'aes128-cbc', // RECOMMENDED AES with a 128-bit key
  701. 'aes192-cbc', // OPTIONAL AES with a 192-bit key
  702. 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
  703. // from <http://tools.ietf.org/html/rfc4344#section-4>:
  704. 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
  705. 'aes192-ctr', // RECOMMENDED AES with 192-bit key
  706. 'aes256-ctr', // RECOMMENDED AES with 256-bit key
  707. '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
  708. '3des-cbc', // REQUIRED three-key 3DES in CBC mode
  709. 'none' // OPTIONAL no encryption; NOT RECOMMENDED
  710. );
  711. static $mac_algorithms = array(
  712. 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
  713. 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
  714. 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
  715. 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
  716. 'none' // OPTIONAL no MAC; NOT RECOMMENDED
  717. );
  718. static $compression_algorithms = array(
  719. 'none' // REQUIRED no compression
  720. //'zlib' // OPTIONAL ZLIB (LZ77) compression
  721. );
  722. static $str_kex_algorithms, $str_server_host_key_algorithms,
  723. $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client,
  724. $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
  725. if (empty($str_kex_algorithms)) {
  726. $str_kex_algorithms = implode(',', $kex_algorithms);
  727. $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
  728. $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
  729. $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
  730. $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
  731. }
  732. $client_cookie = '';
  733. for ($i = 0; $i < 16; $i++) {
  734. $client_cookie.= chr(crypt_random(0, 255));
  735. }
  736. $response = $kexinit_payload_server;
  737. $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
  738. $server_cookie = $this->_string_shift($response, 16);
  739. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  740. $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
  741. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  742. $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
  743. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  744. $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  745. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  746. $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  747. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  748. $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  749. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  750. $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  751. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  752. $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  753. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  754. $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  755. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  756. $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
  757. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  758. $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
  759. extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
  760. $first_kex_packet_follows = $first_kex_packet_follows != 0;
  761. // the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place.
  762. $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
  763. NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms,
  764. strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server),
  765. $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client,
  766. strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client),
  767. $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server,
  768. strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '',
  769. 0, 0
  770. );
  771. if (!$this->_send_binary_packet($kexinit_payload_client)) {
  772. return false;
  773. }
  774. // here ends the second place.
  775. // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
  776. for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++);
  777. if ($i == count($encryption_algorithms)) {
  778. user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE);
  779. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  780. }
  781. // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
  782. // diffie-hellman key exchange as fast as possible
  783. $decrypt = $encryption_algorithms[$i];
  784. switch ($decrypt) {
  785. case '3des-cbc':
  786. case '3des-ctr':
  787. $decryptKeyLength = 24; // eg. 192 / 8
  788. break;
  789. case 'aes256-cbc':
  790. case 'aes256-ctr':
  791. $decryptKeyLength = 32; // eg. 256 / 8
  792. break;
  793. case 'aes192-cbc':
  794. case 'aes192-ctr':
  795. $decryptKeyLength = 24; // eg. 192 / 8
  796. break;
  797. case 'aes128-cbc':
  798. case 'aes128-ctr':
  799. $decryptKeyLength = 16; // eg. 128 / 8
  800. break;
  801. case 'arcfour':
  802. case 'arcfour128':
  803. $decryptKeyLength = 16; // eg. 128 / 8
  804. break;
  805. case 'arcfour256':
  806. $decryptKeyLength = 32; // eg. 128 / 8
  807. break;
  808. case 'none';
  809. $decryptKeyLength = 0;
  810. }
  811. for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++);
  812. if ($i == count($encryption_algorithms)) {
  813. user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE);
  814. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  815. }
  816. $encrypt = $encryption_algorithms[$i];
  817. switch ($encrypt) {
  818. case '3des-cbc':
  819. case '3des-ctr':
  820. $encryptKeyLength = 24;
  821. break;
  822. case 'aes256-cbc':
  823. case 'aes256-ctr':
  824. $encryptKeyLength = 32;
  825. break;
  826. case 'aes192-cbc':
  827. case 'aes192-ctr':
  828. $encryptKeyLength = 24;
  829. break;
  830. case 'aes128-cbc':
  831. case 'aes128-ctr':
  832. $encryptKeyLength = 16;
  833. break;
  834. case 'arcfour':
  835. case 'arcfour128':
  836. $encryptKeyLength = 16;
  837. break;
  838. case 'arcfour256':
  839. $encryptKeyLength = 32;
  840. break;
  841. case 'none';
  842. $encryptKeyLength = 0;
  843. }
  844. $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
  845. // through diffie-hellman key exchange a symmetric key is obtained
  846. for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++);
  847. if ($i == count($kex_algorithms)) {
  848. user_error('No compatible key exchange algorithms found', E_USER_NOTICE);
  849. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  850. }
  851. switch ($kex_algorithms[$i]) {
  852. // see http://tools.ietf.org/html/rfc2409#section-6.2 and
  853. // http://tools.ietf.org/html/rfc2412, appendex E
  854. case 'diffie-hellman-group1-sha1':
  855. $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
  856. '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
  857. '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
  858. 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF');
  859. $keyLength = $keyLength < 160 ? $keyLength : 160;
  860. $hash = 'sha1';
  861. break;
  862. // see http://tools.ietf.org/html/rfc3526#section-3
  863. case 'diffie-hellman-group14-sha1':
  864. $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
  865. '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
  866. '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
  867. 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
  868. '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
  869. '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
  870. 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
  871. '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF');
  872. $keyLength = $keyLength < 160 ? $keyLength : 160;
  873. $hash = 'sha1';
  874. }
  875. $p = new Math_BigInteger($p, 256);
  876. //$q = $p->bitwise_rightShift(1);
  877. /* To increase the speed of the key exchange, both client and server may
  878. reduce the size of their private exponents. It should be at least
  879. twice as long as the key material that is generated from the shared
  880. secret. For more details, see the paper by van Oorschot and Wiener
  881. [VAN-OORSCHOT].
  882. -- http://tools.ietf.org/html/rfc4419#section-6.2 */
  883. $q = new Math_BigInteger(1);
  884. $q = $q->bitwise_leftShift(2 * $keyLength);
  885. $q = $q->subtract(new Math_BigInteger(1));
  886. $g = new Math_BigInteger(2);
  887. $x = new Math_BigInteger();
  888. $x->setRandomGenerator('crypt_random');
  889. $x = $x->random(new Math_BigInteger(1), $q);
  890. $e = $g->modPow($x, $p);
  891. $eBytes = $e->toBytes(true);
  892. $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
  893. if (!$this->_send_binary_packet($data)) {
  894. user_error('Connection closed by server', E_USER_NOTICE);
  895. return false;
  896. }
  897. $response = $this->_get_binary_packet();
  898. if ($response === false) {
  899. user_error('Connection closed by server', E_USER_NOTICE);
  900. return false;
  901. }
  902. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  903. if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
  904. user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE);
  905. return false;
  906. }
  907. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  908. $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
  909. $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
  910. $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
  911. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  912. $fBytes = $this->_string_shift($response, $temp['length']);
  913. $f = new Math_BigInteger($fBytes, -256);
  914. $temp = unpack('Nlength', $this->_string_shift($response, 4));
  915. $this->signature = $this->_string_shift($response, $temp['length']);
  916. $temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
  917. $this->signature_format = $this->_string_shift($this->signature, $temp['length']);
  918. $key = $f->modPow($x, $p);
  919. $keyBytes = $key->toBytes(true);
  920. $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*',
  921. strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier,
  922. strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server),
  923. $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes),
  924. $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes
  925. );
  926. $this->exchange_hash = pack('H*', $hash($this->exchange_hash));
  927. if ($this->session_id === false) {
  928. $this->session_id = $this->exchange_hash;
  929. }
  930. for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++);
  931. if ($i == count($server_host_key_algorithms)) {
  932. user_error('No compatible server host key algorithms found', E_USER_NOTICE);
  933. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  934. }
  935. if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) {
  936. user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE);
  937. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  938. }
  939. $packet = pack('C',
  940. NET_SSH2_MSG_NEWKEYS
  941. );
  942. if (!$this->_send_binary_packet($packet)) {
  943. return false;
  944. }
  945. $response = $this->_get_binary_packet();
  946. if ($response === false) {
  947. user_error('Connection closed by server', E_USER_NOTICE);
  948. return false;
  949. }
  950. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  951. if ($type != NET_SSH2_MSG_NEWKEYS) {
  952. user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE);
  953. return false;
  954. }
  955. switch ($encrypt) {
  956. case '3des-cbc':
  957. $this->encrypt = new Crypt_TripleDES();
  958. // $this->encrypt_block_size = 64 / 8 == the default
  959. break;
  960. case '3des-ctr':
  961. $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
  962. // $this->encrypt_block_size = 64 / 8 == the default
  963. break;
  964. case 'aes256-cbc':
  965. case 'aes192-cbc':
  966. case 'aes128-cbc':
  967. $this->encrypt = new Crypt_AES();
  968. $this->encrypt_block_size = 16; // eg. 128 / 8
  969. break;
  970. case 'aes256-ctr':
  971. case 'aes192-ctr':
  972. case 'aes128-ctr':
  973. $this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
  974. $this->encrypt_block_size = 16; // eg. 128 / 8
  975. break;
  976. case 'arcfour':
  977. case 'arcfour128':
  978. case 'arcfour256':
  979. $this->encrypt = new Crypt_RC4();
  980. break;
  981. case 'none';
  982. //$this->encrypt = new Crypt_Null();
  983. }
  984. switch ($decrypt) {
  985. case '3des-cbc':
  986. $this->decrypt = new Crypt_TripleDES();
  987. break;
  988. case '3des-ctr':
  989. $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
  990. break;
  991. case 'aes256-cbc':
  992. case 'aes192-cbc':
  993. case 'aes128-cbc':
  994. $this->decrypt = new Crypt_AES();
  995. $this->decrypt_block_size = 16;
  996. break;
  997. case 'aes256-ctr':
  998. case 'aes192-ctr':
  999. case 'aes128-ctr':
  1000. $this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
  1001. $this->decrypt_block_size = 16;
  1002. break;
  1003. case 'arcfour':
  1004. case 'arcfour128':
  1005. case 'arcfour256':
  1006. $this->decrypt = new Crypt_RC4();
  1007. break;
  1008. case 'none';
  1009. //$this->decrypt = new Crypt_Null();
  1010. }
  1011. $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
  1012. if ($this->encrypt) {
  1013. $this->encrypt->enableContinuousBuffer();
  1014. $this->encrypt->disablePadding();
  1015. $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id));
  1016. while ($this->encrypt_block_size > strlen($iv)) {
  1017. $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv));
  1018. }
  1019. $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
  1020. $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id));
  1021. while ($encryptKeyLength > strlen($key)) {
  1022. $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
  1023. }
  1024. $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
  1025. }
  1026. if ($this->decrypt) {
  1027. $this->decrypt->enableContinuousBuffer();
  1028. $this->decrypt->disablePadding();
  1029. $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id));
  1030. while ($this->decrypt_block_size > strlen($iv)) {
  1031. $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv));
  1032. }
  1033. $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
  1034. $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id));
  1035. while ($decryptKeyLength > strlen($key)) {
  1036. $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
  1037. }
  1038. $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
  1039. }
  1040. /* The "arcfour128" algorithm is the RC4 cipher, as described in
  1041. [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
  1042. generated by the cipher MUST be discarded, and the first byte of the
  1043. first encrypted packet MUST be encrypted using the 1537th byte of
  1044. keystream.
  1045. -- http://tools.ietf.org/html/rfc4345#section-4 */
  1046. if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
  1047. $this->encrypt->encrypt(str_repeat("\0", 1536));
  1048. }
  1049. if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
  1050. $this->decrypt->decrypt(str_repeat("\0", 1536));
  1051. }
  1052. for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++);
  1053. if ($i == count($mac_algorithms)) {
  1054. user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);
  1055. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1056. }
  1057. $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
  1058. switch ($mac_algorithms[$i]) {
  1059. case 'hmac-sha1':
  1060. $this->hmac_create = new Crypt_Hash('sha1');
  1061. $createKeyLength = 20;
  1062. break;
  1063. case 'hmac-sha1-96':
  1064. $this->hmac_create = new Crypt_Hash('sha1-96');
  1065. $createKeyLength = 20;
  1066. break;
  1067. case 'hmac-md5':
  1068. $this->hmac_create = new Crypt_Hash('md5');
  1069. $createKeyLength = 16;
  1070. break;
  1071. case 'hmac-md5-96':
  1072. $this->hmac_create = new Crypt_Hash('md5-96');
  1073. $createKeyLength = 16;
  1074. }
  1075. for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++);
  1076. if ($i == count($mac_algorithms)) {
  1077. user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE);
  1078. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1079. }
  1080. $checkKeyLength = 0;
  1081. $this->hmac_size = 0;
  1082. switch ($mac_algorithms[$i]) {
  1083. case 'hmac-sha1':
  1084. $this->hmac_check = new Crypt_Hash('sha1');
  1085. $checkKeyLength = 20;
  1086. $this->hmac_size = 20;
  1087. break;
  1088. case 'hmac-sha1-96':
  1089. $this->hmac_check = new Crypt_Hash('sha1-96');
  1090. $checkKeyLength = 20;
  1091. $this->hmac_size = 12;
  1092. break;
  1093. case 'hmac-md5':
  1094. $this->hmac_check = new Crypt_Hash('md5');
  1095. $checkKeyLength = 16;
  1096. $this->hmac_size = 16;
  1097. break;
  1098. case 'hmac-md5-96':
  1099. $this->hmac_check = new Crypt_Hash('md5-96');
  1100. $checkKeyLength = 16;
  1101. $this->hmac_size = 12;
  1102. }
  1103. $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id));
  1104. while ($createKeyLength > strlen($key)) {
  1105. $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
  1106. }
  1107. $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
  1108. $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id));
  1109. while ($checkKeyLength > strlen($key)) {
  1110. $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
  1111. }
  1112. $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
  1113. for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++);
  1114. if ($i == count($compression_algorithms)) {
  1115. user_error('No compatible server to client compression algorithms found', E_USER_NOTICE);
  1116. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1117. }
  1118. $this->decompress = $compression_algorithms[$i] == 'zlib';
  1119. for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++);
  1120. if ($i == count($compression_algorithms)) {
  1121. user_error('No compatible client to server compression algorithms found', E_USER_NOTICE);
  1122. return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
  1123. }
  1124. $this->compress = $compression_algorithms[$i] == 'zlib';
  1125. return true;
  1126. }
  1127. /**
  1128. * Login
  1129. *
  1130. * The $password parameter can be a plaintext password or a Crypt_RSA object.
  1131. *
  1132. * @param String $username
  1133. * @param optional String $password
  1134. * @return Boolean
  1135. * @access public
  1136. * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
  1137. * by sending dummy SSH_MSG_IGNORE messages.
  1138. */
  1139. function login($username, $password = '')
  1140. {
  1141. if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
  1142. return false;
  1143. }
  1144. $packet = pack('CNa*',
  1145. NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth'
  1146. );
  1147. if (!$this->_send_binary_packet($packet)) {
  1148. return false;
  1149. }
  1150. $response = $this->_get_binary_packet();
  1151. if ($response === false) {
  1152. user_error('Connection closed by server', E_USER_NOTICE);
  1153. return false;
  1154. }
  1155. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1156. if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
  1157. user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE);
  1158. return false;
  1159. }
  1160. // although PHP5's get_class() preserves the case, PHP4's does not
  1161. if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') {
  1162. return $this->_privatekey_login($username, $password);
  1163. }
  1164. $utf8_password = utf8_encode($password);
  1165. $packet = pack('CNa*Na*Na*CNa*',
  1166. NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
  1167. strlen('password'), 'password', 0, strlen($utf8_password), $utf8_password
  1168. );
  1169. if (!$this->_send_binary_packet($packet)) {
  1170. return false;
  1171. }
  1172. // remove the username and password from the last logged packet
  1173. if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
  1174. $packet = pack('CNa*Na*Na*CNa*',
  1175. NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection',
  1176. strlen('password'), 'password', 0, strlen('password'), 'password'
  1177. );
  1178. $this->message_log[count($this->message_log) - 1] = $packet;
  1179. }
  1180. $response = $this->_get_binary_packet();
  1181. if ($response === false) {
  1182. user_error('Connection closed by server', E_USER_NOTICE);
  1183. return false;
  1184. }
  1185. extract(unpack('Ctype', $this->_string_shift($response, 1)));
  1186. switch ($type) {
  1187. case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
  1188. if (defined('NET_SSH2_LOGGING')) {
  1189. $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
  1190. }
  1191. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  1192. $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length));
  1193. return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
  1194. case NET_SSH2_MSG_USERAUTH_FAILURE:
  1195. // can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
  1196. // multi-factor authentication
  1197. extract(unpack('Nlength', $this->_string_shift($response, 4)));
  1198. $auth_methods = explode(',', $this->_string_shift($response, $length));
  1199. if (in_array('keyboard-interactive', $auth_methods)) {
  1200. if ($this->_keyboard_interactive_login($username, $password)) {
  1201. $this->bitmap |= NET_SSH2_MASK_LOGIN;
  1202. return true;
  1203. }
  1204. return false;
  1205. }
  1206. return false;
  1207. case NET_SSH2_MSG_USERAUTH_SUCCESS:
  1208. $this->bitmap |= NET_SSH2_MASK_LOGIN;
  1209. return true;
  1210. }
  1211. return false;
  1212. }
  1213. /**
  1214. * Login via keyboard-interactive authentication
  1215. *
  1216. * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator.
  1217. *
  1218. * @param String $username
  1219. * @param String $password
  1220. * @return Boolean
  1221. * @access private
  1222. */
  1223. function _keyboard_interactive_login($username, $password)
  1224. {
  1225. $packet = pack('CNa*Na*Na*Na*Na*',
  1226. NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
  1227. strlen('keyboard-interactive'), 'keyboard-interactive', 0, '', 0, ''
  1228. );
  1229. if (!$this->_send_binary_packet($packet)) {
  1230. return false;
  1231. }
  1232. return $this->_keyboard_interactive_process($password);
  1233. }
  1234. /**
  1235. * Handle the keyboard-interactive requests / responses.
  1236. *
  1237. * @param String $responses...
  1238. * @return Boolean
  1239. * @access private
  1240. */
  1241. function _keyboard_int

Large files files are truncated, but you can click here to view the full file