bdy 1.23.6-dev → 1.23.7-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/distTs/package.json +10 -2
  2. package/distTs/src/agent/linux.js +53 -3
  3. package/distTs/src/agent/manager.js +3 -6
  4. package/distTs/src/agent/osx.js +51 -3
  5. package/distTs/src/agent/system.js +400 -21
  6. package/distTs/src/agent/windows.js +4 -7
  7. package/distTs/src/command/agent/debug.js +2 -2
  8. package/distTs/src/command/agent/install.js +37 -10
  9. package/distTs/src/command/agent/restart.js +2 -2
  10. package/distTs/src/command/agent/run.js +3 -0
  11. package/distTs/src/command/agent/start.js +2 -2
  12. package/distTs/src/command/agent/status.js +19 -0
  13. package/distTs/src/command/agent/stop.js +2 -2
  14. package/distTs/src/command/agent/uninstall.js +5 -8
  15. package/distTs/src/command/agent/update.js +2 -2
  16. package/distTs/src/command/artifact/publish.js +3 -1
  17. package/distTs/src/command/version.js +13 -5
  18. package/distTs/src/logger.js +40 -4
  19. package/distTs/src/texts.js +35 -19
  20. package/distTs/src/utils.js +98 -3
  21. package/node_modules/asn1/Jenkinsfile +65 -0
  22. package/node_modules/asn1/LICENSE +19 -0
  23. package/node_modules/asn1/README.md +50 -0
  24. package/node_modules/asn1/lib/ber/errors.js +13 -0
  25. package/node_modules/asn1/lib/ber/index.js +27 -0
  26. package/node_modules/asn1/lib/ber/reader.js +262 -0
  27. package/node_modules/asn1/lib/ber/types.js +36 -0
  28. package/node_modules/asn1/lib/ber/writer.js +317 -0
  29. package/node_modules/asn1/lib/index.js +20 -0
  30. package/node_modules/asn1/package.json +31 -0
  31. package/node_modules/bcrypt-pbkdf/CONTRIBUTING.md +13 -0
  32. package/node_modules/bcrypt-pbkdf/LICENSE +66 -0
  33. package/node_modules/bcrypt-pbkdf/README.md +45 -0
  34. package/node_modules/bcrypt-pbkdf/index.js +556 -0
  35. package/node_modules/bcrypt-pbkdf/package.json +15 -0
  36. package/node_modules/safer-buffer/LICENSE +21 -0
  37. package/node_modules/safer-buffer/Porting-Buffer.md +268 -0
  38. package/node_modules/safer-buffer/Readme.md +156 -0
  39. package/node_modules/safer-buffer/dangerous.js +58 -0
  40. package/node_modules/safer-buffer/package.json +34 -0
  41. package/node_modules/safer-buffer/safer.js +77 -0
  42. package/node_modules/safer-buffer/tests.js +406 -0
  43. package/node_modules/ssh2/.eslintignore +4 -0
  44. package/node_modules/ssh2/.eslintrc.js +5 -0
  45. package/node_modules/ssh2/.github/workflows/ci.yml +110 -0
  46. package/node_modules/ssh2/.github/workflows/lint.yml +27 -0
  47. package/node_modules/ssh2/LICENSE +19 -0
  48. package/node_modules/ssh2/README.md +1529 -0
  49. package/node_modules/ssh2/SFTP.md +413 -0
  50. package/node_modules/ssh2/examples/server-chat.js +238 -0
  51. package/node_modules/ssh2/examples/sftp-server-download-only.js +134 -0
  52. package/node_modules/ssh2/install.js +27 -0
  53. package/node_modules/ssh2/lib/Channel.js +295 -0
  54. package/node_modules/ssh2/lib/agent.js +1123 -0
  55. package/node_modules/ssh2/lib/client.js +2176 -0
  56. package/node_modules/ssh2/lib/http-agents.js +84 -0
  57. package/node_modules/ssh2/lib/index.js +44 -0
  58. package/node_modules/ssh2/lib/keygen.js +582 -0
  59. package/node_modules/ssh2/lib/protocol/Protocol.js +2136 -0
  60. package/node_modules/ssh2/lib/protocol/SFTP.js +4052 -0
  61. package/node_modules/ssh2/lib/protocol/constants.js +356 -0
  62. package/node_modules/ssh2/lib/protocol/crypto/binding.gyp +23 -0
  63. package/node_modules/ssh2/lib/protocol/crypto/poly1305.js +43 -0
  64. package/node_modules/ssh2/lib/protocol/crypto/src/binding.cc +2300 -0
  65. package/node_modules/ssh2/lib/protocol/crypto.js +1602 -0
  66. package/node_modules/ssh2/lib/protocol/handlers.js +16 -0
  67. package/node_modules/ssh2/lib/protocol/handlers.misc.js +1285 -0
  68. package/node_modules/ssh2/lib/protocol/kex.js +1908 -0
  69. package/node_modules/ssh2/lib/protocol/keyParser.js +1484 -0
  70. package/node_modules/ssh2/lib/protocol/node-fs-compat.js +115 -0
  71. package/node_modules/ssh2/lib/protocol/utils.js +356 -0
  72. package/node_modules/ssh2/lib/protocol/zlib.js +255 -0
  73. package/node_modules/ssh2/lib/server.js +1380 -0
  74. package/node_modules/ssh2/lib/utils.js +336 -0
  75. package/node_modules/ssh2/package.json +49 -0
  76. package/node_modules/ssh2/test/common.js +316 -0
  77. package/node_modules/ssh2/test/fixtures/bad_rsa_private_key +26 -0
  78. package/node_modules/ssh2/test/fixtures/https_cert.pem +33 -0
  79. package/node_modules/ssh2/test/fixtures/https_key.pem +52 -0
  80. package/node_modules/ssh2/test/fixtures/id_dsa +12 -0
  81. package/node_modules/ssh2/test/fixtures/id_ecdsa +5 -0
  82. package/node_modules/ssh2/test/fixtures/id_rsa +15 -0
  83. package/node_modules/ssh2/test/fixtures/id_rsa.ppk +26 -0
  84. package/node_modules/ssh2/test/fixtures/id_rsa_enc +30 -0
  85. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa +21 -0
  86. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub +1 -0
  87. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.pub.result +7 -0
  88. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa.result +7 -0
  89. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc +22 -0
  90. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub +1 -0
  91. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.pub.result +7 -0
  92. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc.result +7 -0
  93. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm +23 -0
  94. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub +1 -0
  95. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.pub.result +7 -0
  96. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_dsa_enc_gcm.result +7 -0
  97. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa +9 -0
  98. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub +1 -0
  99. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.pub.result +7 -0
  100. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa.result +7 -0
  101. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc +10 -0
  102. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub +1 -0
  103. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.pub.result +8 -0
  104. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc.result +7 -0
  105. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm +10 -0
  106. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub +1 -0
  107. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.pub.result +8 -0
  108. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ecdsa_enc_gcm.result +7 -0
  109. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519 +7 -0
  110. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub +1 -0
  111. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.pub.result +7 -0
  112. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_ed25519.result +7 -0
  113. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa +27 -0
  114. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub +1 -0
  115. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.pub.result +7 -0
  116. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa.result +7 -0
  117. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc +28 -0
  118. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub +1 -0
  119. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.pub.result +8 -0
  120. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc.result +7 -0
  121. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm +29 -0
  122. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub +1 -0
  123. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.pub.result +8 -0
  124. package/node_modules/ssh2/test/fixtures/keyParser/openssh_new_rsa_enc_gcm.result +7 -0
  125. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa +12 -0
  126. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub +1 -0
  127. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.pub.result +7 -0
  128. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa.result +7 -0
  129. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc +15 -0
  130. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub +1 -0
  131. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.pub.result +8 -0
  132. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_dsa_enc.result +7 -0
  133. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa +5 -0
  134. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub +1 -0
  135. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.pub.result +7 -0
  136. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa.result +7 -0
  137. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc +8 -0
  138. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub +1 -0
  139. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.pub.result +8 -0
  140. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_ecdsa_enc.result +7 -0
  141. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa +27 -0
  142. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub +1 -0
  143. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.pub.result +7 -0
  144. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa.result +7 -0
  145. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc +30 -0
  146. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub +1 -0
  147. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.pub.result +8 -0
  148. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc.result +7 -0
  149. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256 +54 -0
  150. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub +1 -0
  151. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.pub.result +6 -0
  152. package/node_modules/ssh2/test/fixtures/keyParser/openssh_old_rsa_enc_aes256.result +6 -0
  153. package/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc +17 -0
  154. package/node_modules/ssh2/test/fixtures/keyParser/ppk_dsa_enc.result +7 -0
  155. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa +26 -0
  156. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa.result +7 -0
  157. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc +18 -0
  158. package/node_modules/ssh2/test/fixtures/keyParser/ppk_rsa_enc.result +7 -0
  159. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub +9 -0
  160. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa.pub.result +7 -0
  161. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub +10 -0
  162. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa2.pub.result +7 -0
  163. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub +11 -0
  164. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa3.pub.result +7 -0
  165. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub +11 -0
  166. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa4.pub.result +7 -0
  167. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub +8 -0
  168. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa5.pub.result +7 -0
  169. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub +13 -0
  170. package/node_modules/ssh2/test/fixtures/keyParser/rfc4716_rsa6.pub.result +7 -0
  171. package/node_modules/ssh2/test/fixtures/openssh_new_rsa +27 -0
  172. package/node_modules/ssh2/test/fixtures/ssh_host_dsa_key +12 -0
  173. package/node_modules/ssh2/test/fixtures/ssh_host_ecdsa_key +5 -0
  174. package/node_modules/ssh2/test/fixtures/ssh_host_rsa_key +15 -0
  175. package/node_modules/ssh2/test/test-exec.js +578 -0
  176. package/node_modules/ssh2/test/test-integration-openssh.js +486 -0
  177. package/node_modules/ssh2/test/test-keygen.js +60 -0
  178. package/node_modules/ssh2/test/test-misc-client-server.js +1460 -0
  179. package/node_modules/ssh2/test/test-openssh.js +261 -0
  180. package/node_modules/ssh2/test/test-protocol-crypto.js +631 -0
  181. package/node_modules/ssh2/test/test-protocol-keyparser.js +177 -0
  182. package/node_modules/ssh2/test/test-server-hostkeys.js +138 -0
  183. package/node_modules/ssh2/test/test-sftp.js +842 -0
  184. package/node_modules/ssh2/test/test-shell.js +109 -0
  185. package/node_modules/ssh2/test/test-userauth-agent-openssh.js +110 -0
  186. package/node_modules/ssh2/test/test-userauth-agent.js +171 -0
  187. package/node_modules/ssh2/test/test-userauth.js +611 -0
  188. package/node_modules/ssh2/test/test-worker-imports.js +25 -0
  189. package/node_modules/ssh2/test/test.js +20 -0
  190. package/node_modules/ssh2/util/build_pagent.bat +2 -0
  191. package/node_modules/ssh2/util/pagent.c +88 -0
  192. package/node_modules/ssh2/util/pagent.exe +0 -0
  193. package/node_modules/tweetnacl/.npmignore +4 -0
  194. package/node_modules/tweetnacl/AUTHORS.md +28 -0
  195. package/node_modules/tweetnacl/CHANGELOG.md +221 -0
  196. package/node_modules/tweetnacl/LICENSE +24 -0
  197. package/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md +20 -0
  198. package/node_modules/tweetnacl/README.md +459 -0
  199. package/node_modules/tweetnacl/nacl-fast.js +2388 -0
  200. package/node_modules/tweetnacl/nacl-fast.min.js +2 -0
  201. package/node_modules/tweetnacl/nacl.d.ts +98 -0
  202. package/node_modules/tweetnacl/nacl.js +1175 -0
  203. package/node_modules/tweetnacl/nacl.min.js +1 -0
  204. package/node_modules/tweetnacl/package.json +58 -0
  205. package/package.json +10 -2
