mcs.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. /*
  2. * Copyright (c) 2014-2015 Sylvain Peyrefitte
  3. *
  4. * This file is part of node-rdpjs.
  5. *
  6. * node-rdpjs is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. var inherits = require('util').inherits;
  20. var events = require('events');
  21. var type = require('../../core').type;
  22. var log = require('../../core').log;
  23. var error = require('../../core').error;
  24. var gcc = require('./gcc');
  25. var per = require('./per');
  26. var asn1 = require('../../asn1');
  27. var cliprdr = require('../pdu/cliprdr');
  28. var Message = {
  29. MCS_TYPE_CONNECT_INITIAL : 0x65,
  30. MCS_TYPE_CONNECT_RESPONSE : 0x66
  31. };
  32. var DomainMCSPDU = {
  33. ERECT_DOMAIN_REQUEST : 1,
  34. DISCONNECT_PROVIDER_ULTIMATUM : 8,
  35. ATTACH_USER_REQUEST : 10,
  36. ATTACH_USER_CONFIRM : 11,
  37. CHANNEL_JOIN_REQUEST : 14,
  38. CHANNEL_JOIN_CONFIRM : 15,
  39. SEND_DATA_REQUEST : 25,
  40. SEND_DATA_INDICATION : 26
  41. };
  42. var Channel = {
  43. MCS_GLOBAL_CHANNEL: 1003,
  44. MCS_USERCHANNEL_BASE: 1001,
  45. MCS_CLIPRDR_CHANNEL: 1005
  46. };
  47. /**
  48. * Channel Defined
  49. */
  50. const RdpdrChannelDef = new type.Component({
  51. name: new type.BinaryString(Buffer.from('rdpdr' + '\x00\x00\x00', 'binary'), { readLength: new type.CallableValue(8) }),
  52. options: new type.UInt32Le(0x80800000)
  53. });
  54. const RdpsndChannelDef = new type.Component({
  55. name: new type.BinaryString(Buffer.from('rdpsnd' + '\x00\x00', 'binary'), { readLength: new type.CallableValue(8) }),
  56. options: new type.UInt32Le(0xc0000000)
  57. });
  58. const CliprdrChannelDef = new type.Component({
  59. name: new type.BinaryString(Buffer.from('cliprdr' + '\x00', 'binary'), { readLength: new type.CallableValue(8) }),
  60. // CHANNEL_OPTION_INITIALIZED |
  61. // CHANNEL_OPTION_ENCRYPT_RDP |
  62. // CHANNEL_OPTION_COMPRESS_RDP |
  63. // CHANNEL_OPTION_SHOW_PROTOCOL
  64. options: new type.UInt32Le(0xc0a00000)
  65. });
  66. /**
  67. * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
  68. * @returns {asn1.univ.Sequence}
  69. */
  70. function DomainParameters(maxChannelIds, maxUserIds, maxTokenIds,
  71. numPriorities, minThoughput, maxHeight, maxMCSPDUsize, protocolVersion) {
  72. return new asn1.univ.Sequence({
  73. maxChannelIds : new asn1.univ.Integer(maxChannelIds),
  74. maxUserIds : new asn1.univ.Integer(maxUserIds),
  75. maxTokenIds : new asn1.univ.Integer(maxTokenIds),
  76. numPriorities : new asn1.univ.Integer(numPriorities),
  77. minThoughput : new asn1.univ.Integer(minThoughput),
  78. maxHeight : new asn1.univ.Integer(maxHeight),
  79. maxMCSPDUsize : new asn1.univ.Integer(maxMCSPDUsize),
  80. protocolVersion : new asn1.univ.Integer(protocolVersion)
  81. });
  82. }
  83. /**
  84. * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
  85. * @param userData {Buffer}
  86. * @returns {asn1.univ.Sequence}
  87. */
  88. function ConnectInitial (userData) {
  89. return new asn1.univ.Sequence({
  90. callingDomainSelector : new asn1.univ.OctetString(Buffer.from('\x01', 'binary')),
  91. calledDomainSelector : new asn1.univ.OctetString(Buffer.from('\x01', 'binary')),
  92. upwardFlag : new asn1.univ.Boolean(true),
  93. targetParameters : DomainParameters(34, 2, 0, 1, 0, 1, 0xffff, 2),
  94. minimumParameters : DomainParameters(1, 1, 1, 1, 0, 1, 0x420, 2),
  95. maximumParameters : DomainParameters(0xffff, 0xfc17, 0xffff, 1, 0, 1, 0xffff, 2),
  96. userData : new asn1.univ.OctetString(userData)
  97. }).implicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Application, asn1.spec.TagFormat.Constructed, 101));
  98. }
  99. /**
  100. * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
  101. * @returns {asn1.univ.Sequence}
  102. */
  103. function ConnectResponse (userData) {
  104. return new asn1.univ.Sequence({
  105. result : new asn1.univ.Enumerate(0),
  106. calledConnectId : new asn1.univ.Integer(0),
  107. domainParameters : DomainParameters(22, 3, 0, 1, 0, 1,0xfff8, 2),
  108. userData : new asn1.univ.OctetString(userData)
  109. }).implicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Application, asn1.spec.TagFormat.Constructed, 102));
  110. }
  111. /**
  112. * Format MCS PDU header packet
  113. * @param mcsPdu {integer}
  114. * @param options {integer}
  115. * @returns {type.UInt8} headers
  116. */
  117. function writeMCSPDUHeader(mcsPdu, options) {
  118. options = options || 0;
  119. return new type.UInt8((mcsPdu << 2) | options);
  120. }
  121. /**
  122. * Read MCS PDU header
  123. * @param opcode
  124. * @param mcsPdu
  125. * @returns {Boolean}
  126. */
  127. function readMCSPDUHeader(opcode, mcsPdu) {
  128. return (opcode >> 2) === mcsPdu;
  129. }
  130. /**
  131. * Multi-Channel Services
  132. * @param transport {events.EventEmitter} transport layer listen (connect, data) events
  133. * @param recvOpCode {DomainMCSPDU} opcode use in receive automata
  134. * @param sendOpCode {DomainMCSPDU} opcode use to send message
  135. */
  136. function MCS(transport, recvOpCode, sendOpCode) {
  137. this.transport = transport;
  138. this.recvOpCode = recvOpCode;
  139. this.sendOpCode = sendOpCode;
  140. this.channels = [
  141. { id: Channel.MCS_GLOBAL_CHANNEL, name: 'global' },
  142. { id: Channel.MCS_CLIPRDR_CHANNEL, name: 'cliprdr' }
  143. ];
  144. this.channels.find = function(callback) {
  145. for(var i in this) {
  146. if(callback(this[i])) return this[i];
  147. };
  148. };
  149. // bind events
  150. var self = this;
  151. this.transport.on('close', function () {
  152. self.emit('close');
  153. }).on('error', function (err) {
  154. self.emit('error', err);
  155. });
  156. }
  157. //inherit from Layer
  158. inherits(MCS, events.EventEmitter);
  159. /**
  160. * Send message to a specific channel
  161. * @param channelName {string} name of channel
  162. * @param data {type.*} message to send
  163. */
  164. MCS.prototype.send = function(channelName, data) {
  165. var channelId = this.channels.find(function(element) {
  166. if (element.name === channelName) return true;
  167. }).id;
  168. this.transport.send(new type.Component([
  169. writeMCSPDUHeader(this.sendOpCode),
  170. per.writeInteger16(this.userId, Channel.MCS_USERCHANNEL_BASE),
  171. per.writeInteger16(channelId),
  172. new type.UInt8(0x70),
  173. per.writeLength(data.size()),
  174. data
  175. ]));
  176. };
  177. /**
  178. * Main receive function
  179. * @param s {type.Stream}
  180. */
  181. MCS.prototype.recv = function(s) {
  182. opcode = new type.UInt8().read(s).value;
  183. if (readMCSPDUHeader(opcode, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM)) {
  184. log.info("MCS DISCONNECT_PROVIDER_ULTIMATUM");
  185. this.transport.close();
  186. return
  187. }
  188. else if(!readMCSPDUHeader(opcode, this.recvOpCode)) {
  189. throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_BAD_RECEIVE_OPCODE');
  190. }
  191. per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
  192. var channelId = per.readInteger16(s);
  193. per.readEnumerates(s);
  194. per.readLength(s);
  195. var channelName = this.channels.find(function(e) {
  196. if (e.id === channelId) return true;
  197. }).name;
  198. this.emit(channelName, s);
  199. };
  200. /**
  201. * Only main channels handle actually
  202. * @param transport {event.EventEmitter} bind connect and data events
  203. * @returns
  204. */
  205. function Client(transport) {
  206. MCS.call(this, transport, DomainMCSPDU.SEND_DATA_INDICATION, DomainMCSPDU.SEND_DATA_REQUEST);
  207. // channel context automata
  208. this.channelsConnected = 0;
  209. // init gcc information
  210. this.clientCoreData = gcc.clientCoreData();
  211. // cliprdr channel
  212. this.clientNetworkData = gcc.clientNetworkData(new type.Component([RdpdrChannelDef, CliprdrChannelDef, RdpsndChannelDef]));
  213. this.clientSecurityData = gcc.clientSecurityData();
  214. // must be read from protocol
  215. this.serverCoreData = null;
  216. this.serverSecurityData = null;
  217. this.serverNetworkData = null;
  218. var self = this;
  219. this.transport.on('connect', function(s) {
  220. self.connect(s);
  221. });
  222. }
  223. inherits(Client, MCS);
  224. /**
  225. * Connect event layer
  226. */
  227. Client.prototype.connect = function(selectedProtocol) {
  228. this.clientCoreData.obj.serverSelectedProtocol.value = selectedProtocol;
  229. this.sendConnectInitial();
  230. };
  231. /**
  232. * close stack
  233. */
  234. Client.prototype.close = function() {
  235. this.transport.close();
  236. };
  237. /**
  238. * MCS connect response (server->client)
  239. * @param s {type.Stream}
  240. */
  241. Client.prototype.recvConnectResponse = function(s) {
  242. var userData = new type.Stream(ConnectResponse().decode(s, asn1.ber).value.userData.value);
  243. var serverSettings = gcc.readConferenceCreateResponse(userData);
  244. // record server gcc block
  245. for(var i in serverSettings) {
  246. if(!serverSettings[i].obj) {
  247. continue;
  248. }
  249. switch(serverSettings[i].obj.__TYPE__) {
  250. case gcc.MessageType.SC_CORE:
  251. this.serverCoreData = serverSettings[i];
  252. break;
  253. case gcc.MessageType.SC_SECURITY:
  254. this.serverSecurityData = serverSettings[i];
  255. break;
  256. case gcc.MessageType.SC_NET:
  257. this.serverNetworkData = serverSettings[i];
  258. break;
  259. default:
  260. log.warn('unhandle server gcc block : ' + serverSettings[i].obj.__TYPE__);
  261. }
  262. }
  263. // send domain request
  264. this.sendErectDomainRequest();
  265. // send attach user request
  266. this.sendAttachUserRequest();
  267. // now wait user confirm from server
  268. var self = this;
  269. this.transport.once('data', function(s) {
  270. self.recvAttachUserConfirm(s);
  271. });
  272. };
  273. /**
  274. * MCS connection automata step
  275. * @param s {type.Stream}
  276. */
  277. Client.prototype.recvAttachUserConfirm = function(s) {
  278. if (!readMCSPDUHeader(new type.UInt8().read(s).value, DomainMCSPDU.ATTACH_USER_CONFIRM)) {
  279. throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER');
  280. }
  281. if (per.readEnumerates(s) !== 0) {
  282. throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_REJECT_USER');
  283. }
  284. this.userId = per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
  285. //ask channel for specific user
  286. this.channels.push({ id : this.userId, name : 'user' });
  287. // channel connect automata
  288. this.connectChannels();
  289. };
  290. /**
  291. * Last state in channel connection automata
  292. * @param s {type.Stream}
  293. */
  294. Client.prototype.recvChannelJoinConfirm = function(s) {
  295. var opcode = new type.UInt8().read(s).value;
  296. if (!readMCSPDUHeader(opcode, DomainMCSPDU.CHANNEL_JOIN_CONFIRM)) {
  297. throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM');
  298. }
  299. var confirm = per.readEnumerates(s);
  300. var userId = per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE);
  301. if (this.userId !== userId) {
  302. throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID');
  303. }
  304. var channelId = per.readInteger16(s);
  305. //if ((confirm !== 0) && (channelId === Channel.MCS_GLOBAL_CHANNEL || channelId === this.userId)) {
  306. if ((confirm !== 0) && (channelId === Channel.MCS_CLIPRDR_CHANNEL || channelId === Channel.MCS_GLOBAL_CHANNEL || channelId === this.userId)) {
  307. throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL');
  308. }
  309. this.connectChannels();
  310. };
  311. /**
  312. * First MCS message
  313. */
  314. Client.prototype.sendConnectInitial = function() {
  315. var ccReq = gcc.writeConferenceCreateRequest(new type.Component([
  316. gcc.block(this.clientCoreData),
  317. gcc.block(this.clientNetworkData),
  318. gcc.block(this.clientSecurityData)
  319. ])).toStream().getValue();
  320. this.transport.send(ConnectInitial(ccReq).encode(asn1.ber));
  321. // next event is connect response
  322. var self = this;
  323. this.transport.once('data', function(s) {
  324. self.recvConnectResponse(s);
  325. });
  326. };
  327. /**
  328. * MCS connection automata step
  329. */
  330. Client.prototype.sendErectDomainRequest = function() {
  331. this.transport.send(new type.Component([
  332. writeMCSPDUHeader(DomainMCSPDU.ERECT_DOMAIN_REQUEST),
  333. per.writeInteger(0),
  334. per.writeInteger(0)
  335. ]));
  336. };
  337. /**
  338. * MCS connection automata step
  339. */
  340. Client.prototype.sendAttachUserRequest = function() {
  341. this.transport.send(writeMCSPDUHeader(DomainMCSPDU.ATTACH_USER_REQUEST));
  342. };
  343. /**
  344. * Send a channel join request
  345. * @param channelId {integer} channel id
  346. */
  347. Client.prototype.sendChannelJoinRequest = function(channelId) {
  348. this.transport.send(new type.Component([
  349. writeMCSPDUHeader(DomainMCSPDU.CHANNEL_JOIN_REQUEST),
  350. per.writeInteger16(this.userId, Channel.MCS_USERCHANNEL_BASE),
  351. per.writeInteger16(channelId)
  352. ]));
  353. };
  354. /**
  355. * Connect channels automata
  356. * @param s {type.Stream}
  357. */
  358. Client.prototype.connectChannels = function(s) {
  359. if(this.channelsConnected == this.channels.length) {
  360. var self = this;
  361. this.transport.on('data', function(s) {
  362. self.recv(s);
  363. });
  364. // send client and sever gcc information
  365. this.emit('connect',
  366. {
  367. core : this.clientCoreData.obj,
  368. security : this.clientSecurityData.obj,
  369. net : this.clientNetworkData.obj
  370. },
  371. {
  372. core : this.serverCoreData.obj,
  373. security : this.serverSecurityData.obj
  374. }, this.userId, this.channels);
  375. return;
  376. }
  377. this.sendChannelJoinRequest(this.channels[this.channelsConnected++].id);
  378. var self = this;
  379. this.transport.once('data', function(s) {
  380. self.recvChannelJoinConfirm(s);
  381. });
  382. };
  383. /**
  384. * Server side of MCS layer
  385. * @param transport
  386. */
  387. function Server (transport) {
  388. MCS.call(this, transport, DomainMCSPDU.SEND_DATA_REQUEST, DomainMCSPDU.SEND_DATA_INDICATION);
  389. // must be readed from protocol
  390. this.clientCoreData = null;
  391. this.clientNetworkData = null;
  392. this.clientSecurityData = null;
  393. // init gcc information
  394. this.serverCoreData = gcc.serverCoreData();
  395. this.serverSecurityData = gcc.serverSecurityData();
  396. this.serverNetworkData = gcc.serverNetworkData(new type.Component([]));
  397. var self = this;
  398. this.transport.on('connect', function (selectedProtocol) {
  399. self.serverCoreData.obj.clientRequestedProtocol.value = selectedProtocol;
  400. }).once('data', function (s) {
  401. self.recvConnectInitial(s);
  402. });
  403. }
  404. inherits(Server, MCS);
  405. /**
  406. * First state of server automata
  407. * @param s {type.Stream}
  408. */
  409. Server.prototype.recvConnectInitial = function (s) {
  410. var userData = new type.Stream(ConnectInitial().decode(s, asn1.ber).value.userData.value);
  411. var clientSettings = gcc.readConferenceCreateRequest(userData);
  412. // record server gcc block
  413. for(var i in clientSettings) {
  414. if(!clientSettings[i].obj) {
  415. continue;
  416. }
  417. switch(clientSettings[i].obj.__TYPE__) {
  418. case gcc.MessageType.CS_CORE:
  419. this.clientCoreData = clientSettings[i];
  420. break;
  421. case gcc.MessageType.CS_SECURITY:
  422. this.clientSecurityData = clientSettings[i];
  423. break;
  424. case gcc.MessageType.CS_NET:
  425. this.clientNetworkData = clientSettings[i];
  426. for (var i = 0; i < this.clientNetworkData.obj.channelCount.value; i++) {
  427. this.serverNetworkData.obj.channelIdArray.obj.push(new type.UInt16Le( i + 1 + Channel.MCS_GLOBAL_CHANNEL));
  428. }
  429. break;
  430. default:
  431. log.debug('unhandle client gcc block : ' + clientSettings[i].obj.__TYPE__);
  432. }
  433. }
  434. this.sendConnectResponse();
  435. };
  436. /**
  437. * State 2 in mcs server connection automata
  438. */
  439. Server.prototype.sendConnectResponse = function () {
  440. var ccReq = gcc.writeConferenceCreateResponse(new type.Component([
  441. gcc.block(this.serverCoreData),
  442. gcc.block(this.serverSecurityData),
  443. gcc.block(this.serverNetworkData),
  444. ])).toStream().getValue();
  445. this.transport.send(ConnectResponse(ccReq).encode(asn1.ber));
  446. };
  447. /**
  448. * Module exports
  449. */
  450. module.exports = {
  451. Client : Client,
  452. Server : Server
  453. };