mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	
							parent
							
								
									f88d3063fe
								
							
						
					
					
						commit
						db06ec1975
					
				
					 37 changed files with 28174 additions and 44 deletions
				
			
		
							
								
								
									
										402
									
								
								rdp/protocol/pdu/global.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										402
									
								
								rdp/protocol/pdu/global.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,402 @@ | |||
| /* | ||||
|  * Copyright (c) 2014-2015 Sylvain Peyrefitte | ||||
|  * | ||||
|  * This file is part of node-rdpjs. | ||||
|  * | ||||
|  * node-rdpjs is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| var inherits = require('util').inherits; | ||||
| var events = require('events'); | ||||
| var caps = require('./caps'); | ||||
| var data = require('./data'); | ||||
| var type = require('../../core').type; | ||||
| var log = require('../../core').log; | ||||
| 
 | ||||
| /** | ||||
|  * Global channel for all graphic updates | ||||
|  * capabilities exchange and input handles | ||||
|  */ | ||||
| function Global(transport, fastPathTransport) { | ||||
| 	this.transport = transport; | ||||
| 	this.fastPathTransport = fastPathTransport; | ||||
| 	// must be init via connect event
 | ||||
| 	this.userId = 0; | ||||
| 	this.serverCapabilities = []; | ||||
| 	this.clientCapabilities = []; | ||||
| } | ||||
| 
 | ||||
| //inherit from Layer
 | ||||
| inherits(Global, events.EventEmitter); | ||||
| 
 | ||||
| /** | ||||
|  * Send formated PDU message | ||||
|  * @param message {type.Component} PDU message | ||||
|  */ | ||||
| Global.prototype.sendPDU = function(message) { | ||||
| 	this.transport.send(data.pdu(this.userId, message)); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Send formated Data PDU message | ||||
|  * @param message {type.Component} PDU message | ||||
|  */ | ||||
| Global.prototype.sendDataPDU = function(message) { | ||||
| 	this.sendPDU(data.dataPDU(message, this.shareId)); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Client side of Global channel automata | ||||
|  * @param transport | ||||
|  */ | ||||
| function Client(transport, fastPathTransport) { | ||||
| 	Global.call(this, transport, fastPathTransport); | ||||
| 	var self = this; | ||||
| 	this.transport.once('connect', function(core, userId, channelId) { | ||||
| 		self.connect(core, userId, channelId); | ||||
| 	}).on('close', function() { | ||||
| 		self.emit('close'); | ||||
| 	}).on('error', function (err) { | ||||
| 		self.emit('error', err); | ||||
| 	}); | ||||
| 	 | ||||
| 	if (this.fastPathTransport) { | ||||
| 		this.fastPathTransport.on('fastPathData', function (secFlag, s) { | ||||
| 			self.recvFastPath(secFlag, s); | ||||
| 		}); | ||||
| 	} | ||||
| 	 | ||||
| 	// init client capabilities
 | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL] = caps.generalCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP] = caps.bitmapCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_ORDER] = caps.orderCapability( | ||||
| 			new type.Component([ | ||||
| 			     new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), | ||||
| 			     new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), | ||||
| 			     new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), | ||||
| 			     new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0), new type.UInt8(0) | ||||
| 			])); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAPCACHE] = caps.bitmapCacheCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_POINTER] = caps.pointerCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_INPUT] = caps.inputCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_BRUSH] = caps.brushCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_GLYPHCACHE] = caps.glyphCapability( | ||||
| 			new type.Component([ | ||||
| 			    caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), | ||||
| 			    caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry(), caps.cacheEntry() | ||||
| 			])); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_OFFSCREENCACHE] = caps.offscreenBitmapCacheCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_VIRTUALCHANNEL] = caps.virtualChannelCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSTYPE_SOUND] = caps.soundCapability(); | ||||
| 	this.clientCapabilities[caps.CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE] = caps.multiFragmentUpdate(); | ||||
| } | ||||
| 
 | ||||
| // inherit from Layer
 | ||||
| inherits(Client, Global); | ||||
| 
 | ||||
