From b799abd1a0c387590c2f58ee3e12a640412b6031 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Thu, 23 Mar 2023 12:38:39 -0500 Subject: [PATCH] SSH/SFTP: make message numbers / packet types static as well --- phpseclib/Net/SFTP.php | 314 +++++++++++++++++++++-------------------- phpseclib/Net/SSH2.php | 170 +++++++++++----------- 2 files changed, 244 insertions(+), 240 deletions(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index f02a321a..a157b665 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -93,7 +93,7 @@ class SFTP extends SSH2 * @var array * @access private */ - private $packet_types = []; + private static $packet_types = []; /** * Status Codes @@ -102,19 +102,19 @@ class SFTP extends SSH2 * @var array * @access private */ - private $status_codes = []; + private static $status_codes = []; /** @var array */ - private $attributes; + private static $attributes; /** @var array */ - private $open_flags; + private static $open_flags; /** @var array */ - private $open_flags5; + private static $open_flags5; /** @var array */ - private $file_types; + private static $file_types; /** * The Request ID @@ -360,154 +360,156 @@ class SFTP extends SSH2 $this->max_sftp_packet = 1 << 15; - $this->packet_types = [ - 1 => 'NET_SFTP_INIT', - 2 => 'NET_SFTP_VERSION', - 3 => 'NET_SFTP_OPEN', - 4 => 'NET_SFTP_CLOSE', - 5 => 'NET_SFTP_READ', - 6 => 'NET_SFTP_WRITE', - 7 => 'NET_SFTP_LSTAT', - 9 => 'NET_SFTP_SETSTAT', - 10 => 'NET_SFTP_FSETSTAT', - 11 => 'NET_SFTP_OPENDIR', - 12 => 'NET_SFTP_READDIR', - 13 => 'NET_SFTP_REMOVE', - 14 => 'NET_SFTP_MKDIR', - 15 => 'NET_SFTP_RMDIR', - 16 => 'NET_SFTP_REALPATH', - 17 => 'NET_SFTP_STAT', - 18 => 'NET_SFTP_RENAME', - 19 => 'NET_SFTP_READLINK', - 20 => 'NET_SFTP_SYMLINK', - 21 => 'NET_SFTP_LINK', + if (empty(self::$packet_types)) { + self::$packet_types = [ + 1 => 'NET_SFTP_INIT', + 2 => 'NET_SFTP_VERSION', + 3 => 'NET_SFTP_OPEN', + 4 => 'NET_SFTP_CLOSE', + 5 => 'NET_SFTP_READ', + 6 => 'NET_SFTP_WRITE', + 7 => 'NET_SFTP_LSTAT', + 9 => 'NET_SFTP_SETSTAT', + 10 => 'NET_SFTP_FSETSTAT', + 11 => 'NET_SFTP_OPENDIR', + 12 => 'NET_SFTP_READDIR', + 13 => 'NET_SFTP_REMOVE', + 14 => 'NET_SFTP_MKDIR', + 15 => 'NET_SFTP_RMDIR', + 16 => 'NET_SFTP_REALPATH', + 17 => 'NET_SFTP_STAT', + 18 => 'NET_SFTP_RENAME', + 19 => 'NET_SFTP_READLINK', + 20 => 'NET_SFTP_SYMLINK', + 21 => 'NET_SFTP_LINK', - 101 => 'NET_SFTP_STATUS', - 102 => 'NET_SFTP_HANDLE', - 103 => 'NET_SFTP_DATA', - 104 => 'NET_SFTP_NAME', - 105 => 'NET_SFTP_ATTRS', + 101 => 'NET_SFTP_STATUS', + 102 => 'NET_SFTP_HANDLE', + 103 => 'NET_SFTP_DATA', + 104 => 'NET_SFTP_NAME', + 105 => 'NET_SFTP_ATTRS', - 200 => 'NET_SFTP_EXTENDED' - ]; - $this->status_codes = [ - 0 => 'NET_SFTP_STATUS_OK', - 1 => 'NET_SFTP_STATUS_EOF', - 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE', - 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED', - 4 => 'NET_SFTP_STATUS_FAILURE', - 5 => 'NET_SFTP_STATUS_BAD_MESSAGE', - 6 => 'NET_SFTP_STATUS_NO_CONNECTION', - 7 => 'NET_SFTP_STATUS_CONNECTION_LOST', - 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED', - 9 => 'NET_SFTP_STATUS_INVALID_HANDLE', - 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH', - 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS', - 12 => 'NET_SFTP_STATUS_WRITE_PROTECT', - 13 => 'NET_SFTP_STATUS_NO_MEDIA', - 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM', - 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED', - 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL', - 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT', - 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY', - 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY', - 20 => 'NET_SFTP_STATUS_INVALID_FILENAME', - 21 => 'NET_SFTP_STATUS_LINK_LOOP', - 22 => 'NET_SFTP_STATUS_CANNOT_DELETE', - 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER', - 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY', - 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT', - 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED', - 27 => 'NET_SFTP_STATUS_DELETE_PENDING', - 28 => 'NET_SFTP_STATUS_FILE_CORRUPT', - 29 => 'NET_SFTP_STATUS_OWNER_INVALID', - 30 => 'NET_SFTP_STATUS_GROUP_INVALID', - 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK' - ]; - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1 - // the order, in this case, matters quite a lot - see \phpseclib3\Net\SFTP::_parseAttributes() to understand why - $this->attributes = [ - 0x00000001 => 'NET_SFTP_ATTR_SIZE', - 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+ - 0x00000080 => 'NET_SFTP_ATTR_OWNERGROUP', // defined in SFTPv4+ - 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS', - 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME', - 0x00000010 => 'NET_SFTP_ATTR_CREATETIME', // SFTPv4+ - 0x00000020 => 'NET_SFTP_ATTR_MODIFYTIME', - 0x00000040 => 'NET_SFTP_ATTR_ACL', - 0x00000100 => 'NET_SFTP_ATTR_SUBSECOND_TIMES', - 0x00000200 => 'NET_SFTP_ATTR_BITS', // SFTPv5+ - 0x00000400 => 'NET_SFTP_ATTR_ALLOCATION_SIZE', // SFTPv6+ - 0x00000800 => 'NET_SFTP_ATTR_TEXT_HINT', - 0x00001000 => 'NET_SFTP_ATTR_MIME_TYPE', - 0x00002000 => 'NET_SFTP_ATTR_LINK_COUNT', - 0x00004000 => 'NET_SFTP_ATTR_UNTRANSLATED_NAME', - 0x00008000 => 'NET_SFTP_ATTR_CTIME', - // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers - // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in - // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000. - // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored. - (PHP_INT_SIZE == 4 ? -1 : 0xFFFFFFFF) => 'NET_SFTP_ATTR_EXTENDED' - ]; - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 - // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name - // the array for that $this->open5_flags and similarly alter the constant names. - $this->open_flags = [ - 0x00000001 => 'NET_SFTP_OPEN_READ', - 0x00000002 => 'NET_SFTP_OPEN_WRITE', - 0x00000004 => 'NET_SFTP_OPEN_APPEND', - 0x00000008 => 'NET_SFTP_OPEN_CREATE', - 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE', - 0x00000020 => 'NET_SFTP_OPEN_EXCL', - 0x00000040 => 'NET_SFTP_OPEN_TEXT' // defined in SFTPv4 - ]; - // SFTPv5+ changed the flags up: - // https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-8.1.1.3 - $this->open_flags5 = [ - // when SSH_FXF_ACCESS_DISPOSITION is a 3 bit field that controls how the file is opened - 0x00000000 => 'NET_SFTP_OPEN_CREATE_NEW', - 0x00000001 => 'NET_SFTP_OPEN_CREATE_TRUNCATE', - 0x00000002 => 'NET_SFTP_OPEN_OPEN_EXISTING', - 0x00000003 => 'NET_SFTP_OPEN_OPEN_OR_CREATE', - 0x00000004 => 'NET_SFTP_OPEN_TRUNCATE_EXISTING', - // the rest of the flags are not supported - 0x00000008 => 'NET_SFTP_OPEN_APPEND_DATA', // "the offset field of SS_FXP_WRITE requests is ignored" - 0x00000010 => 'NET_SFTP_OPEN_APPEND_DATA_ATOMIC', - 0x00000020 => 'NET_SFTP_OPEN_TEXT_MODE', - 0x00000040 => 'NET_SFTP_OPEN_BLOCK_READ', - 0x00000080 => 'NET_SFTP_OPEN_BLOCK_WRITE', - 0x00000100 => 'NET_SFTP_OPEN_BLOCK_DELETE', - 0x00000200 => 'NET_SFTP_OPEN_BLOCK_ADVISORY', - 0x00000400 => 'NET_SFTP_OPEN_NOFOLLOW', - 0x00000800 => 'NET_SFTP_OPEN_DELETE_ON_CLOSE', - 0x00001000 => 'NET_SFTP_OPEN_ACCESS_AUDIT_ALARM_INFO', - 0x00002000 => 'NET_SFTP_OPEN_ACCESS_BACKUP', - 0x00004000 => 'NET_SFTP_OPEN_BACKUP_STREAM', - 0x00008000 => 'NET_SFTP_OPEN_OVERRIDE_OWNER', - ]; - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 - // see \phpseclib3\Net\SFTP::_parseLongname() for an explanation - $this->file_types = [ - 1 => 'NET_SFTP_TYPE_REGULAR', - 2 => 'NET_SFTP_TYPE_DIRECTORY', - 3 => 'NET_SFTP_TYPE_SYMLINK', - 4 => 'NET_SFTP_TYPE_SPECIAL', - 5 => 'NET_SFTP_TYPE_UNKNOWN', - // the following types were first defined for use in SFTPv5+ - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2 - 6 => 'NET_SFTP_TYPE_SOCKET', - 7 => 'NET_SFTP_TYPE_CHAR_DEVICE', - 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE', - 9 => 'NET_SFTP_TYPE_FIFO' - ]; - self::define_array( - $this->packet_types, - $this->status_codes, - $this->attributes, - $this->open_flags, - $this->open_flags5, - $this->file_types - ); + 200 => 'NET_SFTP_EXTENDED' + ]; + self::$status_codes = [ + 0 => 'NET_SFTP_STATUS_OK', + 1 => 'NET_SFTP_STATUS_EOF', + 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE', + 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED', + 4 => 'NET_SFTP_STATUS_FAILURE', + 5 => 'NET_SFTP_STATUS_BAD_MESSAGE', + 6 => 'NET_SFTP_STATUS_NO_CONNECTION', + 7 => 'NET_SFTP_STATUS_CONNECTION_LOST', + 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED', + 9 => 'NET_SFTP_STATUS_INVALID_HANDLE', + 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH', + 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS', + 12 => 'NET_SFTP_STATUS_WRITE_PROTECT', + 13 => 'NET_SFTP_STATUS_NO_MEDIA', + 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM', + 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED', + 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL', + 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT', + 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY', + 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY', + 20 => 'NET_SFTP_STATUS_INVALID_FILENAME', + 21 => 'NET_SFTP_STATUS_LINK_LOOP', + 22 => 'NET_SFTP_STATUS_CANNOT_DELETE', + 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER', + 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY', + 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT', + 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED', + 27 => 'NET_SFTP_STATUS_DELETE_PENDING', + 28 => 'NET_SFTP_STATUS_FILE_CORRUPT', + 29 => 'NET_SFTP_STATUS_OWNER_INVALID', + 30 => 'NET_SFTP_STATUS_GROUP_INVALID', + 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK' + ]; + // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1 + // the order, in this case, matters quite a lot - see \phpseclib3\Net\SFTP::_parseAttributes() to understand why + self::$attributes = [ + 0x00000001 => 'NET_SFTP_ATTR_SIZE', + 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+ + 0x00000080 => 'NET_SFTP_ATTR_OWNERGROUP', // defined in SFTPv4+ + 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS', + 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME', + 0x00000010 => 'NET_SFTP_ATTR_CREATETIME', // SFTPv4+ + 0x00000020 => 'NET_SFTP_ATTR_MODIFYTIME', + 0x00000040 => 'NET_SFTP_ATTR_ACL', + 0x00000100 => 'NET_SFTP_ATTR_SUBSECOND_TIMES', + 0x00000200 => 'NET_SFTP_ATTR_BITS', // SFTPv5+ + 0x00000400 => 'NET_SFTP_ATTR_ALLOCATION_SIZE', // SFTPv6+ + 0x00000800 => 'NET_SFTP_ATTR_TEXT_HINT', + 0x00001000 => 'NET_SFTP_ATTR_MIME_TYPE', + 0x00002000 => 'NET_SFTP_ATTR_LINK_COUNT', + 0x00004000 => 'NET_SFTP_ATTR_UNTRANSLATED_NAME', + 0x00008000 => 'NET_SFTP_ATTR_CTIME', + // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers + // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in + // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000. + // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored. + (PHP_INT_SIZE == 4 ? -1 : 0xFFFFFFFF) => 'NET_SFTP_ATTR_EXTENDED' + ]; + // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 + // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name + // the array for that $this->open5_flags and similarly alter the constant names. + self::$open_flags = [ + 0x00000001 => 'NET_SFTP_OPEN_READ', + 0x00000002 => 'NET_SFTP_OPEN_WRITE', + 0x00000004 => 'NET_SFTP_OPEN_APPEND', + 0x00000008 => 'NET_SFTP_OPEN_CREATE', + 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE', + 0x00000020 => 'NET_SFTP_OPEN_EXCL', + 0x00000040 => 'NET_SFTP_OPEN_TEXT' // defined in SFTPv4 + ]; + // SFTPv5+ changed the flags up: + // https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-8.1.1.3 + self::$open_flags5 = [ + // when SSH_FXF_ACCESS_DISPOSITION is a 3 bit field that controls how the file is opened + 0x00000000 => 'NET_SFTP_OPEN_CREATE_NEW', + 0x00000001 => 'NET_SFTP_OPEN_CREATE_TRUNCATE', + 0x00000002 => 'NET_SFTP_OPEN_OPEN_EXISTING', + 0x00000003 => 'NET_SFTP_OPEN_OPEN_OR_CREATE', + 0x00000004 => 'NET_SFTP_OPEN_TRUNCATE_EXISTING', + // the rest of the flags are not supported + 0x00000008 => 'NET_SFTP_OPEN_APPEND_DATA', // "the offset field of SS_FXP_WRITE requests is ignored" + 0x00000010 => 'NET_SFTP_OPEN_APPEND_DATA_ATOMIC', + 0x00000020 => 'NET_SFTP_OPEN_TEXT_MODE', + 0x00000040 => 'NET_SFTP_OPEN_BLOCK_READ', + 0x00000080 => 'NET_SFTP_OPEN_BLOCK_WRITE', + 0x00000100 => 'NET_SFTP_OPEN_BLOCK_DELETE', + 0x00000200 => 'NET_SFTP_OPEN_BLOCK_ADVISORY', + 0x00000400 => 'NET_SFTP_OPEN_NOFOLLOW', + 0x00000800 => 'NET_SFTP_OPEN_DELETE_ON_CLOSE', + 0x00001000 => 'NET_SFTP_OPEN_ACCESS_AUDIT_ALARM_INFO', + 0x00002000 => 'NET_SFTP_OPEN_ACCESS_BACKUP', + 0x00004000 => 'NET_SFTP_OPEN_BACKUP_STREAM', + 0x00008000 => 'NET_SFTP_OPEN_OVERRIDE_OWNER', + ]; + // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 + // see \phpseclib3\Net\SFTP::_parseLongname() for an explanation + self::$file_types = [ + 1 => 'NET_SFTP_TYPE_REGULAR', + 2 => 'NET_SFTP_TYPE_DIRECTORY', + 3 => 'NET_SFTP_TYPE_SYMLINK', + 4 => 'NET_SFTP_TYPE_SPECIAL', + 5 => 'NET_SFTP_TYPE_UNKNOWN', + // the following types were first defined for use in SFTPv5+ + // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2 + 6 => 'NET_SFTP_TYPE_SOCKET', + 7 => 'NET_SFTP_TYPE_CHAR_DEVICE', + 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE', + 9 => 'NET_SFTP_TYPE_FIFO' + ]; + self::define_array( + self::$packet_types, + self::$status_codes, + self::$attributes, + self::$open_flags, + self::$open_flags5, + self::$file_types + ); + } if (!defined('NET_SFTP_QUEUE_SIZE')) { define('NET_SFTP_QUEUE_SIZE', 32); @@ -815,7 +817,7 @@ class SFTP extends SSH2 list($status) = Strings::unpackSSH2('N', $response); } - $error = $this->status_codes[$status]; + $error = self::$status_codes[$status]; if ($this->version > 2) { list($message) = Strings::unpackSSH2('s', $response); @@ -3041,7 +3043,7 @@ class SFTP extends SSH2 list($flags) = Strings::unpackSSH2('N', $response); } - foreach ($this->attributes as $key => $value) { + foreach (self::$attributes as $key => $value) { switch ($flags & $key) { case NET_SFTP_ATTR_UIDGID: if ($this->version > 3) { @@ -3272,7 +3274,7 @@ class SFTP extends SSH2 $stop = microtime(true); if (defined('NET_SFTP_LOGGING')) { - $packet_type = '-> ' . $this->packet_types[$type] . + $packet_type = '-> ' . self::$packet_types[$type] . ' (' . round($stop - $start, 4) . 's)'; $this->append_log($packet_type, $data); } @@ -3376,7 +3378,7 @@ class SFTP extends SSH2 $packet = Strings::shift($this->packet_buffer, $length); if (defined('NET_SFTP_LOGGING')) { - $packet_type = '<- ' . $this->packet_types[$this->packet_type] . + $packet_type = '<- ' . self::$packet_types[$this->packet_type] . ' (' . round($stop - $start, 4) . 's)'; $this->append_log($packet_type, $packet); } diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 91af6098..19d52576 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -553,7 +553,7 @@ class SSH2 * @var array * @access private */ - private $message_numbers = []; + private static $message_numbers = []; /** * Disconnection Message 'reason codes' defined in RFC4253 @@ -562,7 +562,7 @@ class SSH2 * @var array * @access private */ - private $disconnect_reasons = []; + private static $disconnect_reasons = []; /** * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254 @@ -571,7 +571,7 @@ class SSH2 * @var array * @access private */ - private $channel_open_failure_reasons = []; + private static $channel_open_failure_reasons = []; /** * Terminal Modes @@ -581,7 +581,7 @@ class SSH2 * @var array * @access private */ - private $terminal_modes = []; + private static $terminal_modes = []; /** * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes @@ -591,7 +591,7 @@ class SSH2 * @var array * @access private */ - private $channel_extended_data_type_codes = []; + private static $channel_extended_data_type_codes = []; /** * Send Sequence Number @@ -1099,84 +1099,86 @@ class SSH2 */ public function __construct($host, $port = 22, $timeout = 10) { - $this->message_numbers = [ - 1 => 'NET_SSH2_MSG_DISCONNECT', - 2 => 'NET_SSH2_MSG_IGNORE', - 3 => 'NET_SSH2_MSG_UNIMPLEMENTED', - 4 => 'NET_SSH2_MSG_DEBUG', - 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', - 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', - 20 => 'NET_SSH2_MSG_KEXINIT', - 21 => 'NET_SSH2_MSG_NEWKEYS', - 30 => 'NET_SSH2_MSG_KEXDH_INIT', - 31 => 'NET_SSH2_MSG_KEXDH_REPLY', - 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST', - 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE', - 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS', - 53 => 'NET_SSH2_MSG_USERAUTH_BANNER', + if (empty(self::$message_numbers)) { + self::$message_numbers = [ + 1 => 'NET_SSH2_MSG_DISCONNECT', + 2 => 'NET_SSH2_MSG_IGNORE', + 3 => 'NET_SSH2_MSG_UNIMPLEMENTED', + 4 => 'NET_SSH2_MSG_DEBUG', + 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', + 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', + 20 => 'NET_SSH2_MSG_KEXINIT', + 21 => 'NET_SSH2_MSG_NEWKEYS', + 30 => 'NET_SSH2_MSG_KEXDH_INIT', + 31 => 'NET_SSH2_MSG_KEXDH_REPLY', + 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST', + 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE', + 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS', + 53 => 'NET_SSH2_MSG_USERAUTH_BANNER', - 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST', - 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS', - 82 => 'NET_SSH2_MSG_REQUEST_FAILURE', - 90 => 'NET_SSH2_MSG_CHANNEL_OPEN', - 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION', - 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE', - 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST', - 94 => 'NET_SSH2_MSG_CHANNEL_DATA', - 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA', - 96 => 'NET_SSH2_MSG_CHANNEL_EOF', - 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE', - 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST', - 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS', - 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE' - ]; - $this->disconnect_reasons = [ - 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT', - 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR', - 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED', - 4 => 'NET_SSH2_DISCONNECT_RESERVED', - 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR', - 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR', - 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE', - 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED', - 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE', - 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST', - 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION', - 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS', - 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER', - 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE', - 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' - ]; - $this->channel_open_failure_reasons = [ - 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' - ]; - $this->terminal_modes = [ - 0 => 'NET_SSH2_TTY_OP_END' - ]; - $this->channel_extended_data_type_codes = [ - 1 => 'NET_SSH2_EXTENDED_DATA_STDERR' - ]; + 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST', + 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS', + 82 => 'NET_SSH2_MSG_REQUEST_FAILURE', + 90 => 'NET_SSH2_MSG_CHANNEL_OPEN', + 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION', + 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE', + 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST', + 94 => 'NET_SSH2_MSG_CHANNEL_DATA', + 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA', + 96 => 'NET_SSH2_MSG_CHANNEL_EOF', + 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE', + 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST', + 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS', + 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE' + ]; + self::$disconnect_reasons = [ + 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT', + 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR', + 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED', + 4 => 'NET_SSH2_DISCONNECT_RESERVED', + 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR', + 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR', + 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE', + 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED', + 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE', + 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST', + 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION', + 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS', + 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER', + 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE', + 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' + ]; + self::$channel_open_failure_reasons = [ + 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' + ]; + self::$terminal_modes = [ + 0 => 'NET_SSH2_TTY_OP_END' + ]; + self::$channel_extended_data_type_codes = [ + 1 => 'NET_SSH2_EXTENDED_DATA_STDERR' + ]; - self::define_array( - $this->message_numbers, - $this->disconnect_reasons, - $this->channel_open_failure_reasons, - $this->terminal_modes, - $this->channel_extended_data_type_codes, - [60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'], - [60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'], - [60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', - 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'], - // RFC 4419 - diffie-hellman-group-exchange-sha{1,256} - [30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD', - 31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP', - 32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT', - 33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY', - 34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST'], - // RFC 5656 - Elliptic Curves (for curve25519-sha256@libssh.org) - [30 => 'NET_SSH2_MSG_KEX_ECDH_INIT', - 31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY'] - ); + self::define_array( + self::$message_numbers, + self::$disconnect_reasons, + self::$channel_open_failure_reasons, + self::$terminal_modes, + self::$channel_extended_data_type_codes, + [60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'], + [60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'], + [60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', + 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'], + // RFC 4419 - diffie-hellman-group-exchange-sha{1,256} + [30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD', + 31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP', + 32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT', + 33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY', + 34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST'], + // RFC 5656 - Elliptic Curves (for curve25519-sha256@libssh.org) + [30 => 'NET_SSH2_MSG_KEX_ECDH_INIT', + 31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY'] + ); + } /** * Typehint is required due to a bug in Psalm: https://github.com/vimeo/psalm/issues/7508 @@ -3600,7 +3602,7 @@ class SSH2 if (defined('NET_SSH2_LOGGING')) { $current = microtime(true); - $message_number = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')'; + $message_number = isset(self::$message_numbers[ord($payload[0])]) ? self::$message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')'; $message_number = '<- ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; $this->append_log($message_number, $payload); @@ -3682,7 +3684,7 @@ class SSH2 case NET_SSH2_MSG_DISCONNECT: Strings::shift($payload, 1); list($reason_code, $message) = Strings::unpackSSH2('Ns', $payload); - $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n$message"; + $this->errors[] = 'SSH_MSG_DISCONNECT: ' . static::$disconnect_reasons[$reason_code] . "\r\n$message"; $this->bitmap = 0; return false; case NET_SSH2_MSG_IGNORE: @@ -4255,7 +4257,7 @@ class SSH2 if (defined('NET_SSH2_LOGGING')) { $current = microtime(true); - $message_number = isset($this->message_numbers[ord($logged[0])]) ? $this->message_numbers[ord($logged[0])] : 'UNKNOWN (' . ord($logged[0]) . ')'; + $message_number = isset(self::$message_numbers[ord($logged[0])]) ? self::$message_numbers[ord($logged[0])] : 'UNKNOWN (' . ord($logged[0]) . ')'; $message_number = '-> ' . $message_number . ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)'; $this->append_log($message_number, $logged);