@@ -0,0 +1,2136 @@
1
+ /*
2
+ TODO:
3
+ * Replace `buffer._pos` usage in keyParser.js and elsewhere
4
+ * Utilize optional "writev" support when writing packets from
5
+ cipher.encrypt()
6
+ * Built-in support for automatic re-keying, on by default
7
+ * Revisit receiving unexpected/unknown packets
8
+ * Error (fatal or otherwise) or ignore or pass on to user (in some or all
9
+ cases)?
10
+ * Including server/client check for single directional packet types?
11
+ * Check packets for validity or bail as early as possible?
12
+ * Automatic re-key every 2**31 packets after the last key exchange (sent or
13
+ received), as suggested by RFC4344. OpenSSH currently does this.
14
+ * Automatic re-key every so many blocks depending on cipher. RFC4344:
15
+ Because of a birthday property of block ciphers and some modes of
16
+ operation, implementations must be careful not to encrypt too many
17
+ blocks with the same encryption key.
18
+
19
+ Let L be the block length (in bits) of an SSH encryption method's
20
+ block cipher (e.g., 128 for AES). If L is at least 128, then, after
21
+ rekeying, an SSH implementation SHOULD NOT encrypt more than 2**(L/4)
22
+ blocks before rekeying again. If L is at least 128, then SSH
23
+ implementations should also attempt to force a rekey before receiving
24
+ more than 2**(L/4) blocks. If L is less than 128 (which is the case
25
+ for older ciphers such as 3DES, Blowfish, CAST-128, and IDEA), then,
26
+ although it may be too expensive to rekey every 2**(L/4) blocks, it
27
+ is still advisable for SSH implementations to follow the original
28
+ recommendation in [RFC4253]: rekey at least once for every gigabyte
29
+ of transmitted data.
30
+
31
+ Note that if L is less than or equal to 128, then the recommendation
32
+ in this subsection supersedes the recommendation in Section 3.1. If
33
+ an SSH implementation uses a block cipher with a larger block size
34
+ (e.g., Rijndael with 256-bit blocks), then the recommendations in
35
+ Section 3.1 may supersede the recommendations in this subsection
36
+ (depending on the lengths of the packets).
37
+ */
38
+
39
+ 'use strict';
40
+
41
+ const { inspect } = require('util');
42
+
43
+ const { bindingAvailable, NullCipher, NullDecipher } = require('./crypto.js');
44
+ const {
45
+ COMPAT_CHECKS,
46
+ DISCONNECT_REASON,
47
+ eddsaSupported,
48
+ MESSAGE,
49
+ SIGNALS,
50
+ TERMINAL_MODE,
51
+ } = require('./constants.js');
52
+ const {
53
+ DEFAULT_KEXINIT_CLIENT,
54
+ DEFAULT_KEXINIT_SERVER,
55
+ KexInit,
56
+ kexinit,
57
+ onKEXPayload,
58
+ } = require('./kex.js');
59
+ const {
60
+ parseKey,
61
+ } = require('./keyParser.js');
62
+ const MESSAGE_HANDLERS = require('./handlers.js');
63
+ const {
64
+ bufferCopy,
65
+ bufferFill,
66
+ bufferSlice,
67
+ convertSignature,
68
+ sendPacket,
69
+ writeUInt32BE,
70
+ } = require('./utils.js');
71
+ const {
72
+ PacketReader,
73
+ PacketWriter,
74
+ ZlibPacketReader,
75
+ ZlibPacketWriter,
76
+ } = require('./zlib.js');
77
+
78
+ const MODULE_VER = require('../../package.json').version;
79
+
80
+ const VALID_DISCONNECT_REASONS = new Map(
81
+ Object.values(DISCONNECT_REASON).map((n) => [n, 1])
82
+ );
83
+ const IDENT_RAW = Buffer.from(`SSH-2.0-ssh2js${MODULE_VER}`);
84
+ const IDENT = Buffer.from(`${IDENT_RAW}\r\n`);
85
+ const MAX_LINE_LEN = 8192;
86
+ const MAX_LINES = 1024;
87
+ const PING_PAYLOAD = Buffer.from([
88
+ MESSAGE.GLOBAL_REQUEST,
89
+ // "keepalive@openssh.com"
90
+ 0, 0, 0, 21,
91
+ 107, 101, 101, 112, 97, 108, 105, 118, 101, 64, 111, 112, 101, 110, 115,
92
+ 115, 104, 46, 99, 111, 109,
93
+ // Request a reply
94
+ 1,
95
+ ]);
96
+ const NO_TERMINAL_MODES_BUFFER = Buffer.from([ TERMINAL_MODE.TTY_OP_END ]);
97
+
98
+ function noop() {}
99
+
100
+ /*
101
+ Inbound:
102
+ * kexinit payload (needed only until exchange hash is generated)
103
+ * raw ident
104
+ * rekey packet queue
105
+ * expected packet (implemented as separate _parse() function?)
106
+ Outbound:
107
+ * kexinit payload (needed only until exchange hash is generated)
108
+ * rekey packet queue
109
+ * kex secret (needed only until NEWKEYS)
110
+ * exchange hash (needed only until NEWKEYS)
111
+ * session ID (set to exchange hash from initial handshake)
112
+ */
113
+ class Protocol {
114
+ constructor(config) {
115
+ const onWrite = config.onWrite;
116
+ if (typeof onWrite !== 'function')
117
+ throw new Error('Missing onWrite function');
118
+ this._onWrite = (data) => { onWrite(data); };
119
+
120
+ const onError = config.onError;
121
+ if (typeof onError !== 'function')
122
+ throw new Error('Missing onError function');
123
+ this._onError = (err) => { onError(err); };
124
+
125
+ const debug = config.debug;
126
+ this._debug = (typeof debug === 'function'
127
+ ? (msg) => { debug(msg); }
128
+ : undefined);
129
+
130
+ const onHeader = config.onHeader;
131
+ this._onHeader = (typeof onHeader === 'function'
132
+ ? (...args) => { onHeader(...args); }
133
+ : noop);
134
+
135
+ const onPacket = config.onPacket;
136
+ this._onPacket = (typeof onPacket === 'function'
137
+ ? () => { onPacket(); }
138
+ : noop);
139
+
140
+ let onHandshakeComplete = config.onHandshakeComplete;
141
+ if (typeof onHandshakeComplete !== 'function')
142
+ onHandshakeComplete = noop;
143
+ let firstHandshake;
144
+ this._onHandshakeComplete = (...args) => {
145
+ this._debug && this._debug('Handshake completed');
146
+ if (firstHandshake === undefined)
147
+ firstHandshake = true;
148
+ else
149
+ firstHandshake = false;
150
+
151
+ // Process packets queued during a rekey where necessary
152
+ const oldQueue = this._queue;
153
+ if (oldQueue) {
154
+ this._queue = undefined;
155
+ this._debug && this._debug(
156
+ `Draining outbound queue (${oldQueue.length}) ...`
157
+ );
158
+ for (let i = 0; i < oldQueue.length; ++i) {
159
+ const data = oldQueue[i];
160
+ // data === payload only
161
+
162
+ // XXX: hacky
163
+ let finalized = this._packetRW.write.finalize(data);
164
+ if (finalized === data) {
165
+ const packet = this._cipher.allocPacket(data.length);
166
+ packet.set(data, 5);
167
+ finalized = packet;
168
+ }
169
+
170
+ sendPacket(this, finalized);
171
+ }
172
+ this._debug && this._debug('... finished draining outbound queue');
173
+ }
174
+
175
+ if (firstHandshake && this._server && this._kex.remoteExtInfoEnabled)
176
+ sendExtInfo(this);
177
+
178
+ onHandshakeComplete(...args);
179
+ };
180
+ this._queue = undefined;
181
+
182
+ const messageHandlers = config.messageHandlers;
183
+ if (typeof messageHandlers === 'object' && messageHandlers !== null)
184
+ this._handlers = messageHandlers;
185
+ else
186
+ this._handlers = {};
187
+
188
+ this._onPayload = onPayload.bind(this);
189
+
190
+ this._server = !!config.server;
191
+ this._banner = undefined;
192
+ let greeting;
193
+ if (this._server) {
194
+ if (typeof config.hostKeys !== 'object' || config.hostKeys === null)
195
+ throw new Error('Missing server host key(s)');
196
+ this._hostKeys = config.hostKeys;
197
+
198
+ // Greeting displayed before the ssh identification string is sent, this
199
+ // is usually ignored by most clients
200
+ if (typeof config.greeting === 'string' && config.greeting.length) {
201
+ greeting = (config.greeting.slice(-2) === '\r\n'
202
+ ? config.greeting
203
+ : `${config.greeting}\r\n`);
204
+ }
205
+
206
+ // Banner shown after the handshake completes, but before user
207
+ // authentication begins
208
+ if (typeof config.banner === 'string' && config.banner.length) {
209
+ this._banner = (config.banner.slice(-2) === '\r\n'
210
+ ? config.banner
211
+ : `${config.banner}\r\n`);
212
+ }
213
+ } else {
214
+ this._hostKeys = undefined;
215
+ }
216
+
217
+ let offer = config.offer;
218
+ if (typeof offer !== 'object' || offer === null) {
219
+ offer = (this._server ? DEFAULT_KEXINIT_SERVER : DEFAULT_KEXINIT_CLIENT);
220
+ } else if (offer.constructor !== KexInit) {
221
+ if (this._server) {
222
+ offer.kex = offer.kex.concat(['kex-strict-s-v00@openssh.com']);
223
+ } else {
224
+ offer.kex = offer.kex.concat([
225
+ 'ext-info-c',
226
+ 'kex-strict-c-v00@openssh.com',
227
+ ]);
228
+ }
229
+ offer = new KexInit(offer);
230
+ }
231
+ this._kex = undefined;
232
+ this._strictMode = undefined;
233
+ this._kexinit = undefined;
234
+ this._offer = offer;
235
+ this._cipher = new NullCipher(0, this._onWrite);
236
+ this._decipher = undefined;
237
+ this._skipNextInboundPacket = false;
238
+ this._packetRW = {
239
+ read: new PacketReader(),
240
+ write: new PacketWriter(this),
241
+ };
242
+ this._hostVerifier = (!this._server
243
+ && typeof config.hostVerifier === 'function'
244
+ ? config.hostVerifier
245
+ : undefined);
246
+
247
+ this._parse = parseHeader;
248
+ this._buffer = undefined;
249
+ this._authsQueue = [];
250
+ this._authenticated = false;
251
+ this._remoteIdentRaw = undefined;
252
+ let sentIdent;
253
+ if (typeof config.ident === 'string') {
254
+ this._identRaw = Buffer.from(`SSH-2.0-${config.ident}`);
255
+
256
+ sentIdent = Buffer.allocUnsafe(this._identRaw.length + 2);
257
+ sentIdent.set(this._identRaw, 0);
258
+ sentIdent[sentIdent.length - 2] = 13; // '\r'
259
+ sentIdent[sentIdent.length - 1] = 10; // '\n'
260
+ } else if (Buffer.isBuffer(config.ident)) {
261
+ const fullIdent = Buffer.allocUnsafe(8 + config.ident.length);
262
+ fullIdent.latin1Write('SSH-2.0-', 0, 8);
263
+ fullIdent.set(config.ident, 8);
264
+ this._identRaw = fullIdent;
265
+
266
+ sentIdent = Buffer.allocUnsafe(fullIdent.length + 2);
267
+ sentIdent.set(fullIdent, 0);
268
+ sentIdent[sentIdent.length - 2] = 13; // '\r'
269
+ sentIdent[sentIdent.length - 1] = 10; // '\n'
270
+ } else {
271
+ this._identRaw = IDENT_RAW;
272
+ sentIdent = IDENT;
273
+ }
274
+ this._compatFlags = 0;
275
+
276
+ if (this._debug) {
277
+ if (bindingAvailable)
278
+ this._debug('Custom crypto binding available');
279
+ else
280
+ this._debug('Custom crypto binding not available');
281
+ }
282
+
283
+ this._debug && this._debug(
284
+ `Local ident: ${inspect(this._identRaw.toString())}`
285
+ );
286
+ this.start = () => {
287
+ this.start = undefined;
288
+ if (greeting)
289
+ this._onWrite(greeting);
290
+ this._onWrite(sentIdent);
291
+ };
292
+ }
293
+ _destruct(reason) {
294
+ this._packetRW.read.cleanup();
295
+ this._packetRW.write.cleanup();
296
+ this._cipher && this._cipher.free();
297
+ this._decipher && this._decipher.free();
298
+ if (typeof reason !== 'string' || reason.length === 0)
299
+ reason = 'fatal error';
300
+ this.parse = () => {
301
+ throw new Error(`Instance unusable after ${reason}`);
302
+ };
303
+ this._onWrite = () => {
304
+ throw new Error(`Instance unusable after ${reason}`);
305
+ };
306
+ this._destruct = undefined;
307
+ }
308
+ cleanup() {
309
+ this._destruct && this._destruct();
310
+ }
311
+ parse(chunk, i, len) {
312
+ while (i < len)
313
+ i = this._parse(chunk, i, len);
314
+ }
315
+
316
+ // Protocol message API
317
+
318
+ // ===========================================================================
319
+ // Common/Shared =============================================================
320
+ // ===========================================================================
321
+
322
+ // Global
323
+ // ------
324
+ disconnect(reason) {
325
+ const pktLen = 1 + 4 + 4 + 4;
326
+ // We don't use _packetRW.write.* here because we need to make sure that
327
+ // we always get a full packet allocated because this message can be sent
328
+ // at any time -- even during a key exchange
329
+ let p = this._packetRW.write.allocStartKEX;
330
+ const packet = this._packetRW.write.alloc(pktLen, true);
331
+ const end = p + pktLen;
332
+
333
+ if (!VALID_DISCONNECT_REASONS.has(reason))
334
+ reason = DISCONNECT_REASON.PROTOCOL_ERROR;
335
+
336
+ packet[p] = MESSAGE.DISCONNECT;
337
+ writeUInt32BE(packet, reason, ++p);
338
+ packet.fill(0, p += 4, end);
339
+
340
+ this._debug && this._debug(`Outbound: Sending DISCONNECT (${reason})`);
341
+ sendPacket(this, this._packetRW.write.finalize(packet, true), true);
342
+ }
343
+ ping() {
344
+ const p = this._packetRW.write.allocStart;
345
+ const packet = this._packetRW.write.alloc(PING_PAYLOAD.length);
346
+
347
+ packet.set(PING_PAYLOAD, p);
348
+
349
+ this._debug && this._debug(
350
+ 'Outbound: Sending ping (GLOBAL_REQUEST: keepalive@openssh.com)'
351
+ );
352
+ sendPacket(this, this._packetRW.write.finalize(packet));
353
+ }
354
+ rekey() {
355
+ if (this._kexinit === undefined) {
356
+ this._debug && this._debug('Outbound: Initiated explicit rekey');
357
+ this._queue = [];
358
+ kexinit(this);
359
+ } else {
360
+ this._debug && this._debug('Outbound: Ignoring rekey during handshake');
361
+ }
362
+ }
363
+
364
+ // 'ssh-connection' service-specific
365
+ // ---------------------------------
366
+ requestSuccess(data) {
367
+ let p = this._packetRW.write.allocStart;
368
+ let packet;
369
+ if (Buffer.isBuffer(data)) {
370
+ packet = this._packetRW.write.alloc(1 + data.length);
371
+
372
+ packet[p] = MESSAGE.REQUEST_SUCCESS;
373
+
374
+ packet.set(data, ++p);
375
+ } else {
376
+ packet = this._packetRW.write.alloc(1);
377
+
378
+ packet[p] = MESSAGE.REQUEST_SUCCESS;
379
+ }
380
+
381
+ this._debug && this._debug('Outbound: Sending REQUEST_SUCCESS');
382
+ sendPacket(this, this._packetRW.write.finalize(packet));
383
+ }
384
+ requestFailure() {
385
+ const p = this._packetRW.write.allocStart;
386
+ const packet = this._packetRW.write.alloc(1);
387
+
388
+ packet[p] = MESSAGE.REQUEST_FAILURE;
389
+
390
+ this._debug && this._debug('Outbound: Sending REQUEST_FAILURE');
391
+ sendPacket(this, this._packetRW.write.finalize(packet));
392
+ }
393
+ channelSuccess(chan) {
394
+ // Does not consume window space
395
+
396
+ let p = this._packetRW.write.allocStart;
397
+ const packet = this._packetRW.write.alloc(1 + 4);
398
+
399
+ packet[p] = MESSAGE.CHANNEL_SUCCESS;
400
+
401
+ writeUInt32BE(packet, chan, ++p);
402
+
403
+ this._debug && this._debug(`Outbound: Sending CHANNEL_SUCCESS (r:${chan})`);
404
+ sendPacket(this, this._packetRW.write.finalize(packet));
405
+ }
406
+ channelFailure(chan) {
407
+ // Does not consume window space
408
+
409
+ let p = this._packetRW.write.allocStart;
410
+ const packet = this._packetRW.write.alloc(1 + 4);
411
+
412
+ packet[p] = MESSAGE.CHANNEL_FAILURE;
413
+
414
+ writeUInt32BE(packet, chan, ++p);
415
+
416
+ this._debug && this._debug(`Outbound: Sending CHANNEL_FAILURE (r:${chan})`);
417
+ sendPacket(this, this._packetRW.write.finalize(packet));
418
+ }
419
+ channelEOF(chan) {
420
+ // Does not consume window space
421
+
422
+ let p = this._packetRW.write.allocStart;
423
+ const packet = this._packetRW.write.alloc(1 + 4);
424
+
425
+ packet[p] = MESSAGE.CHANNEL_EOF;
426
+
427
+ writeUInt32BE(packet, chan, ++p);
428
+
429
+ this._debug && this._debug(`Outbound: Sending CHANNEL_EOF (r:${chan})`);
430
+ sendPacket(this, this._packetRW.write.finalize(packet));
431
+ }
432
+ channelClose(chan) {
433
+ // Does not consume window space
434
+
435
+ let p = this._packetRW.write.allocStart;
436
+ const packet = this._packetRW.write.alloc(1 + 4);
437
+
438
+ packet[p] = MESSAGE.CHANNEL_CLOSE;
439
+
440
+ writeUInt32BE(packet, chan, ++p);
441
+
442
+ this._debug && this._debug(`Outbound: Sending CHANNEL_CLOSE (r:${chan})`);
443
+ sendPacket(this, this._packetRW.write.finalize(packet));
444
+ }
445
+ channelWindowAdjust(chan, amount) {
446
+ // Does not consume window space
447
+
448
+ let p = this._packetRW.write.allocStart;
449
+ const packet = this._packetRW.write.alloc(1 + 4 + 4);
450
+
451
+ packet[p] = MESSAGE.CHANNEL_WINDOW_ADJUST;
452
+
453
+ writeUInt32BE(packet, chan, ++p);
454
+
455
+ writeUInt32BE(packet, amount, p += 4);
456
+
457
+ this._debug && this._debug(
458
+ `Outbound: Sending CHANNEL_WINDOW_ADJUST (r:${chan}, ${amount})`
459
+ );
460
+ sendPacket(this, this._packetRW.write.finalize(packet));
461
+ }
462
+ channelData(chan, data) {
463
+ const isBuffer = Buffer.isBuffer(data);
464
+ const dataLen = (isBuffer ? data.length : Buffer.byteLength(data));
465
+ let p = this._packetRW.write.allocStart;
466
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + dataLen);
467
+
468
+ packet[p] = MESSAGE.CHANNEL_DATA;
469
+
470
+ writeUInt32BE(packet, chan, ++p);
471
+
472
+ writeUInt32BE(packet, dataLen, p += 4);
473
+
474
+ if (isBuffer)
475
+ packet.set(data, p += 4);
476
+ else
477
+ packet.utf8Write(data, p += 4, dataLen);
478
+
479
+ this._debug && this._debug(
480
+ `Outbound: Sending CHANNEL_DATA (r:${chan}, ${dataLen})`
481
+ );
482
+ sendPacket(this, this._packetRW.write.finalize(packet));
483
+ }
484
+ channelExtData(chan, data, type) {
485
+ const isBuffer = Buffer.isBuffer(data);
486
+ const dataLen = (isBuffer ? data.length : Buffer.byteLength(data));
487
+ let p = this._packetRW.write.allocStart;
488
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + 4 + dataLen);
489
+
490
+ packet[p] = MESSAGE.CHANNEL_EXTENDED_DATA;
491
+
492
+ writeUInt32BE(packet, chan, ++p);
493
+
494
+ writeUInt32BE(packet, type, p += 4);
495
+
496
+ writeUInt32BE(packet, dataLen, p += 4);
497
+
498
+ if (isBuffer)
499
+ packet.set(data, p += 4);
500
+ else
501
+ packet.utf8Write(data, p += 4, dataLen);
502
+
503
+ this._debug
504
+ && this._debug(`Outbound: Sending CHANNEL_EXTENDED_DATA (r:${chan})`);
505
+ sendPacket(this, this._packetRW.write.finalize(packet));
506
+ }
507
+ channelOpenConfirm(remote, local, initWindow, maxPacket) {
508
+ let p = this._packetRW.write.allocStart;
509
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + 4 + 4);
510
+
511
+ packet[p] = MESSAGE.CHANNEL_OPEN_CONFIRMATION;
512
+
513
+ writeUInt32BE(packet, remote, ++p);
514
+
515
+ writeUInt32BE(packet, local, p += 4);
516
+
517
+ writeUInt32BE(packet, initWindow, p += 4);
518
+
519
+ writeUInt32BE(packet, maxPacket, p += 4);
520
+
521
+ this._debug && this._debug(
522
+ `Outbound: Sending CHANNEL_OPEN_CONFIRMATION (r:${remote}, l:${local})`
523
+ );
524
+ sendPacket(this, this._packetRW.write.finalize(packet));
525
+ }
526
+ channelOpenFail(remote, reason, desc) {
527
+ if (typeof desc !== 'string')
528
+ desc = '';
529
+
530
+ const descLen = Buffer.byteLength(desc);
531
+ let p = this._packetRW.write.allocStart;
532
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + 4 + descLen + 4);
533
+
534
+ packet[p] = MESSAGE.CHANNEL_OPEN_FAILURE;
535
+
536
+ writeUInt32BE(packet, remote, ++p);
537
+
538
+ writeUInt32BE(packet, reason, p += 4);
539
+
540
+ writeUInt32BE(packet, descLen, p += 4);
541
+
542
+ p += 4;
543
+ if (descLen) {
544
+ packet.utf8Write(desc, p, descLen);
545
+ p += descLen;
546
+ }
547
+
548
+ writeUInt32BE(packet, 0, p); // Empty language tag
549
+
550
+ this._debug
551
+ && this._debug(`Outbound: Sending CHANNEL_OPEN_FAILURE (r:${remote})`);
552
+ sendPacket(this, this._packetRW.write.finalize(packet));
553
+ }
554
+
555
+ // ===========================================================================
556
+ // Client-specific ===========================================================
557
+ // ===========================================================================
558
+
559
+ // Global
560
+ // ------
561
+ service(name) {
562
+ if (this._server)
563
+ throw new Error('Client-only method called in server mode');
564
+
565
+ const nameLen = Buffer.byteLength(name);
566
+ let p = this._packetRW.write.allocStart;
567
+ const packet = this._packetRW.write.alloc(1 + 4 + nameLen);
568
+
569
+ packet[p] = MESSAGE.SERVICE_REQUEST;
570
+
571
+ writeUInt32BE(packet, nameLen, ++p);
572
+ packet.utf8Write(name, p += 4, nameLen);
573
+
574
+ this._debug && this._debug(`Outbound: Sending SERVICE_REQUEST (${name})`);
575
+ sendPacket(this, this._packetRW.write.finalize(packet));
576
+ }
577
+
578
+ // 'ssh-userauth' service-specific
579
+ // -------------------------------
580
+ authPassword(username, password, newPassword) {
581
+ if (this._server)
582
+ throw new Error('Client-only method called in server mode');
583
+
584
+ const userLen = Buffer.byteLength(username);
585
+ const passLen = Buffer.byteLength(password);
586
+ const newPassLen = (newPassword ? Buffer.byteLength(newPassword) : 0);
587
+ let p = this._packetRW.write.allocStart;
588
+ const packet = this._packetRW.write.alloc(
589
+ 1 + 4 + userLen + 4 + 14 + 4 + 8 + 1 + 4 + passLen
590
+ + (newPassword ? 4 + newPassLen : 0)
591
+ );
592
+
593
+ packet[p] = MESSAGE.USERAUTH_REQUEST;
594
+
595
+ writeUInt32BE(packet, userLen, ++p);
596
+ packet.utf8Write(username, p += 4, userLen);
597
+
598
+ writeUInt32BE(packet, 14, p += userLen);
599
+ packet.utf8Write('ssh-connection', p += 4, 14);
600
+
601
+ writeUInt32BE(packet, 8, p += 14);
602
+ packet.utf8Write('password', p += 4, 8);
603
+
604
+ packet[p += 8] = (newPassword ? 1 : 0);
605
+
606
+ writeUInt32BE(packet, passLen, ++p);
607
+ if (Buffer.isBuffer(password))
608
+ bufferCopy(password, packet, 0, passLen, p += 4);
609
+ else
610
+ packet.utf8Write(password, p += 4, passLen);
611
+
612
+ if (newPassword) {
613
+ writeUInt32BE(packet, newPassLen, p += passLen);
614
+ if (Buffer.isBuffer(newPassword))
615
+ bufferCopy(newPassword, packet, 0, newPassLen, p += 4);
616
+ else
617
+ packet.utf8Write(newPassword, p += 4, newPassLen);
618
+ this._debug && this._debug(
619
+ 'Outbound: Sending USERAUTH_REQUEST (changed password)'
620
+ );
621
+ } else {
622
+ this._debug && this._debug(
623
+ 'Outbound: Sending USERAUTH_REQUEST (password)'
624
+ );
625
+ }
626
+
627
+ this._authsQueue.push('password');
628
+
629
+ sendPacket(this, this._packetRW.write.finalize(packet));
630
+ }
631
+ authPK(username, pubKey, keyAlgo, cbSign) {
632
+ if (this._server)
633
+ throw new Error('Client-only method called in server mode');
634
+
635
+ pubKey = parseKey(pubKey);
636
+ if (pubKey instanceof Error)
637
+ throw new Error('Invalid key');
638
+
639
+ const keyType = pubKey.type;
640
+ pubKey = pubKey.getPublicSSH();
641
+
642
+ if (typeof keyAlgo === 'function') {
643
+ cbSign = keyAlgo;
644
+ keyAlgo = undefined;
645
+ }
646
+ if (!keyAlgo)
647
+ keyAlgo = keyType;
648
+
649
+ const userLen = Buffer.byteLength(username);
650
+ const algoLen = Buffer.byteLength(keyAlgo);
651
+ const pubKeyLen = pubKey.length;
652
+ const sessionID = this._kex.sessionID;
653
+ const sesLen = sessionID.length;
654
+ const payloadLen =
655
+ (cbSign ? 4 + sesLen : 0)
656
+ + 1 + 4 + userLen + 4 + 14 + 4 + 9 + 1 + 4 + algoLen + 4 + pubKeyLen;
657
+ let packet;
658
+ let p;
659
+ if (cbSign) {
660
+ packet = Buffer.allocUnsafe(payloadLen);
661
+ p = 0;
662
+ writeUInt32BE(packet, sesLen, p);
663
+ packet.set(sessionID, p += 4);
664
+ p += sesLen;
665
+ } else {
666
+ packet = this._packetRW.write.alloc(payloadLen);
667
+ p = this._packetRW.write.allocStart;
668
+ }
669
+
670
+ packet[p] = MESSAGE.USERAUTH_REQUEST;
671
+
672
+ writeUInt32BE(packet, userLen, ++p);
673
+ packet.utf8Write(username, p += 4, userLen);
674
+
675
+ writeUInt32BE(packet, 14, p += userLen);
676
+ packet.utf8Write('ssh-connection', p += 4, 14);
677
+
678
+ writeUInt32BE(packet, 9, p += 14);
679
+ packet.utf8Write('publickey', p += 4, 9);
680
+
681
+ packet[p += 9] = (cbSign ? 1 : 0);
682
+
683
+ writeUInt32BE(packet, algoLen, ++p);
684
+ packet.utf8Write(keyAlgo, p += 4, algoLen);
685
+
686
+ writeUInt32BE(packet, pubKeyLen, p += algoLen);
687
+ packet.set(pubKey, p += 4);
688
+
689
+ if (!cbSign) {
690
+ this._authsQueue.push('publickey');
691
+
692
+ this._debug && this._debug(
693
+ 'Outbound: Sending USERAUTH_REQUEST (publickey -- check)'
694
+ );
695
+ sendPacket(this, this._packetRW.write.finalize(packet));
696
+ return;
697
+ }
698
+
699
+ cbSign(packet, (signature) => {
700
+ signature = convertSignature(signature, keyType);
701
+ if (signature === false)
702
+ throw new Error('Error while converting handshake signature');
703
+
704
+ const sigLen = signature.length;
705
+ p = this._packetRW.write.allocStart;
706
+ packet = this._packetRW.write.alloc(
707
+ 1 + 4 + userLen + 4 + 14 + 4 + 9 + 1 + 4 + algoLen + 4 + pubKeyLen + 4
708
+ + 4 + algoLen + 4 + sigLen
709
+ );
710
+
711
+ // TODO: simply copy from original "packet" to new `packet` to avoid
712
+ // having to write each individual field a second time?
713
+ packet[p] = MESSAGE.USERAUTH_REQUEST;
714
+
715
+ writeUInt32BE(packet, userLen, ++p);
716
+ packet.utf8Write(username, p += 4, userLen);
717
+
718
+ writeUInt32BE(packet, 14, p += userLen);
719
+ packet.utf8Write('ssh-connection', p += 4, 14);
720
+
721
+ writeUInt32BE(packet, 9, p += 14);
722
+ packet.utf8Write('publickey', p += 4, 9);
723
+
724
+ packet[p += 9] = 1;
725
+
726
+ writeUInt32BE(packet, algoLen, ++p);
727
+ packet.utf8Write(keyAlgo, p += 4, algoLen);
728
+
729
+ writeUInt32BE(packet, pubKeyLen, p += algoLen);
730
+ packet.set(pubKey, p += 4);
731
+
732
+ writeUInt32BE(packet, 4 + algoLen + 4 + sigLen, p += pubKeyLen);
733
+
734
+ writeUInt32BE(packet, algoLen, p += 4);
735
+ packet.utf8Write(keyAlgo, p += 4, algoLen);
736
+
737
+ writeUInt32BE(packet, sigLen, p += algoLen);
738
+ packet.set(signature, p += 4);
739
+
740
+ // Servers shouldn't send packet type 60 in response to signed publickey
741
+ // attempts, but if they do, interpret as type 60.
742
+ this._authsQueue.push('publickey');
743
+
744
+ this._debug && this._debug(
745
+ 'Outbound: Sending USERAUTH_REQUEST (publickey)'
746
+ );
747
+ sendPacket(this, this._packetRW.write.finalize(packet));
748
+ });
749
+ }
750
+ authHostbased(username, pubKey, hostname, userlocal, keyAlgo, cbSign) {
751
+ // TODO: Make DRY by sharing similar code with authPK()
752
+ if (this._server)
753
+ throw new Error('Client-only method called in server mode');
754
+
755
+ pubKey = parseKey(pubKey);
756
+ if (pubKey instanceof Error)
757
+ throw new Error('Invalid key');
758
+
759
+ const keyType = pubKey.type;
760
+ pubKey = pubKey.getPublicSSH();
761
+
762
+ if (typeof keyAlgo === 'function') {
763
+ cbSign = keyAlgo;
764
+ keyAlgo = undefined;
765
+ }
766
+ if (!keyAlgo)
767
+ keyAlgo = keyType;
768
+
769
+ const userLen = Buffer.byteLength(username);
770
+ const algoLen = Buffer.byteLength(keyAlgo);
771
+ const pubKeyLen = pubKey.length;
772
+ const sessionID = this._kex.sessionID;
773
+ const sesLen = sessionID.length;
774
+ const hostnameLen = Buffer.byteLength(hostname);
775
+ const userlocalLen = Buffer.byteLength(userlocal);
776
+ const data = Buffer.allocUnsafe(
777
+ 4 + sesLen + 1 + 4 + userLen + 4 + 14 + 4 + 9 + 4 + algoLen
778
+ + 4 + pubKeyLen + 4 + hostnameLen + 4 + userlocalLen
779
+ );
780
+ let p = 0;
781
+
782
+ writeUInt32BE(data, sesLen, p);
783
+ data.set(sessionID, p += 4);
784
+
785
+ data[p += sesLen] = MESSAGE.USERAUTH_REQUEST;
786
+
787
+ writeUInt32BE(data, userLen, ++p);
788
+ data.utf8Write(username, p += 4, userLen);
789
+
790
+ writeUInt32BE(data, 14, p += userLen);
791
+ data.utf8Write('ssh-connection', p += 4, 14);
792
+
793
+ writeUInt32BE(data, 9, p += 14);
794
+ data.utf8Write('hostbased', p += 4, 9);
795
+
796
+ writeUInt32BE(data, algoLen, p += 9);
797
+ data.utf8Write(keyAlgo, p += 4, algoLen);
798
+
799
+ writeUInt32BE(data, pubKeyLen, p += algoLen);
800
+ data.set(pubKey, p += 4);
801
+
802
+ writeUInt32BE(data, hostnameLen, p += pubKeyLen);
803
+ data.utf8Write(hostname, p += 4, hostnameLen);
804
+
805
+ writeUInt32BE(data, userlocalLen, p += hostnameLen);
806
+ data.utf8Write(userlocal, p += 4, userlocalLen);
807
+
808
+ cbSign(data, (signature) => {
809
+ signature = convertSignature(signature, keyType);
810
+ if (!signature)
811
+ throw new Error('Error while converting handshake signature');
812
+
813
+ const sigLen = signature.length;
814
+ const reqDataLen = (data.length - sesLen - 4);
815
+ p = this._packetRW.write.allocStart;
816
+ const packet = this._packetRW.write.alloc(
817
+ reqDataLen + 4 + 4 + algoLen + 4 + sigLen
818
+ );
819
+
820
+ bufferCopy(data, packet, 4 + sesLen, data.length, p);
821
+
822
+ writeUInt32BE(packet, 4 + algoLen + 4 + sigLen, p += reqDataLen);
823
+ writeUInt32BE(packet, algoLen, p += 4);
824
+ packet.utf8Write(keyAlgo, p += 4, algoLen);
825
+ writeUInt32BE(packet, sigLen, p += algoLen);
826
+ packet.set(signature, p += 4);
827
+
828
+ this._authsQueue.push('hostbased');
829
+
830
+ this._debug && this._debug(
831
+ 'Outbound: Sending USERAUTH_REQUEST (hostbased)'
832
+ );
833
+ sendPacket(this, this._packetRW.write.finalize(packet));
834
+ });
835
+ }
836
+ authKeyboard(username) {
837
+ if (this._server)
838
+ throw new Error('Client-only method called in server mode');
839
+
840
+ const userLen = Buffer.byteLength(username);
841
+ let p = this._packetRW.write.allocStart;
842
+ const packet = this._packetRW.write.alloc(
843
+ 1 + 4 + userLen + 4 + 14 + 4 + 20 + 4 + 4
844
+ );
845
+
846
+ packet[p] = MESSAGE.USERAUTH_REQUEST;
847
+
848
+ writeUInt32BE(packet, userLen, ++p);
849
+ packet.utf8Write(username, p += 4, userLen);
850
+
851
+ writeUInt32BE(packet, 14, p += userLen);
852
+ packet.utf8Write('ssh-connection', p += 4, 14);
853
+
854
+ writeUInt32BE(packet, 20, p += 14);
855
+ packet.utf8Write('keyboard-interactive', p += 4, 20);
856
+
857
+ writeUInt32BE(packet, 0, p += 20);
858
+
859
+ writeUInt32BE(packet, 0, p += 4);
860
+
861
+ this._authsQueue.push('keyboard-interactive');
862
+
863
+ this._debug && this._debug(
864
+ 'Outbound: Sending USERAUTH_REQUEST (keyboard-interactive)'
865
+ );
866
+ sendPacket(this, this._packetRW.write.finalize(packet));
867
+ }
868
+ authNone(username) {
869
+ if (this._server)
870
+ throw new Error('Client-only method called in server mode');
871
+
872
+ const userLen = Buffer.byteLength(username);
873
+ let p = this._packetRW.write.allocStart;
874
+ const packet = this._packetRW.write.alloc(1 + 4 + userLen + 4 + 14 + 4 + 4);
875
+
876
+ packet[p] = MESSAGE.USERAUTH_REQUEST;
877
+
878
+ writeUInt32BE(packet, userLen, ++p);
879
+ packet.utf8Write(username, p += 4, userLen);
880
+
881
+ writeUInt32BE(packet, 14, p += userLen);
882
+ packet.utf8Write('ssh-connection', p += 4, 14);
883
+
884
+ writeUInt32BE(packet, 4, p += 14);
885
+ packet.utf8Write('none', p += 4, 4);
886
+
887
+ this._authsQueue.push('none');
888
+
889
+ this._debug && this._debug('Outbound: Sending USERAUTH_REQUEST (none)');
890
+ sendPacket(this, this._packetRW.write.finalize(packet));
891
+ }
892
+ authInfoRes(responses) {
893
+ if (this._server)
894
+ throw new Error('Client-only method called in server mode');
895
+
896
+ let responsesTotalLen = 0;
897
+ let responseLens;
898
+
899
+ if (responses) {
900
+ responseLens = new Array(responses.length);
901
+ for (let i = 0; i < responses.length; ++i) {
902
+ const len = Buffer.byteLength(responses[i]);
903
+ responseLens[i] = len;
904
+ responsesTotalLen += 4 + len;
905
+ }
906
+ }
907
+
908
+ let p = this._packetRW.write.allocStart;
909
+ const packet = this._packetRW.write.alloc(1 + 4 + responsesTotalLen);
910
+
911
+ packet[p] = MESSAGE.USERAUTH_INFO_RESPONSE;
912
+
913
+ if (responses) {
914
+ writeUInt32BE(packet, responses.length, ++p);
915
+ p += 4;
916
+ for (let i = 0; i < responses.length; ++i) {
917
+ const len = responseLens[i];
918
+ writeUInt32BE(packet, len, p);
919
+ p += 4;
920
+ if (len) {
921
+ packet.utf8Write(responses[i], p, len);
922
+ p += len;
923
+ }
924
+ }
925
+ } else {
926
+ writeUInt32BE(packet, 0, ++p);
927
+ }
928
+
929
+ this._debug && this._debug('Outbound: Sending USERAUTH_INFO_RESPONSE');
930
+ sendPacket(this, this._packetRW.write.finalize(packet));
931
+ }
932
+
933
+ // 'ssh-connection' service-specific
934
+ // ---------------------------------
935
+ tcpipForward(bindAddr, bindPort, wantReply) {
936
+ if (this._server)
937
+ throw new Error('Client-only method called in server mode');
938
+
939
+ const addrLen = Buffer.byteLength(bindAddr);
940
+ let p = this._packetRW.write.allocStart;
941
+ const packet = this._packetRW.write.alloc(1 + 4 + 13 + 1 + 4 + addrLen + 4);
942
+
943
+ packet[p] = MESSAGE.GLOBAL_REQUEST;
944
+
945
+ writeUInt32BE(packet, 13, ++p);
946
+ packet.utf8Write('tcpip-forward', p += 4, 13);
947
+
948
+ packet[p += 13] = (wantReply === undefined || wantReply === true ? 1 : 0);
949
+
950
+ writeUInt32BE(packet, addrLen, ++p);
951
+ packet.utf8Write(bindAddr, p += 4, addrLen);
952
+
953
+ writeUInt32BE(packet, bindPort, p += addrLen);
954
+
955
+ this._debug
956
+ && this._debug('Outbound: Sending GLOBAL_REQUEST (tcpip-forward)');
957
+ sendPacket(this, this._packetRW.write.finalize(packet));
958
+ }
959
+ cancelTcpipForward(bindAddr, bindPort, wantReply) {
960
+ if (this._server)
961
+ throw new Error('Client-only method called in server mode');
962
+
963
+ const addrLen = Buffer.byteLength(bindAddr);
964
+ let p = this._packetRW.write.allocStart;
965
+ const packet = this._packetRW.write.alloc(1 + 4 + 20 + 1 + 4 + addrLen + 4);
966
+
967
+ packet[p] = MESSAGE.GLOBAL_REQUEST;
968
+
969
+ writeUInt32BE(packet, 20, ++p);
970
+ packet.utf8Write('cancel-tcpip-forward', p += 4, 20);
971
+
972
+ packet[p += 20] = (wantReply === undefined || wantReply === true ? 1 : 0);
973
+
974
+ writeUInt32BE(packet, addrLen, ++p);
975
+ packet.utf8Write(bindAddr, p += 4, addrLen);
976
+
977
+ writeUInt32BE(packet, bindPort, p += addrLen);
978
+
979
+ this._debug
980
+ && this._debug('Outbound: Sending GLOBAL_REQUEST (cancel-tcpip-forward)');
981
+ sendPacket(this, this._packetRW.write.finalize(packet));
982
+ }
983
+ openssh_streamLocalForward(socketPath, wantReply) {
984
+ if (this._server)
985
+ throw new Error('Client-only method called in server mode');
986
+
987
+ const socketPathLen = Buffer.byteLength(socketPath);
988
+ let p = this._packetRW.write.allocStart;
989
+ const packet = this._packetRW.write.alloc(
990
+ 1 + 4 + 31 + 1 + 4 + socketPathLen
991
+ );
992
+
993
+ packet[p] = MESSAGE.GLOBAL_REQUEST;
994
+
995
+ writeUInt32BE(packet, 31, ++p);
996
+ packet.utf8Write('streamlocal-forward@openssh.com', p += 4, 31);
997
+
998
+ packet[p += 31] = (wantReply === undefined || wantReply === true ? 1 : 0);
999
+
1000
+ writeUInt32BE(packet, socketPathLen, ++p);
1001
+ packet.utf8Write(socketPath, p += 4, socketPathLen);
1002
+
1003
+ this._debug && this._debug(
1004
+ 'Outbound: Sending GLOBAL_REQUEST (streamlocal-forward@openssh.com)'
1005
+ );
1006
+ sendPacket(this, this._packetRW.write.finalize(packet));
1007
+ }
1008
+ openssh_cancelStreamLocalForward(socketPath, wantReply) {
1009
+ if (this._server)
1010
+ throw new Error('Client-only method called in server mode');
1011
+
1012
+ const socketPathLen = Buffer.byteLength(socketPath);
1013
+ let p = this._packetRW.write.allocStart;
1014
+ const packet = this._packetRW.write.alloc(
1015
+ 1 + 4 + 38 + 1 + 4 + socketPathLen
1016
+ );
1017
+
1018
+ packet[p] = MESSAGE.GLOBAL_REQUEST;
1019
+
1020
+ writeUInt32BE(packet, 38, ++p);
1021
+ packet.utf8Write('cancel-streamlocal-forward@openssh.com', p += 4, 38);
1022
+
1023
+ packet[p += 38] = (wantReply === undefined || wantReply === true ? 1 : 0);
1024
+
1025
+ writeUInt32BE(packet, socketPathLen, ++p);
1026
+ packet.utf8Write(socketPath, p += 4, socketPathLen);
1027
+
1028
+ if (this._debug) {
1029
+ this._debug(
1030
+ 'Outbound: Sending GLOBAL_REQUEST '
1031
+ + '(cancel-streamlocal-forward@openssh.com)'
1032
+ );
1033
+ }
1034
+ sendPacket(this, this._packetRW.write.finalize(packet));
1035
+ }
1036
+ directTcpip(chan, initWindow, maxPacket, cfg) {
1037
+ if (this._server)
1038
+ throw new Error('Client-only method called in server mode');
1039
+
1040
+ const srcLen = Buffer.byteLength(cfg.srcIP);
1041
+ const dstLen = Buffer.byteLength(cfg.dstIP);
1042
+ let p = this._packetRW.write.allocStart;
1043
+ const packet = this._packetRW.write.alloc(
1044
+ 1 + 4 + 12 + 4 + 4 + 4 + 4 + srcLen + 4 + 4 + dstLen + 4
1045
+ );
1046
+
1047
+ packet[p] = MESSAGE.CHANNEL_OPEN;
1048
+
1049
+ writeUInt32BE(packet, 12, ++p);
1050
+ packet.utf8Write('direct-tcpip', p += 4, 12);
1051
+
1052
+ writeUInt32BE(packet, chan, p += 12);
1053
+
1054
+ writeUInt32BE(packet, initWindow, p += 4);
1055
+
1056
+ writeUInt32BE(packet, maxPacket, p += 4);
1057
+
1058
+ writeUInt32BE(packet, dstLen, p += 4);
1059
+ packet.utf8Write(cfg.dstIP, p += 4, dstLen);
1060
+
1061
+ writeUInt32BE(packet, cfg.dstPort, p += dstLen);
1062
+
1063
+ writeUInt32BE(packet, srcLen, p += 4);
1064
+ packet.utf8Write(cfg.srcIP, p += 4, srcLen);
1065
+
1066
+ writeUInt32BE(packet, cfg.srcPort, p += srcLen);
1067
+
1068
+ this._debug && this._debug(
1069
+ `Outbound: Sending CHANNEL_OPEN (r:${chan}, direct-tcpip)`
1070
+ );
1071
+ sendPacket(this, this._packetRW.write.finalize(packet));
1072
+ }
1073
+ openssh_directStreamLocal(chan, initWindow, maxPacket, cfg) {
1074
+ if (this._server)
1075
+ throw new Error('Client-only method called in server mode');
1076
+
1077
+ const pathLen = Buffer.byteLength(cfg.socketPath);
1078
+ let p = this._packetRW.write.allocStart;
1079
+ const packet = this._packetRW.write.alloc(
1080
+ 1 + 4 + 30 + 4 + 4 + 4 + 4 + pathLen + 4 + 4
1081
+ );
1082
+
1083
+ packet[p] = MESSAGE.CHANNEL_OPEN;
1084
+
1085
+ writeUInt32BE(packet, 30, ++p);
1086
+ packet.utf8Write('direct-streamlocal@openssh.com', p += 4, 30);
1087
+
1088
+ writeUInt32BE(packet, chan, p += 30);
1089
+
1090
+ writeUInt32BE(packet, initWindow, p += 4);
1091
+
1092
+ writeUInt32BE(packet, maxPacket, p += 4);
1093
+
1094
+ writeUInt32BE(packet, pathLen, p += 4);
1095
+ packet.utf8Write(cfg.socketPath, p += 4, pathLen);
1096
+
1097
+ // zero-fill reserved fields (string and uint32)
1098
+ bufferFill(packet, 0, p += pathLen, p + 8);
1099
+
1100
+ if (this._debug) {
1101
+ this._debug(
1102
+ 'Outbound: Sending CHANNEL_OPEN '
1103
+ + `(r:${chan}, direct-streamlocal@openssh.com)`
1104
+ );
1105
+ }
1106
+ sendPacket(this, this._packetRW.write.finalize(packet));
1107
+ }
1108
+ openssh_noMoreSessions(wantReply) {
1109
+ if (this._server)
1110
+ throw new Error('Client-only method called in server mode');
1111
+
1112
+ let p = this._packetRW.write.allocStart;
1113
+ const packet = this._packetRW.write.alloc(1 + 4 + 28 + 1);
1114
+
1115
+ packet[p] = MESSAGE.GLOBAL_REQUEST;
1116
+
1117
+ writeUInt32BE(packet, 28, ++p);
1118
+ packet.utf8Write('no-more-sessions@openssh.com', p += 4, 28);
1119
+
1120
+ packet[p += 28] = (wantReply === undefined || wantReply === true ? 1 : 0);
1121
+
1122
+ this._debug && this._debug(
1123
+ 'Outbound: Sending GLOBAL_REQUEST (no-more-sessions@openssh.com)'
1124
+ );
1125
+ sendPacket(this, this._packetRW.write.finalize(packet));
1126
+ }
1127
+ session(chan, initWindow, maxPacket) {
1128
+ if (this._server)
1129
+ throw new Error('Client-only method called in server mode');
1130
+
1131
+ // Does not consume window space
1132
+
1133
+ let p = this._packetRW.write.allocStart;
1134
+ const packet = this._packetRW.write.alloc(1 + 4 + 7 + 4 + 4 + 4);
1135
+
1136
+ packet[p] = MESSAGE.CHANNEL_OPEN;
1137
+
1138
+ writeUInt32BE(packet, 7, ++p);
1139
+ packet.utf8Write('session', p += 4, 7);
1140
+
1141
+ writeUInt32BE(packet, chan, p += 7);
1142
+
1143
+ writeUInt32BE(packet, initWindow, p += 4);
1144
+
1145
+ writeUInt32BE(packet, maxPacket, p += 4);
1146
+
1147
+ this._debug
1148
+ && this._debug(`Outbound: Sending CHANNEL_OPEN (r:${chan}, session)`);
1149
+ sendPacket(this, this._packetRW.write.finalize(packet));
1150
+ }
1151
+ windowChange(chan, rows, cols, height, width) {
1152
+ if (this._server)
1153
+ throw new Error('Client-only method called in server mode');
1154
+
1155
+ // Does not consume window space
1156
+
1157
+ let p = this._packetRW.write.allocStart;
1158
+ const packet = this._packetRW.write.alloc(
1159
+ 1 + 4 + 4 + 13 + 1 + 4 + 4 + 4 + 4
1160
+ );
1161
+
1162
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1163
+
1164
+ writeUInt32BE(packet, chan, ++p);
1165
+
1166
+ writeUInt32BE(packet, 13, p += 4);
1167
+ packet.utf8Write('window-change', p += 4, 13);
1168
+
1169
+ packet[p += 13] = 0;
1170
+
1171
+ writeUInt32BE(packet, cols, ++p);
1172
+
1173
+ writeUInt32BE(packet, rows, p += 4);
1174
+
1175
+ writeUInt32BE(packet, width, p += 4);
1176
+
1177
+ writeUInt32BE(packet, height, p += 4);
1178
+
1179
+ this._debug && this._debug(
1180
+ `Outbound: Sending CHANNEL_REQUEST (r:${chan}, window-change)`
1181
+ );
1182
+ sendPacket(this, this._packetRW.write.finalize(packet));
1183
+ }
1184
+ pty(chan, rows, cols, height, width, term, modes, wantReply) {
1185
+ if (this._server)
1186
+ throw new Error('Client-only method called in server mode');
1187
+
1188
+ // Does not consume window space
1189
+
1190
+ if (!term || !term.length)
1191
+ term = 'vt100';
1192
+ if (modes
1193
+ && !Buffer.isBuffer(modes)
1194
+ && !Array.isArray(modes)
1195
+ && typeof modes === 'object'
1196
+ && modes !== null) {
1197
+ modes = modesToBytes(modes);
1198
+ }
1199
+ if (!modes || !modes.length)
1200
+ modes = NO_TERMINAL_MODES_BUFFER;
1201
+
1202
+ const termLen = term.length;
1203
+ const modesLen = modes.length;
1204
+ let p = this._packetRW.write.allocStart;
1205
+ const packet = this._packetRW.write.alloc(
1206
+ 1 + 4 + 4 + 7 + 1 + 4 + termLen + 4 + 4 + 4 + 4 + 4 + modesLen
1207
+ );
1208
+
1209
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1210
+
1211
+ writeUInt32BE(packet, chan, ++p);
1212
+
1213
+ writeUInt32BE(packet, 7, p += 4);
1214
+ packet.utf8Write('pty-req', p += 4, 7);
1215
+
1216
+ packet[p += 7] = (wantReply === undefined || wantReply === true ? 1 : 0);
1217
+
1218
+ writeUInt32BE(packet, termLen, ++p);
1219
+ packet.utf8Write(term, p += 4, termLen);
1220
+
1221
+ writeUInt32BE(packet, cols, p += termLen);
1222
+
1223
+ writeUInt32BE(packet, rows, p += 4);
1224
+
1225
+ writeUInt32BE(packet, width, p += 4);
1226
+
1227
+ writeUInt32BE(packet, height, p += 4);
1228
+
1229
+ writeUInt32BE(packet, modesLen, p += 4);
1230
+ p += 4;
1231
+ if (Array.isArray(modes)) {
1232
+ for (let i = 0; i < modesLen; ++i)
1233
+ packet[p++] = modes[i];
1234
+ } else if (Buffer.isBuffer(modes)) {
1235
+ packet.set(modes, p);
1236
+ }
1237
+
1238
+ this._debug
1239
+ && this._debug(`Outbound: Sending CHANNEL_REQUEST (r:${chan}, pty-req)`);
1240
+ sendPacket(this, this._packetRW.write.finalize(packet));
1241
+ }
1242
+ shell(chan, wantReply) {
1243
+ if (this._server)
1244
+ throw new Error('Client-only method called in server mode');
1245
+
1246
+ // Does not consume window space
1247
+
1248
+ let p = this._packetRW.write.allocStart;
1249
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + 5 + 1);
1250
+
1251
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1252
+
1253
+ writeUInt32BE(packet, chan, ++p);
1254
+
1255
+ writeUInt32BE(packet, 5, p += 4);
1256
+ packet.utf8Write('shell', p += 4, 5);
1257
+
1258
+ packet[p += 5] = (wantReply === undefined || wantReply === true ? 1 : 0);
1259
+
1260
+ this._debug
1261
+ && this._debug(`Outbound: Sending CHANNEL_REQUEST (r:${chan}, shell)`);
1262
+ sendPacket(this, this._packetRW.write.finalize(packet));
1263
+ }
1264
+ exec(chan, cmd, wantReply) {
1265
+ if (this._server)
1266
+ throw new Error('Client-only method called in server mode');
1267
+
1268
+ // Does not consume window space
1269
+
1270
+ const isBuf = Buffer.isBuffer(cmd);
1271
+ const cmdLen = (isBuf ? cmd.length : Buffer.byteLength(cmd));
1272
+ let p = this._packetRW.write.allocStart;
1273
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + 4 + 1 + 4 + cmdLen);
1274
+
1275
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1276
+
1277
+ writeUInt32BE(packet, chan, ++p);
1278
+
1279
+ writeUInt32BE(packet, 4, p += 4);
1280
+ packet.utf8Write('exec', p += 4, 4);
1281
+
1282
+ packet[p += 4] = (wantReply === undefined || wantReply === true ? 1 : 0);
1283
+
1284
+ writeUInt32BE(packet, cmdLen, ++p);
1285
+ if (isBuf)
1286
+ packet.set(cmd, p += 4);
1287
+ else
1288
+ packet.utf8Write(cmd, p += 4, cmdLen);
1289
+
1290
+ this._debug && this._debug(
1291
+ `Outbound: Sending CHANNEL_REQUEST (r:${chan}, exec: ${cmd})`
1292
+ );
1293
+ sendPacket(this, this._packetRW.write.finalize(packet));
1294
+ }
1295
+ signal(chan, signal) {
1296
+ if (this._server)
1297
+ throw new Error('Client-only method called in server mode');
1298
+
1299
+ // Does not consume window space
1300
+
1301
+ const origSignal = signal;
1302
+
1303
+ signal = signal.toUpperCase();
1304
+ if (signal.slice(0, 3) === 'SIG')
1305
+ signal = signal.slice(3);
1306
+
1307
+ if (SIGNALS[signal] !== 1)
1308
+ throw new Error(`Invalid signal: ${origSignal}`);
1309
+
1310
+ const signalLen = signal.length;
1311
+ let p = this._packetRW.write.allocStart;
1312
+ const packet = this._packetRW.write.alloc(
1313
+ 1 + 4 + 4 + 6 + 1 + 4 + signalLen
1314
+ );
1315
+
1316
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1317
+
1318
+ writeUInt32BE(packet, chan, ++p);
1319
+
1320
+ writeUInt32BE(packet, 6, p += 4);
1321
+ packet.utf8Write('signal', p += 4, 6);
1322
+
1323
+ packet[p += 6] = 0;
1324
+
1325
+ writeUInt32BE(packet, signalLen, ++p);
1326
+ packet.utf8Write(signal, p += 4, signalLen);
1327
+
1328
+ this._debug && this._debug(
1329
+ `Outbound: Sending CHANNEL_REQUEST (r:${chan}, signal: ${signal})`
1330
+ );
1331
+ sendPacket(this, this._packetRW.write.finalize(packet));
1332
+ }
1333
+ env(chan, key, val, wantReply) {
1334
+ if (this._server)
1335
+ throw new Error('Client-only method called in server mode');
1336
+
1337
+ // Does not consume window space
1338
+
1339
+ const keyLen = Buffer.byteLength(key);
1340
+ const isBuf = Buffer.isBuffer(val);
1341
+ const valLen = (isBuf ? val.length : Buffer.byteLength(val));
1342
+ let p = this._packetRW.write.allocStart;
1343
+ const packet = this._packetRW.write.alloc(
1344
+ 1 + 4 + 4 + 3 + 1 + 4 + keyLen + 4 + valLen
1345
+ );
1346
+
1347
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1348
+
1349
+ writeUInt32BE(packet, chan, ++p);
1350
+
1351
+ writeUInt32BE(packet, 3, p += 4);
1352
+ packet.utf8Write('env', p += 4, 3);
1353
+
1354
+ packet[p += 3] = (wantReply === undefined || wantReply === true ? 1 : 0);
1355
+
1356
+ writeUInt32BE(packet, keyLen, ++p);
1357
+ packet.utf8Write(key, p += 4, keyLen);
1358
+
1359
+ writeUInt32BE(packet, valLen, p += keyLen);
1360
+ if (isBuf)
1361
+ packet.set(val, p += 4);
1362
+ else
1363
+ packet.utf8Write(val, p += 4, valLen);
1364
+
1365
+ this._debug && this._debug(
1366
+ `Outbound: Sending CHANNEL_REQUEST (r:${chan}, env: ${key}=${val})`
1367
+ );
1368
+ sendPacket(this, this._packetRW.write.finalize(packet));
1369
+ }
1370
+ x11Forward(chan, cfg, wantReply) {
1371
+ if (this._server)
1372
+ throw new Error('Client-only method called in server mode');
1373
+
1374
+ // Does not consume window space
1375
+
1376
+ const protocol = cfg.protocol;
1377
+ const cookie = cfg.cookie;
1378
+ const isBufProto = Buffer.isBuffer(protocol);
1379
+ const protoLen = (isBufProto
1380
+ ? protocol.length
1381
+ : Buffer.byteLength(protocol));
1382
+ const isBufCookie = Buffer.isBuffer(cookie);
1383
+ const cookieLen = (isBufCookie
1384
+ ? cookie.length
1385
+ : Buffer.byteLength(cookie));
1386
+ let p = this._packetRW.write.allocStart;
1387
+ const packet = this._packetRW.write.alloc(
1388
+ 1 + 4 + 4 + 7 + 1 + 1 + 4 + protoLen + 4 + cookieLen + 4
1389
+ );
1390
+
1391
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1392
+
1393
+ writeUInt32BE(packet, chan, ++p);
1394
+
1395
+ writeUInt32BE(packet, 7, p += 4);
1396
+ packet.utf8Write('x11-req', p += 4, 7);
1397
+
1398
+ packet[p += 7] = (wantReply === undefined || wantReply === true ? 1 : 0);
1399
+
1400
+ packet[++p] = (cfg.single ? 1 : 0);
1401
+
1402
+ writeUInt32BE(packet, protoLen, ++p);
1403
+ if (isBufProto)
1404
+ packet.set(protocol, p += 4);
1405
+ else
1406
+ packet.utf8Write(protocol, p += 4, protoLen);
1407
+
1408
+ writeUInt32BE(packet, cookieLen, p += protoLen);
1409
+ if (isBufCookie)
1410
+ packet.set(cookie, p += 4);
1411
+ else
1412
+ packet.latin1Write(cookie, p += 4, cookieLen);
1413
+
1414
+ writeUInt32BE(packet, (cfg.screen || 0), p += cookieLen);
1415
+
1416
+ this._debug
1417
+ && this._debug(`Outbound: Sending CHANNEL_REQUEST (r:${chan}, x11-req)`);
1418
+ sendPacket(this, this._packetRW.write.finalize(packet));
1419
+ }
1420
+ subsystem(chan, name, wantReply) {
1421
+ if (this._server)
1422
+ throw new Error('Client-only method called in server mode');
1423
+
1424
+ // Does not consume window space
1425
+ const nameLen = Buffer.byteLength(name);
1426
+ let p = this._packetRW.write.allocStart;
1427
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + 9 + 1 + 4 + nameLen);
1428
+
1429
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1430
+
1431
+ writeUInt32BE(packet, chan, ++p);
1432
+
1433
+ writeUInt32BE(packet, 9, p += 4);
1434
+ packet.utf8Write('subsystem', p += 4, 9);
1435
+
1436
+ packet[p += 9] = (wantReply === undefined || wantReply === true ? 1 : 0);
1437
+
1438
+ writeUInt32BE(packet, nameLen, ++p);
1439
+ packet.utf8Write(name, p += 4, nameLen);
1440
+
1441
+ this._debug && this._debug(
1442
+ `Outbound: Sending CHANNEL_REQUEST (r:${chan}, subsystem: ${name})`
1443
+ );
1444
+ sendPacket(this, this._packetRW.write.finalize(packet));
1445
+ }
1446
+ openssh_agentForward(chan, wantReply) {
1447
+ if (this._server)
1448
+ throw new Error('Client-only method called in server mode');
1449
+
1450
+ // Does not consume window space
1451
+
1452
+ let p = this._packetRW.write.allocStart;
1453
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + 26 + 1);
1454
+
1455
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1456
+
1457
+ writeUInt32BE(packet, chan, ++p);
1458
+
1459
+ writeUInt32BE(packet, 26, p += 4);
1460
+ packet.utf8Write('auth-agent-req@openssh.com', p += 4, 26);
1461
+
1462
+ packet[p += 26] = (wantReply === undefined || wantReply === true ? 1 : 0);
1463
+
1464
+ if (this._debug) {
1465
+ this._debug(
1466
+ 'Outbound: Sending CHANNEL_REQUEST '
1467
+ + `(r:${chan}, auth-agent-req@openssh.com)`
1468
+ );
1469
+ }
1470
+ sendPacket(this, this._packetRW.write.finalize(packet));
1471
+ }
1472
+ openssh_hostKeysProve(keys) {
1473
+ if (this._server)
1474
+ throw new Error('Client-only method called in server mode');
1475
+
1476
+ let keysTotal = 0;
1477
+ const publicKeys = [];
1478
+ for (const key of keys) {
1479
+ const publicKey = key.getPublicSSH();
1480
+ keysTotal += 4 + publicKey.length;
1481
+ publicKeys.push(publicKey);
1482
+ }
1483
+
1484
+ let p = this._packetRW.write.allocStart;
1485
+ const packet = this._packetRW.write.alloc(1 + 4 + 29 + 1 + keysTotal);
1486
+
1487
+ packet[p] = MESSAGE.GLOBAL_REQUEST;
1488
+
1489
+ writeUInt32BE(packet, 29, ++p);
1490
+ packet.utf8Write('hostkeys-prove-00@openssh.com', p += 4, 29);
1491
+
1492
+ packet[p += 29] = 1; // want reply
1493
+
1494
+ ++p;
1495
+ for (const buf of publicKeys) {
1496
+ writeUInt32BE(packet, buf.length, p);
1497
+ bufferCopy(buf, packet, 0, buf.length, p += 4);
1498
+ p += buf.length;
1499
+ }
1500
+
1501
+ if (this._debug) {
1502
+ this._debug(
1503
+ 'Outbound: Sending GLOBAL_REQUEST (hostkeys-prove-00@openssh.com)'
1504
+ );
1505
+ }
1506
+ sendPacket(this, this._packetRW.write.finalize(packet));
1507
+ }
1508
+
1509
+ // ===========================================================================
1510
+ // Server-specific ===========================================================
1511
+ // ===========================================================================
1512
+
1513
+ // Global
1514
+ // ------
1515
+ serviceAccept(svcName) {
1516
+ if (!this._server)
1517
+ throw new Error('Server-only method called in client mode');
1518
+
1519
+ const svcNameLen = Buffer.byteLength(svcName);
1520
+ let p = this._packetRW.write.allocStart;
1521
+ const packet = this._packetRW.write.alloc(1 + 4 + svcNameLen);
1522
+
1523
+ packet[p] = MESSAGE.SERVICE_ACCEPT;
1524
+
1525
+ writeUInt32BE(packet, svcNameLen, ++p);
1526
+ packet.utf8Write(svcName, p += 4, svcNameLen);
1527
+
1528
+ this._debug && this._debug(`Outbound: Sending SERVICE_ACCEPT (${svcName})`);
1529
+ sendPacket(this, this._packetRW.write.finalize(packet));
1530
+
1531
+ if (this._server && this._banner && svcName === 'ssh-userauth') {
1532
+ const banner = this._banner;
1533
+ this._banner = undefined; // Prevent banner from being displayed again
1534
+ const bannerLen = Buffer.byteLength(banner);
1535
+ p = this._packetRW.write.allocStart;
1536
+ const packet = this._packetRW.write.alloc(1 + 4 + bannerLen + 4);
1537
+
1538
+ packet[p] = MESSAGE.USERAUTH_BANNER;
1539
+
1540
+ writeUInt32BE(packet, bannerLen, ++p);
1541
+ packet.utf8Write(banner, p += 4, bannerLen);
1542
+
1543
+ writeUInt32BE(packet, 0, p += bannerLen); // Empty language tag
1544
+
1545
+ this._debug && this._debug('Outbound: Sending USERAUTH_BANNER');
1546
+ sendPacket(this, this._packetRW.write.finalize(packet));
1547
+ }
1548
+ }
1549
+ // 'ssh-connection' service-specific
1550
+ forwardedTcpip(chan, initWindow, maxPacket, cfg) {
1551
+ if (!this._server)
1552
+ throw new Error('Server-only method called in client mode');
1553
+
1554
+ const boundAddrLen = Buffer.byteLength(cfg.boundAddr);
1555
+ const remoteAddrLen = Buffer.byteLength(cfg.remoteAddr);
1556
+ let p = this._packetRW.write.allocStart;
1557
+ const packet = this._packetRW.write.alloc(
1558
+ 1 + 4 + 15 + 4 + 4 + 4 + 4 + boundAddrLen + 4 + 4 + remoteAddrLen + 4
1559
+ );
1560
+
1561
+ packet[p] = MESSAGE.CHANNEL_OPEN;
1562
+
1563
+ writeUInt32BE(packet, 15, ++p);
1564
+ packet.utf8Write('forwarded-tcpip', p += 4, 15);
1565
+
1566
+ writeUInt32BE(packet, chan, p += 15);
1567
+
1568
+ writeUInt32BE(packet, initWindow, p += 4);
1569
+
1570
+ writeUInt32BE(packet, maxPacket, p += 4);
1571
+
1572
+ writeUInt32BE(packet, boundAddrLen, p += 4);
1573
+ packet.utf8Write(cfg.boundAddr, p += 4, boundAddrLen);
1574
+
1575
+ writeUInt32BE(packet, cfg.boundPort, p += boundAddrLen);
1576
+
1577
+ writeUInt32BE(packet, remoteAddrLen, p += 4);
1578
+ packet.utf8Write(cfg.remoteAddr, p += 4, remoteAddrLen);
1579
+
1580
+ writeUInt32BE(packet, cfg.remotePort, p += remoteAddrLen);
1581
+
1582
+ this._debug && this._debug(
1583
+ `Outbound: Sending CHANNEL_OPEN (r:${chan}, forwarded-tcpip)`
1584
+ );
1585
+ sendPacket(this, this._packetRW.write.finalize(packet));
1586
+ }
1587
+ x11(chan, initWindow, maxPacket, cfg) {
1588
+ if (!this._server)
1589
+ throw new Error('Server-only method called in client mode');
1590
+
1591
+ const addrLen = Buffer.byteLength(cfg.originAddr);
1592
+ let p = this._packetRW.write.allocStart;
1593
+ const packet = this._packetRW.write.alloc(
1594
+ 1 + 4 + 3 + 4 + 4 + 4 + 4 + addrLen + 4
1595
+ );
1596
+
1597
+ packet[p] = MESSAGE.CHANNEL_OPEN;
1598
+
1599
+ writeUInt32BE(packet, 3, ++p);
1600
+ packet.utf8Write('x11', p += 4, 3);
1601
+
1602
+ writeUInt32BE(packet, chan, p += 3);
1603
+
1604
+ writeUInt32BE(packet, initWindow, p += 4);
1605
+
1606
+ writeUInt32BE(packet, maxPacket, p += 4);
1607
+
1608
+ writeUInt32BE(packet, addrLen, p += 4);
1609
+ packet.utf8Write(cfg.originAddr, p += 4, addrLen);
1610
+
1611
+ writeUInt32BE(packet, cfg.originPort, p += addrLen);
1612
+
1613
+ this._debug && this._debug(
1614
+ `Outbound: Sending CHANNEL_OPEN (r:${chan}, x11)`
1615
+ );
1616
+ sendPacket(this, this._packetRW.write.finalize(packet));
1617
+ }
1618
+ openssh_authAgent(chan, initWindow, maxPacket) {
1619
+ if (!this._server)
1620
+ throw new Error('Server-only method called in client mode');
1621
+
1622
+ let p = this._packetRW.write.allocStart;
1623
+ const packet = this._packetRW.write.alloc(1 + 4 + 22 + 4 + 4 + 4);
1624
+
1625
+ packet[p] = MESSAGE.CHANNEL_OPEN;
1626
+
1627
+ writeUInt32BE(packet, 22, ++p);
1628
+ packet.utf8Write('auth-agent@openssh.com', p += 4, 22);
1629
+
1630
+ writeUInt32BE(packet, chan, p += 22);
1631
+
1632
+ writeUInt32BE(packet, initWindow, p += 4);
1633
+
1634
+ writeUInt32BE(packet, maxPacket, p += 4);
1635
+
1636
+ this._debug && this._debug(
1637
+ `Outbound: Sending CHANNEL_OPEN (r:${chan}, auth-agent@openssh.com)`
1638
+ );
1639
+ sendPacket(this, this._packetRW.write.finalize(packet));
1640
+ }
1641
+ openssh_forwardedStreamLocal(chan, initWindow, maxPacket, cfg) {
1642
+ if (!this._server)
1643
+ throw new Error('Server-only method called in client mode');
1644
+
1645
+ const pathLen = Buffer.byteLength(cfg.socketPath);
1646
+ let p = this._packetRW.write.allocStart;
1647
+ const packet = this._packetRW.write.alloc(
1648
+ 1 + 4 + 33 + 4 + 4 + 4 + 4 + pathLen + 4
1649
+ );
1650
+
1651
+ packet[p] = MESSAGE.CHANNEL_OPEN;
1652
+
1653
+ writeUInt32BE(packet, 33, ++p);
1654
+ packet.utf8Write('forwarded-streamlocal@openssh.com', p += 4, 33);
1655
+
1656
+ writeUInt32BE(packet, chan, p += 33);
1657
+
1658
+ writeUInt32BE(packet, initWindow, p += 4);
1659
+
1660
+ writeUInt32BE(packet, maxPacket, p += 4);
1661
+
1662
+ writeUInt32BE(packet, pathLen, p += 4);
1663
+ packet.utf8Write(cfg.socketPath, p += 4, pathLen);
1664
+
1665
+ writeUInt32BE(packet, 0, p += pathLen);
1666
+
1667
+ if (this._debug) {
1668
+ this._debug(
1669
+ 'Outbound: Sending CHANNEL_OPEN '
1670
+ + `(r:${chan}, forwarded-streamlocal@openssh.com)`
1671
+ );
1672
+ }
1673
+ sendPacket(this, this._packetRW.write.finalize(packet));
1674
+ }
1675
+ exitStatus(chan, status) {
1676
+ if (!this._server)
1677
+ throw new Error('Server-only method called in client mode');
1678
+
1679
+ // Does not consume window space
1680
+ let p = this._packetRW.write.allocStart;
1681
+ const packet = this._packetRW.write.alloc(1 + 4 + 4 + 11 + 1 + 4);
1682
+
1683
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1684
+
1685
+ writeUInt32BE(packet, chan, ++p);
1686
+
1687
+ writeUInt32BE(packet, 11, p += 4);
1688
+ packet.utf8Write('exit-status', p += 4, 11);
1689
+
1690
+ packet[p += 11] = 0;
1691
+
1692
+ writeUInt32BE(packet, status, ++p);
1693
+
1694
+ this._debug && this._debug(
1695
+ `Outbound: Sending CHANNEL_REQUEST (r:${chan}, exit-status: ${status})`
1696
+ );
1697
+ sendPacket(this, this._packetRW.write.finalize(packet));
1698
+ }
1699
+ exitSignal(chan, name, coreDumped, msg) {
1700
+ if (!this._server)
1701
+ throw new Error('Server-only method called in client mode');
1702
+
1703
+ // Does not consume window space
1704
+
1705
+ const origSignal = name;
1706
+
1707
+ if (typeof origSignal !== 'string' || !origSignal)
1708
+ throw new Error(`Invalid signal: ${origSignal}`);
1709
+
1710
+ let signal = name.toUpperCase();
1711
+ if (signal.slice(0, 3) === 'SIG')
1712
+ signal = signal.slice(3);
1713
+
1714
+ if (SIGNALS[signal] !== 1)
1715
+ throw new Error(`Invalid signal: ${origSignal}`);
1716
+
1717
+ const nameLen = Buffer.byteLength(signal);
1718
+ const msgLen = (msg ? Buffer.byteLength(msg) : 0);
1719
+ let p = this._packetRW.write.allocStart;
1720
+ const packet = this._packetRW.write.alloc(
1721
+ 1 + 4 + 4 + 11 + 1 + 4 + nameLen + 1 + 4 + msgLen + 4
1722
+ );
1723
+
1724
+ packet[p] = MESSAGE.CHANNEL_REQUEST;
1725
+
1726
+ writeUInt32BE(packet, chan, ++p);
1727
+
1728
+ writeUInt32BE(packet, 11, p += 4);
1729
+ packet.utf8Write('exit-signal', p += 4, 11);
1730
+
1731
+ packet[p += 11] = 0;
1732
+
1733
+ writeUInt32BE(packet, nameLen, ++p);
1734
+ packet.utf8Write(signal, p += 4, nameLen);
1735
+
1736
+ packet[p += nameLen] = (coreDumped ? 1 : 0);
1737
+
1738
+ writeUInt32BE(packet, msgLen, ++p);
1739
+
1740
+ p += 4;
1741
+ if (msgLen) {
1742
+ packet.utf8Write(msg, p, msgLen);
1743
+ p += msgLen;
1744
+ }
1745
+
1746
+ writeUInt32BE(packet, 0, p);
1747
+
1748
+ this._debug && this._debug(
1749
+ `Outbound: Sending CHANNEL_REQUEST (r:${chan}, exit-signal: ${name})`
1750
+ );
1751
+ sendPacket(this, this._packetRW.write.finalize(packet));
1752
+ }
1753
+ // 'ssh-userauth' service-specific
1754
+ authFailure(authMethods, isPartial) {
1755
+ if (!this._server)
1756
+ throw new Error('Server-only method called in client mode');
1757
+
1758
+ if (this._authsQueue.length === 0)
1759
+ throw new Error('No auth in progress');
1760
+
1761
+ let methods;
1762
+
1763
+ if (typeof authMethods === 'boolean') {
1764
+ isPartial = authMethods;
1765
+ authMethods = undefined;
1766
+ }
1767
+
1768
+ if (authMethods) {
1769
+ methods = [];
1770
+ for (let i = 0; i < authMethods.length; ++i) {
1771
+ if (authMethods[i].toLowerCase() === 'none')
1772
+ continue;
1773
+ methods.push(authMethods[i]);
1774
+ }
1775
+ methods = methods.join(',');
1776
+ } else {
1777
+ methods = '';
1778
+ }
1779
+
1780
+ const methodsLen = methods.length;
1781
+ let p = this._packetRW.write.allocStart;
1782
+ const packet = this._packetRW.write.alloc(1 + 4 + methodsLen + 1);
1783
+
1784
+ packet[p] = MESSAGE.USERAUTH_FAILURE;
1785
+
1786
+ writeUInt32BE(packet, methodsLen, ++p);
1787
+ packet.utf8Write(methods, p += 4, methodsLen);
1788
+
1789
+ packet[p += methodsLen] = (isPartial === true ? 1 : 0);
1790
+
1791
+ this._authsQueue.shift();
1792
+
1793
+ this._debug && this._debug('Outbound: Sending USERAUTH_FAILURE');
1794
+ sendPacket(this, this._packetRW.write.finalize(packet));
1795
+ }
1796
+ authSuccess() {
1797
+ if (!this._server)
1798
+ throw new Error('Server-only method called in client mode');
1799
+
1800
+ if (this._authsQueue.length === 0)
1801
+ throw new Error('No auth in progress');
1802
+
1803
+ const p = this._packetRW.write.allocStart;
1804
+ const packet = this._packetRW.write.alloc(1);
1805
+
1806
+ packet[p] = MESSAGE.USERAUTH_SUCCESS;
1807
+
1808
+ this._authsQueue.shift();
1809
+ this._authenticated = true;
1810
+
1811
+ this._debug && this._debug('Outbound: Sending USERAUTH_SUCCESS');
1812
+ sendPacket(this, this._packetRW.write.finalize(packet));
1813
+
1814
+ if (this._kex.negotiated.cs.compress === 'zlib@openssh.com')
1815
+ this._packetRW.read = new ZlibPacketReader();
1816
+ if (this._kex.negotiated.sc.compress === 'zlib@openssh.com')
1817
+ this._packetRW.write = new ZlibPacketWriter(this);
1818
+ }
1819
+ authPKOK(keyAlgo, key) {
1820
+ if (!this._server)
1821
+ throw new Error('Server-only method called in client mode');
1822
+
1823
+ if (this._authsQueue.length === 0 || this._authsQueue[0] !== 'publickey')
1824
+ throw new Error('"publickey" auth not in progress');
1825
+
1826
+ // TODO: support parsed key for `key`
1827
+
1828
+ const keyAlgoLen = Buffer.byteLength(keyAlgo);
1829
+ const keyLen = key.length;
1830
+ let p = this._packetRW.write.allocStart;
1831
+ const packet = this._packetRW.write.alloc(1 + 4 + keyAlgoLen + 4 + keyLen);
1832
+
1833
+ packet[p] = MESSAGE.USERAUTH_PK_OK;
1834
+
1835
+ writeUInt32BE(packet, keyAlgoLen, ++p);
1836
+ packet.utf8Write(keyAlgo, p += 4, keyAlgoLen);
1837
+
1838
+ writeUInt32BE(packet, keyLen, p += keyAlgoLen);
1839
+ packet.set(key, p += 4);
1840
+
1841
+ this._authsQueue.shift();
1842
+
1843
+ this._debug && this._debug('Outbound: Sending USERAUTH_PK_OK');
1844
+ sendPacket(this, this._packetRW.write.finalize(packet));
1845
+ }
1846
+ authPasswdChg(prompt) {
1847
+ if (!this._server)
1848
+ throw new Error('Server-only method called in client mode');
1849
+
1850
+ const promptLen = Buffer.byteLength(prompt);
1851
+ let p = this._packetRW.write.allocStart;
1852
+ const packet = this._packetRW.write.alloc(1 + 4 + promptLen + 4);
1853
+
1854
+ packet[p] = MESSAGE.USERAUTH_PASSWD_CHANGEREQ;
1855
+
1856
+ writeUInt32BE(packet, promptLen, ++p);
1857
+ packet.utf8Write(prompt, p += 4, promptLen);
1858
+
1859
+ writeUInt32BE(packet, 0, p += promptLen); // Empty language tag
1860
+
1861
+ this._debug && this._debug('Outbound: Sending USERAUTH_PASSWD_CHANGEREQ');
1862
+ sendPacket(this, this._packetRW.write.finalize(packet));
1863
+ }
1864
+ authInfoReq(name, instructions, prompts) {
1865
+ if (!this._server)
1866
+ throw new Error('Server-only method called in client mode');
1867
+
1868
+ let promptsLen = 0;
1869
+ const nameLen = name ? Buffer.byteLength(name) : 0;
1870
+ const instrLen = instructions ? Buffer.byteLength(instructions) : 0;
1871
+
1872
+ for (let i = 0; i < prompts.length; ++i)
1873
+ promptsLen += 4 + Buffer.byteLength(prompts[i].prompt) + 1;
1874
+
1875
+ let p = this._packetRW.write.allocStart;
1876
+ const packet = this._packetRW.write.alloc(
1877
+ 1 + 4 + nameLen + 4 + instrLen + 4 + 4 + promptsLen
1878
+ );
1879
+
1880
+ packet[p] = MESSAGE.USERAUTH_INFO_REQUEST;
1881
+
1882
+ writeUInt32BE(packet, nameLen, ++p);
1883
+ p += 4;
1884
+ if (name) {
1885
+ packet.utf8Write(name, p, nameLen);
1886
+ p += nameLen;
1887
+ }
1888
+
1889
+ writeUInt32BE(packet, instrLen, p);
1890
+ p += 4;
1891
+ if (instructions) {
1892
+ packet.utf8Write(instructions, p, instrLen);
1893
+ p += instrLen;
1894
+ }
1895
+
1896
+ writeUInt32BE(packet, 0, p);
1897
+
1898
+ writeUInt32BE(packet, prompts.length, p += 4);
1899
+ p += 4;
1900
+ for (let i = 0; i < prompts.length; ++i) {
1901
+ const prompt = prompts[i];
1902
+ const promptLen = Buffer.byteLength(prompt.prompt);
1903
+
1904
+ writeUInt32BE(packet, promptLen, p);
1905
+ p += 4;
1906
+ if (promptLen) {
1907
+ packet.utf8Write(prompt.prompt, p, promptLen);
1908
+ p += promptLen;
1909
+ }
1910
+ packet[p++] = (prompt.echo ? 1 : 0);
1911
+ }
1912
+
1913
+ this._debug && this._debug('Outbound: Sending USERAUTH_INFO_REQUEST');
1914
+ sendPacket(this, this._packetRW.write.finalize(packet));
1915
+ }
1916
+ }
1917
+
1918
+ // SSH-protoversion-softwareversion (SP comments) CR LF
1919
+ const RE_IDENT = /^SSH-(2\.0|1\.99)-([^ ]+)(?: (.*))?$/;
1920
+
1921
+ // TODO: optimize this by starting n bytes from the end of this._buffer instead
1922
+ // of the beginning
1923
+ function parseHeader(chunk, p, len) {
1924
+ let data;
1925
+ let chunkOffset;
1926
+ if (this._buffer) {
1927
+ data = Buffer.allocUnsafe(this._buffer.length + (len - p));
1928
+ data.set(this._buffer, 0);
1929
+ if (p === 0) {
1930
+ data.set(chunk, this._buffer.length);
1931
+ } else {
1932
+ data.set(new Uint8Array(chunk.buffer,
1933
+ chunk.byteOffset + p,
1934
+ (len - p)),
1935
+ this._buffer.length);
1936
+ }
1937
+ chunkOffset = this._buffer.length;
1938
+ p = 0;
1939
+ } else {
1940
+ data = chunk;
1941
+ chunkOffset = 0;
1942
+ }
1943
+ const op = p;
1944
+ let start = p;
1945
+ let end = p;
1946
+ let needNL = false;
1947
+ let lineLen = 0;
1948
+ let lines = 0;
1949
+ for (; p < data.length; ++p) {
1950
+ const ch = data[p];
1951
+
1952
+ if (ch === 13 /* '\r' */) {
1953
+ needNL = true;
1954
+ continue;
1955
+ }
1956
+
1957
+ if (ch === 10 /* '\n' */) {
1958
+ if (end > start
1959
+ && end - start > 4
1960
+ && data[start] === 83 /* 'S' */
1961
+ && data[start + 1] === 83 /* 'S' */
1962
+ && data[start + 2] === 72 /* 'H' */
1963
+ && data[start + 3] === 45 /* '-' */) {
1964
+
1965
+ const full = data.latin1Slice(op, end + 1);
1966
+ const identRaw = (start === op ? full : full.slice(start - op));
1967
+ const m = RE_IDENT.exec(identRaw);
1968
+ if (!m)
1969
+ throw new Error('Invalid identification string');
1970
+
1971
+ const header = {
1972
+ greeting: (start === op ? '' : full.slice(0, start - op)),
1973
+ identRaw,
1974
+ versions: {
1975
+ protocol: m[1],
1976
+ software: m[2],
1977
+ },
1978
+ comments: m[3]
1979
+ };
1980
+
1981
+ // Needed during handshake
1982
+ this._remoteIdentRaw = Buffer.from(identRaw);
1983
+
1984
+ this._debug && this._debug(`Remote ident: ${inspect(identRaw)}`);
1985
+ this._compatFlags = getCompatFlags(header);
1986
+
1987
+ this._buffer = undefined;
1988
+ this._decipher =
1989
+ new NullDecipher(0, onKEXPayload.bind(this, { firstPacket: true }));
1990
+ this._parse = parsePacket;
1991
+
1992
+ this._onHeader(header);
1993
+ if (!this._destruct) {
1994
+ // We disconnected inside _onHeader
1995
+ return len;
1996
+ }
1997
+
1998
+ kexinit(this);
1999
+
2000
+ return p + 1 - chunkOffset;
2001
+ }
2002
+
2003
+ // Only allow pre-ident greetings when we're a client
2004
+ if (this._server)
2005
+ throw new Error('Greetings from clients not permitted');
2006
+
2007
+ if (++lines > MAX_LINES)
2008
+ throw new Error('Max greeting lines exceeded');
2009
+
2010
+ needNL = false;
2011
+ start = p + 1;
2012
+ lineLen = 0;
2013
+ } else if (needNL) {
2014
+ throw new Error('Invalid header: expected newline');
2015
+ } else if (++lineLen >= MAX_LINE_LEN) {
2016
+ throw new Error('Header line too long');
2017
+ }
2018
+
2019
+ end = p;
2020
+ }
2021
+ if (!this._buffer)
2022
+ this._buffer = bufferSlice(data, op);
2023
+
2024
+ return p - chunkOffset;
2025
+ }
2026
+
2027
+ function parsePacket(chunk, p, len) {
2028
+ return this._decipher.decrypt(chunk, p, len);
2029
+ }
2030
+
2031
+ function onPayload(payload) {
2032
+ // XXX: move this to the Decipher implementations?
2033
+
2034
+ this._onPacket();
2035
+
2036
+ if (payload.length === 0) {
2037
+ this._debug && this._debug('Inbound: Skipping empty packet payload');
2038
+ return;
2039
+ }
2040
+
2041
+ payload = this._packetRW.read.read(payload);
2042
+
2043
+ const type = payload[0];
2044
+ if (type === MESSAGE.USERAUTH_SUCCESS
2045
+ && !this._server
2046
+ && !this._authenticated) {
2047
+ this._authenticated = true;
2048
+ if (this._kex.negotiated.cs.compress === 'zlib@openssh.com')
2049
+ this._packetRW.write = new ZlibPacketWriter(this);
2050
+ if (this._kex.negotiated.sc.compress === 'zlib@openssh.com')
2051
+ this._packetRW.read = new ZlibPacketReader();
2052
+ }
2053
+ const handler = MESSAGE_HANDLERS[type];
2054
+ if (handler === undefined) {
2055
+ this._debug && this._debug(`Inbound: Unsupported message type: ${type}`);
2056
+ return;
2057
+ }
2058
+
2059
+ return handler(this, payload);
2060
+ }
2061
+
2062
+ function getCompatFlags(header) {
2063
+ const software = header.versions.software;
2064
+
2065
+ let flags = 0;
2066
+
2067
+ for (const rule of COMPAT_CHECKS) {
2068
+ if (typeof rule[0] === 'string') {
2069
+ if (software === rule[0])
2070
+ flags |= rule[1];
2071
+ } else if (rule[0].test(software)) {
2072
+ flags |= rule[1];
2073
+ }
2074
+ }
2075
+
2076
+ return flags;
2077
+ }
2078
+
2079
+ function modesToBytes(modes) {
2080
+ const keys = Object.keys(modes);
2081
+ const bytes = Buffer.allocUnsafe((5 * keys.length) + 1);
2082
+ let b = 0;
2083
+
2084
+ for (let i = 0; i < keys.length; ++i) {
2085
+ const key = keys[i];
2086
+ if (key === 'TTY_OP_END')
2087
+ continue;
2088
+
2089
+ const opcode = TERMINAL_MODE[key];
2090
+ if (opcode === undefined)
2091
+ continue;
2092
+
2093
+ const val = modes[key];
2094
+ if (typeof val === 'number' && isFinite(val)) {
2095
+ bytes[b++] = opcode;
2096
+ bytes[b++] = val >>> 24;
2097
+ bytes[b++] = val >>> 16;
2098
+ bytes[b++] = val >>> 8;
2099
+ bytes[b++] = val;
2100
+ }
2101
+ }
2102
+
2103
+ bytes[b++] = TERMINAL_MODE.TTY_OP_END;
2104
+
2105
+ if (b < bytes.length)
2106
+ return bufferSlice(bytes, 0, b);
2107
+
2108
+ return bytes;
2109
+ }
2110
+
2111
+ function sendExtInfo(proto) {
2112
+ let serverSigAlgs =
2113
+ 'ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521'
2114
+ + 'rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss';
2115
+ if (eddsaSupported)
2116
+ serverSigAlgs = `ssh-ed25519,${serverSigAlgs}`;
2117
+ const algsLen = Buffer.byteLength(serverSigAlgs);
2118
+
2119
+ let p = proto._packetRW.write.allocStart;
2120
+ const packet = proto._packetRW.write.alloc(1 + 4 + 4 + 15 + 4 + algsLen);
2121
+
2122
+ packet[p] = MESSAGE.EXT_INFO;
2123
+
2124
+ writeUInt32BE(packet, 1, ++p);
2125
+
2126
+ writeUInt32BE(packet, 15, p += 4);
2127
+ packet.utf8Write('server-sig-algs', p += 4, 15);
2128
+
2129
+ writeUInt32BE(packet, algsLen, p += 15);
2130
+ packet.utf8Write(serverSigAlgs, p += 4, algsLen);
2131
+
2132
+ proto._debug && proto._debug('Outbound: Sending EXT_INFO');
2133
+ sendPacket(proto, proto._packetRW.write.finalize(packet));
2134
+ }
2135
+
2136
+ module.exports = Protocol;