| /** | ||||
|  * connect function | ||||
|  * @param gccCore {type.Component(clientCoreData)} | ||||
|  */ | ||||
| Client.prototype.connect = function(gccCore, userId, channelId) { | ||||
| 	this.gccCore = gccCore; | ||||
| 	this.userId = userId; | ||||
| 	this.channelId = channelId; | ||||
| 	var self = this; | ||||
| 	this.transport.once('data', function(s) { | ||||
| 		self.recvDemandActivePDU(s); | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * close stack | ||||
|  */ | ||||
| Client.prototype.close = function() { | ||||
| 	this.transport.close(); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Receive capabilities from server | ||||
|  * @param s {type.Stream} | ||||
|  */ | ||||
| Client.prototype.recvDemandActivePDU = function(s) { | ||||
| 	var pdu = data.pdu().read(s); | ||||
| 	if (pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DEMANDACTIVEPDU) { | ||||
| 		log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence'); | ||||
| 		 | ||||
| 		// loop on state
 | ||||
| 		var self = this; | ||||
| 		this.transport.once('data', function(s) { | ||||
| 			self.recvDemandActivePDU(s); | ||||
| 		}); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	// store share id
 | ||||
| 	this.shareId = pdu.obj.pduMessage.obj.shareId.value; | ||||
| 	 | ||||
| 	// store server capabilities
 | ||||
| 	for(var i in pdu.obj.pduMessage.obj.capabilitySets.obj) { | ||||
| 		var cap = pdu.obj.pduMessage.obj.capabilitySets.obj[i].obj.capability; | ||||
| 		if(!cap.obj) { | ||||
| 			continue; | ||||
| 		} | ||||
| 		this.serverCapabilities[cap.obj.__TYPE__] = cap; | ||||
| 	} | ||||
| 	 | ||||
| 	this.transport.enableSecureCheckSum = !!(this.serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].obj.extraFlags.value & caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM); | ||||
| 	 | ||||
| 	this.sendConfirmActivePDU(); | ||||
| 	this.sendClientFinalizeSynchronizePDU(); | ||||
| 	 | ||||
| 	var self = this; | ||||
| 	this.transport.once('data', function(s) { | ||||
| 		self.recvServerSynchronizePDU(s); | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * global channel automata state | ||||
|  * @param s {type.Stream} | ||||
|  */ | ||||
| Client.prototype.recvServerSynchronizePDU = function(s) { | ||||
| 	var pdu = data.pdu().read(s); | ||||
| 	if (	pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU  | ||||
| 		|| 	pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_SYNCHRONIZE) { | ||||
| 		log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence'); | ||||
| 		// loop on state
 | ||||
| 		var self = this; | ||||
| 		this.transport.once('data', function(s) { | ||||
| 			self.recvServerSynchronizePDU(s); | ||||
| 		}); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	var self = this; | ||||
| 	this.transport.once('data', function(s) { | ||||
| 		self.recvServerControlCooperatePDU(s); | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * global channel automata state | ||||
|  * @param s {type.Stream} | ||||
|  */ | ||||
| Client.prototype.recvServerControlCooperatePDU = function(s) { | ||||
| 	var pdu = data.pdu().read(s); | ||||
| 	if (	pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU  | ||||
| 		|| 	pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_CONTROL  | ||||
| 		||	pdu.obj.pduMessage.obj.pduData.obj.action.value !== data.Action.CTRLACTION_COOPERATE) { | ||||
| 		log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence'); | ||||
| 		 | ||||
| 		// loop on state
 | ||||
| 		var self = this; | ||||
| 		this.transport.once('data', function(s) { | ||||
| 			self.recvServerControlCooperatePDU(s); | ||||
| 		}); | ||||
| 	} | ||||
| 	 | ||||
| 	var self = this; | ||||
| 	this.transport.once('data', function(s) { | ||||
| 		self.recvServerControlGrantedPDU(s); | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * global channel automata state | ||||
|  * @param s {type.Stream} | ||||
|  */ | ||||
| Client.prototype.recvServerControlGrantedPDU = function(s) { | ||||
| 	var pdu = data.pdu().read(s); | ||||
| 	if (	pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU  | ||||
| 		||	pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_CONTROL  | ||||
| 		||	pdu.obj.pduMessage.obj.pduData.obj.action.value !== data.Action.CTRLACTION_GRANTED_CONTROL) { | ||||
| 		log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence'); | ||||
| 		 | ||||
| 		// loop on state
 | ||||
| 		var self = this; | ||||
| 		this.transport.once('data', function(s) { | ||||
| 			self.recvServerControlGrantedPDU(s); | ||||
| 		}); | ||||
| 	} | ||||
| 	 | ||||
| 	var self = this; | ||||
| 	this.transport.once('data', function(s) { | ||||
| 		self.recvServerFontMapPDU(s); | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * global channel automata state | ||||
|  * @param s {type.Stream} | ||||
|  */ | ||||
| Client.prototype.recvServerFontMapPDU = function(s) { | ||||
| 	var pdu = data.pdu().read(s); | ||||
| 	if (	pdu.obj.shareControlHeader.obj.pduType.value !== data.PDUType.PDUTYPE_DATAPDU  | ||||
| 		||	pdu.obj.pduMessage.obj.shareDataHeader.obj.pduType2.value !== data.PDUType2.PDUTYPE2_FONTMAP) { | ||||
| 		log.debug('ignore message type ' + pdu.obj.shareControlHeader.obj.pduType.value + ' during connection sequence'); | ||||
| 		 | ||||
| 		// loop on state
 | ||||
| 		var self = this; | ||||
| 		this.transport.once('data', function(s) { | ||||
| 			self.recvServerFontMapPDU(s); | ||||
| 		}); | ||||
| 	} | ||||
| 	 | ||||
| 	this.emit('connect'); | ||||
| 	var self = this; | ||||
| 	this.transport.on('data', function(s) { | ||||
| 		self.recvPDU(s); | ||||
| 	}); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Main reveive fast path | ||||
|  * @param secFlag {integer}  | ||||
|  * @param s {type.Stream} | ||||
|  */ | ||||
| Client.prototype.recvFastPath = function (secFlag, s) { | ||||
| 	while (s.availableLength() > 0) { | ||||
| 		var pdu = data.fastPathUpdatePDU().read(s); | ||||
| 		switch (pdu.obj.updateHeader.value & 0xf) { | ||||
| 		case data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP: | ||||
| 			this.emit('bitmap', pdu.obj.updateData.obj.rectangles.obj); | ||||
| 			break; | ||||
| 		default: | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * global channel automata state | ||||
|  * @param s {type.Stream} | ||||
|  */ | ||||
| Client.prototype.recvPDU = function(s) { | ||||
| 	while (s.availableLength() > 0) { | ||||
| 		var pdu = data.pdu().read(s); | ||||
| 		switch(pdu.obj.shareControlHeader.obj.pduType.value) { | ||||
| 		case data.PDUType.PDUTYPE_DEACTIVATEALLPDU: | ||||
| 			var self = this; | ||||
| 			this.transport.removeAllListeners('data'); | ||||
| 			this.transport.once('data', function(s) { | ||||
| 				self.recvDemandActivePDU(s); | ||||
| 			}); | ||||
| 			break; | ||||
| 		case data.PDUType.PDUTYPE_DATAPDU: | ||||
| 			this.readDataPDU(pdu.obj.pduMessage) | ||||
| 			break; | ||||
| 		default: | ||||
| 			log.debug('ignore pdu type ' + pdu.obj.shareControlHeader.obj.pduType.value); | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * main receive for data PDU packet | ||||
|  * @param dataPDU {data.dataPDU} | ||||
|  */ | ||||
| Client.prototype.readDataPDU = function (dataPDU) { | ||||
| 	switch(dataPDU.obj.shareDataHeader.obj.pduType2.value) { | ||||
| 	case data.PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU: | ||||
| 		break; | ||||
| 	case data.PDUType2.PDUTYPE2_SHUTDOWN_DENIED: | ||||
| 		this.transport.close(); | ||||
| 		break; | ||||
| 	case data.PDUType2.PDUTYPE2_SAVE_SESSION_INFO: | ||||
| 		this.emit('session'); | ||||
| 		break; | ||||
| 	case data.PDUType2.PDUTYPE2_UPDATE: | ||||
| 		this.readUpdateDataPDU(dataPDU.obj.pduData) | ||||
| 		break; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Main upadate pdu receive function | ||||
|  * @param updateDataPDU | ||||
|  */ | ||||
| Client.prototype.readUpdateDataPDU = function (updateDataPDU) { | ||||
| 	switch(updateDataPDU.obj.updateType.value) { | ||||
| 	case data.UpdateType.UPDATETYPE_BITMAP: | ||||
| 		this.emit('bitmap', updateDataPDU.obj.updateData.obj.rectangles.obj) | ||||
| 		break; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * send all client capabilities | ||||
|  */ | ||||
| Client.prototype.sendConfirmActivePDU = function () { | ||||
| 	var generalCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].obj; | ||||
| 	generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS; | ||||
| 	generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT; | ||||
| 	generalCapability.extraFlags.value = 	caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED  | ||||
| 										| 	caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR  | ||||
| 										| 	caps.GeneralExtraFlag.ENC_SALTED_CHECKSUM | ||||
| 										|	caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED; | ||||
| 	 | ||||
| 	var bitmapCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].obj; | ||||
| 	bitmapCapability.preferredBitsPerPixel.value = this.gccCore.highColorDepth.value; | ||||
|     bitmapCapability.desktopWidth.value = this.gccCore.desktopWidth.value; | ||||
|     bitmapCapability.desktopHeight.value = this.gccCore.desktopHeight.value; | ||||
|      | ||||
|     var orderCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_ORDER].obj; | ||||
|     orderCapability.orderFlags.value |= caps.OrderFlag.ZEROBOUNDSDELTASSUPPORT; | ||||
|      | ||||
|     var inputCapability = this.clientCapabilities[caps.CapsType.CAPSTYPE_INPUT].obj; | ||||
|     inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX | caps.InputFlags.INPUT_FLAG_UNICODE; | ||||
|     inputCapability.keyboardLayout = this.gccCore.kbdLayout; | ||||
|     inputCapability.keyboardType = this.gccCore.keyboardType; | ||||
|     inputCapability.keyboardSubType = this.gccCore.keyboardSubType; | ||||
|     inputCapability.keyboardrFunctionKey = this.gccCore.keyboardFnKeys; | ||||
|     inputCapability.imeFileName = this.gccCore.imeFileName; | ||||
|      | ||||
|     var capabilities = new type.Component([]); | ||||
|     for(var i in this.clientCapabilities) { | ||||
|     	capabilities.obj.push(caps.capability(this.clientCapabilities[i])); | ||||
|     } | ||||
|      | ||||
|     var confirmActivePDU = data.confirmActivePDU(capabilities, this.shareId); | ||||
|      | ||||
|     this.sendPDU(confirmActivePDU); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * send synchronize PDU | ||||
|  */ | ||||
| Client.prototype.sendClientFinalizeSynchronizePDU = function() { | ||||
| 	this.sendDataPDU(data.synchronizeDataPDU(this.channelId)); | ||||
| 	this.sendDataPDU(data.controlDataPDU(data.Action.CTRLACTION_COOPERATE)); | ||||
| 	this.sendDataPDU(data.controlDataPDU(data.Action.CTRLACTION_REQUEST_CONTROL)); | ||||
| 	this.sendDataPDU(data.fontListDataPDU()); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Send input event as slow path input | ||||
|  * @param inputEvents {array} | ||||
|  */ | ||||
| Client.prototype.sendInputEvents = function (inputEvents) { | ||||
| 	var pdu = data.clientInputEventPDU(new type.Component(inputEvents.map(function (e) { | ||||
| 		return data.slowPathInputEvent(e); | ||||
| 	}))); | ||||
| 	 | ||||
| 	this.sendDataPDU(pdu); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Module exports | ||||
|  */ | ||||
| module.exports = { | ||||
| 	Client : Client | ||||
| }; | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue