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