handlers.misc.js 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. 'use strict';
  2. const {
  3. bufferSlice,
  4. bufferParser,
  5. doFatalError,
  6. sigSSHToASN1,
  7. writeUInt32BE,
  8. } = require('./utils.js');
  9. const {
  10. CHANNEL_OPEN_FAILURE,
  11. COMPAT,
  12. MESSAGE,
  13. TERMINAL_MODE,
  14. } = require('./constants.js');
  15. const {
  16. parseKey,
  17. } = require('./keyParser.js');
  18. const TERMINAL_MODE_BY_VALUE =
  19. Array.from(Object.entries(TERMINAL_MODE))
  20. .reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {});
  21. module.exports = {
  22. // Transport layer protocol ==================================================
  23. [MESSAGE.DISCONNECT]: (self, payload) => {
  24. /*
  25. byte SSH_MSG_DISCONNECT
  26. uint32 reason code
  27. string description in ISO-10646 UTF-8 encoding
  28. string language tag
  29. */
  30. bufferParser.init(payload, 1);
  31. const reason = bufferParser.readUInt32BE();
  32. const desc = bufferParser.readString(true);
  33. const lang = bufferParser.readString();
  34. bufferParser.clear();
  35. if (lang === undefined) {
  36. return doFatalError(
  37. self,
  38. 'Inbound: Malformed DISCONNECT packet'
  39. );
  40. }
  41. self._debug && self._debug(
  42. `Inbound: Received DISCONNECT (${reason}, "${desc}")`
  43. );
  44. const handler = self._handlers.DISCONNECT;
  45. handler && handler(self, reason, desc);
  46. },
  47. [MESSAGE.IGNORE]: (self, payload) => {
  48. /*
  49. byte SSH_MSG_IGNORE
  50. string data
  51. */
  52. self._debug && self._debug('Inbound: Received IGNORE');
  53. },
  54. [MESSAGE.UNIMPLEMENTED]: (self, payload) => {
  55. /*
  56. byte SSH_MSG_UNIMPLEMENTED
  57. uint32 packet sequence number of rejected message
  58. */
  59. bufferParser.init(payload, 1);
  60. const seqno = bufferParser.readUInt32BE();
  61. bufferParser.clear();
  62. if (seqno === undefined) {
  63. return doFatalError(
  64. self,
  65. 'Inbound: Malformed UNIMPLEMENTED packet'
  66. );
  67. }
  68. self._debug
  69. && self._debug(`Inbound: Received UNIMPLEMENTED (seqno ${seqno})`);
  70. },
  71. [MESSAGE.DEBUG]: (self, payload) => {
  72. /*
  73. byte SSH_MSG_DEBUG
  74. boolean always_display
  75. string message in ISO-10646 UTF-8 encoding [RFC3629]
  76. string language tag [RFC3066]
  77. */
  78. bufferParser.init(payload, 1);
  79. const display = bufferParser.readBool();
  80. const msg = bufferParser.readString(true);
  81. const lang = bufferParser.readString();
  82. bufferParser.clear();
  83. if (lang === undefined) {
  84. return doFatalError(
  85. self,
  86. 'Inbound: Malformed DEBUG packet'
  87. );
  88. }
  89. self._debug && self._debug('Inbound: Received DEBUG');
  90. const handler = self._handlers.DEBUG;
  91. handler && handler(self, display, msg);
  92. },
  93. [MESSAGE.SERVICE_REQUEST]: (self, payload) => {
  94. /*
  95. byte SSH_MSG_SERVICE_REQUEST
  96. string service name
  97. */
  98. bufferParser.init(payload, 1);
  99. const name = bufferParser.readString(true);
  100. bufferParser.clear();
  101. if (name === undefined) {
  102. return doFatalError(
  103. self,
  104. 'Inbound: Malformed SERVICE_REQUEST packet'
  105. );
  106. }
  107. self._debug && self._debug(`Inbound: Received SERVICE_REQUEST (${name})`);
  108. const handler = self._handlers.SERVICE_REQUEST;
  109. handler && handler(self, name);
  110. },
  111. [MESSAGE.SERVICE_ACCEPT]: (self, payload) => {
  112. // S->C
  113. /*
  114. byte SSH_MSG_SERVICE_ACCEPT
  115. string service name
  116. */
  117. bufferParser.init(payload, 1);
  118. const name = bufferParser.readString(true);
  119. bufferParser.clear();
  120. if (name === undefined) {
  121. return doFatalError(
  122. self,
  123. 'Inbound: Malformed SERVICE_ACCEPT packet'
  124. );
  125. }
  126. self._debug && self._debug(`Inbound: Received SERVICE_ACCEPT (${name})`);
  127. const handler = self._handlers.SERVICE_ACCEPT;
  128. handler && handler(self, name);
  129. },
  130. // User auth protocol -- generic =============================================
  131. [MESSAGE.USERAUTH_REQUEST]: (self, payload) => {
  132. /*
  133. byte SSH_MSG_USERAUTH_REQUEST
  134. string user name in ISO-10646 UTF-8 encoding [RFC3629]
  135. string service name in US-ASCII
  136. string method name in US-ASCII
  137. .... method specific fields
  138. */
  139. bufferParser.init(payload, 1);
  140. const user = bufferParser.readString(true);
  141. const service = bufferParser.readString(true);
  142. const method = bufferParser.readString(true);
  143. let methodData;
  144. let methodDesc;
  145. switch (method) {
  146. case 'none':
  147. methodData = null;
  148. break;
  149. case 'password': {
  150. /*
  151. boolean <new password follows (old) plaintext password?>
  152. string plaintext password in ISO-10646 UTF-8 encoding [RFC3629]
  153. [string new password]
  154. */
  155. const isChange = bufferParser.readBool();
  156. if (isChange !== undefined) {
  157. methodData = bufferParser.readString(true);
  158. if (methodData !== undefined && isChange) {
  159. const newPassword = bufferParser.readString(true);
  160. if (newPassword !== undefined)
  161. methodData = { oldPassword: methodData, newPassword };
  162. else
  163. methodData = undefined;
  164. }
  165. }
  166. break;
  167. }
  168. case 'publickey': {
  169. /*
  170. boolean <signature follows public key blob?>
  171. string public key algorithm name
  172. string public key blob
  173. [string signature]
  174. */
  175. const hasSig = bufferParser.readBool();
  176. if (hasSig !== undefined) {
  177. const keyAlgo = bufferParser.readString(true);
  178. const key = bufferParser.readString();
  179. if (hasSig) {
  180. const blobEnd = bufferParser.pos();
  181. let signature = bufferParser.readString();
  182. if (signature !== undefined) {
  183. if (signature.length > (4 + keyAlgo.length + 4)
  184. && signature.utf8Slice(4, 4 + keyAlgo.length) === keyAlgo) {
  185. // Skip algoLen + algo + sigLen
  186. signature = bufferSlice(signature, 4 + keyAlgo.length + 4);
  187. }
  188. signature = sigSSHToASN1(signature, keyAlgo);
  189. if (signature) {
  190. const sessionID = self._kex.sessionID;
  191. const blob = Buffer.allocUnsafe(4 + sessionID.length + blobEnd);
  192. writeUInt32BE(blob, sessionID.length, 0);
  193. blob.set(sessionID, 4);
  194. blob.set(
  195. new Uint8Array(payload.buffer, payload.byteOffset, blobEnd),
  196. 4 + sessionID.length
  197. );
  198. methodData = {
  199. keyAlgo,
  200. key,
  201. signature,
  202. blob,
  203. };
  204. }
  205. }
  206. } else {
  207. methodData = { keyAlgo, key };
  208. methodDesc = 'publickey -- check';
  209. }
  210. }
  211. break;
  212. }
  213. case 'hostbased': {
  214. /*
  215. string public key algorithm for host key
  216. string public host key and certificates for client host
  217. string client host name expressed as the FQDN in US-ASCII
  218. string user name on the client host in ISO-10646 UTF-8 encoding
  219. [RFC3629]
  220. string signature
  221. */
  222. const keyAlgo = bufferParser.readString(true);
  223. const key = bufferParser.readString();
  224. const localHostname = bufferParser.readString(true);
  225. const localUsername = bufferParser.readString(true);
  226. const blobEnd = bufferParser.pos();
  227. let signature = bufferParser.readString();
  228. if (signature !== undefined) {
  229. if (signature.length > (4 + keyAlgo.length + 4)
  230. && signature.utf8Slice(4, 4 + keyAlgo.length) === keyAlgo) {
  231. // Skip algoLen + algo + sigLen
  232. signature = bufferSlice(signature, 4 + keyAlgo.length + 4);
  233. }
  234. signature = sigSSHToASN1(signature, keyAlgo);
  235. if (signature !== undefined) {
  236. const sessionID = self._kex.sessionID;
  237. const blob = Buffer.allocUnsafe(4 + sessionID.length + blobEnd);
  238. writeUInt32BE(blob, sessionID.length, 0);
  239. blob.set(sessionID, 4);
  240. blob.set(
  241. new Uint8Array(payload.buffer, payload.byteOffset, blobEnd),
  242. 4 + sessionID.length
  243. );
  244. methodData = {
  245. keyAlgo,
  246. key,
  247. signature,
  248. blob,
  249. localHostname,
  250. localUsername,
  251. };
  252. }
  253. }
  254. break;
  255. }
  256. case 'keyboard-interactive':
  257. /*
  258. string language tag (as defined in [RFC-3066])
  259. string submethods (ISO-10646 UTF-8)
  260. */
  261. // Skip/ignore language field -- it's deprecated in RFC 4256
  262. bufferParser.skipString();
  263. methodData = bufferParser.readList();
  264. break;
  265. default:
  266. if (method !== undefined)
  267. methodData = bufferParser.readRaw();
  268. }
  269. bufferParser.clear();
  270. if (methodData === undefined) {
  271. return doFatalError(
  272. self,
  273. 'Inbound: Malformed USERAUTH_REQUEST packet'
  274. );
  275. }
  276. if (methodDesc === undefined)
  277. methodDesc = method;
  278. self._authsQueue.push(method);
  279. self._debug
  280. && self._debug(`Inbound: Received USERAUTH_REQUEST (${methodDesc})`);
  281. const handler = self._handlers.USERAUTH_REQUEST;
  282. handler && handler(self, user, service, method, methodData);
  283. },
  284. [MESSAGE.USERAUTH_FAILURE]: (self, payload) => {
  285. // S->C
  286. /*
  287. byte SSH_MSG_USERAUTH_FAILURE
  288. name-list authentications that can continue
  289. boolean partial success
  290. */
  291. bufferParser.init(payload, 1);
  292. const authMethods = bufferParser.readList();
  293. const partialSuccess = bufferParser.readBool();
  294. bufferParser.clear();
  295. if (partialSuccess === undefined) {
  296. return doFatalError(
  297. self,
  298. 'Inbound: Malformed USERAUTH_FAILURE packet'
  299. );
  300. }
  301. self._debug
  302. && self._debug(`Inbound: Received USERAUTH_FAILURE (${authMethods})`);
  303. self._authsQueue.shift();
  304. const handler = self._handlers.USERAUTH_FAILURE;
  305. handler && handler(self, authMethods, partialSuccess);
  306. },
  307. [MESSAGE.USERAUTH_SUCCESS]: (self, payload) => {
  308. // S->C
  309. /*
  310. byte SSH_MSG_USERAUTH_SUCCESS
  311. */
  312. self._debug && self._debug('Inbound: Received USERAUTH_SUCCESS');
  313. self._authsQueue.shift();
  314. const handler = self._handlers.USERAUTH_SUCCESS;
  315. handler && handler(self);
  316. },
  317. [MESSAGE.USERAUTH_BANNER]: (self, payload) => {
  318. // S->C
  319. /*
  320. byte SSH_MSG_USERAUTH_BANNER
  321. string message in ISO-10646 UTF-8 encoding [RFC3629]
  322. string language tag [RFC3066]
  323. */
  324. bufferParser.init(payload, 1);
  325. const msg = bufferParser.readString(true);
  326. const lang = bufferParser.readString();
  327. bufferParser.clear();
  328. if (lang === undefined) {
  329. return doFatalError(
  330. self,
  331. 'Inbound: Malformed USERAUTH_BANNER packet'
  332. );
  333. }
  334. self._debug && self._debug('Inbound: Received USERAUTH_BANNER');
  335. const handler = self._handlers.USERAUTH_BANNER;
  336. handler && handler(self, msg);
  337. },
  338. // User auth protocol -- method-specific =====================================
  339. 60: (self, payload) => {
  340. if (!self._authsQueue.length) {
  341. self._debug
  342. && self._debug('Inbound: Received payload type 60 without auth');
  343. return;
  344. }
  345. switch (self._authsQueue[0]) {
  346. case 'password': {
  347. // S->C
  348. /*
  349. byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
  350. string prompt in ISO-10646 UTF-8 encoding [RFC3629]
  351. string language tag [RFC3066]
  352. */
  353. bufferParser.init(payload, 1);
  354. const prompt = bufferParser.readString(true);
  355. const lang = bufferParser.readString();
  356. bufferParser.clear();
  357. if (lang === undefined) {
  358. return doFatalError(
  359. self,
  360. 'Inbound: Malformed USERAUTH_PASSWD_CHANGEREQ packet'
  361. );
  362. }
  363. self._debug
  364. && self._debug('Inbound: Received USERAUTH_PASSWD_CHANGEREQ');
  365. const handler = self._handlers.USERAUTH_PASSWD_CHANGEREQ;
  366. handler && handler(self, prompt);
  367. break;
  368. }
  369. case 'publickey': {
  370. // S->C
  371. /*
  372. byte SSH_MSG_USERAUTH_PK_OK
  373. string public key algorithm name from the request
  374. string public key blob from the request
  375. */
  376. bufferParser.init(payload, 1);
  377. const keyAlgo = bufferParser.readString(true);
  378. const key = bufferParser.readString();
  379. bufferParser.clear();
  380. if (key === undefined) {
  381. return doFatalError(
  382. self,
  383. 'Inbound: Malformed USERAUTH_PK_OK packet'
  384. );
  385. }
  386. self._debug && self._debug('Inbound: Received USERAUTH_PK_OK');
  387. self._authsQueue.shift();
  388. const handler = self._handlers.USERAUTH_PK_OK;
  389. handler && handler(self, keyAlgo, key);
  390. break;
  391. }
  392. case 'keyboard-interactive': {
  393. // S->C
  394. /*
  395. byte SSH_MSG_USERAUTH_INFO_REQUEST
  396. string name (ISO-10646 UTF-8)
  397. string instruction (ISO-10646 UTF-8)
  398. string language tag (as defined in [RFC-3066])
  399. int num-prompts
  400. string prompt[1] (ISO-10646 UTF-8)
  401. boolean echo[1]
  402. ...
  403. string prompt[num-prompts] (ISO-10646 UTF-8)
  404. boolean echo[num-prompts]
  405. */
  406. bufferParser.init(payload, 1);
  407. const name = bufferParser.readString(true);
  408. const instructions = bufferParser.readString(true);
  409. bufferParser.readString(); // skip lang
  410. const numPrompts = bufferParser.readUInt32BE();
  411. let prompts;
  412. if (numPrompts !== undefined) {
  413. prompts = new Array(numPrompts);
  414. let i;
  415. for (i = 0; i < numPrompts; ++i) {
  416. const prompt = bufferParser.readString(true);
  417. const echo = bufferParser.readBool();
  418. if (echo === undefined)
  419. break;
  420. prompts[i] = { prompt, echo };
  421. }
  422. if (i !== numPrompts)
  423. prompts = undefined;
  424. }
  425. bufferParser.clear();
  426. if (prompts === undefined) {
  427. return doFatalError(
  428. self,
  429. 'Inbound: Malformed USERAUTH_INFO_REQUEST packet'
  430. );
  431. }
  432. self._debug && self._debug('Inbound: Received USERAUTH_INFO_REQUEST');
  433. const handler = self._handlers.USERAUTH_INFO_REQUEST;
  434. handler && handler(self, name, instructions, prompts);
  435. break;
  436. }
  437. default:
  438. self._debug
  439. && self._debug('Inbound: Received unexpected payload type 60');
  440. }
  441. },
  442. 61: (self, payload) => {
  443. if (!self._authsQueue.length) {
  444. self._debug
  445. && self._debug('Inbound: Received payload type 61 without auth');
  446. return;
  447. }
  448. /*
  449. byte SSH_MSG_USERAUTH_INFO_RESPONSE
  450. int num-responses
  451. string response[1] (ISO-10646 UTF-8)
  452. ...
  453. string response[num-responses] (ISO-10646 UTF-8)
  454. */
  455. if (self._authsQueue[0] !== 'keyboard-interactive') {
  456. return doFatalError(
  457. self,
  458. 'Inbound: Received unexpected payload type 61'
  459. );
  460. }
  461. bufferParser.init(payload, 1);
  462. const numResponses = bufferParser.readUInt32BE();
  463. let responses;
  464. if (numResponses !== undefined) {
  465. responses = new Array(numResponses);
  466. let i;
  467. for (i = 0; i < numResponses; ++i) {
  468. const response = bufferParser.readString(true);
  469. if (response === undefined)
  470. break;
  471. responses[i] = response;
  472. }
  473. if (i !== numResponses)
  474. responses = undefined;
  475. }
  476. bufferParser.clear();
  477. if (responses === undefined) {
  478. return doFatalError(
  479. self,
  480. 'Inbound: Malformed USERAUTH_INFO_RESPONSE packet'
  481. );
  482. }
  483. self._debug && self._debug('Inbound: Received USERAUTH_INFO_RESPONSE');
  484. const handler = self._handlers.USERAUTH_INFO_RESPONSE;
  485. handler && handler(self, responses);
  486. },
  487. // Connection protocol -- generic ============================================
  488. [MESSAGE.GLOBAL_REQUEST]: (self, payload) => {
  489. /*
  490. byte SSH_MSG_GLOBAL_REQUEST
  491. string request name in US-ASCII only
  492. boolean want reply
  493. .... request-specific data follows
  494. */
  495. bufferParser.init(payload, 1);
  496. const name = bufferParser.readString(true);
  497. const wantReply = bufferParser.readBool();
  498. let data;
  499. if (wantReply !== undefined) {
  500. switch (name) {
  501. case 'tcpip-forward':
  502. case 'cancel-tcpip-forward': {
  503. /*
  504. string address to bind (e.g., "0.0.0.0")
  505. uint32 port number to bind
  506. */
  507. const bindAddr = bufferParser.readString(true);
  508. const bindPort = bufferParser.readUInt32BE();
  509. if (bindPort !== undefined)
  510. data = { bindAddr, bindPort };
  511. break;
  512. }
  513. case 'streamlocal-forward@openssh.com':
  514. case 'cancel-streamlocal-forward@openssh.com': {
  515. /*
  516. string socket path
  517. */
  518. const socketPath = bufferParser.readString(true);
  519. if (socketPath !== undefined)
  520. data = { socketPath };
  521. break;
  522. }
  523. case 'no-more-sessions@openssh.com':
  524. data = null;
  525. break;
  526. case 'hostkeys-00@openssh.com': {
  527. data = [];
  528. while (bufferParser.avail() > 0) {
  529. const keyRaw = bufferParser.readString();
  530. if (keyRaw === undefined) {
  531. data = undefined;
  532. break;
  533. }
  534. const key = parseKey(keyRaw);
  535. if (!(key instanceof Error))
  536. data.push(key);
  537. }
  538. break;
  539. }
  540. default:
  541. data = bufferParser.readRaw();
  542. }
  543. }
  544. bufferParser.clear();
  545. if (data === undefined) {
  546. return doFatalError(
  547. self,
  548. 'Inbound: Malformed GLOBAL_REQUEST packet'
  549. );
  550. }
  551. self._debug && self._debug(`Inbound: GLOBAL_REQUEST (${name})`);
  552. const handler = self._handlers.GLOBAL_REQUEST;
  553. if (handler)
  554. handler(self, name, wantReply, data);
  555. else
  556. self.requestFailure(); // Auto reject
  557. },
  558. [MESSAGE.REQUEST_SUCCESS]: (self, payload) => {
  559. /*
  560. byte SSH_MSG_REQUEST_SUCCESS
  561. .... response specific data
  562. */
  563. const data = (payload.length > 1 ? bufferSlice(payload, 1) : null);
  564. self._debug && self._debug('Inbound: REQUEST_SUCCESS');
  565. const handler = self._handlers.REQUEST_SUCCESS;
  566. handler && handler(self, data);
  567. },
  568. [MESSAGE.REQUEST_FAILURE]: (self, payload) => {
  569. /*
  570. byte SSH_MSG_REQUEST_FAILURE
  571. */
  572. self._debug && self._debug('Inbound: Received REQUEST_FAILURE');
  573. const handler = self._handlers.REQUEST_FAILURE;
  574. handler && handler(self);
  575. },
  576. // Connection protocol -- channel-related ====================================
  577. [MESSAGE.CHANNEL_OPEN]: (self, payload) => {
  578. /*
  579. byte SSH_MSG_CHANNEL_OPEN
  580. string channel type in US-ASCII only
  581. uint32 sender channel
  582. uint32 initial window size
  583. uint32 maximum packet size
  584. .... channel type specific data follows
  585. */
  586. bufferParser.init(payload, 1);
  587. const type = bufferParser.readString(true);
  588. const sender = bufferParser.readUInt32BE();
  589. const window = bufferParser.readUInt32BE();
  590. const packetSize = bufferParser.readUInt32BE();
  591. let channelInfo;
  592. switch (type) {
  593. case 'forwarded-tcpip': // S->C
  594. case 'direct-tcpip': { // C->S
  595. /*
  596. string address that was connected / host to connect
  597. uint32 port that was connected / port to connect
  598. string originator IP address
  599. uint32 originator port
  600. */
  601. const destIP = bufferParser.readString(true);
  602. const destPort = bufferParser.readUInt32BE();
  603. const srcIP = bufferParser.readString(true);
  604. const srcPort = bufferParser.readUInt32BE();
  605. if (srcPort !== undefined) {
  606. channelInfo = {
  607. type,
  608. sender,
  609. window,
  610. packetSize,
  611. data: { destIP, destPort, srcIP, srcPort }
  612. };
  613. }
  614. break;
  615. }
  616. case 'forwarded-streamlocal@openssh.com': // S->C
  617. case 'direct-streamlocal@openssh.com': { // C->S
  618. /*
  619. string socket path
  620. string reserved for future use
  621. (direct-streamlocal@openssh.com additionally has:)
  622. uint32 reserved
  623. */
  624. const socketPath = bufferParser.readString(true);
  625. if (socketPath !== undefined) {
  626. channelInfo = {
  627. type,
  628. sender,
  629. window,
  630. packetSize,
  631. data: { socketPath }
  632. };
  633. }
  634. break;
  635. }
  636. case 'x11': { // S->C
  637. /*
  638. string originator address (e.g., "192.168.7.38")
  639. uint32 originator port
  640. */
  641. const srcIP = bufferParser.readString(true);
  642. const srcPort = bufferParser.readUInt32BE();
  643. if (srcPort !== undefined) {
  644. channelInfo = {
  645. type,
  646. sender,
  647. window,
  648. packetSize,
  649. data: { srcIP, srcPort }
  650. };
  651. }
  652. break;
  653. }
  654. default:
  655. // Includes:
  656. // 'session' (C->S)
  657. // 'auth-agent@openssh.com' (S->C)
  658. channelInfo = {
  659. type,
  660. sender,
  661. window,
  662. packetSize,
  663. data: {}
  664. };
  665. }
  666. bufferParser.clear();
  667. if (channelInfo === undefined) {
  668. return doFatalError(
  669. self,
  670. 'Inbound: Malformed CHANNEL_OPEN packet'
  671. );
  672. }
  673. self._debug && self._debug(`Inbound: CHANNEL_OPEN (s:${sender}, ${type})`);
  674. const handler = self._handlers.CHANNEL_OPEN;
  675. if (handler) {
  676. handler(self, channelInfo);
  677. } else {
  678. self.channelOpenFail(
  679. channelInfo.sender,
  680. CHANNEL_OPEN_FAILURE.ADMINISTRATIVELY_PROHIBITED,
  681. '',
  682. ''
  683. );
  684. }
  685. },
  686. [MESSAGE.CHANNEL_OPEN_CONFIRMATION]: (self, payload) => {
  687. /*
  688. byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION
  689. uint32 recipient channel
  690. uint32 sender channel
  691. uint32 initial window size
  692. uint32 maximum packet size
  693. .... channel type specific data follows
  694. */
  695. // "The 'recipient channel' is the channel number given in the
  696. // original open request, and 'sender channel' is the channel number
  697. // allocated by the other side."
  698. bufferParser.init(payload, 1);
  699. const recipient = bufferParser.readUInt32BE();
  700. const sender = bufferParser.readUInt32BE();
  701. const window = bufferParser.readUInt32BE();
  702. const packetSize = bufferParser.readUInt32BE();
  703. const data = (bufferParser.avail() ? bufferParser.readRaw() : undefined);
  704. bufferParser.clear();
  705. if (packetSize === undefined) {
  706. return doFatalError(
  707. self,
  708. 'Inbound: Malformed CHANNEL_OPEN_CONFIRMATION packet'
  709. );
  710. }
  711. self._debug && self._debug(
  712. `Inbound: CHANNEL_OPEN_CONFIRMATION (r:${recipient}, s:${sender})`
  713. );
  714. const handler = self._handlers.CHANNEL_OPEN_CONFIRMATION;
  715. if (handler)
  716. handler(self, { recipient, sender, window, packetSize, data });
  717. },
  718. [MESSAGE.CHANNEL_OPEN_FAILURE]: (self, payload) => {
  719. /*
  720. byte SSH_MSG_CHANNEL_OPEN_FAILURE
  721. uint32 recipient channel
  722. uint32 reason code
  723. string description in ISO-10646 UTF-8 encoding [RFC3629]
  724. string language tag [RFC3066]
  725. */
  726. bufferParser.init(payload, 1);
  727. const recipient = bufferParser.readUInt32BE();
  728. const reason = bufferParser.readUInt32BE();
  729. const description = bufferParser.readString(true);
  730. const lang = bufferParser.readString();
  731. bufferParser.clear();
  732. if (lang === undefined) {
  733. return doFatalError(
  734. self,
  735. 'Inbound: Malformed CHANNEL_OPEN_FAILURE packet'
  736. );
  737. }
  738. self._debug
  739. && self._debug(`Inbound: CHANNEL_OPEN_FAILURE (r:${recipient})`);
  740. const handler = self._handlers.CHANNEL_OPEN_FAILURE;
  741. handler && handler(self, recipient, reason, description);
  742. },
  743. [MESSAGE.CHANNEL_WINDOW_ADJUST]: (self, payload) => {
  744. /*
  745. byte SSH_MSG_CHANNEL_WINDOW_ADJUST
  746. uint32 recipient channel
  747. uint32 bytes to add
  748. */
  749. bufferParser.init(payload, 1);
  750. const recipient = bufferParser.readUInt32BE();
  751. const bytesToAdd = bufferParser.readUInt32BE();
  752. bufferParser.clear();
  753. if (bytesToAdd === undefined) {
  754. return doFatalError(
  755. self,
  756. 'Inbound: Malformed CHANNEL_WINDOW_ADJUST packet'
  757. );
  758. }
  759. self._debug && self._debug(
  760. `Inbound: CHANNEL_WINDOW_ADJUST (r:${recipient}, ${bytesToAdd})`
  761. );
  762. const handler = self._handlers.CHANNEL_WINDOW_ADJUST;
  763. handler && handler(self, recipient, bytesToAdd);
  764. },
  765. [MESSAGE.CHANNEL_DATA]: (self, payload) => {
  766. /*
  767. byte SSH_MSG_CHANNEL_DATA
  768. uint32 recipient channel
  769. string data
  770. */
  771. bufferParser.init(payload, 1);
  772. const recipient = bufferParser.readUInt32BE();
  773. const data = bufferParser.readString();
  774. bufferParser.clear();
  775. if (data === undefined) {
  776. return doFatalError(
  777. self,
  778. 'Inbound: Malformed CHANNEL_DATA packet'
  779. );
  780. }
  781. self._debug
  782. && self._debug(`Inbound: CHANNEL_DATA (r:${recipient}, ${data.length})`);
  783. const handler = self._handlers.CHANNEL_DATA;
  784. handler && handler(self, recipient, data);
  785. },
  786. [MESSAGE.CHANNEL_EXTENDED_DATA]: (self, payload) => {
  787. /*
  788. byte SSH_MSG_CHANNEL_EXTENDED_DATA
  789. uint32 recipient channel
  790. uint32 data_type_code
  791. string data
  792. */
  793. bufferParser.init(payload, 1);
  794. const recipient = bufferParser.readUInt32BE();
  795. const type = bufferParser.readUInt32BE();
  796. const data = bufferParser.readString();
  797. bufferParser.clear();
  798. if (data === undefined) {
  799. return doFatalError(
  800. self,
  801. 'Inbound: Malformed CHANNEL_EXTENDED_DATA packet'
  802. );
  803. }
  804. self._debug && self._debug(
  805. `Inbound: CHANNEL_EXTENDED_DATA (r:${recipient}, ${data.length})`
  806. );
  807. const handler = self._handlers.CHANNEL_EXTENDED_DATA;
  808. handler && handler(self, recipient, data, type);
  809. },
  810. [MESSAGE.CHANNEL_EOF]: (self, payload) => {
  811. /*
  812. byte SSH_MSG_CHANNEL_EOF
  813. uint32 recipient channel
  814. */
  815. bufferParser.init(payload, 1);
  816. const recipient = bufferParser.readUInt32BE();
  817. bufferParser.clear();
  818. if (recipient === undefined) {
  819. return doFatalError(
  820. self,
  821. 'Inbound: Malformed CHANNEL_EOF packet'
  822. );
  823. }
  824. self._debug && self._debug(`Inbound: CHANNEL_EOF (r:${recipient})`);
  825. const handler = self._handlers.CHANNEL_EOF;
  826. handler && handler(self, recipient);
  827. },
  828. [MESSAGE.CHANNEL_CLOSE]: (self, payload) => {
  829. /*
  830. byte SSH_MSG_CHANNEL_CLOSE
  831. uint32 recipient channel
  832. */
  833. bufferParser.init(payload, 1);
  834. const recipient = bufferParser.readUInt32BE();
  835. bufferParser.clear();
  836. if (recipient === undefined) {
  837. return doFatalError(
  838. self,
  839. 'Inbound: Malformed CHANNEL_CLOSE packet'
  840. );
  841. }
  842. self._debug && self._debug(`Inbound: CHANNEL_CLOSE (r:${recipient})`);
  843. const handler = self._handlers.CHANNEL_CLOSE;
  844. handler && handler(self, recipient);
  845. },
  846. [MESSAGE.CHANNEL_REQUEST]: (self, payload) => {
  847. /*
  848. byte SSH_MSG_CHANNEL_REQUEST
  849. uint32 recipient channel
  850. string request type in US-ASCII characters only
  851. boolean want reply
  852. .... type-specific data follows
  853. */
  854. bufferParser.init(payload, 1);
  855. const recipient = bufferParser.readUInt32BE();
  856. const type = bufferParser.readString(true);
  857. const wantReply = bufferParser.readBool();
  858. let data;
  859. if (wantReply !== undefined) {
  860. switch (type) {
  861. case 'exit-status': // S->C
  862. /*
  863. uint32 exit_status
  864. */
  865. data = bufferParser.readUInt32BE();
  866. self._debug && self._debug(
  867. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})`
  868. );
  869. break;
  870. case 'exit-signal': { // S->C
  871. /*
  872. string signal name (without the "SIG" prefix)
  873. boolean core dumped
  874. string error message in ISO-10646 UTF-8 encoding
  875. string language tag
  876. */
  877. let signal;
  878. let coreDumped;
  879. if (self._compatFlags & COMPAT.OLD_EXIT) {
  880. /*
  881. Instead of `signal name` and `core dumped`, we have just:
  882. uint32 signal number
  883. */
  884. const num = bufferParser.readUInt32BE();
  885. switch (num) {
  886. case 1:
  887. signal = 'HUP';
  888. break;
  889. case 2:
  890. signal = 'INT';
  891. break;
  892. case 3:
  893. signal = 'QUIT';
  894. break;
  895. case 6:
  896. signal = 'ABRT';
  897. break;
  898. case 9:
  899. signal = 'KILL';
  900. break;
  901. case 14:
  902. signal = 'ALRM';
  903. break;
  904. case 15:
  905. signal = 'TERM';
  906. break;
  907. default:
  908. if (num !== undefined) {
  909. // Unknown or OS-specific
  910. signal = `UNKNOWN (${num})`;
  911. }
  912. }
  913. coreDumped = false;
  914. } else {
  915. signal = bufferParser.readString(true);
  916. coreDumped = bufferParser.readBool();
  917. if (coreDumped === undefined)
  918. signal = undefined;
  919. }
  920. const errorMessage = bufferParser.readString(true);
  921. if (bufferParser.skipString() !== undefined)
  922. data = { signal, coreDumped, errorMessage };
  923. self._debug && self._debug(
  924. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${signal})`
  925. );
  926. break;
  927. }
  928. case 'pty-req': { // C->S
  929. /*
  930. string TERM environment variable value (e.g., vt100)
  931. uint32 terminal width, characters (e.g., 80)
  932. uint32 terminal height, rows (e.g., 24)
  933. uint32 terminal width, pixels (e.g., 640)
  934. uint32 terminal height, pixels (e.g., 480)
  935. string encoded terminal modes
  936. */
  937. const term = bufferParser.readString(true);
  938. const cols = bufferParser.readUInt32BE();
  939. const rows = bufferParser.readUInt32BE();
  940. const width = bufferParser.readUInt32BE();
  941. const height = bufferParser.readUInt32BE();
  942. const modesBinary = bufferParser.readString();
  943. if (modesBinary !== undefined) {
  944. bufferParser.init(modesBinary, 1);
  945. let modes = {};
  946. while (bufferParser.avail()) {
  947. const opcode = bufferParser.readByte();
  948. if (opcode === TERMINAL_MODE.TTY_OP_END)
  949. break;
  950. const name = TERMINAL_MODE_BY_VALUE[opcode];
  951. const value = bufferParser.readUInt32BE();
  952. if (opcode === undefined
  953. || name === undefined
  954. || value === undefined) {
  955. modes = undefined;
  956. break;
  957. }
  958. modes[name] = value;
  959. }
  960. if (modes !== undefined)
  961. data = { term, cols, rows, width, height, modes };
  962. }
  963. self._debug && self._debug(
  964. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})`
  965. );
  966. break;
  967. }
  968. case 'window-change': { // C->S
  969. /*
  970. uint32 terminal width, columns
  971. uint32 terminal height, rows
  972. uint32 terminal width, pixels
  973. uint32 terminal height, pixels
  974. */
  975. const cols = bufferParser.readUInt32BE();
  976. const rows = bufferParser.readUInt32BE();
  977. const width = bufferParser.readUInt32BE();
  978. const height = bufferParser.readUInt32BE();
  979. if (height !== undefined)
  980. data = { cols, rows, width, height };
  981. self._debug && self._debug(
  982. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})`
  983. );
  984. break;
  985. }
  986. case 'x11-req': { // C->S
  987. /*
  988. boolean single connection
  989. string x11 authentication protocol
  990. string x11 authentication cookie
  991. uint32 x11 screen number
  992. */
  993. const single = bufferParser.readBool();
  994. const protocol = bufferParser.readString(true);
  995. const cookie = bufferParser.readString();
  996. const screen = bufferParser.readUInt32BE();
  997. if (screen !== undefined)
  998. data = { single, protocol, cookie, screen };
  999. self._debug && self._debug(
  1000. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})`
  1001. );
  1002. break;
  1003. }
  1004. case 'env': { // C->S
  1005. /*
  1006. string variable name
  1007. string variable value
  1008. */
  1009. const name = bufferParser.readString(true);
  1010. const value = bufferParser.readString(true);
  1011. if (value !== undefined)
  1012. data = { name, value };
  1013. if (self._debug) {
  1014. self._debug(
  1015. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: `
  1016. + `${name}=${value})`
  1017. );
  1018. }
  1019. break;
  1020. }
  1021. case 'shell': // C->S
  1022. data = null; // No extra data
  1023. self._debug && self._debug(
  1024. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})`
  1025. );
  1026. break;
  1027. case 'exec': // C->S
  1028. /*
  1029. string command
  1030. */
  1031. data = bufferParser.readString(true);
  1032. self._debug && self._debug(
  1033. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})`
  1034. );
  1035. break;
  1036. case 'subsystem': // C->S
  1037. /*
  1038. string subsystem name
  1039. */
  1040. data = bufferParser.readString(true);
  1041. self._debug && self._debug(
  1042. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})`
  1043. );
  1044. break;
  1045. case 'signal': // C->S
  1046. /*
  1047. string signal name (without the "SIG" prefix)
  1048. */
  1049. data = bufferParser.readString(true);
  1050. self._debug && self._debug(
  1051. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})`
  1052. );
  1053. break;
  1054. case 'xon-xoff': // C->S
  1055. /*
  1056. boolean client can do
  1057. */
  1058. data = bufferParser.readBool();
  1059. self._debug && self._debug(
  1060. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type}: ${data})`
  1061. );
  1062. break;
  1063. case 'auth-agent-req@openssh.com': // C-S
  1064. data = null; // No extra data
  1065. self._debug && self._debug(
  1066. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})`
  1067. );
  1068. break;
  1069. default:
  1070. data = (bufferParser.avail() ? bufferParser.readRaw() : null);
  1071. self._debug && self._debug(
  1072. `Inbound: CHANNEL_REQUEST (r:${recipient}, ${type})`
  1073. );
  1074. }
  1075. }
  1076. bufferParser.clear();
  1077. if (data === undefined) {
  1078. return doFatalError(
  1079. self,
  1080. 'Inbound: Malformed CHANNEL_REQUEST packet'
  1081. );
  1082. }
  1083. const handler = self._handlers.CHANNEL_REQUEST;
  1084. handler && handler(self, recipient, type, wantReply, data);
  1085. },
  1086. [MESSAGE.CHANNEL_SUCCESS]: (self, payload) => {
  1087. /*
  1088. byte SSH_MSG_CHANNEL_SUCCESS
  1089. uint32 recipient channel
  1090. */
  1091. bufferParser.init(payload, 1);
  1092. const recipient = bufferParser.readUInt32BE();
  1093. bufferParser.clear();
  1094. if (recipient === undefined) {
  1095. return doFatalError(
  1096. self,
  1097. 'Inbound: Malformed CHANNEL_SUCCESS packet'
  1098. );
  1099. }
  1100. self._debug && self._debug(`Inbound: CHANNEL_SUCCESS (r:${recipient})`);
  1101. const handler = self._handlers.CHANNEL_SUCCESS;
  1102. handler && handler(self, recipient);
  1103. },
  1104. [MESSAGE.CHANNEL_FAILURE]: (self, payload) => {
  1105. /*
  1106. byte SSH_MSG_CHANNEL_FAILURE
  1107. uint32 recipient channel
  1108. */
  1109. bufferParser.init(payload, 1);
  1110. const recipient = bufferParser.readUInt32BE();
  1111. bufferParser.clear();
  1112. if (recipient === undefined) {
  1113. return doFatalError(
  1114. self,
  1115. 'Inbound: Malformed CHANNEL_FAILURE packet'
  1116. );
  1117. }
  1118. self._debug && self._debug(`Inbound: CHANNEL_FAILURE (r:${recipient})`);
  1119. const handler = self._handlers.CHANNEL_FAILURE;
  1120. handler && handler(self, recipient);
  1121. },
  1122. };