mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-10-29 15:25:01 -04:00 
			
		
		
		
	
							parent
							
								
									f88d3063fe
								
							
						
					
					
						commit
						db06ec1975
					
				| @ -182,6 +182,37 @@ | |||||||
|     <Compile Include="public\novnc\vendor\promise.js" /> |     <Compile Include="public\novnc\vendor\promise.js" /> | ||||||
|     <Compile Include="public\scripts\agent-redir-rtc-0.1.0.js" /> |     <Compile Include="public\scripts\agent-redir-rtc-0.1.0.js" /> | ||||||
|     <Compile Include="public\serviceworker.js" /> |     <Compile Include="public\serviceworker.js" /> | ||||||
|  |     <Compile Include="rdp\asn1\ber.js" /> | ||||||
|  |     <Compile Include="rdp\asn1\index.js" /> | ||||||
|  |     <Compile Include="rdp\asn1\spec.js" /> | ||||||
|  |     <Compile Include="rdp\asn1\univ.js" /> | ||||||
|  |     <Compile Include="rdp\core\error.js" /> | ||||||
|  |     <Compile Include="rdp\core\index.js" /> | ||||||
|  |     <Compile Include="rdp\core\layer.js" /> | ||||||
|  |     <Compile Include="rdp\core\log.js" /> | ||||||
|  |     <Compile Include="rdp\core\rle.js" /> | ||||||
|  |     <Compile Include="rdp\core\type.js" /> | ||||||
|  |     <Compile Include="rdp\index.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\cert.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\index.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\nla.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\pdu\caps.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\pdu\data.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\pdu\global.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\pdu\index.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\pdu\lic.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\pdu\sec.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\rdp.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\t125\gcc.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\t125\index.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\t125\mcs.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\t125\per.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\tpkt.js" /> | ||||||
|  |     <Compile Include="rdp\protocol\x224.js" /> | ||||||
|  |     <Compile Include="rdp\security\index.js" /> | ||||||
|  |     <Compile Include="rdp\security\jsbn.js" /> | ||||||
|  |     <Compile Include="rdp\security\rsa.js" /> | ||||||
|  |     <Compile Include="rdp\security\x509.js" /> | ||||||
|     <Compile Include="swarmserver.js" /> |     <Compile Include="swarmserver.js" /> | ||||||
|     <Compile Include="multiserver.js" /> |     <Compile Include="multiserver.js" /> | ||||||
|     <Compile Include="pass.js" /> |     <Compile Include="pass.js" /> | ||||||
| @ -550,6 +581,8 @@ | |||||||
|     <Content Include="public\styles\style.css" /> |     <Content Include="public\styles\style.css" /> | ||||||
|     <Content Include="public\translate.bat" /> |     <Content Include="public\translate.bat" /> | ||||||
|     <Content Include="public\translator.htm" /> |     <Content Include="public\translator.htm" /> | ||||||
|  |     <Content Include="rdp\LICENSE" /> | ||||||
|  |     <Content Include="rdp\README.md" /> | ||||||
|     <Content Include="readme.md" /> |     <Content Include="readme.md" /> | ||||||
|     <Content Include="sample-config-advanced.json" /> |     <Content Include="sample-config-advanced.json" /> | ||||||
|     <Content Include="sample-config.json" /> |     <Content Include="sample-config.json" /> | ||||||
| @ -624,6 +657,13 @@ | |||||||
|     <Folder Include="public\styles\font-awesome\fonts\" /> |     <Folder Include="public\styles\font-awesome\fonts\" /> | ||||||
|     <Folder Include="public\styles\font-awesome\less\" /> |     <Folder Include="public\styles\font-awesome\less\" /> | ||||||
|     <Folder Include="public\styles\font-awesome\scss\" /> |     <Folder Include="public\styles\font-awesome\scss\" /> | ||||||
|  |     <Folder Include="rdp\" /> | ||||||
|  |     <Folder Include="rdp\asn1\" /> | ||||||
|  |     <Folder Include="rdp\core\" /> | ||||||
|  |     <Folder Include="rdp\protocol\" /> | ||||||
|  |     <Folder Include="rdp\protocol\pdu\" /> | ||||||
|  |     <Folder Include="rdp\protocol\t125\" /> | ||||||
|  |     <Folder Include="rdp\security\" /> | ||||||
|     <Folder Include="translate\" /> |     <Folder Include="translate\" /> | ||||||
|     <Folder Include="typings\" /> |     <Folder Include="typings\" /> | ||||||
|     <Folder Include="typings\globals\" /> |     <Folder Include="typings\globals\" /> | ||||||
|  | |||||||
| @ -129,8 +129,9 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { | |||||||
|     function startRdp(port) { |     function startRdp(port) { | ||||||
|         parent.parent.debug('relay', 'RDP: Starting RDP client on loopback port ' + port); |         parent.parent.debug('relay', 'RDP: Starting RDP client on loopback port ' + port); | ||||||
|         try { |         try { | ||||||
|             rdpClient = require('node-rdpjs-2').createClient({ |             //rdpClient = require('node-rdpjs-2').createClient({
 | ||||||
|                 logLevel: 'ERROR', |             rdpClient = require('./rdp').createClient({ | ||||||
|  |                 logLevel: 'NONE', // 'ERROR',
 | ||||||
|                 domain: obj.infos.domain, |                 domain: obj.infos.domain, | ||||||
|                 userName: obj.infos.username, |                 userName: obj.infos.username, | ||||||
|                 password: obj.infos.password, |                 password: obj.infos.password, | ||||||
|  | |||||||
| @ -3478,13 +3478,16 @@ function mainStart() { | |||||||
|         const verSplit = process.version.substring(1).split('.'); |         const verSplit = process.version.substring(1).split('.'); | ||||||
|         var nodeVersion = parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); |         var nodeVersion = parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); | ||||||
| 
 | 
 | ||||||
|  |         // Check if RDP support if present
 | ||||||
|  |         var mstsc = true; | ||||||
|  |         try { require('./rdp') } catch (ex) { mstsc = false; } | ||||||
|  | 
 | ||||||
|         // Check if Windows SSPI, LDAP, Passport and YubiKey OTP will be used
 |         // Check if Windows SSPI, LDAP, Passport and YubiKey OTP will be used
 | ||||||
|         var sspi = false; |         var sspi = false; | ||||||
|         var ldap = false; |         var ldap = false; | ||||||
|         var passport = null; |         var passport = null; | ||||||
|         var allsspi = true; |         var allsspi = true; | ||||||
|         var yubikey = false; |         var yubikey = false; | ||||||
|         var mstsc = false; |  | ||||||
|         var ssh = false; |         var ssh = false; | ||||||
|         var sessionRecording = false; |         var sessionRecording = false; | ||||||
|         var domainCount = 0; |         var domainCount = 0; | ||||||
| @ -3499,7 +3502,7 @@ function mainStart() { | |||||||
|             if (config.domains[i].sendgrid != null) { sendgrid = true; } |             if (config.domains[i].sendgrid != null) { sendgrid = true; } | ||||||
|             if (config.domains[i].yubikey != null) { yubikey = true; } |             if (config.domains[i].yubikey != null) { yubikey = true; } | ||||||
|             if (config.domains[i].auth == 'ldap') { ldap = true; } |             if (config.domains[i].auth == 'ldap') { ldap = true; } | ||||||
|             if (config.domains[i].mstsc == true) { mstsc = true; } |             if (mstsc == false) { config.domains[i].mstsc = false; } | ||||||
|             if (config.domains[i].ssh == true) { if (nodeVersion < 11) { config.domains[i].ssh = false; } ssh = true; } |             if (config.domains[i].ssh == true) { if (nodeVersion < 11) { config.domains[i].ssh = false; } ssh = true; } | ||||||
|             if ((typeof config.domains[i].authstrategies == 'object')) { |             if ((typeof config.domains[i].authstrategies == 'object')) { | ||||||
|                 if (passport == null) { passport = ['passport']; } |                 if (passport == null) { passport = ['passport']; } | ||||||
| @ -3519,7 +3522,6 @@ function mainStart() { | |||||||
|         var modules = ['ws@5.2.3', 'cbor@5.2.0', '@yetzt/nedb', 'https', 'yauzl', 'ipcheck', 'express', 'archiver@4.0.2', 'multiparty', 'node-forge', 'express-ws@4.0.0', 'compression', 'body-parser', 'cookie-session@1.4.0', 'express-handlebars']; |         var modules = ['ws@5.2.3', 'cbor@5.2.0', '@yetzt/nedb', 'https', 'yauzl', 'ipcheck', 'express', 'archiver@4.0.2', 'multiparty', 'node-forge', 'express-ws@4.0.0', 'compression', 'body-parser', 'cookie-session@1.4.0', 'express-handlebars']; | ||||||
|         if (require('os').platform() == 'win32') { modules.push('node-windows@0.1.4'); modules.push('loadavg-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
 |         if (require('os').platform() == 'win32') { modules.push('node-windows@0.1.4'); modules.push('loadavg-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
 | ||||||
|         if (ldap == true) { modules.push('ldapauth-fork'); } |         if (ldap == true) { modules.push('ldapauth-fork'); } | ||||||
|         if (mstsc == true) { modules.push('node-rdpjs-2'); } |  | ||||||
|         if (ssh == true) { if (nodeVersion < 11) { addServerWarning('MeshCentral SSH support requires NodeJS 11 or higher.', 1); } else { modules.push('ssh2'); } } |         if (ssh == true) { if (nodeVersion < 11) { addServerWarning('MeshCentral SSH support requires NodeJS 11 or higher.', 1); } else { modules.push('ssh2'); } } | ||||||
|         if (passport != null) { modules.push(...passport); } |         if (passport != null) { modules.push(...passport); } | ||||||
|         if (sessionRecording == true) { modules.push('image-size'); } // Need to get the remote desktop JPEG sizes to index the recodring file.
 |         if (sessionRecording == true) { modules.push('image-size'); } // Need to get the remote desktop JPEG sizes to index the recodring file.
 | ||||||
|  | |||||||
							
								
								
									
										674
									
								
								rdp/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										674
									
								
								rdp/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,674 @@ | |||||||
|  | GNU GENERAL PUBLIC LICENSE | ||||||
|  |                        Version 3, 29 June 2007 | ||||||
|  | 
 | ||||||
|  |  Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | ||||||
|  |  Everyone is permitted to copy and distribute verbatim copies | ||||||
|  |  of this license document, but changing it is not allowed. | ||||||
|  | 
 | ||||||
|  |                             Preamble | ||||||
|  | 
 | ||||||
|  |   The GNU General Public License is a free, copyleft license for | ||||||
|  | software and other kinds of works. | ||||||
|  | 
 | ||||||
|  |   The licenses for most software and other practical works are designed | ||||||
|  | to take away your freedom to share and change the works.  By contrast, | ||||||
|  | the GNU General Public License is intended to guarantee your freedom to | ||||||
|  | share and change all versions of a program--to make sure it remains free | ||||||
|  | software for all its users.  We, the Free Software Foundation, use the | ||||||
|  | GNU General Public License for most of our software; it applies also to | ||||||
|  | any other work released this way by its authors.  You can apply it to | ||||||
|  | your programs, too. | ||||||
|  | 
 | ||||||
|  |   When we speak of free software, we are referring to freedom, not | ||||||
|  | price.  Our General Public Licenses are designed to make sure that you | ||||||
|  | have the freedom to distribute copies of free software (and charge for | ||||||
|  | them if you wish), that you receive source code or can get it if you | ||||||
|  | want it, that you can change the software or use pieces of it in new | ||||||
|  | free programs, and that you know you can do these things. | ||||||
|  | 
 | ||||||
|  |   To protect your rights, we need to prevent others from denying you | ||||||
|  | these rights or asking you to surrender the rights.  Therefore, you have | ||||||
|  | certain responsibilities if you distribute copies of the software, or if | ||||||
|  | you modify it: responsibilities to respect the freedom of others. | ||||||
|  | 
 | ||||||
|  |   For example, if you distribute copies of such a program, whether | ||||||
|  | gratis or for a fee, you must pass on to the recipients the same | ||||||
|  | freedoms that you received.  You must make sure that they, too, receive | ||||||
|  | or can get the source code.  And you must show them these terms so they | ||||||
|  | know their rights. | ||||||
|  | 
 | ||||||
|  |   Developers that use the GNU GPL protect your rights with two steps: | ||||||
|  | (1) assert copyright on the software, and (2) offer you this License | ||||||
|  | giving you legal permission to copy, distribute and/or modify it. | ||||||
|  | 
 | ||||||
|  |   For the developers' and authors' protection, the GPL clearly explains | ||||||
|  | that there is no warranty for this free software.  For both users' and | ||||||
|  | authors' sake, the GPL requires that modified versions be marked as | ||||||
|  | changed, so that their problems will not be attributed erroneously to | ||||||
|  | authors of previous versions. | ||||||
|  | 
 | ||||||
|  |   Some devices are designed to deny users access to install or run | ||||||
|  | modified versions of the software inside them, although the manufacturer | ||||||
|  | can do so.  This is fundamentally incompatible with the aim of | ||||||
|  | protecting users' freedom to change the software.  The systematic | ||||||
|  | pattern of such abuse occurs in the area of products for individuals to | ||||||
|  | use, which is precisely where it is most unacceptable.  Therefore, we | ||||||
|  | have designed this version of the GPL to prohibit the practice for those | ||||||
|  | products.  If such problems arise substantially in other domains, we | ||||||
|  | stand ready to extend this provision to those domains in future versions | ||||||
|  | of the GPL, as needed to protect the freedom of users. | ||||||
|  | 
 | ||||||
|  |   Finally, every program is threatened constantly by software patents. | ||||||
|  | States should not allow patents to restrict development and use of | ||||||
|  | software on general-purpose computers, but in those that do, we wish to | ||||||
|  | avoid the special danger that patents applied to a free program could | ||||||
|  | make it effectively proprietary.  To prevent this, the GPL assures that | ||||||
|  | patents cannot be used to render the program non-free. | ||||||
|  | 
 | ||||||
|  |   The precise terms and conditions for copying, distribution and | ||||||
|  | modification follow. | ||||||
|  | 
 | ||||||
|  |                        TERMS AND CONDITIONS | ||||||
|  | 
 | ||||||
|  |   0. Definitions. | ||||||
|  | 
 | ||||||
|  |   "This License" refers to version 3 of the GNU General Public License. | ||||||
|  | 
 | ||||||
|  |   "Copyright" also means copyright-like laws that apply to other kinds of | ||||||
|  | works, such as semiconductor masks. | ||||||
|  | 
 | ||||||
|  |   "The Program" refers to any copyrightable work licensed under this | ||||||
|  | License.  Each licensee is addressed as "you".  "Licensees" and | ||||||
|  | "recipients" may be individuals or organizations. | ||||||
|  | 
 | ||||||
|  |   To "modify" a work means to copy from or adapt all or part of the work | ||||||
|  | in a fashion requiring copyright permission, other than the making of an | ||||||
|  | exact copy.  The resulting work is called a "modified version" of the | ||||||
|  | earlier work or a work "based on" the earlier work. | ||||||
|  | 
 | ||||||
|  |   A "covered work" means either the unmodified Program or a work based | ||||||
|  | on the Program. | ||||||
|  | 
 | ||||||
|  |   To "propagate" a work means to do anything with it that, without | ||||||
|  | permission, would make you directly or secondarily liable for | ||||||
|  | infringement under applicable copyright law, except executing it on a | ||||||
|  | computer or modifying a private copy.  Propagation includes copying, | ||||||
|  | distribution (with or without modification), making available to the | ||||||
|  | public, and in some countries other activities as well. | ||||||
|  | 
 | ||||||
|  |   To "convey" a work means any kind of propagation that enables other | ||||||
|  | parties to make or receive copies.  Mere interaction with a user through | ||||||
|  | a computer network, with no transfer of a copy, is not conveying. | ||||||
|  | 
 | ||||||
|  |   An interactive user interface displays "Appropriate Legal Notices" | ||||||
|  | to the extent that it includes a convenient and prominently visible | ||||||
|  | feature that (1) displays an appropriate copyright notice, and (2) | ||||||
|  | tells the user that there is no warranty for the work (except to the | ||||||
|  | extent that warranties are provided), that licensees may convey the | ||||||
|  | work under this License, and how to view a copy of this License.  If | ||||||
|  | the interface presents a list of user commands or options, such as a | ||||||
|  | menu, a prominent item in the list meets this criterion. | ||||||
|  | 
 | ||||||
|  |   1. Source Code. | ||||||
|  | 
 | ||||||
|  |   The "source code" for a work means the preferred form of the work | ||||||
|  | for making modifications to it.  "Object code" means any non-source | ||||||
|  | form of a work. | ||||||
|  | 
 | ||||||
|  |   A "Standard Interface" means an interface that either is an official | ||||||
|  | standard defined by a recognized standards body, or, in the case of | ||||||
|  | interfaces specified for a particular programming language, one that | ||||||
|  | is widely used among developers working in that language. | ||||||
|  | 
 | ||||||
|  |   The "System Libraries" of an executable work include anything, other | ||||||
|  | than the work as a whole, that (a) is included in the normal form of | ||||||
|  | packaging a Major Component, but which is not part of that Major | ||||||
|  | Component, and (b) serves only to enable use of the work with that | ||||||
|  | Major Component, or to implement a Standard Interface for which an | ||||||
|  | implementation is available to the public in source code form.  A | ||||||
|  | "Major Component", in this context, means a major essential component | ||||||
|  | (kernel, window system, and so on) of the specific operating system | ||||||
|  | (if any) on which the executable work runs, or a compiler used to | ||||||
|  | produce the work, or an object code interpreter used to run it. | ||||||
|  | 
 | ||||||
|  |   The "Corresponding Source" for a work in object code form means all | ||||||
|  | the source code needed to generate, install, and (for an executable | ||||||
|  | work) run the object code and to modify the work, including scripts to | ||||||
|  | control those activities.  However, it does not include the work's | ||||||
|  | System Libraries, or general-purpose tools or generally available free | ||||||
|  | programs which are used unmodified in performing those activities but | ||||||
|  | which are not part of the work.  For example, Corresponding Source | ||||||
|  | includes interface definition files associated with source files for | ||||||
|  | the work, and the source code for shared libraries and dynamically | ||||||
|  | linked subprograms that the work is specifically designed to require, | ||||||
|  | such as by intimate data communication or control flow between those | ||||||
|  | subprograms and other parts of the work. | ||||||
|  | 
 | ||||||
|  |   The Corresponding Source need not include anything that users | ||||||
|  | can regenerate automatically from other parts of the Corresponding | ||||||
|  | Source. | ||||||
|  | 
 | ||||||
|  |   The Corresponding Source for a work in source code form is that | ||||||
|  | same work. | ||||||
|  | 
 | ||||||
|  |   2. Basic Permissions. | ||||||
|  | 
 | ||||||
|  |   All rights granted under this License are granted for the term of | ||||||
|  | copyright on the Program, and are irrevocable provided the stated | ||||||
|  | conditions are met.  This License explicitly affirms your unlimited | ||||||
|  | permission to run the unmodified Program.  The output from running a | ||||||
|  | covered work is covered by this License only if the output, given its | ||||||
|  | content, constitutes a covered work.  This License acknowledges your | ||||||
|  | rights of fair use or other equivalent, as provided by copyright law. | ||||||
|  | 
 | ||||||
|  |   You may make, run and propagate covered works that you do not | ||||||
|  | convey, without conditions so long as your license otherwise remains | ||||||
|  | in force.  You may convey covered works to others for the sole purpose | ||||||
|  | of having them make modifications exclusively for you, or provide you | ||||||
|  | with facilities for running those works, provided that you comply with | ||||||
|  | the terms of this License in conveying all material for which you do | ||||||
|  | not control copyright.  Those thus making or running the covered works | ||||||
|  | for you must do so exclusively on your behalf, under your direction | ||||||
|  | and control, on terms that prohibit them from making any copies of | ||||||
|  | your copyrighted material outside their relationship with you. | ||||||
|  | 
 | ||||||
|  |   Conveying under any other circumstances is permitted solely under | ||||||
|  | the conditions stated below.  Sublicensing is not allowed; section 10 | ||||||
|  | makes it unnecessary. | ||||||
|  | 
 | ||||||
|  |   3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||||||
|  | 
 | ||||||
|  |   No covered work shall be deemed part of an effective technological | ||||||
|  | measure under any applicable law fulfilling obligations under article | ||||||
|  | 11 of the WIPO copyright treaty adopted on 20 December 1996, or | ||||||
|  | similar laws prohibiting or restricting circumvention of such | ||||||
|  | measures. | ||||||
|  | 
 | ||||||
|  |   When you convey a covered work, you waive any legal power to forbid | ||||||
|  | circumvention of technological measures to the extent such circumvention | ||||||
|  | is effected by exercising rights under this License with respect to | ||||||
|  | the covered work, and you disclaim any intention to limit operation or | ||||||
|  | modification of the work as a means of enforcing, against the work's | ||||||
|  | users, your or third parties' legal rights to forbid circumvention of | ||||||
|  | technological measures. | ||||||
|  | 
 | ||||||
|  |   4. Conveying Verbatim Copies. | ||||||
|  | 
 | ||||||
|  |   You may convey verbatim copies of the Program's source code as you | ||||||
|  | receive it, in any medium, provided that you conspicuously and | ||||||
|  | appropriately publish on each copy an appropriate copyright notice; | ||||||
|  | keep intact all notices stating that this License and any | ||||||
|  | non-permissive terms added in accord with section 7 apply to the code; | ||||||
|  | keep intact all notices of the absence of any warranty; and give all | ||||||
|  | recipients a copy of this License along with the Program. | ||||||
|  | 
 | ||||||
|  |   You may charge any price or no price for each copy that you convey, | ||||||
|  | and you may offer support or warranty protection for a fee. | ||||||
|  | 
 | ||||||
|  |   5. Conveying Modified Source Versions. | ||||||
|  | 
 | ||||||
|  |   You may convey a work based on the Program, or the modifications to | ||||||
|  | produce it from the Program, in the form of source code under the | ||||||
|  | terms of section 4, provided that you also meet all of these conditions: | ||||||
|  | 
 | ||||||
|  |     a) The work must carry prominent notices stating that you modified | ||||||
|  |     it, and giving a relevant date. | ||||||
|  | 
 | ||||||
|  |     b) The work must carry prominent notices stating that it is | ||||||
|  |     released under this License and any conditions added under section | ||||||
|  |     7.  This requirement modifies the requirement in section 4 to | ||||||
|  |     "keep intact all notices". | ||||||
|  | 
 | ||||||
|  |     c) You must license the entire work, as a whole, under this | ||||||
|  |     License to anyone who comes into possession of a copy.  This | ||||||
|  |     License will therefore apply, along with any applicable section 7 | ||||||
|  |     additional terms, to the whole of the work, and all its parts, | ||||||
|  |     regardless of how they are packaged.  This License gives no | ||||||
|  |     permission to license the work in any other way, but it does not | ||||||
|  |     invalidate such permission if you have separately received it. | ||||||
|  | 
 | ||||||
|  |     d) If the work has interactive user interfaces, each must display | ||||||
|  |     Appropriate Legal Notices; however, if the Program has interactive | ||||||
|  |     interfaces that do not display Appropriate Legal Notices, your | ||||||
|  |     work need not make them do so. | ||||||
|  | 
 | ||||||
|  |   A compilation of a covered work with other separate and independent | ||||||
|  | works, which are not by their nature extensions of the covered work, | ||||||
|  | and which are not combined with it such as to form a larger program, | ||||||
|  | in or on a volume of a storage or distribution medium, is called an | ||||||
|  | "aggregate" if the compilation and its resulting copyright are not | ||||||
|  | used to limit the access or legal rights of the compilation's users | ||||||
|  | beyond what the individual works permit.  Inclusion of a covered work | ||||||
|  | in an aggregate does not cause this License to apply to the other | ||||||
|  | parts of the aggregate. | ||||||
|  | 
 | ||||||
|  |   6. Conveying Non-Source Forms. | ||||||
|  | 
 | ||||||
|  |   You may convey a covered work in object code form under the terms | ||||||
|  | of sections 4 and 5, provided that you also convey the | ||||||
|  | machine-readable Corresponding Source under the terms of this License, | ||||||
|  | in one of these ways: | ||||||
|  | 
 | ||||||
|  |     a) Convey the object code in, or embodied in, a physical product | ||||||
|  |     (including a physical distribution medium), accompanied by the | ||||||
|  |     Corresponding Source fixed on a durable physical medium | ||||||
|  |     customarily used for software interchange. | ||||||
|  | 
 | ||||||
|  |     b) Convey the object code in, or embodied in, a physical product | ||||||
|  |     (including a physical distribution medium), accompanied by a | ||||||
|  |     written offer, valid for at least three years and valid for as | ||||||
|  |     long as you offer spare parts or customer support for that product | ||||||
|  |     model, to give anyone who possesses the object code either (1) a | ||||||
|  |     copy of the Corresponding Source for all the software in the | ||||||
|  |     product that is covered by this License, on a durable physical | ||||||
|  |     medium customarily used for software interchange, for a price no | ||||||
|  |     more than your reasonable cost of physically performing this | ||||||
|  |     conveying of source, or (2) access to copy the | ||||||
|  |     Corresponding Source from a network server at no charge. | ||||||
|  | 
 | ||||||
|  |     c) Convey individual copies of the object code with a copy of the | ||||||
|  |     written offer to provide the Corresponding Source.  This | ||||||
|  |     alternative is allowed only occasionally and noncommercially, and | ||||||
|  |     only if you received the object code with such an offer, in accord | ||||||
|  |     with subsection 6b. | ||||||
|  | 
 | ||||||
|  |     d) Convey the object code by offering access from a designated | ||||||
|  |     place (gratis or for a charge), and offer equivalent access to the | ||||||
|  |     Corresponding Source in the same way through the same place at no | ||||||
|  |     further charge.  You need not require recipients to copy the | ||||||
|  |     Corresponding Source along with the object code.  If the place to | ||||||
|  |     copy the object code is a network server, the Corresponding Source | ||||||
|  |     may be on a different server (operated by you or a third party) | ||||||
|  |     that supports equivalent copying facilities, provided you maintain | ||||||
|  |     clear directions next to the object code saying where to find the | ||||||
|  |     Corresponding Source.  Regardless of what server hosts the | ||||||
|  |     Corresponding Source, you remain obligated to ensure that it is | ||||||
|  |     available for as long as needed to satisfy these requirements. | ||||||
|  | 
 | ||||||
|  |     e) Convey the object code using peer-to-peer transmission, provided | ||||||
|  |     you inform other peers where the object code and Corresponding | ||||||
|  |     Source of the work are being offered to the general public at no | ||||||
|  |     charge under subsection 6d. | ||||||
|  | 
 | ||||||
|  |   A separable portion of the object code, whose source code is excluded | ||||||
|  | from the Corresponding Source as a System Library, need not be | ||||||
|  | included in conveying the object code work. | ||||||
|  | 
 | ||||||
|  |   A "User Product" is either (1) a "consumer product", which means any | ||||||
|  | tangible personal property which is normally used for personal, family, | ||||||
|  | or household purposes, or (2) anything designed or sold for incorporation | ||||||
|  | into a dwelling.  In determining whether a product is a consumer product, | ||||||
|  | doubtful cases shall be resolved in favor of coverage.  For a particular | ||||||
|  | product received by a particular user, "normally used" refers to a | ||||||
|  | typical or common use of that class of product, regardless of the status | ||||||
|  | of the particular user or of the way in which the particular user | ||||||
|  | actually uses, or expects or is expected to use, the product.  A product | ||||||
|  | is a consumer product regardless of whether the product has substantial | ||||||
|  | commercial, industrial or non-consumer uses, unless such uses represent | ||||||
|  | the only significant mode of use of the product. | ||||||
|  | 
 | ||||||
|  |   "Installation Information" for a User Product means any methods, | ||||||
|  | procedures, authorization keys, or other information required to install | ||||||
|  | and execute modified versions of a covered work in that User Product from | ||||||
|  | a modified version of its Corresponding Source.  The information must | ||||||
|  | suffice to ensure that the continued functioning of the modified object | ||||||
|  | code is in no case prevented or interfered with solely because | ||||||
|  | modification has been made. | ||||||
|  | 
 | ||||||
|  |   If you convey an object code work under this section in, or with, or | ||||||
|  | specifically for use in, a User Product, and the conveying occurs as | ||||||
|  | part of a transaction in which the right of possession and use of the | ||||||
|  | User Product is transferred to the recipient in perpetuity or for a | ||||||
|  | fixed term (regardless of how the transaction is characterized), the | ||||||
|  | Corresponding Source conveyed under this section must be accompanied | ||||||
|  | by the Installation Information.  But this requirement does not apply | ||||||
|  | if neither you nor any third party retains the ability to install | ||||||
|  | modified object code on the User Product (for example, the work has | ||||||
|  | been installed in ROM). | ||||||
|  | 
 | ||||||
|  |   The requirement to provide Installation Information does not include a | ||||||
|  | requirement to continue to provide support service, warranty, or updates | ||||||
|  | for a work that has been modified or installed by the recipient, or for | ||||||
|  | the User Product in which it has been modified or installed.  Access to a | ||||||
|  | network may be denied when the modification itself materially and | ||||||
|  | adversely affects the operation of the network or violates the rules and | ||||||
|  | protocols for communication across the network. | ||||||
|  | 
 | ||||||
|  |   Corresponding Source conveyed, and Installation Information provided, | ||||||
|  | in accord with this section must be in a format that is publicly | ||||||
|  | documented (and with an implementation available to the public in | ||||||
|  | source code form), and must require no special password or key for | ||||||
|  | unpacking, reading or copying. | ||||||
|  | 
 | ||||||
|  |   7. Additional Terms. | ||||||
|  | 
 | ||||||
|  |   "Additional permissions" are terms that supplement the terms of this | ||||||
|  | License by making exceptions from one or more of its conditions. | ||||||
|  | Additional permissions that are applicable to the entire Program shall | ||||||
|  | be treated as though they were included in this License, to the extent | ||||||
|  | that they are valid under applicable law.  If additional permissions | ||||||
|  | apply only to part of the Program, that part may be used separately | ||||||
|  | under those permissions, but the entire Program remains governed by | ||||||
|  | this License without regard to the additional permissions. | ||||||
|  | 
 | ||||||
|  |   When you convey a copy of a covered work, you may at your option | ||||||
|  | remove any additional permissions from that copy, or from any part of | ||||||
|  | it.  (Additional permissions may be written to require their own | ||||||
|  | removal in certain cases when you modify the work.)  You may place | ||||||
|  | additional permissions on material, added by you to a covered work, | ||||||
|  | for which you have or can give appropriate copyright permission. | ||||||
|  | 
 | ||||||
|  |   Notwithstanding any other provision of this License, for material you | ||||||
|  | add to a covered work, you may (if authorized by the copyright holders of | ||||||
|  | that material) supplement the terms of this License with terms: | ||||||
|  | 
 | ||||||
|  |     a) Disclaiming warranty or limiting liability differently from the | ||||||
|  |     terms of sections 15 and 16 of this License; or | ||||||
|  | 
 | ||||||
|  |     b) Requiring preservation of specified reasonable legal notices or | ||||||
|  |     author attributions in that material or in the Appropriate Legal | ||||||
|  |     Notices displayed by works containing it; or | ||||||
|  | 
 | ||||||
|  |     c) Prohibiting misrepresentation of the origin of that material, or | ||||||
|  |     requiring that modified versions of such material be marked in | ||||||
|  |     reasonable ways as different from the original version; or | ||||||
|  | 
 | ||||||
|  |     d) Limiting the use for publicity purposes of names of licensors or | ||||||
|  |     authors of the material; or | ||||||
|  | 
 | ||||||
|  |     e) Declining to grant rights under trademark law for use of some | ||||||
|  |     trade names, trademarks, or service marks; or | ||||||
|  | 
 | ||||||
|  |     f) Requiring indemnification of licensors and authors of that | ||||||
|  |     material by anyone who conveys the material (or modified versions of | ||||||
|  |     it) with contractual assumptions of liability to the recipient, for | ||||||
|  |     any liability that these contractual assumptions directly impose on | ||||||
|  |     those licensors and authors. | ||||||
|  | 
 | ||||||
|  |   All other non-permissive additional terms are considered "further | ||||||
|  | restrictions" within the meaning of section 10.  If the Program as you | ||||||
|  | received it, or any part of it, contains a notice stating that it is | ||||||
|  | governed by this License along with a term that is a further | ||||||
|  | restriction, you may remove that term.  If a license document contains | ||||||
|  | a further restriction but permits relicensing or conveying under this | ||||||
|  | License, you may add to a covered work material governed by the terms | ||||||
|  | of that license document, provided that the further restriction does | ||||||
|  | not survive such relicensing or conveying. | ||||||
|  | 
 | ||||||
|  |   If you add terms to a covered work in accord with this section, you | ||||||
|  | must place, in the relevant source files, a statement of the | ||||||
|  | additional terms that apply to those files, or a notice indicating | ||||||
|  | where to find the applicable terms. | ||||||
|  | 
 | ||||||
|  |   Additional terms, permissive or non-permissive, may be stated in the | ||||||
|  | form of a separately written license, or stated as exceptions; | ||||||
|  | the above requirements apply either way. | ||||||
|  | 
 | ||||||
|  |   8. Termination. | ||||||
|  | 
 | ||||||
|  |   You may not propagate or modify a covered work except as expressly | ||||||
|  | provided under this License.  Any attempt otherwise to propagate or | ||||||
|  | modify it is void, and will automatically terminate your rights under | ||||||
|  | this License (including any patent licenses granted under the third | ||||||
|  | paragraph of section 11). | ||||||
|  | 
 | ||||||
|  |   However, if you cease all violation of this License, then your | ||||||
|  | license from a particular copyright holder is reinstated (a) | ||||||
|  | provisionally, unless and until the copyright holder explicitly and | ||||||
|  | finally terminates your license, and (b) permanently, if the copyright | ||||||
|  | holder fails to notify you of the violation by some reasonable means | ||||||
|  | prior to 60 days after the cessation. | ||||||
|  | 
 | ||||||
|  |   Moreover, your license from a particular copyright holder is | ||||||
|  | reinstated permanently if the copyright holder notifies you of the | ||||||
|  | violation by some reasonable means, this is the first time you have | ||||||
|  | received notice of violation of this License (for any work) from that | ||||||
|  | copyright holder, and you cure the violation prior to 30 days after | ||||||
|  | your receipt of the notice. | ||||||
|  | 
 | ||||||
|  |   Termination of your rights under this section does not terminate the | ||||||
|  | licenses of parties who have received copies or rights from you under | ||||||
|  | this License.  If your rights have been terminated and not permanently | ||||||
|  | reinstated, you do not qualify to receive new licenses for the same | ||||||
|  | material under section 10. | ||||||
|  | 
 | ||||||
|  |   9. Acceptance Not Required for Having Copies. | ||||||
|  | 
 | ||||||
|  |   You are not required to accept this License in order to receive or | ||||||
|  | run a copy of the Program.  Ancillary propagation of a covered work | ||||||
|  | occurring solely as a consequence of using peer-to-peer transmission | ||||||
|  | to receive a copy likewise does not require acceptance.  However, | ||||||
|  | nothing other than this License grants you permission to propagate or | ||||||
|  | modify any covered work.  These actions infringe copyright if you do | ||||||
|  | not accept this License.  Therefore, by modifying or propagating a | ||||||
|  | covered work, you indicate your acceptance of this License to do so. | ||||||
|  | 
 | ||||||
|  |   10. Automatic Licensing of Downstream Recipients. | ||||||
|  | 
 | ||||||
|  |   Each time you convey a covered work, the recipient automatically | ||||||
|  | receives a license from the original licensors, to run, modify and | ||||||
|  | propagate that work, subject to this License.  You are not responsible | ||||||
|  | for enforcing compliance by third parties with this License. | ||||||
|  | 
 | ||||||
|  |   An "entity transaction" is a transaction transferring control of an | ||||||
|  | organization, or substantially all assets of one, or subdividing an | ||||||
|  | organization, or merging organizations.  If propagation of a covered | ||||||
|  | work results from an entity transaction, each party to that | ||||||
|  | transaction who receives a copy of the work also receives whatever | ||||||
|  | licenses to the work the party's predecessor in interest had or could | ||||||
|  | give under the previous paragraph, plus a right to possession of the | ||||||
|  | Corresponding Source of the work from the predecessor in interest, if | ||||||
|  | the predecessor has it or can get it with reasonable efforts. | ||||||
|  | 
 | ||||||
|  |   You may not impose any further restrictions on the exercise of the | ||||||
|  | rights granted or affirmed under this License.  For example, you may | ||||||
|  | not impose a license fee, royalty, or other charge for exercise of | ||||||
|  | rights granted under this License, and you may not initiate litigation | ||||||
|  | (including a cross-claim or counterclaim in a lawsuit) alleging that | ||||||
|  | any patent claim is infringed by making, using, selling, offering for | ||||||
|  | sale, or importing the Program or any portion of it. | ||||||
|  | 
 | ||||||
|  |   11. Patents. | ||||||
|  | 
 | ||||||
|  |   A "contributor" is a copyright holder who authorizes use under this | ||||||
|  | License of the Program or a work on which the Program is based.  The | ||||||
|  | work thus licensed is called the contributor's "contributor version". | ||||||
|  | 
 | ||||||
|  |   A contributor's "essential patent claims" are all patent claims | ||||||
|  | owned or controlled by the contributor, whether already acquired or | ||||||
|  | hereafter acquired, that would be infringed by some manner, permitted | ||||||
|  | by this License, of making, using, or selling its contributor version, | ||||||
|  | but do not include claims that would be infringed only as a | ||||||
|  | consequence of further modification of the contributor version.  For | ||||||
|  | purposes of this definition, "control" includes the right to grant | ||||||
|  | patent sublicenses in a manner consistent with the requirements of | ||||||
|  | this License. | ||||||
|  | 
 | ||||||
|  |   Each contributor grants you a non-exclusive, worldwide, royalty-free | ||||||
|  | patent license under the contributor's essential patent claims, to | ||||||
|  | make, use, sell, offer for sale, import and otherwise run, modify and | ||||||
|  | propagate the contents of its contributor version. | ||||||
|  | 
 | ||||||
|  |   In the following three paragraphs, a "patent license" is any express | ||||||
|  | agreement or commitment, however denominated, not to enforce a patent | ||||||
|  | (such as an express permission to practice a patent or covenant not to | ||||||
|  | sue for patent infringement).  To "grant" such a patent license to a | ||||||
|  | party means to make such an agreement or commitment not to enforce a | ||||||
|  | patent against the party. | ||||||
|  | 
 | ||||||
|  |   If you convey a covered work, knowingly relying on a patent license, | ||||||
|  | and the Corresponding Source of the work is not available for anyone | ||||||
|  | to copy, free of charge and under the terms of this License, through a | ||||||
|  | publicly available network server or other readily accessible means, | ||||||
|  | then you must either (1) cause the Corresponding Source to be so | ||||||
|  | available, or (2) arrange to deprive yourself of the benefit of the | ||||||
|  | patent license for this particular work, or (3) arrange, in a manner | ||||||
|  | consistent with the requirements of this License, to extend the patent | ||||||
|  | license to downstream recipients.  "Knowingly relying" means you have | ||||||
|  | actual knowledge that, but for the patent license, your conveying the | ||||||
|  | covered work in a country, or your recipient's use of the covered work | ||||||
|  | in a country, would infringe one or more identifiable patents in that | ||||||
|  | country that you have reason to believe are valid. | ||||||
|  | 
 | ||||||
|  |   If, pursuant to or in connection with a single transaction or | ||||||
|  | arrangement, you convey, or propagate by procuring conveyance of, a | ||||||
|  | covered work, and grant a patent license to some of the parties | ||||||
|  | receiving the covered work authorizing them to use, propagate, modify | ||||||
|  | or convey a specific copy of the covered work, then the patent license | ||||||
|  | you grant is automatically extended to all recipients of the covered | ||||||
|  | work and works based on it. | ||||||
|  | 
 | ||||||
|  |   A patent license is "discriminatory" if it does not include within | ||||||
|  | the scope of its coverage, prohibits the exercise of, or is | ||||||
|  | conditioned on the non-exercise of one or more of the rights that are | ||||||
|  | specifically granted under this License.  You may not convey a covered | ||||||
|  | work if you are a party to an arrangement with a third party that is | ||||||
|  | in the business of distributing software, under which you make payment | ||||||
|  | to the third party based on the extent of your activity of conveying | ||||||
|  | the work, and under which the third party grants, to any of the | ||||||
|  | parties who would receive the covered work from you, a discriminatory | ||||||
|  | patent license (a) in connection with copies of the covered work | ||||||
|  | conveyed by you (or copies made from those copies), or (b) primarily | ||||||
|  | for and in connection with specific products or compilations that | ||||||
|  | contain the covered work, unless you entered into that arrangement, | ||||||
|  | or that patent license was granted, prior to 28 March 2007. | ||||||
|  | 
 | ||||||
|  |   Nothing in this License shall be construed as excluding or limiting | ||||||
|  | any implied license or other defenses to infringement that may | ||||||
|  | otherwise be available to you under applicable patent law. | ||||||
|  | 
 | ||||||
|  |   12. No Surrender of Others' Freedom. | ||||||
|  | 
 | ||||||
|  |   If conditions are imposed on you (whether by court order, agreement or | ||||||
|  | otherwise) that contradict the conditions of this License, they do not | ||||||
|  | excuse you from the conditions of this License.  If you cannot convey a | ||||||
|  | covered work so as to satisfy simultaneously your obligations under this | ||||||
|  | License and any other pertinent obligations, then as a consequence you may | ||||||
|  | not convey it at all.  For example, if you agree to terms that obligate you | ||||||
|  | to collect a royalty for further conveying from those to whom you convey | ||||||
|  | the Program, the only way you could satisfy both those terms and this | ||||||
|  | License would be to refrain entirely from conveying the Program. | ||||||
|  | 
 | ||||||
|  |   13. Use with the GNU Affero General Public License. | ||||||
|  | 
 | ||||||
|  |   Notwithstanding any other provision of this License, you have | ||||||
|  | permission to link or combine any covered work with a work licensed | ||||||
|  | under version 3 of the GNU Affero General Public License into a single | ||||||
|  | combined work, and to convey the resulting work.  The terms of this | ||||||
|  | License will continue to apply to the part which is the covered work, | ||||||
|  | but the special requirements of the GNU Affero General Public License, | ||||||
|  | section 13, concerning interaction through a network will apply to the | ||||||
|  | combination as such. | ||||||
|  | 
 | ||||||
|  |   14. Revised Versions of this License. | ||||||
|  | 
 | ||||||
|  |   The Free Software Foundation may publish revised and/or new versions of | ||||||
|  | the GNU General Public License from time to time.  Such new versions will | ||||||
|  | be similar in spirit to the present version, but may differ in detail to | ||||||
|  | address new problems or concerns. | ||||||
|  | 
 | ||||||
|  |   Each version is given a distinguishing version number.  If the | ||||||
|  | Program specifies that a certain numbered version of the GNU General | ||||||
|  | Public License "or any later version" applies to it, you have the | ||||||
|  | option of following the terms and conditions either of that numbered | ||||||
|  | version or of any later version published by the Free Software | ||||||
|  | Foundation.  If the Program does not specify a version number of the | ||||||
|  | GNU General Public License, you may choose any version ever published | ||||||
|  | by the Free Software Foundation. | ||||||
|  | 
 | ||||||
|  |   If the Program specifies that a proxy can decide which future | ||||||
|  | versions of the GNU General Public License can be used, that proxy's | ||||||
|  | public statement of acceptance of a version permanently authorizes you | ||||||
|  | to choose that version for the Program. | ||||||
|  | 
 | ||||||
|  |   Later license versions may give you additional or different | ||||||
|  | permissions.  However, no additional obligations are imposed on any | ||||||
|  | author or copyright holder as a result of your choosing to follow a | ||||||
|  | later version. | ||||||
|  | 
 | ||||||
|  |   15. Disclaimer of Warranty. | ||||||
|  | 
 | ||||||
|  |   THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | ||||||
|  | APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | ||||||
|  | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | ||||||
|  | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | ||||||
|  | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||||
|  | PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | ||||||
|  | IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | ||||||
|  | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||||||
|  | 
 | ||||||
|  |   16. Limitation of Liability. | ||||||
|  | 
 | ||||||
|  |   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||||
|  | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | ||||||
|  | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | ||||||
|  | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | ||||||
|  | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | ||||||
|  | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | ||||||
|  | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | ||||||
|  | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | ||||||
|  | SUCH DAMAGES. | ||||||
|  | 
 | ||||||
|  |   17. Interpretation of Sections 15 and 16. | ||||||
|  | 
 | ||||||
|  |   If the disclaimer of warranty and limitation of liability provided | ||||||
|  | above cannot be given local legal effect according to their terms, | ||||||
|  | reviewing courts shall apply local law that most closely approximates | ||||||
|  | an absolute waiver of all civil liability in connection with the | ||||||
|  | Program, unless a warranty or assumption of liability accompanies a | ||||||
|  | copy of the Program in return for a fee. | ||||||
|  | 
 | ||||||
|  |                      END OF TERMS AND CONDITIONS | ||||||
|  | 
 | ||||||
|  |             How to Apply These Terms to Your New Programs | ||||||
|  | 
 | ||||||
|  |   If you develop a new program, and you want it to be of the greatest | ||||||
|  | possible use to the public, the best way to achieve this is to make it | ||||||
|  | free software which everyone can redistribute and change under these terms. | ||||||
|  | 
 | ||||||
|  |   To do so, attach the following notices to the program.  It is safest | ||||||
|  | to attach them to the start of each source file to most effectively | ||||||
|  | state the exclusion of warranty; and each file should have at least | ||||||
|  | the "copyright" line and a pointer to where the full notice is found. | ||||||
|  | 
 | ||||||
|  |     {one line to give the program's name and a brief idea of what it does.} | ||||||
|  |     Copyright (C) {year}  {name of author} | ||||||
|  | 
 | ||||||
|  |     This program 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/>. | ||||||
|  | 
 | ||||||
|  | Also add information on how to contact you by electronic and paper mail. | ||||||
|  | 
 | ||||||
|  |   If the program does terminal interaction, make it output a short | ||||||
|  | notice like this when it starts in an interactive mode: | ||||||
|  | 
 | ||||||
|  |     {project}  Copyright (C) {year}  {fullname} | ||||||
|  |     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||||
|  |     This is free software, and you are welcome to redistribute it | ||||||
|  |     under certain conditions; type `show c' for details. | ||||||
|  | 
 | ||||||
|  | The hypothetical commands `show w' and `show c' should show the appropriate | ||||||
|  | parts of the General Public License.  Of course, your program's commands | ||||||
|  | might be different; for a GUI interface, you would use an "about box". | ||||||
|  | 
 | ||||||
|  |   You should also get your employer (if you work as a programmer) or school, | ||||||
|  | if any, to sign a "copyright disclaimer" for the program, if necessary. | ||||||
|  | For more information on this, and how to apply and follow the GNU GPL, see | ||||||
|  | <http://www.gnu.org/licenses/>. | ||||||
|  | 
 | ||||||
|  |   The GNU General Public License does not permit incorporating your program | ||||||
|  | into proprietary programs.  If your program is a subroutine library, you | ||||||
|  | may consider it more useful to permit linking proprietary applications with | ||||||
|  | the library.  If this is what you want to do, use the GNU Lesser General | ||||||
|  | Public License instead of this License.  But first, please read | ||||||
|  | <http://www.gnu.org/philosophy/why-not-lgpl.html>. | ||||||
							
								
								
									
										10
									
								
								rdp/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								rdp/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | node-rdpjs | ||||||
|  | ========== | ||||||
|  | 
 | ||||||
|  | This folder contains a fork of the node-rdpjs2 package which is identical to [node-rdpjs](github.com/citronneur/node-rdpjs) v0.2.1 but just updated for | ||||||
|  | latest versions of Node along with more modifications to remove dependencies and more importantly, added support for Network Layer Authentication (NLA). | ||||||
|  | 
 | ||||||
|  | NLA support was ported from [RDP-RS](https://github.com/citronneur/rdp-rs) which is a Rust RDP solution by the same author as node-rdpjs. | ||||||
|  | 
 | ||||||
|  | The license for node-rdpjs is GPL 3.0 and is limited the the "rdp" folder. If this is a concern, you can delete the "rdp" folder and MeshCentral will | ||||||
|  | still work perfectly without RDP functionality. | ||||||
							
								
								
									
										111
									
								
								rdp/asn1/ber.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								rdp/asn1/ber.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../core').type; | ||||||
|  | var log = require('../core').log; | ||||||
|  | var error = require('../core').error; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Parse tag(T) field of BER TLV | ||||||
|  |  * And check with expected tag | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param tag {spec.tag} | ||||||
|  |  * @returns {Boolean} True for valid tag matching | ||||||
|  |  */ | ||||||
|  | function decodeTag(s, tag) { | ||||||
|  | 	var nextTag = new type.UInt8().read(s).value; | ||||||
|  | 	if (tag.tagNumber > 30) { | ||||||
|  | 		nextTagNumber = new type.UInt8().read(s).value; | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		nextTagNumber = nextTag & 0x1F; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return ((nextTag & 0xE0) === (tag.tagClass | tag.tagFormat)) && (nextTagNumber === tag.tagNumber); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Parse length(L) field of BER TLV | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @returns {integer} | ||||||
|  |  */ | ||||||
|  | function decodeLength(s) { | ||||||
|  | 	var size = new type.UInt8().read(s).value; | ||||||
|  | 	if(size & 0x80) { | ||||||
|  | 		size &= ~0x80; | ||||||
|  | 		if(size === 1) { | ||||||
|  | 			size = new type.UInt8().read(s).value; | ||||||
|  | 		} | ||||||
|  | 		else if(size === 2) { | ||||||
|  | 			size = new type.UInt16Be().read(s).value; | ||||||
|  | 		} | ||||||
|  | 		else{ | ||||||
|  | 			throw new error.ProtocolError('NODE_RDP_ASN1_BER_INVALID_LENGTH'); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return size; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Decode tuple TLV (Tag Length Value) of BER | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param tag {spec.Asn1Tag} expected tag | ||||||
|  |  * @returns {type.BinaryString} Value of tuple | ||||||
|  |  */ | ||||||
|  | function decode(s, tag) { | ||||||
|  | 	if (!decodeTag(s, tag)) { | ||||||
|  | 		throw new error.ProtocolError('NODE_RDP_ASN1_BER_INVALID_TAG'); | ||||||
|  | 	} | ||||||
|  | 	var length = decodeLength(s); | ||||||
|  | 	 | ||||||
|  | 	if (length === 0) { | ||||||
|  | 		return new type.Stream(0); | ||||||
|  | 	} | ||||||
|  | 	return new type.BinaryString(null,{ readLength : new type.CallableValue(length) }).read(s); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | function encodeTag(tag) { | ||||||
|  | 	if(tag.tagNumber > 30) { | ||||||
|  | 		return new type.Component([new type.UInt8(tag.tagClass | tag.tagFormat | 0x1F), new type.UInt8(tag.tagNumber)]); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		return new type.UInt8((tag.tagClass | tag.tagFormat) | (tag.tagNumber & 0x1F)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function encodeLength(length) { | ||||||
|  | 	if(length > 0x7f) { | ||||||
|  |         return new type.Component([new type.UInt8(0x82), new type.UInt16Be(length)]); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         return new type.UInt8(length); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function encode(tag, buffer) { | ||||||
|  | 	return new type.Component([encodeTag(tag), encodeLength(buffer.size()), buffer]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module Export | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	decode : decode, | ||||||
|  | 	encode : encode | ||||||
|  | }; | ||||||
							
								
								
									
										28
									
								
								rdp/asn1/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								rdp/asn1/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | /* | ||||||
|  |  * 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 ber = require('./ber'); | ||||||
|  | var univ = require('./univ'); | ||||||
|  | var spec = require('./spec'); | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  | 	ber : ber, | ||||||
|  | 	univ : univ, | ||||||
|  | 	spec : spec | ||||||
|  | }; | ||||||
							
								
								
									
										139
									
								
								rdp/asn1/spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								rdp/asn1/spec.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,139 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../core').type; | ||||||
|  | var error = require('../core').error; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Tag Class | ||||||
|  |  */ | ||||||
|  | var TagClass = { | ||||||
|  | 	Universal : 0x00, | ||||||
|  | 	Application : 0x40, | ||||||
|  | 	Context : 0x80, | ||||||
|  | 	Private : 0xC0 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Tag Format | ||||||
|  |  */ | ||||||
|  | var TagFormat = { | ||||||
|  | 	Primitive : 0x00, | ||||||
|  | 	Constructed : 0x20 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ASN.1 tag | ||||||
|  |  * @param tagClass {TagClass} | ||||||
|  |  * @param tagFormat {TagFormat} | ||||||
|  |  * @param tagNumber {integer} | ||||||
|  |  */ | ||||||
|  | function Asn1Tag(tagClass, tagFormat, tagNumber) { | ||||||
|  | 	this.tagClass = tagClass; | ||||||
|  | 	this.tagFormat = tagFormat; | ||||||
|  | 	this.tagNumber = tagNumber; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ASN.1 Specification | ||||||
|  |  * @param tag {Asn1Tag} | ||||||
|  |  */ | ||||||
|  | function Asn1Spec(tag) { | ||||||
|  | 	this.tag = tag; | ||||||
|  | 	this.opt = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add an implicit tag | ||||||
|  |  * override tag | ||||||
|  |  * @param tag {Asn1Tag} | ||||||
|  |  * @returns {Asn1Spec} | ||||||
|  |  */ | ||||||
|  | Asn1Spec.prototype.implicitTag = function(tag) { | ||||||
|  | 	this.tag = tag; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Set optional to true | ||||||
|  |  * @returns {Asn1Spec} | ||||||
|  |  */ | ||||||
|  | Asn1Spec.prototype.optional = function() { | ||||||
|  | 	this.opt = true; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Add explicit tag | ||||||
|  |  * Append new tag header to existing tag | ||||||
|  |  * @param tag {Asn1Tag} | ||||||
|  |  * @returns {Asn1SpecExplicitTag} | ||||||
|  |  */ | ||||||
|  | Asn1Spec.prototype.explicitTag = function(tag) { | ||||||
|  | 	return new Asn1SpecExplicitTag(tag, this); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Decode must be implemented by all sub type | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder | ||||||
|  |  */ | ||||||
|  | Asn1Spec.prototype.decode = function(s, decoder) { | ||||||
|  | 	throw new error.FatalError('NODE_RDP_AS1_SPEC_DECODE_NOT_IMPLEMENTED'); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Encode must be implemented by all sub type | ||||||
|  |  * @param decoder | ||||||
|  |  */ | ||||||
|  | Asn1Spec.prototype.encode = function(encoder) { | ||||||
|  | 	throw new error.FatalError('NODE_RDP_AS1_SPEC_ENCODE_NOT_IMPLEMENTED'); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Component Asn1Spec object | ||||||
|  |  */ | ||||||
|  | function Asn1SpecExplicitTag(tag, spec) { | ||||||
|  | 	Asn1Spec.call(this, tag); | ||||||
|  | 	this.spec = spec; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Asn1SpecExplicitTag, Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Decode first header | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder | ||||||
|  |  */ | ||||||
|  | Asn1Spec.prototype.decode = function(s, decoder) { | ||||||
|  | 	var specStream = new type.Stream(decoder.decode(s, this.tag).value); | ||||||
|  | 	this.spec.decode(specStream, decoder); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	TagClass : TagClass, | ||||||
|  | 	TagFormat : TagFormat, | ||||||
|  | 	Asn1Tag : Asn1Tag, | ||||||
|  | 	Asn1Spec : Asn1Spec, | ||||||
|  | 	Asn1SpecExplicitTag : Asn1SpecExplicitTag | ||||||
|  | }; | ||||||
							
								
								
									
										606
									
								
								rdp/asn1/univ.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										606
									
								
								rdp/asn1/univ.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,606 @@ | |||||||
|  | /* | ||||||
|  |  * 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 spec = require('./spec'); | ||||||
|  | var type = require('../core').type; | ||||||
|  | var error = require('../core').error; | ||||||
|  | var inherits = require('util').inherits; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ASN.1 Universal tags | ||||||
|  |  * @see http://www.obj-sys.com/asn1tutorial/node124.html
 | ||||||
|  |  */ | ||||||
|  | var UniversalTag = { | ||||||
|  | 	Boolean : 1, | ||||||
|  | 	Integer : 2, | ||||||
|  | 	BitString : 3, | ||||||
|  | 	OctetString : 4, | ||||||
|  | 	Null : 5, | ||||||
|  | 	ObjectIdentifier : 6, | ||||||
|  | 	ObjectDescriptor : 7, | ||||||
|  | 	Enumerate : 10, | ||||||
|  | 	UTF8String : 12, | ||||||
|  | 	Sequence : 16, | ||||||
|  | 	Set : 17, | ||||||
|  | 	PrintableString : 19, | ||||||
|  | 	T61String : 20, | ||||||
|  | 	IA5String : 22, | ||||||
|  |  	UTCTime : 23, | ||||||
|  |  	GeneralizedTime : 24, | ||||||
|  | 	UniversalString : 28, | ||||||
|  | 	BMPString : 30 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Boolean type | ||||||
|  |  * @param value {boolean} inner value | ||||||
|  |  */ | ||||||
|  | function Boolean(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Boolean)); | ||||||
|  | 	this.value = value || false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Boolean, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {Boolean} | ||||||
|  |  */ | ||||||
|  | Boolean.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = new type.UInt8().read(new type.Stream(decoder.decode(s, this.tag).value)).value !== 0; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {type.*} | ||||||
|  |  */ | ||||||
|  | Boolean.prototype.encode = function(encoder) { | ||||||
|  | 	if(this.value) { | ||||||
|  | 		return encoder.encode(this.tag, new type.UInt8(0xff)); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		return encoder.encode(this.tag, new type.UInt8(0)); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Integer type | ||||||
|  |  * @param value {integer | Buffer} | ||||||
|  |  */ | ||||||
|  | function Integer(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Integer)); | ||||||
|  | 	this.value = value || 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Integer, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {Integer} | ||||||
|  |  */ | ||||||
|  | Integer.prototype.decode = function(s, decoder) { | ||||||
|  | 	var integerBuffer = decoder.decode(s, this.tag).value; | ||||||
|  | 	if(integerBuffer.length < 5) { | ||||||
|  | 		var integerStream = new type.Stream(integerBuffer); | ||||||
|  | 		while (integerStream.availableLength() > 0) { | ||||||
|  | 			this.value = this.value << 8; | ||||||
|  | 			this.value |= new type.UInt8().read(integerStream).value; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// bignum case
 | ||||||
|  | 	else { | ||||||
|  | 		this.value = integerBuffer; | ||||||
|  | 	} | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param encoder {ber.decoder} | ||||||
|  |  * @returns {type.*} | ||||||
|  |  */ | ||||||
|  | Integer.prototype.encode = function(encoder) { | ||||||
|  | 	if(this.value <= 0xff) { | ||||||
|  |         return encoder.encode(this.tag, new type.UInt8(this.value)); | ||||||
|  |     } | ||||||
|  |     else if(this.value <= 0xffff) { | ||||||
|  |         return encoder.encode(this.tag, new type.UInt16Be(this.value)); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         return encoder.encode(this.tag, new type.UInt32Be(this.value)); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Sequence type | ||||||
|  |  * @param value {object} | ||||||
|  |  */ | ||||||
|  | function Sequence(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Sequence)); | ||||||
|  | 	this.value = value || []; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Sequence, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {Sequence} | ||||||
|  |  */ | ||||||
|  | Sequence.prototype.decode = function(s, decoder) { | ||||||
|  | 	var sequenceStream = new type.Stream(decoder.decode(s, this.tag).value); | ||||||
|  | 	for (var i in this.value) { | ||||||
|  | 		var rec = sequenceStream.offset; | ||||||
|  | 		try { | ||||||
|  | 			this.value[i].decode(sequenceStream, decoder); | ||||||
|  | 		} catch(e) { | ||||||
|  | 			if ((e.message === 'NODE_RDP_ASN1_BER_INVALID_TAG') && !this.value[i].opt) { | ||||||
|  | 				throw new error.ProtocolError('NODE_RDP_ASN1_UNIV_SEQUENCE_FIELD_NOT_PRESENT'); | ||||||
|  | 			} | ||||||
|  | 			sequenceStream.offset = rec; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Encode sequence | ||||||
|  |  * @param encoder | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | Sequence.prototype.encode = function(encoder) { | ||||||
|  | 	var sequence = new type.Component([]); | ||||||
|  | 	for (var i in this.value) { | ||||||
|  | 		sequence.obj.push(this.value[i].encode(encoder)) | ||||||
|  | 	} | ||||||
|  | 	return encoder.encode(this.tag, sequence); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Enumerate type | ||||||
|  |  * @param value {integer} | ||||||
|  |  */ | ||||||
|  | function Enumerate(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Enumerate)); | ||||||
|  | 	this.value = value || 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Enumerate, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {Enumerate} | ||||||
|  |  */ | ||||||
|  | Enumerate.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = new type.UInt8().read(new type.Stream(decoder.decode(s, this.tag).value)).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Encode enumerate type | ||||||
|  |  * @param encoder | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | Enumerate.prototype.encode = function(encoder) { | ||||||
|  | 	return encoder.encode(this.tag, new type.UInt8(this.value)); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * OctetString type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function OctetString(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.OctetString)); | ||||||
|  | 	this.value = value || Buffer.alloc(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(OctetString, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {OctetString} | ||||||
|  |  */ | ||||||
|  | OctetString.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Encode Octet String | ||||||
|  |  * @param encoder | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | OctetString.prototype.encode = function(encoder) { | ||||||
|  | 	return encoder.encode(this.tag, new type.BinaryString(this.value)); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ObjectIdentifier type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function ObjectIdentifier(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.ObjectIdentifier)); | ||||||
|  | 	this.value = value || Buffer.alloc(5); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(ObjectIdentifier, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {ObjectIdentifier} | ||||||
|  |  */ | ||||||
|  | ObjectIdentifier.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Null type | ||||||
|  |  */ | ||||||
|  | function Null() { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.Null)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Null, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {Null} | ||||||
|  |  */ | ||||||
|  | Null.prototype.decode = function(s, decoder) { | ||||||
|  | 	decoder.decode(s, this.tag); | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Choice type | ||||||
|  |  * @param value {object} list of available type | ||||||
|  |  */ | ||||||
|  | function Choice(value) { | ||||||
|  | 	// not tagged type
 | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag()); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Choice, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {Choice} | ||||||
|  |  */ | ||||||
|  | Choice.prototype.decode = function(s, decoder) { | ||||||
|  | 	for (var i in this.value) { | ||||||
|  | 		var rec = s.offset; | ||||||
|  | 		try { | ||||||
|  | 			this.value[i].decode(s, decoder); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		catch(e) { | ||||||
|  | 			s.offset = rec; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * SetOf type | ||||||
|  |  * @param factory	{function} type builder | ||||||
|  |  * @param value {object} list of available type | ||||||
|  |  */ | ||||||
|  | function SetOf(factory, value) { | ||||||
|  | 	// not tagged type
 | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Set)); | ||||||
|  | 	this.factory = factory; | ||||||
|  | 	this.value = value || []; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(SetOf, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {SetOf} | ||||||
|  |  */ | ||||||
|  | SetOf.prototype.decode = function(s, decoder) { | ||||||
|  | 	var setOfStream = new type.Stream(decoder.decode(s, this.tag).value); | ||||||
|  | 	while (setOfStream.availableLength() > 0) { | ||||||
|  | 		this.value.push(this.factory().decode(setOfStream, decoder)); | ||||||
|  | 	} | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * SequenceOf type | ||||||
|  |  * @param factory	{function} type builder | ||||||
|  |  * @param value {object} list of available type | ||||||
|  |  */ | ||||||
|  | function SequenceOf(factory, value) { | ||||||
|  | 	// not tagged type
 | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Constructed, UniversalTag.Sequence)); | ||||||
|  | 	this.factory = factory; | ||||||
|  | 	this.value = value || []; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(SequenceOf, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {SequenceOf} | ||||||
|  |  */ | ||||||
|  | SequenceOf.prototype.decode = function(s, decoder) { | ||||||
|  | 	var sequenceOfStream = new type.Stream(decoder.decode(s, this.tag).value); | ||||||
|  | 	while (sequenceOfStream.availableLength() > 0) { | ||||||
|  | 		this.value.push(this.factory().decode(sequenceOfStream, decoder)); | ||||||
|  | 	} | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * BitString type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function BitString(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.BitString)); | ||||||
|  | 	this.value = []; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(BitString, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {BitString} | ||||||
|  |  */ | ||||||
|  | BitString.prototype.decode = function(s, decoder) { | ||||||
|  | 	var bitStream = new type.Stream(decoder.decode(s, this.tag).value); | ||||||
|  | 	var padding = new type.UInt8().read(bitStream).value; | ||||||
|  | 	var value = []; | ||||||
|  | 	for(var i = 0; i < padding; i++) { | ||||||
|  | 		value.push(0); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	while(bitStream.availableLength() > 0) { | ||||||
|  | 		var octet = new type.UInt8().read(bitStream).value; | ||||||
|  | 		var currentPadding = 0; | ||||||
|  | 		if(bitStream.availableLength() === 0) { | ||||||
|  | 			currentPadding = padding; | ||||||
|  | 		} | ||||||
|  | 		for(var i = 7; i >= currentPadding; i--) { | ||||||
|  | 			value.push(((octet >> i) & 1)?1:0); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	this.value = value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Convert bit string to buffer object | ||||||
|  |  * @returns {Buffer} | ||||||
|  |  */ | ||||||
|  | BitString.prototype.toBuffer = function () { | ||||||
|  | 	var length = this.value.length / 8; | ||||||
|  | 	var resultStream = new type.Stream(length); | ||||||
|  | 	for (var i = 0; i < length; i ++) { | ||||||
|  | 		var currentOctet = 0; | ||||||
|  | 		for (var j = 0; j < 8; j++) { | ||||||
|  | 			currentOctet = currentOctet  | (this.value[i * 8 + j] << (7 - j)); | ||||||
|  | 		} | ||||||
|  | 		new type.UInt8(currentOctet).write(resultStream); | ||||||
|  | 	} | ||||||
|  | 	return resultStream.buffer; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * T61String type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function T61String(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.T61String)); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(T61String, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {T61String} | ||||||
|  |  */ | ||||||
|  | T61String.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * PrintableString type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function PrintableString(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.PrintableString)); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(PrintableString, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {PrintableString} | ||||||
|  |  */ | ||||||
|  | PrintableString.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * UniversalString type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function UniversalString(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UniversalString)); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(UniversalString, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {UniversalString} | ||||||
|  |  */ | ||||||
|  | UniversalString.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * UTF8String type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function UTF8String(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UTF8String)); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(UTF8String, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {UTF8String} | ||||||
|  |  */ | ||||||
|  | UTF8String.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * BMPString type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function BMPString(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.BMPString)); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(BMPString, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {BMPString} | ||||||
|  |  */ | ||||||
|  | BMPString.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * IA5String type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function IA5String(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.IA5String)); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(IA5String, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {IA5String} | ||||||
|  |  */ | ||||||
|  | IA5String.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * UTCTime type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function UTCTime(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.UTCTime)); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(UTCTime, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {UTCTime} | ||||||
|  |  */ | ||||||
|  | UTCTime.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * GeneralizedTime type | ||||||
|  |  * @param value {Buffer} | ||||||
|  |  */ | ||||||
|  | function GeneralizedTime(value) { | ||||||
|  | 	spec.Asn1Spec.call(this, new spec.Asn1Tag(spec.TagClass.Universal, spec.TagFormat.Primitive, UniversalTag.GeneralizedTime)); | ||||||
|  | 	this.value = value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(GeneralizedTime, spec.Asn1Spec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param decoder {ber.decoder} | ||||||
|  |  * @returns {GeneralizedTime} | ||||||
|  |  */ | ||||||
|  | GeneralizedTime.prototype.decode = function(s, decoder) { | ||||||
|  | 	this.value = decoder.decode(s, this.tag).value; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  | 	Boolean : Boolean, | ||||||
|  | 	Integer : Integer, | ||||||
|  | 	Sequence : Sequence, | ||||||
|  | 	Enumerate : Enumerate, | ||||||
|  | 	OctetString : OctetString, | ||||||
|  | 	ObjectIdentifier : ObjectIdentifier, | ||||||
|  | 	Null : Null, | ||||||
|  | 	Choice : Choice, | ||||||
|  | 	SequenceOf : SequenceOf, | ||||||
|  | 	SetOf : SetOf, | ||||||
|  | 	BitString : BitString, | ||||||
|  | 	T61String : T61String, | ||||||
|  | 	PrintableString : PrintableString, | ||||||
|  | 	UniversalString : UniversalString, | ||||||
|  | 	UTF8String : UTF8String, | ||||||
|  | 	BMPString : BMPString, | ||||||
|  | 	IA5String : IA5String, | ||||||
|  | 	UTCTime : UTCTime, | ||||||
|  | 	GeneralizedTime : GeneralizedTime | ||||||
|  | }; | ||||||
							
								
								
									
										71
									
								
								rdp/core/error.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								rdp/core/error.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | /* | ||||||
|  |  * 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; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Fatal error stop program | ||||||
|  |  */ | ||||||
|  | function FatalError(message, code) { | ||||||
|  | 	Error.captureStackTrace(this); | ||||||
|  | 	this.message = message || ""; | ||||||
|  | 	this.code = code || 'NODE_RDP_CORE_ERROR_NO_ERROR_CODE'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * inherit from error | ||||||
|  |  */ | ||||||
|  | inherits(FatalError, Error); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Protocol error (non fatal); | ||||||
|  |  */ | ||||||
|  | function ProtocolError(code, message) { | ||||||
|  | 	Error.captureStackTrace(this); | ||||||
|  | 	this.code = code; | ||||||
|  | 	this.message = message || ""; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * inherit from error | ||||||
|  |  */ | ||||||
|  | inherits(ProtocolError, Error); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ImplementationError error (non fatal); | ||||||
|  |  */ | ||||||
|  | function ImplementationError(code, message) { | ||||||
|  | 	Error.captureStackTrace(this); | ||||||
|  | 	this.code = code; | ||||||
|  | 	this.message = message || ""; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * inherit from error | ||||||
|  |  */ | ||||||
|  | inherits(ImplementationError, Error); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 		FatalError : FatalError, | ||||||
|  | 		ProtocolError : ProtocolError, | ||||||
|  | 		ImplementationError : ImplementationError | ||||||
|  | }; | ||||||
							
								
								
									
										32
									
								
								rdp/core/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								rdp/core/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | /* | ||||||
|  |  * 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 layer = require('./layer'); | ||||||
|  | var type = require('./type'); | ||||||
|  | var log = require('./log'); | ||||||
|  | var error = require('./error'); | ||||||
|  | var rle = require('./rle'); | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  | 	layer : layer, | ||||||
|  | 	type : type, | ||||||
|  | 	log : log, | ||||||
|  | 	error : error, | ||||||
|  | 	rle : rle | ||||||
|  | }; | ||||||
							
								
								
									
										229
									
								
								rdp/core/layer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								rdp/core/layer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,229 @@ | |||||||
|  | /* | ||||||
|  |  * 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 fs = require('fs'); | ||||||
|  | var type = require('./type'); | ||||||
|  | var log = require('./log'); | ||||||
|  | var tls = require('tls'); | ||||||
|  | var crypto = require('crypto'); | ||||||
|  | var events = require('events'); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Buffer data from socket to present | ||||||
|  |  * well formed packets | ||||||
|  |  */ | ||||||
|  | function BufferLayer(socket) { | ||||||
|  | 	//for ssl connection
 | ||||||
|  | 	this.secureSocket = null; | ||||||
|  | 	this.socket = socket; | ||||||
|  | 
 | ||||||
|  | 	var self = this; | ||||||
|  | 	// bind event
 | ||||||
|  | 	this.socket.on('data', function(data) { | ||||||
|  | 		try { | ||||||
|  | 			self.recv(data); | ||||||
|  | 		} | ||||||
|  | 		catch(e) { | ||||||
|  | 			self.socket.destroy(); | ||||||
|  | 			self.emit('error', e); | ||||||
|  | 		} | ||||||
|  | 	}).on('close', function() { | ||||||
|  | 		self.emit('close'); | ||||||
|  | 	}).on('error', function (err) { | ||||||
|  | 		self.emit('error', err); | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	//buffer data
 | ||||||
|  | 	this.buffers = []; | ||||||
|  | 	this.bufferLength = 0; | ||||||
|  | 	//expected size
 | ||||||
|  | 	this.expectedSize = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(BufferLayer, events.EventEmitter); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Call from tcp layer | ||||||
|  |  * @param data tcp stream | ||||||
|  |  */ | ||||||
|  | BufferLayer.prototype.recv = function (data) { | ||||||
|  |     if (this.buffers.length == 0) { this.bufferLength = 0; } // CORRECT
 | ||||||
|  | 	this.buffers[this.buffers.length] = data; | ||||||
|  | 	this.bufferLength += data.length; | ||||||
|  | 
 | ||||||
|  | 	//console.log('TCP RECV', this.bufferLength, this.expectedSize, data.toString('hex'));
 | ||||||
|  | 	//console.log('this.buffers', this.buffers);
 | ||||||
|  | 	//console.log('this.expectedSize', this.expectedSize);
 | ||||||
|  | 	//console.log('this.bufferLength', this.bufferLength);
 | ||||||
|  | 
 | ||||||
|  | 	if (this.expectedSize == 0) { console.log('this.expectedSize == 0'); return; } | ||||||
|  | 
 | ||||||
|  | 	while (this.bufferLength >= this.expectedSize) { | ||||||
|  | 	    //console.log('this.expectedSize', this.expectedSize);
 | ||||||
|  | 	    //console.log('this.bufferLength', this.bufferLength);
 | ||||||
|  | 
 | ||||||
|  | 		//linear buffer
 | ||||||
|  | 		var expectedData = new type.Stream(this.expectedSize); | ||||||
|  | 
 | ||||||
|  | 		//create expected data
 | ||||||
|  | 		while (expectedData.availableLength() > 0) { | ||||||
|  | 
 | ||||||
|  | 			var rest = expectedData.availableLength(); | ||||||
|  | 			var buffer = this.buffers.shift(); | ||||||
|  | 
 | ||||||
|  | 			//console.log('xx', rest, buffer);
 | ||||||
|  | 
 | ||||||
|  | 			if (buffer.length > expectedData.availableLength()) { | ||||||
|  | 				this.buffers.unshift(buffer.slice(rest)); | ||||||
|  | 				new type.BinaryString(buffer, { readLength : new type.CallableValue(expectedData.availableLength()) }).write(expectedData); | ||||||
|  | 			} else { | ||||||
|  | 				new type.BinaryString(buffer).write(expectedData); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		this.bufferLength -= this.expectedSize; | ||||||
|  |         expectedData.offset = 0; | ||||||
|  | 
 | ||||||
|  |         //console.log('TCP EMIT', expectedData);
 | ||||||
|  | 		this.emit('data', expectedData); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Call tcp socket to write stream | ||||||
|  |  * @param {type.Type} packet | ||||||
|  |  */ | ||||||
|  | BufferLayer.prototype.send = function(data) { | ||||||
|  | 	var s = new type.Stream(data.size()); | ||||||
|  | 	data.write(s); | ||||||
|  | 	if(this.secureSocket) { | ||||||
|  | 		this.secureSocket.write(s.buffer); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		this.socket.write(s.buffer); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Call tcp socket to write a buffer | ||||||
|  |  */ | ||||||
|  | BufferLayer.prototype.sendBuffer = function (buffer) { | ||||||
|  |     if (this.secureSocket) { | ||||||
|  |         //console.log('SSL sendBuffer', buffer.length, buffer.toString('hex'));
 | ||||||
|  |         this.secureSocket.write(buffer); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         //console.log('TCP sendBuffer', buffer.length, buffer.toString('hex'));
 | ||||||
|  |         this.socket.write(buffer); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Wait expected size data before call callback function | ||||||
|  |  * @param {number} expectSize	size expected | ||||||
|  |  */ | ||||||
|  | BufferLayer.prototype.expect = function(expectedSize) { | ||||||
|  | 	this.expectedSize = expectedSize; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Convert connection to TLS connection | ||||||
|  |  * @param callback {func} when connection is done | ||||||
|  |  */ | ||||||
|  | BufferLayer.prototype.startTLS = function(callback) { | ||||||
|  | 	var self = this; | ||||||
|  | 
 | ||||||
|  | 	this.secureSocket = tls.connect({ | ||||||
|  | 		socket: this.socket, | ||||||
|  | 		secureContext: tls.createSecureContext(), | ||||||
|  | 		isServer: false, | ||||||
|  | 		requestCert: false, | ||||||
|  | 		rejectUnauthorized: false | ||||||
|  | 	}, (err) => { | ||||||
|  | 		log.warn(err); | ||||||
|  | 		callback(err); | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  |     this.secureSocket.on('data', function (data) { | ||||||
|  | 
 | ||||||
|  |         //console.log('SSL RECV', data.length, data);
 | ||||||
|  | 
 | ||||||
|  | 		try { | ||||||
|  | 			self.recv(data); | ||||||
|  | 		} | ||||||
|  |         catch (e) { | ||||||
|  |             //console.log('SSL RECV ERR', e);
 | ||||||
|  | 			self.socket.destroy(); | ||||||
|  | 			self.emit('error', e); | ||||||
|  | 		} | ||||||
|  | 	}).on('error', function (err) { | ||||||
|  | 		self.emit('error', err); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Convert connection to TLS server | ||||||
|  |  * @param keyFilePath	{string} key file path | ||||||
|  |  * @param crtFilePath	{string} certificat file path | ||||||
|  |  * @param callback	{function} | ||||||
|  |  */ | ||||||
|  | BufferLayer.prototype.listenTLS = function(keyFilePath, crtFilePath, callback) { | ||||||
|  | 	var self = this; | ||||||
|  | 
 | ||||||
|  | 	this.secureSocket = tls.connect({ | ||||||
|  | 		socket: this.socket, | ||||||
|  | 		secureContext: tls.createSecureContext({ | ||||||
|  | 			key: fs.readFileSync(keyFilePath), | ||||||
|  | 			cert: fs.readFileSync(crtFilePath), | ||||||
|  | 		}), | ||||||
|  | 		isServer: true, | ||||||
|  | 		requestCert: false, | ||||||
|  | 		rejectUnauthorized: false | ||||||
|  | 	}, (err) => { | ||||||
|  | 		log.warn(err); | ||||||
|  | 		callback(err); | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	this.secureSocket.on('data', function(data) { | ||||||
|  | 		try { | ||||||
|  | 			self.recv(data); | ||||||
|  | 		} | ||||||
|  | 		catch(e) { | ||||||
|  | 			self.socket.destroy(); | ||||||
|  | 			self.emit('error', e); | ||||||
|  | 		} | ||||||
|  | 	}).on('error', function (err) { | ||||||
|  | 		self.emit('error', err); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * close stack | ||||||
|  |  */ | ||||||
|  | BufferLayer.prototype.close = function() { | ||||||
|  | 	this.socket.end(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	BufferLayer : BufferLayer | ||||||
|  | }; | ||||||
							
								
								
									
										81
									
								
								rdp/core/log.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								rdp/core/log.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | |||||||
|  | /* | ||||||
|  |  * 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 Levels = { | ||||||
|  |     'DEBUG': 1, | ||||||
|  |     'INFO': 2, | ||||||
|  |     'WARN': 3, | ||||||
|  |     'ERROR': 4, | ||||||
|  |     'NONE': 5 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | var Logger = require('bunyan'); | ||||||
|  | 
 | ||||||
|  | let logStreams = []; | ||||||
|  | 
 | ||||||
|  | if (process.env.enable_log_file === 'true') { | ||||||
|  | 	logStreams.push( | ||||||
|  | 		{ | ||||||
|  | 			type: 'rotating-file', | ||||||
|  | 			period: '1d', | ||||||
|  | 			count: 2, | ||||||
|  | 			path: `node-rdpjs${process.pid}.log`, | ||||||
|  | 			level: process.env.log_level | ||||||
|  | 		} | ||||||
|  | 	); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | logStreams.push( | ||||||
|  | 	{ | ||||||
|  | 		stream: process.stderr, | ||||||
|  | 		level: process.env.log_level | ||||||
|  | 	} | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | var logger = Logger.createLogger({ | ||||||
|  | 	name: 'node-rdpjs', | ||||||
|  | 	streams: logStreams | ||||||
|  | }); | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | function log(level, message) { | ||||||
|  | 	if (Levels[level] < module.exports.level) return; | ||||||
|  | 	console.log("[node-rdpjs] " + level + ":\t" + message); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  |     level: Levels.INFO, // Levels.INFO,
 | ||||||
|  | 	Levels: Levels, | ||||||
|  | 	debug: function (message) { | ||||||
|  | 	    //logger.debug(message);
 | ||||||
|  | 	}, | ||||||
|  | 	info: function (message) { | ||||||
|  | 	    //logger.info(message);
 | ||||||
|  | 	}, | ||||||
|  | 	warn: function (message) { | ||||||
|  | 	    //logger.warn(message);
 | ||||||
|  | 	}, | ||||||
|  | 	error: function (message) { | ||||||
|  | 	    //logger.error(message);
 | ||||||
|  | 	} | ||||||
|  | }; | ||||||
							
								
								
									
										17868
									
								
								rdp/core/rle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17868
									
								
								rdp/core/rle.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										488
									
								
								rdp/core/type.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										488
									
								
								rdp/core/type.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,488 @@ | |||||||
|  | /* | ||||||
|  |  * 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 log = require('./log'); | ||||||
|  | var error = require('./error'); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Stream wrapper around buffer type | ||||||
|  |  * @param i {Buffer | integer} size of init buffer | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function Stream(i) { | ||||||
|  | 	this.offset = 0; | ||||||
|  | 	if (i instanceof Buffer) { | ||||||
|  | 		this.buffer = i; | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		this.buffer = Buffer.alloc(i || 8192); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Return length of available data in stream | ||||||
|  |  * @returns {Number} length of available data in stream | ||||||
|  |  */ | ||||||
|  | Stream.prototype.availableLength = function() { | ||||||
|  | 	return this.buffer.length - this.offset; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * increment offset | ||||||
|  |  * @param length {integer} length of padding | ||||||
|  |  */ | ||||||
|  | Stream.prototype.readPadding = function(length) { | ||||||
|  | 	this.offset += length; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Format string buffer | ||||||
|  |  * @returns {string} buffer stringified | ||||||
|  |  */ | ||||||
|  | Stream.prototype.getValue = function() { | ||||||
|  | 	return this.buffer; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param value {object | function} inner value | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function CallableValue(value) { | ||||||
|  | 	if(value) { | ||||||
|  | 		this.value = value; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * For syntaxic purpose | ||||||
|  |  */ | ||||||
|  | Object.defineProperty(CallableValue.prototype, "value", { | ||||||
|  | 	get: function() { return this._value(); }, | ||||||
|  | 	set: function(e) { | ||||||
|  | 		if(typeof e !== 'function') { | ||||||
|  | 			this._value = function () { return e; }; | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			this._value = e; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Type readable or writable by binary stream | ||||||
|  |  * @param {object} opt  | ||||||
|  |  * 			.conditional {boolean} read or write type depend on conditional call | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function Type(opt) { | ||||||
|  | 	CallableValue.call(this); | ||||||
|  | 	this.opt = opt || {}; | ||||||
|  | 	this.isReaded = false; | ||||||
|  | 	this.isWritten = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Type, CallableValue); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Write type into binary stream s | ||||||
|  |  * @param {type.Stream} s binary stream | ||||||
|  |  */ | ||||||
|  | Type.prototype.write = function(s) { | ||||||
|  | 	//do not write false conditional type
 | ||||||
|  | 	if(this.opt.conditional && !this.opt.conditional()) | ||||||
|  | 		return this; | ||||||
|  | 	 | ||||||
|  | 	this.isWritten = true; | ||||||
|  | 	 | ||||||
|  | 	this.writeValue(s); | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read type from binary stream  | ||||||
|  |  * @param {type.Stream} s binary stream | ||||||
|  |  * @returns this to chain call | ||||||
|  |  */ | ||||||
|  | Type.prototype.read = function(s) { | ||||||
|  | 	//do not read false conditional type
 | ||||||
|  | 	if(this.opt.conditional && !this.opt.conditional()) | ||||||
|  | 		return this; | ||||||
|  | 	 | ||||||
|  | 	if(this.opt.optional && s.availableLength() < this.size()) | ||||||
|  | 		return this; | ||||||
|  | 	 | ||||||
|  | 	this.isReaded = true; | ||||||
|  | 	 | ||||||
|  | 	//constant case
 | ||||||
|  | 	if(this.opt.constant) { | ||||||
|  | 		var oldValue = this.value; | ||||||
|  | 		try { | ||||||
|  | 			this.readValue(s); | ||||||
|  | 		} | ||||||
|  | 		catch(e) { | ||||||
|  | 			if (e instanceof RangeError) { | ||||||
|  | 				throw new error.ProtocolError("NODE_RDP_CORE_TYPE_STREAM_TOO_SMALL"); | ||||||
|  | 			} | ||||||
|  | 			throw e; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if(oldValue !== this.value) { | ||||||
|  | 			log.error('constant value mismatch ' + oldValue + ' != ' + this.value); | ||||||
|  | 			throw new error.ProtocolError("NODE_RDP_CORE_TYPE_CONSTANT_VALUE_MISMATCH"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		try { | ||||||
|  | 			this.readValue(s); | ||||||
|  | 		} | ||||||
|  | 		catch(e) { | ||||||
|  | 			if (e instanceof RangeError) { | ||||||
|  | 				throw new error.ProtocolError("NODE_RDP_CORE_TYPE_STREAM_TOO_SMALL"); | ||||||
|  | 			} | ||||||
|  | 			throw e; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Size of type | ||||||
|  |  * @returns {int} Size of type | ||||||
|  |  */ | ||||||
|  | Type.prototype.size = function() { | ||||||
|  | 	if(this.opt.conditional && !this.opt.conditional()) | ||||||
|  | 		return 0; | ||||||
|  | 	return this._size_(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Convert type to stream | ||||||
|  |  * Usefull when you want to buffer | ||||||
|  |  * @returns {Stream} | ||||||
|  |  */ | ||||||
|  | Type.prototype.toStream = function() { | ||||||
|  | 	var result = new Stream(this.size()); | ||||||
|  | 	this.write(result); | ||||||
|  | 	return result; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Node of Raw types | ||||||
|  |  * @param {object} obj composite object | ||||||
|  |  * @param {object} opt Type parameters | ||||||
|  |  */ | ||||||
|  | function Component(obj, opt) { | ||||||
|  | 	Type.call(this, opt); | ||||||
|  | 	this.obj = obj; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(Component, Type); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * ignore criterion | ||||||
|  |  * @param i {string} index name in obj | ||||||
|  |  * @returns {Boolean} true if can be ignore | ||||||
|  |  */ | ||||||
|  | Component.prototype.ignore = function(i) { | ||||||
|  | 	// ignore meta information
 | ||||||
|  | 	if(i.lastIndexOf("__", 0) === 0) { | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	// ignore function
 | ||||||
|  | 	if(typeof(this.obj[i]) === 'function') { | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Write each sub type into stream | ||||||
|  |  * @param {Stream} s | ||||||
|  |  */ | ||||||
|  | Component.prototype.writeValue = function(s) { | ||||||
|  | 	for(var i in this.obj) { | ||||||
|  | 		if(this.ignore(i)) { | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		try { | ||||||
|  | 			this.obj[i].write(s); | ||||||
|  | 		} | ||||||
|  | 		catch(e) { | ||||||
|  | 			log.info('during write of field ' + i); | ||||||
|  | 			throw e; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read each sub type into stream | ||||||
|  |  * @param {Stream} s from read stream | ||||||
|  |  */ | ||||||
|  | Component.prototype.readValue = function(s) { | ||||||
|  | 	var readStream = s; | ||||||
|  | 	if(this.opt.readLength) { | ||||||
|  | 		readStream = new Stream(s.buffer.slice(s.offset, s.offset + this.opt.readLength.value)); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	for(var i in this.obj) { | ||||||
|  | 		// ignore meta information
 | ||||||
|  | 		if(this.ignore(i)) { | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		try { | ||||||
|  | 			this.obj[i].read(readStream); | ||||||
|  | 		} | ||||||
|  | 		catch(e) { | ||||||
|  | 			log.info('during read of field ' + i); | ||||||
|  | 			throw e; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	// padding
 | ||||||
|  | 	if (this.opt.readLength) { | ||||||
|  | 		s.offset += this.opt.readLength.value; | ||||||
|  | 		if (readStream.offset < this.opt.readLength.value) { | ||||||
|  | 			log.debug('still have available data : read it as padding'); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Sum size of sub types | ||||||
|  |  */ | ||||||
|  | Component.prototype._size_ = function() { | ||||||
|  | 	var size = 0; | ||||||
|  | 	for(var i in this.obj) { | ||||||
|  | 		if(this.ignore(i)) { | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		size += this.obj[i].size(); | ||||||
|  | 	} | ||||||
|  | 	return size; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Leaf of tree type | ||||||
|  |  * @param {number} value of type | ||||||
|  |  * @param {function} readBufferCallback Buffer prototype read function | ||||||
|  |  * @param {function} writeBufferCallback Buffer prototype write function | ||||||
|  |  * @param {object} opt Type parameter | ||||||
|  |  */ | ||||||
|  | function SingleType(value, nbBytes, readBufferCallback, writeBufferCallback, opt){ | ||||||
|  | 	Type.call(this, opt); | ||||||
|  | 	this.value = value || 0; | ||||||
|  | 	this.nbBytes = nbBytes; | ||||||
|  | 	this.readBufferCallback = readBufferCallback; | ||||||
|  | 	this.writeBufferCallback = writeBufferCallback; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(SingleType, Type); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Write SingleType value into stream | ||||||
|  |  * @param s | ||||||
|  |  */ | ||||||
|  | SingleType.prototype.writeValue = function(s) { | ||||||
|  | 	this.writeBufferCallback.call(s.buffer, this.value, s.offset); | ||||||
|  | 	s.offset += this._size_(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read SingleType value into stream | ||||||
|  |  * @param {Stream} s from read stream | ||||||
|  |  */ | ||||||
|  | SingleType.prototype.readValue = function(s) { | ||||||
|  | 	this.value = this.readBufferCallback.call(s.buffer, s.offset); | ||||||
|  | 	s.offset += this._size_(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Size of single type | ||||||
|  |  * @returns Size of single type | ||||||
|  |  */ | ||||||
|  | SingleType.prototype._size_ = function() { | ||||||
|  | 	return this.nbBytes; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Integer on 1 byte | ||||||
|  |  * @param {number | function} value of type | ||||||
|  |  * @param {object} opt	Type parameter | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function UInt8(value, opt) { | ||||||
|  | 	SingleType.call(this, value, 1, Buffer.prototype.readUInt8, Buffer.prototype.writeUInt8, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(UInt8, SingleType); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Integer on 2 bytes in Little Endian | ||||||
|  |  * @param {number | function} value to write or compare if constant | ||||||
|  |  * @param {object} opt	Type parameter | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function UInt16Le(value, opt) { | ||||||
|  | 	SingleType.call(this, value, 2, Buffer.prototype.readUInt16LE, Buffer.prototype.writeUInt16LE, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(UInt16Le, SingleType); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Integer on 2 bytes in Big Endian | ||||||
|  |  * @param {number | function} value to write or compare if constant | ||||||
|  |  * @param {object} opt	Type parameter | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function UInt16Be(value, opt) { | ||||||
|  | 	SingleType.call(this, value, 2, Buffer.prototype.readUInt16BE, Buffer.prototype.writeUInt16BE, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(UInt16Be, SingleType); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Integer on 4 bytes in Little Endian | ||||||
|  |  * @param {number | function} value to write or compare if constant | ||||||
|  |  * @param {object} opt	Type parameter | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function UInt32Le(value, opt) { | ||||||
|  | 	SingleType.call(this, value, 4, Buffer.prototype.readUInt32LE, Buffer.prototype.writeUInt32LE, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(UInt32Le, SingleType); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Integer on 4 bytes in Big Endian | ||||||
|  |  * @param {number | function} value to write or compare if constant | ||||||
|  |  * @param {object} opt	Type parameter | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function UInt32Be(value, opt) { | ||||||
|  | 	SingleType.call(this, value, 4, Buffer.prototype.readUInt32BE, Buffer.prototype.writeUInt32BE, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(UInt32Be, SingleType); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param value {Buffer} javascript source string | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * 	.readLength {type} length for reading operation | ||||||
|  |  * @returns {type.BinaryString} | ||||||
|  |  */ | ||||||
|  | function BinaryString(value, opt) { | ||||||
|  | 	Type.call(this, opt); | ||||||
|  | 	this.value = value || Buffer.alloc(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(BinaryString, Type); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Write value into string | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | BinaryString.prototype.writeValue = function(s) { | ||||||
|  | 	this.value.copy(s.buffer, s.offset); | ||||||
|  | 	s.offset += this._size_(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read string from offset to read length if specified or end of stream | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | BinaryString.prototype.readValue = function(s) { | ||||||
|  | 	if(this.opt.readLength) { | ||||||
|  | 		this.value = s.buffer.slice(s.offset, s.offset + this.opt.readLength.value); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		this.value = s.buffer.slice(s.offset); | ||||||
|  | 	} | ||||||
|  | 	s.offset += this._size_(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @returns {integer} length of string | ||||||
|  |  */ | ||||||
|  | BinaryString.prototype._size_ = function() { | ||||||
|  | 	return this.value.length; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Dynamic built type depend on factory function | ||||||
|  |  * @param message {object} parent object | ||||||
|  |  * @param field {string} name of object field | ||||||
|  |  * @param factory {function} factory use to built new type | ||||||
|  |  * @param opt {object}	type options | ||||||
|  |  */ | ||||||
|  | function Factory(factory, opt) { | ||||||
|  | 	Type.call(this, opt); | ||||||
|  | 	this.factory = factory; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from type
 | ||||||
|  | inherits(Factory, Type); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * build type and write into stream | ||||||
|  |  * @param s {Stream} input stream | ||||||
|  |  */ | ||||||
|  | Factory.prototype.writeValue = function(s) { | ||||||
|  | 	this.factory(s); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * build type and read from stream | ||||||
|  |  * @param s {Stream} input stream | ||||||
|  |  */ | ||||||
|  | Factory.prototype.readValue = function(s) { | ||||||
|  | 	this.factory(s); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * must be never called | ||||||
|  |  */ | ||||||
|  | Factory.prototype._size_ = function() { | ||||||
|  | 	throw new error.FatalError('NODE_RDP_CORE_TYPE_FACTORY_TYPE_HAVE_NO_SIZE'); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	Stream : Stream, | ||||||
|  | 	Component : Component, | ||||||
|  | 	UInt8 : UInt8, | ||||||
|  | 	UInt16Le : UInt16Le, | ||||||
|  | 	UInt16Be : UInt16Be, | ||||||
|  | 	UInt32Le : UInt32Le, | ||||||
|  | 	UInt32Be : UInt32Be, | ||||||
|  | 	BinaryString : BinaryString, | ||||||
|  | 	CallableValue : CallableValue, | ||||||
|  | 	Factory : Factory | ||||||
|  | }; | ||||||
							
								
								
									
										24
									
								
								rdp/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								rdp/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | /* | ||||||
|  |  * 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 protocol = require('./protocol'); | ||||||
|  | module.exports = { | ||||||
|  | 	createClient : protocol.rdp.createClient, | ||||||
|  | 	createServer : protocol.rdp.createServer | ||||||
|  | }; | ||||||
							
								
								
									
										175
									
								
								rdp/protocol/cert.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								rdp/protocol/cert.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,175 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../core').type; | ||||||
|  | var log = require('../core').log; | ||||||
|  | var x509 = require('../security').x509; | ||||||
|  | var rsa = require('../security').rsa; | ||||||
|  | var asn1 = require('../asn1'); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  *  @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
 | ||||||
|  |  */ | ||||||
|  | var CertificateType = { | ||||||
|  |     CERT_CHAIN_VERSION_1 : 0x00000001, | ||||||
|  |     CERT_CHAIN_VERSION_2 : 0x00000002 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240520.aspx
 | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function rsaPublicKey(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		magic : new type.UInt32Le(0x31415352, { constant : true }), | ||||||
|  |         keylen : new type.UInt32Le(function() { | ||||||
|  |         	return self.modulus.size() + self.paddinf.size(); | ||||||
|  |         }), | ||||||
|  |         bitlen : new type.UInt32Le(function() { | ||||||
|  |         	return (self.keylen.value - 8) * 8; | ||||||
|  |         }), | ||||||
|  |         datalen : new type.UInt32Le(function() { | ||||||
|  |         	return (self.bitlen.value / 8) - 1; | ||||||
|  |         }), | ||||||
|  |         pubExp : new type.UInt32Le(), | ||||||
|  |         modulus : new type.BinaryString(null, { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.keylen.value - 8; | ||||||
|  |         }) }), | ||||||
|  |         padding : new type.BinaryString(Buffer.from(Array(8 + 1).join('\x00')), { readLength : new type.CallableValue(8) }) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * http://msdn.microsoft.com/en-us/library/cc240519.aspx
 | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function proprietaryCertificate() { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CertificateType.CERT_CHAIN_VERSION_1, | ||||||
|  | 		dwSigAlgId : new type.UInt32Le(0x00000001, { constant : true }), | ||||||
|  |         dwKeyAlgId : new type.UInt32Le(0x00000001, { constant : true }), | ||||||
|  |         wPublicKeyBlobType : new type.UInt16Le(0x0006, { constant : true }), | ||||||
|  |         wPublicKeyBlobLen : new type.UInt16Le(function() { | ||||||
|  |         	return self.PublicKeyBlob.size(); | ||||||
|  |         }), | ||||||
|  |         PublicKeyBlob : rsaPublicKey({ readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.wPublicKeyBlobLen.value; | ||||||
|  |         }) }), | ||||||
|  |         wSignatureBlobType : new type.UInt16Le(0x0008, { constant : true }), | ||||||
|  |         wSignatureBlobLen : new type.UInt16Le(function() { | ||||||
|  |         	return self.SignatureBlob.size() + self.padding.size(); | ||||||
|  |         }), | ||||||
|  |         SignatureBlob : new type.BinaryString(null, { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.wSignatureBlobLen.value - self.padding.size; | ||||||
|  |         }) }), | ||||||
|  |         padding : new type.BinaryString(Array(8 + 1).join('\x00'), { readLength : new type.CallableValue(8) }), | ||||||
|  |         /** | ||||||
|  |          * @return {object} rsa.publicKey | ||||||
|  |          */ | ||||||
|  |         getPublicKey : function() { | ||||||
|  |         	return rsa.publicKey(self.PublicKeyBlob.obj.modulus.value, self.PublicKeyBlob.obj.pubExp.value); | ||||||
|  |         } | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * For x509 certificate | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241911.aspx
 | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function certBlob() { | ||||||
|  | 	var self = { | ||||||
|  | 		cbCert : new type.UInt32Le(function() { | ||||||
|  | 			return self.abCert.size(); | ||||||
|  | 		}), | ||||||
|  |         abCert : new type.BinaryString(null, { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.cbCert.value; | ||||||
|  |         }) }) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * x509 certificate chain | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241910.aspx
 | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function x509CertificateChain() { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CertificateType.CERT_CHAIN_VERSION_2, | ||||||
|  | 		NumCertBlobs : new type.UInt32Le(), | ||||||
|  |         CertBlobArray : new type.Factory(function(s) { | ||||||
|  |         	self.CertBlobArray = new type.Component([]); | ||||||
|  |         	for(var i = 0; i < self.NumCertBlobs.value; i++) { | ||||||
|  |         		self.CertBlobArray.obj.push(certBlob().read(s)); | ||||||
|  |         	} | ||||||
|  |         }), | ||||||
|  |         padding : new type.BinaryString(null, { readLength : new type.CallableValue(function() { | ||||||
|  |         	return 8 + 4 * self.NumCertBlobs.value; | ||||||
|  |         }) }), | ||||||
|  |         /** | ||||||
|  |          * @return {object} {n : modulus{bignum}, e : publicexponent{integer} | ||||||
|  |          */ | ||||||
|  |         getPublicKey : function(){ | ||||||
|  |         	var cert = x509.X509Certificate().decode(new type.Stream(self.CertBlobArray.obj[self.CertBlobArray.obj.length - 1].obj.abCert.value), asn1.ber); | ||||||
|  |         	var publikeyStream = new type.Stream(cert.value.tbsCertificate.value.subjectPublicKeyInfo.value.subjectPublicKey.toBuffer()); | ||||||
|  |         	var asn1PublicKey = x509.RSAPublicKey().decode(publikeyStream, asn1.ber); | ||||||
|  |         	return rsa.publicKey(asn1PublicKey.value.modulus.value, asn1PublicKey.value.publicExponent.value); | ||||||
|  |         } | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function certificate() { | ||||||
|  | 	var self = { | ||||||
|  | 		dwVersion : new type.UInt32Le(function() { | ||||||
|  | 			return self.certData.__TYPE__; | ||||||
|  | 		}), | ||||||
|  | 		certData : new type.Factory(function(s) { | ||||||
|  | 			switch(self.dwVersion.value & 0x7fffffff) { | ||||||
|  | 			case CertificateType.CERT_CHAIN_VERSION_1: | ||||||
|  | 				log.debug('read proprietary certificate'); | ||||||
|  | 				self.certData = proprietaryCertificate().read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CertificateType.CERT_CHAIN_VERSION_2: | ||||||
|  | 				log.debug('read x.509 certificate chain'); | ||||||
|  | 				self.certData = x509CertificateChain().read(s); | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				log.error('unknown cert type ' + self.dwVersion.value & 0x7fffffff); | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	CertificateType : CertificateType, | ||||||
|  | 	certificate : certificate | ||||||
|  | }; | ||||||
							
								
								
									
										30
									
								
								rdp/protocol/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								rdp/protocol/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | /* | ||||||
|  |  * 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 TPKT = require('./tpkt'); | ||||||
|  | var x224 = require('./x224'); | ||||||
|  | var t125 = require('./t125'); | ||||||
|  | var rdp = require('./rdp'); | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  | 	TPKT : TPKT, | ||||||
|  | 	x224 : x224, | ||||||
|  | 	t125 : t125, | ||||||
|  | 	rdp : rdp | ||||||
|  | }; | ||||||
| @ -1,8 +1,223 @@ | |||||||
|  | const inherits = require('util').inherits; | ||||||
|  | const type = require('../core').type; | ||||||
|  | const events = require('events'); | ||||||
| const crypto = require('crypto'); | const crypto = require('crypto'); | ||||||
| const forge = require('node-forge'); | const forge = require('node-forge'); | ||||||
| const asn1 = forge.asn1; | const asn1 = forge.asn1; | ||||||
| const pki = forge.pki; | const pki = forge.pki; | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * NLA layer of rdp stack | ||||||
|  |  */ | ||||||
|  | function NLA(transport, nlaCompletedFunc, domain, user, password) { | ||||||
|  |     // Get NTLM ready
 | ||||||
|  |     const ntlm = Create_Ntlm(); | ||||||
|  |     ntlm.domain = domain; | ||||||
|  |     ntlm.completedFunc = nlaCompletedFunc; | ||||||
|  |     ntlm.user = user; | ||||||
|  |     ntlm.password = password; | ||||||
|  |     ntlm.response_key_nt = ntowfv2(ntlm.password, ntlm.user, ntlm.domain); | ||||||
|  |     ntlm.response_key_lm = lmowfv2(ntlm.password, ntlm.user, ntlm.domain); | ||||||
|  |     this.ntlm = ntlm; | ||||||
|  |     this.state = 1; | ||||||
|  | 
 | ||||||
|  |     // Get transport ready
 | ||||||
|  | 	this.transport = transport; | ||||||
|  | 	// Wait 2 bytes
 | ||||||
|  | 	this.transport.expect(2); | ||||||
|  | 	// Next state is receive header
 | ||||||
|  | 	var self = this; | ||||||
|  | 
 | ||||||
|  | 	this.oldDataListeners = this.transport.listeners('data'); | ||||||
|  | 	this.oldCloseListeners = this.transport.listeners('close'); | ||||||
|  | 	this.oldErrorListeners = this.transport.listeners('error'); | ||||||
|  | 
 | ||||||
|  |     // Unhook the previous transport handler
 | ||||||
|  | 	this.transport.removeAllListeners('data'); | ||||||
|  | 	this.transport.removeAllListeners('close'); | ||||||
|  | 	this.transport.removeAllListeners('error'); | ||||||
|  | 
 | ||||||
|  |     // Hook this module as the transport handler
 | ||||||
|  |     this.transport.once('data', function (s) { | ||||||
|  |         self.recvHeader(s); | ||||||
|  |     }).on('close', function () { | ||||||
|  |         self.emit('close'); | ||||||
|  |     }).on('error', function (err) { | ||||||
|  |         self.emit('close'); // Errors occur when NLA authentication fails, for now, just close.
 | ||||||
|  |         //self.emit('error', err);
 | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * inherit from a packet layer | ||||||
|  |  */ | ||||||
|  | inherits(NLA, events.EventEmitter); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive correct packet as expected | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | NLA.prototype.recvHeader = function (s) { | ||||||
|  |     //console.log('NLA - recvHeader', s);
 | ||||||
|  |     var self = this; | ||||||
|  |     var derType = new type.UInt8().read(s).value; | ||||||
|  |     var derLen = new type.UInt8().read(s).value; | ||||||
|  |     self.buffers = [ s.buffer ]; | ||||||
|  | 
 | ||||||
|  |     if (derLen < 128) { | ||||||
|  |         // wait for the entire data block
 | ||||||
|  |         this.transport.expect(derLen); | ||||||
|  |         this.transport.once('data', function (s) { self.recvData(s); }); | ||||||
|  |     } else { | ||||||
|  |         // wait for the header size
 | ||||||
|  |         this.transport.expect(derLen - 128); | ||||||
|  |         this.transport.once('data', function (s) { self.recvHeaderSize(s); }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     //console.log('NLA - DER', derType, derLen);
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive correct packet as expected | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | NLA.prototype.recvHeaderSize = function (s) { | ||||||
|  |     //console.log('NLA - recvHeaderSize', s.buffer.length);
 | ||||||
|  |     var self = this; | ||||||
|  |     self.buffers.push(s.buffer); | ||||||
|  |     if (s.buffer.length == 1) { | ||||||
|  |         // wait for the entire data block
 | ||||||
|  |         var derLen = s.buffer.readUInt8(0); | ||||||
|  |         this.transport.expect(derLen); | ||||||
|  |         this.transport.once('data', function (s) { self.recvData(s); }); | ||||||
|  |     } else if (s.buffer.length == 2) { | ||||||
|  |         // wait for the entire data block
 | ||||||
|  |         var derLen = s.buffer.readUInt16BE(0); | ||||||
|  |         this.transport.expect(derLen); | ||||||
|  |         this.transport.once('data', function (s) { self.recvData(s); }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive correct packet as expected | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | NLA.prototype.recvData = function (s) { | ||||||
|  |     //console.log('NLA - recvData', s.buffer.length);
 | ||||||
|  |     var self = this; | ||||||
|  |     self.buffers.push(s.buffer); | ||||||
|  |     var entireBuffer = Buffer.concat(self.buffers); | ||||||
|  |     //console.log('entireBuffer', entireBuffer.toString('hex'));
 | ||||||
|  | 
 | ||||||
|  |     // We have a full ASN1 data block, decode it now
 | ||||||
|  |     const der = asn1.fromDer(entireBuffer.toString('binary')); | ||||||
|  |     const derNum = der.value[0].value[0].value.charCodeAt(0); | ||||||
|  |     //console.log('NLA - Number', derNum);
 | ||||||
|  | 
 | ||||||
|  |     if (derNum == 6) { | ||||||
|  |         if (this.state == 1) { | ||||||
|  |             const derBuffer = Buffer.from(der.value[1].value[0].value[0].value[0].value[0].value, 'binary'); | ||||||
|  |             const client_challenge = read_challenge_message(this.ntlm, derBuffer); | ||||||
|  |             self.security_interface = build_security_interface(this.ntlm); | ||||||
|  |             const peer_cert = this.transport.secureSocket.getPeerCertificate(); | ||||||
|  |             const challenge = create_ts_authenticate(client_challenge, self.security_interface.gss_wrapex(peer_cert.pubkey.slice(24))); | ||||||
|  |             this.ntlm.publicKeyDer = peer_cert.pubkey.slice(24); | ||||||
|  |             this.send(challenge); | ||||||
|  |             this.state = 2; | ||||||
|  |         } else if (this.state == 2) { | ||||||
|  |             const derBuffer = Buffer.from(der.value[1].value[0].value, 'binary'); | ||||||
|  |             const publicKeyDer = self.security_interface.gss_unwrapex(derBuffer); | ||||||
|  | 
 | ||||||
|  |             // Check that the public key is identical except the first byte which is the DER encoding type.
 | ||||||
|  |             if (!this.ntlm.publicKeyDer.slice(1).equals(publicKeyDer.slice(1))) { console.log('RDP man-in-the-middle detected.'); close(); return; } | ||||||
|  |             delete this.ntlm.publicKeyDer; // Clean this up, we don't need it anymore.
 | ||||||
|  | 
 | ||||||
|  |             var xdomain, xuser, xpassword; | ||||||
|  |             if (this.ntlm.is_unicode) { | ||||||
|  |                 xdomain = toUnicode(this.ntlm.domain); | ||||||
|  |                 xuser = toUnicode(this.ntlm.user); | ||||||
|  |                 xpassword = toUnicode(this.ntlm.password); | ||||||
|  |             } else { | ||||||
|  |                 xdomain = Buffer.from(this.ntlm.domain, 'utf8'); | ||||||
|  |                 xuser = Buffer.from(this.ntlm.user, 'utf8'); | ||||||
|  |                 xpassword = Buffer.from(this.ntlm.password, 'utf8'); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             const credentials = create_ts_authinfo(self.security_interface.gss_wrapex(create_ts_credentials(xdomain, xuser, xpassword))); | ||||||
|  |             this.send(credentials); | ||||||
|  | 
 | ||||||
|  |             // Rehook the previous transport handler
 | ||||||
|  |             this.transport.removeAllListeners('data'); | ||||||
|  |             this.transport.removeAllListeners('close'); | ||||||
|  |             this.transport.removeAllListeners('error'); | ||||||
|  | 
 | ||||||
|  |             for (var i in this.oldDataListeners) { this.transport.once('data', this.oldDataListeners[i]); } | ||||||
|  |             for (var i in this.oldCloseListeners) { this.transport.on('close', this.oldCloseListeners[i]); } | ||||||
|  |             for (var i in this.oldErrorListeners) { this.transport.on('error', this.oldErrorListeners[i]); } | ||||||
|  | 
 | ||||||
|  |             // Done!
 | ||||||
|  |             this.transport.expect(2); | ||||||
|  |             this.state = 3; | ||||||
|  |             this.ntlm.completedFunc(); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Receive next block of data
 | ||||||
|  |     this.transport.expect(2); | ||||||
|  |     this.transport.once('data', function (s) { self.recvHeader(s); }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send message throught NLA layer | ||||||
|  |  * @param message {type.*} | ||||||
|  |  */ | ||||||
|  | NLA.prototype.send = function (message) { | ||||||
|  |     this.transport.sendBuffer(message); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * close stack | ||||||
|  |  */ | ||||||
|  | NLA.prototype.close = function() { | ||||||
|  | 	this.transport.close(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | NLA.prototype.sendNegotiateMessage = function () { | ||||||
|  |     // Create create_ts_request
 | ||||||
|  |     this.ntlm.negotiate_message = create_negotiate_message(); | ||||||
|  |     const asn1obj = | ||||||
|  |         asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |             asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ | ||||||
|  |                 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, asn1.integerToDer(2)), | ||||||
|  |             ]), | ||||||
|  |             asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [ | ||||||
|  |                 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |                     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |                         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ | ||||||
|  |                             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, this.ntlm.negotiate_message.toString('binary')) | ||||||
|  |                         ]) | ||||||
|  |                     ]) | ||||||
|  |                 ]) | ||||||
|  |             ]) | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |     // Serialize an ASN.1 object to DER format
 | ||||||
|  |     this.send(Buffer.from(asn1.toDer(asn1obj).data, 'binary')); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = NLA; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| const NegotiateFlags = { | const NegotiateFlags = { | ||||||
|     NtlmsspNegociate56: 0x80000000, |     NtlmsspNegociate56: 0x80000000, | ||||||
|     NtlmsspNegociateKeyExch: 0x40000000, |     NtlmsspNegociateKeyExch: 0x40000000, | ||||||
| @ -171,10 +386,10 @@ function build_security_interface(ntlm) { | |||||||
|         const encrypted_data = obj.encrypt.update(data); |         const encrypted_data = obj.encrypt.update(data); | ||||||
|         const signature = mac(obj.encrypt, obj.signing_key, obj.seq_num, data); |         const signature = mac(obj.encrypt, obj.signing_key, obj.seq_num, data); | ||||||
|         obj.seq_num++; |         obj.seq_num++; | ||||||
|         return Buffer.concat([ signature, encrypted_data ] ); |         return Buffer.concat([signature, encrypted_data]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     obj.gss_unwrapex = function(data) { |     obj.gss_unwrapex = function (data) { | ||||||
|         const version = data.readInt32LE(0); |         const version = data.readInt32LE(0); | ||||||
|         const checksum = data.slice(4, 12); |         const checksum = data.slice(4, 12); | ||||||
|         const seqnum = data.readInt32LE(12); |         const seqnum = data.readInt32LE(12); | ||||||
| @ -183,9 +398,9 @@ function build_security_interface(ntlm) { | |||||||
|         const plaintext_checksum = obj.decrypt.update(checksum); |         const plaintext_checksum = obj.decrypt.update(checksum); | ||||||
|         const seqnumbuf = Buffer.alloc(4); |         const seqnumbuf = Buffer.alloc(4); | ||||||
|         seqnumbuf.writeInt32LE(seqnum, 0); |         seqnumbuf.writeInt32LE(seqnum, 0); | ||||||
|         const computed_checksum = hmac_md5(obj.verify_key, Buffer.concat([ seqnumbuf, plaintext_payload ])).slice(0, 8); |         const computed_checksum = hmac_md5(obj.verify_key, Buffer.concat([seqnumbuf, plaintext_payload])).slice(0, 8); | ||||||
|         if (!plaintext_checksum.equals(computed_checksum)) { console.log("Invalid checksum on NTLMv2"); } |         if (!plaintext_checksum.equals(computed_checksum)) { console.log("Invalid checksum on NTLMv2"); } | ||||||
|         return plaintext_payload.toString(); |         return plaintext_payload; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return obj; |     return obj; | ||||||
| @ -220,19 +435,19 @@ function authenticate_message(lm_challenge_response, nt_challenge_response, doma | |||||||
|     buf.writeInt32LE(3, 8); // MessageType
 |     buf.writeInt32LE(3, 8); // MessageType
 | ||||||
|     buf.writeInt16LE(lm_challenge_response.length, 12); // LmChallengeResponseLen
 |     buf.writeInt16LE(lm_challenge_response.length, 12); // LmChallengeResponseLen
 | ||||||
|     buf.writeInt16LE(lm_challenge_response.length, 14); // LmChallengeResponseMaxLen
 |     buf.writeInt16LE(lm_challenge_response.length, 14); // LmChallengeResponseMaxLen
 | ||||||
|     if (lm_challenge_response.length > 0) { buf.writeInt32LE(offset, 16); } // LmChallengeResponseBufferOffset
 |     buf.writeInt32LE(offset, 16); // LmChallengeResponseBufferOffset
 | ||||||
|     buf.writeInt16LE(nt_challenge_response.length, 20); // NtChallengeResponseLen
 |     buf.writeInt16LE(nt_challenge_response.length, 20); // NtChallengeResponseLen
 | ||||||
|     buf.writeInt16LE(nt_challenge_response.length, 22); // NtChallengeResponseMaxLen
 |     buf.writeInt16LE(nt_challenge_response.length, 22); // NtChallengeResponseMaxLen
 | ||||||
|     if (nt_challenge_response.length > 0) { buf.writeInt32LE(offset + lm_challenge_response.length, 24); } // NtChallengeResponseBufferOffset
 |     buf.writeInt32LE(offset + lm_challenge_response.length, 24); // NtChallengeResponseBufferOffset
 | ||||||
|     buf.writeInt16LE(domain.length, 28); // DomainNameLen
 |     buf.writeInt16LE(domain.length, 28); // DomainNameLen
 | ||||||
|     buf.writeInt16LE(domain.length, 30); // DomainNameMaxLen
 |     buf.writeInt16LE(domain.length, 30); // DomainNameMaxLen
 | ||||||
|     if (domain.length > 0) { buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length, 32); } // DomainNameBufferOffset
 |     buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length, 32); // DomainNameBufferOffset
 | ||||||
|     buf.writeInt16LE(user.length, 36); // UserNameLen
 |     buf.writeInt16LE(user.length, 36); // UserNameLen
 | ||||||
|     buf.writeInt16LE(user.length, 38); // UserNameMaxLen
 |     buf.writeInt16LE(user.length, 38); // UserNameMaxLen
 | ||||||
|     if (user.length > 0) { buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length, 40); } // UserNameBufferOffset
 |     buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length, 40); // UserNameBufferOffset
 | ||||||
|     buf.writeInt16LE(workstation.length, 44); // WorkstationLen
 |     buf.writeInt16LE(workstation.length, 44); // WorkstationLen
 | ||||||
|     buf.writeInt16LE(workstation.length, 46); // WorkstationMaxLen
 |     buf.writeInt16LE(workstation.length, 46); // WorkstationMaxLen
 | ||||||
|     if (workstation.length > 0) { buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length, 48); } // WorkstationBufferOffset
 |     buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length, 48); // WorkstationBufferOffset
 | ||||||
|     buf.writeInt16LE(encrypted_random_session_key.length, 52); // EncryptedRandomSessionLen
 |     buf.writeInt16LE(encrypted_random_session_key.length, 52); // EncryptedRandomSessionLen
 | ||||||
|     buf.writeInt16LE(encrypted_random_session_key.length, 54); // EncryptedRandomSessionMaxLen
 |     buf.writeInt16LE(encrypted_random_session_key.length, 54); // EncryptedRandomSessionMaxLen
 | ||||||
|     buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length + workstation.length, 56); // EncryptedRandomSessionBufferOffset
 |     buf.writeInt32LE(offset + lm_challenge_response.length + nt_challenge_response.length + domain.length + user.length + workstation.length, 56); // EncryptedRandomSessionBufferOffset
 | ||||||
| @ -248,7 +463,81 @@ function authenticate_message(lm_challenge_response, nt_challenge_response, doma | |||||||
|     return [buf, payload]; |     return [buf, payload]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function create_ts_authinfo(auth_info) { | ||||||
|  |     asn1obj = | ||||||
|  |     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ | ||||||
|  |             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, asn1.integerToDer(2)), | ||||||
|  |         ]), | ||||||
|  |         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [ | ||||||
|  |             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, auth_info.toString('binary')) | ||||||
|  |         ]) | ||||||
|  |     ]); | ||||||
|  |     return Buffer.from(asn1.toDer(asn1obj).data, 'binary'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function create_ts_credentials(domain, user, password) { | ||||||
|  |     var asn1obj = | ||||||
|  |     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ | ||||||
|  |             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, domain.toString('binary')) | ||||||
|  |         ]), | ||||||
|  |         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [ | ||||||
|  |             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, user.toString('binary')) | ||||||
|  |         ]), | ||||||
|  |         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 2, true, [ | ||||||
|  |             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, password.toString('binary')) | ||||||
|  |         ]) | ||||||
|  |     ]); | ||||||
|  |     const ts_password_cred_encoded = asn1.toDer(asn1obj).data; | ||||||
|  |     asn1obj = | ||||||
|  |     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ | ||||||
|  |             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, asn1.integerToDer(1)), | ||||||
|  |         ]), | ||||||
|  |         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [ | ||||||
|  |             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, ts_password_cred_encoded) | ||||||
|  |         ]) | ||||||
|  |     ]); | ||||||
|  |     return Buffer.from(asn1.toDer(asn1obj).data, 'binary'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function create_ts_authenticate(nego, pub_key_auth) { | ||||||
|  |     // Create create_ts_request
 | ||||||
|  |     const asn1obj = | ||||||
|  |         asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |             asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ | ||||||
|  |                 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, asn1.integerToDer(2)), | ||||||
|  |             ]), | ||||||
|  |             asn1.create(asn1.Class.CONTEXT_SPECIFIC, 1, true, [ | ||||||
|  |                 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |                     asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ | ||||||
|  |                         asn1.create(asn1.Class.CONTEXT_SPECIFIC, 0, true, [ | ||||||
|  |                             asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, nego.toString('binary')) | ||||||
|  |                         ]) | ||||||
|  |                     ]) | ||||||
|  |                 ]) | ||||||
|  |             ]), | ||||||
|  |             asn1.create(asn1.Class.CONTEXT_SPECIFIC, 3, true, [ | ||||||
|  |                 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false, pub_key_auth.toString('binary')) | ||||||
|  |             ]), | ||||||
|  |         ]); | ||||||
|  | 
 | ||||||
|  |     // Serialize an ASN.1 object to DER format
 | ||||||
|  |     return Buffer.from(asn1.toDer(asn1obj).data, 'binary'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function read_challenge_message(ntlm, derBuffer) { | function read_challenge_message(ntlm, derBuffer) { | ||||||
|  | 
 | ||||||
|  |     //console.log('ntlm.negotiate_message', ntlm.negotiate_message.toString('hex'));
 | ||||||
|  |     //ntlm.negotiate_message = Buffer.from('4e544c4d53535000010000003582086000000000000000000000000000000000', 'hex');
 | ||||||
|  | 
 | ||||||
|  |     // ********
 | ||||||
|  |     //ntlm.exported_session_key = Buffer.from('9a1ed052e932834a311daf90c2750219', 'hex'); // *************************
 | ||||||
|  |     //derBuffer = Buffer.from('4e544c4d53535000020000000e000e003800000035828a6259312ef59a4517dd000000000000000058005800460000000a00614a0000000f430045004e005400520041004c0002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c00070008007b7b3bee9e5ad80100000000', 'hex');
 | ||||||
|  | 
 | ||||||
|  |     //console.log("YST: read_challenge_message1: ", derBuffer.toString('hex'));
 | ||||||
|  | 
 | ||||||
|     const headerSignature = derBuffer.slice(0, 8); |     const headerSignature = derBuffer.slice(0, 8); | ||||||
|     if (headerSignature.toString('hex') != '4e544c4d53535000') { console.log('BAD SIGNATURE'); } |     if (headerSignature.toString('hex') != '4e544c4d53535000') { console.log('BAD SIGNATURE'); } | ||||||
|     const messageType = derBuffer.readInt32LE(8); |     const messageType = derBuffer.readInt32LE(8); | ||||||
| @ -264,22 +553,40 @@ function read_challenge_message(ntlm, derBuffer) { | |||||||
|     const targetInfoLenMax = derBuffer.readInt16LE(42); |     const targetInfoLenMax = derBuffer.readInt16LE(42); | ||||||
|     const targetInfoBufferOffset = derBuffer.readInt32LE(44); |     const targetInfoBufferOffset = derBuffer.readInt32LE(44); | ||||||
|     const targetName = derBuffer.slice(targetNameBufferOffset, targetNameBufferOffset + targetNameLen); |     const targetName = derBuffer.slice(targetNameBufferOffset, targetNameBufferOffset + targetNameLen); | ||||||
|  |     const targetInfoBuf = derBuffer.slice(targetInfoBufferOffset, targetInfoBufferOffset + targetInfoLen); | ||||||
|     const targetInfo = decodeTargetInfo(derBuffer.slice(targetInfoBufferOffset, targetInfoBufferOffset + targetInfoLen)); |     const targetInfo = decodeTargetInfo(derBuffer.slice(targetInfoBufferOffset, targetInfoBufferOffset + targetInfoLen)); | ||||||
|     const timestamp = targetInfo[7]; |     const timestamp = targetInfo[7]; | ||||||
|  |     //const timestamp = Buffer.from('7b7b3bee9e5ad801', 'hex'); // **************
 | ||||||
|     if (timestamp == null) { console.log('NO TIMESTAMP'); } |     if (timestamp == null) { console.log('NO TIMESTAMP'); } | ||||||
|     const clientChallenge = crypto.randomBytes(8); |     const clientChallenge = crypto.randomBytes(8); | ||||||
|  |     //const clientChallenge = Buffer.from('10aac9679ef64e66', 'hex'); // *****************************
 | ||||||
|     const response_key_nt = ntowfv2(ntlm.password, ntlm.user, ntlm.domain); // Password, Username, Domain
 |     const response_key_nt = ntowfv2(ntlm.password, ntlm.user, ntlm.domain); // Password, Username, Domain
 | ||||||
|     const response_key_lm = lmowfv2(ntlm.password, ntlm.user, ntlm.domain); // Password, Username, Domain
 |     const response_key_lm = lmowfv2(ntlm.password, ntlm.user, ntlm.domain); // Password, Username, Domain
 | ||||||
| 
 | 
 | ||||||
|     var resp = compute_response_v2(response_key_nt, response_key_lm, serverChallenge, clientChallenge, timestamp, targetName); |     //console.log("YST: target_name:", targetInfoBuf.toString('hex'));
 | ||||||
|  |     //console.log("YST: timestamp:", timestamp.toString('hex'));
 | ||||||
|  |     //console.log('YST: client_challenge:', clientChallenge.toString('hex'));
 | ||||||
|  |     //console.log("YST: response_key_nt:", response_key_nt.toString('hex'));
 | ||||||
|  |     //console.log("YST: response_key_lm:", response_key_lm.toString('hex'));
 | ||||||
|  | 
 | ||||||
|  |     var resp = compute_response_v2(response_key_nt, response_key_lm, serverChallenge, clientChallenge, timestamp, targetInfoBuf); | ||||||
|     const nt_challenge_response = resp[0]; |     const nt_challenge_response = resp[0]; | ||||||
|     const lm_challenge_response = resp[1]; |     const lm_challenge_response = resp[1]; | ||||||
|     const session_base_key = resp[2]; |     const session_base_key = resp[2]; | ||||||
| 
 | 
 | ||||||
|  |     //console.log('YST: nt_challenge_response:', nt_challenge_response.toString('hex'));
 | ||||||
|  |     //console.log('YST: lm_challenge_response:', lm_challenge_response.toString('hex'));
 | ||||||
|  |     //console.log("YST: session_base_key:", session_base_key.toString('hex'));
 | ||||||
|  | 
 | ||||||
|     const key_exchange_key = kx_key_v2(session_base_key, lm_challenge_response, serverChallenge); |     const key_exchange_key = kx_key_v2(session_base_key, lm_challenge_response, serverChallenge); | ||||||
|     const encrypted_random_session_key = rc4k(key_exchange_key, ntlm.exported_session_key); |     const encrypted_random_session_key = rc4k(key_exchange_key, ntlm.exported_session_key); | ||||||
| 
 | 
 | ||||||
|  |     //console.log("YST: key_exchange_key:", key_exchange_key.toString('hex'));
 | ||||||
|  |     //console.log("YST: self.exported_session_key:", ntlm.exported_session_key.toString('hex'));
 | ||||||
|  |     //console.log("YST: encrypted_random_session_key:", encrypted_random_session_key.toString('hex'));
 | ||||||
|  | 
 | ||||||
|     ntlm.is_unicode = ((negotiateFlags & 1) != 0) |     ntlm.is_unicode = ((negotiateFlags & 1) != 0) | ||||||
|  |     //console.log("YST: self.is_unicode: {}", ntlm.is_unicode);
 | ||||||
|     var xdomain = null; |     var xdomain = null; | ||||||
|     var xuser = null; |     var xuser = null; | ||||||
|     if (ntlm.is_unicode) { |     if (ntlm.is_unicode) { | ||||||
| @ -290,39 +597,28 @@ function read_challenge_message(ntlm, derBuffer) { | |||||||
|         xuser = Buffer.from(ntlm.user, 'utf8'); |         xuser = Buffer.from(ntlm.user, 'utf8'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     //console.log("YST: domain:", xdomain.toString('hex'));
 | ||||||
|  |     //console.log("YST: user:", xuser.toString('hex'));
 | ||||||
|  | 
 | ||||||
|     const auth_message_compute = authenticate_message(lm_challenge_response, nt_challenge_response, xdomain, xuser, zeroBuffer(0), encrypted_random_session_key, negotiateFlags); |     const auth_message_compute = authenticate_message(lm_challenge_response, nt_challenge_response, xdomain, xuser, zeroBuffer(0), encrypted_random_session_key, negotiateFlags); | ||||||
| 
 | 
 | ||||||
|     // Write a tmp message to compute MIC and then include it into final message
 |     // Write a tmp message to compute MIC and then include it into final message
 | ||||||
|     const tmp_final_auth_message = Buffer.concat([auth_message_compute[0], zeroBuffer(16), auth_message_compute[1]]); |     const tmp_final_auth_message = Buffer.concat([auth_message_compute[0], zeroBuffer(16), auth_message_compute[1]]); | ||||||
| 
 | 
 | ||||||
|  |     //console.log("YST: tmp_final_auth_message: {}", tmp_final_auth_message.toString('hex'));
 | ||||||
|  | 
 | ||||||
|     const signature = mic(ntlm.exported_session_key, ntlm.negotiate_message, derBuffer, tmp_final_auth_message); |     const signature = mic(ntlm.exported_session_key, ntlm.negotiate_message, derBuffer, tmp_final_auth_message); | ||||||
|     return Buffer.concat([auth_message_compute[0], signature, auth_message_compute[1]]); | 
 | ||||||
|  |     //console.log("YST: signature: {}", signature.toString('hex'));
 | ||||||
|  | 
 | ||||||
|  |     const r = Buffer.concat([auth_message_compute[0], signature, auth_message_compute[1]]); | ||||||
|  | 
 | ||||||
|  |     //console.log("YST: read_challenge_message2: {}", r.toString('hex'));
 | ||||||
|  | 
 | ||||||
|  |     return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* |  | ||||||
| // Create create_ts_request
 |  | ||||||
| 
 |  | ||||||
| const entireBuffer = Buffer.from('3081b2a003020106a181aa3081a73081a4a081a104819e4e544c4d53535000020000000e000e003800000035828a62f2290572b3cac375000000000000000058005800460000000a00614a0000000f430045004e005400520041004c0002000e00430045004e005400520041004c0001000e00430045004e005400520041004c0004000e00430065006e007400720061006c0003000e00430065006e007400720061006c0007000800afbc2c2a9256d80100000000', 'hex').toString('binary'); |  | ||||||
| 
 |  | ||||||
| const ntml = Create_Ntlm(); |  | ||||||
| ntml.domain = ""; |  | ||||||
| ntml.user = "default"; |  | ||||||
| ntml.password = ""; |  | ||||||
| ntml.negotiate_message = Buffer.from('4e544c4d53535000010000003582086000000000000000000000000000000000', 'hex'); |  | ||||||
| 
 |  | ||||||
| // We have a full ASN1 data block, decode it now
 |  | ||||||
| const der = asn1.fromDer(entireBuffer.toString('binary')); |  | ||||||
| const derNum = der.value[0].value[0].value.charCodeAt(0); |  | ||||||
| const derBuffer = Buffer.from(der.value[1].value[0].value[0].value[0].value[0].value, 'binary'); |  | ||||||
| const client_challenge = read_challenge_message(ntml, derBuffer); |  | ||||||
| 
 |  | ||||||
| console.log('client_challenge', client_challenge.toString('hex')); |  | ||||||
| 
 |  | ||||||
| const NTLMv2SecurityInterface = build_security_interface(ntml); |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function unitTest() { | function unitTest() { | ||||||
|     console.log('--- Starting RDP NLA Unit Tests'); |     console.log('--- Starting RDP NLA Unit Tests'); | ||||||
| 
 | 
 | ||||||
| @ -387,9 +683,19 @@ function unitTest() { | |||||||
|     r = rc4.update(Buffer.from("bar")); |     r = rc4.update(Buffer.from("bar")); | ||||||
|     console.log(compareArray(bufToArr(r), [201, 67, 159]) ? "RC4 1 passed." : "RC4 1 failed."); |     console.log(compareArray(bufToArr(r), [201, 67, 159]) ? "RC4 1 passed." : "RC4 1 failed."); | ||||||
|     r = rc4.update(Buffer.from("bar")); |     r = rc4.update(Buffer.from("bar")); | ||||||
|     console.log(compareArray(bufToArr(r), [75, 169, 19]) ? "RC4 2 passed." : "RC4  failed."); |     console.log(compareArray(bufToArr(r), [75, 169, 19]) ? "RC4 2 passed." : "RC4 2 failed."); | ||||||
|  | 
 | ||||||
|  |     // Test create_ts_authenticate
 | ||||||
|  |     r = create_ts_authenticate(Buffer.from("000102", 'hex'), Buffer.from("000102", 'hex')); | ||||||
|  |     console.log(compareArray(bufToArr(r), [48, 25, 160, 3, 2, 1, 2, 161, 11, 48, 9, 48, 7, 160, 5, 4, 3, 0, 1, 2, 163, 5, 4, 3, 0, 1, 2]) ? "create_ts_authenticate passed." : "create_ts_authenticate failed."); | ||||||
|  | 
 | ||||||
|  |     // Test test_create_ts_credentials
 | ||||||
|  |     r = create_ts_credentials(Buffer.from("domain"), Buffer.from("user"), Buffer.from("password")); | ||||||
|  |     console.log(compareArray(bufToArr(r), [48, 41, 160, 3, 2, 1, 1, 161, 34, 4, 32, 48, 30, 160, 8, 4, 6, 100, 111, 109, 97, 105, 110, 161, 6, 4, 4, 117, 115, 101, 114, 162, 10, 4, 8, 112, 97, 115, 115, 119, 111, 114, 100]) ? "test_create_ts_credentials passed." : "test_create_ts_credentials failed."); | ||||||
|  |      | ||||||
|  |     // Test create_ts_authinfo
 | ||||||
|  |     r = create_ts_authinfo(Buffer.from("foo")); | ||||||
|  |     console.log(compareArray(bufToArr(r), [48, 12, 160, 3, 2, 1, 2, 162, 5, 4, 3, 102, 111, 111]) ? "create_ts_authinfo passed." : "create_ts_authinfo failed."); | ||||||
| 
 | 
 | ||||||
|     console.log('--- RDP NLA Unit Tests Completed'); |     console.log('--- RDP NLA Unit Tests Completed'); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| unitTest(); |  | ||||||
							
								
								
									
										704
									
								
								rdp/protocol/pdu/caps.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										704
									
								
								rdp/protocol/pdu/caps.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,704 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../../core').type; | ||||||
|  | var log = require('../../core').log; | ||||||
|  | var error = require('../../core').error; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
 | ||||||
|  |  */ | ||||||
|  | var CapsType = { | ||||||
|  | 	CAPSTYPE_GENERAL : 0x0001, | ||||||
|  | 	CAPSTYPE_BITMAP : 0x0002, | ||||||
|  | 	CAPSTYPE_ORDER : 0x0003, | ||||||
|  | 	CAPSTYPE_BITMAPCACHE : 0x0004, | ||||||
|  | 	CAPSTYPE_CONTROL : 0x0005, | ||||||
|  | 	CAPSTYPE_ACTIVATION : 0x0007, | ||||||
|  | 	CAPSTYPE_POINTER : 0x0008, | ||||||
|  | 	CAPSTYPE_SHARE : 0x0009, | ||||||
|  | 	CAPSTYPE_COLORCACHE : 0x000A, | ||||||
|  | 	CAPSTYPE_SOUND : 0x000C, | ||||||
|  | 	CAPSTYPE_INPUT : 0x000D, | ||||||
|  | 	CAPSTYPE_FONT : 0x000E, | ||||||
|  | 	CAPSTYPE_BRUSH : 0x000F, | ||||||
|  | 	CAPSTYPE_GLYPHCACHE : 0x0010, | ||||||
|  | 	CAPSTYPE_OFFSCREENCACHE : 0x0011, | ||||||
|  | 	CAPSTYPE_BITMAPCACHE_HOSTSUPPORT : 0x0012, | ||||||
|  | 	CAPSTYPE_BITMAPCACHE_REV2 : 0x0013, | ||||||
|  | 	CAPSTYPE_VIRTUALCHANNEL : 0x0014, | ||||||
|  | 	CAPSTYPE_DRAWNINEGRIDCACHE : 0x0015, | ||||||
|  | 	CAPSTYPE_DRAWGDIPLUS : 0x0016, | ||||||
|  | 	CAPSTYPE_RAIL : 0x0017, | ||||||
|  | 	CAPSTYPE_WINDOW : 0x0018, | ||||||
|  | 	CAPSETTYPE_COMPDESK : 0x0019, | ||||||
|  | 	CAPSETTYPE_MULTIFRAGMENTUPDATE : 0x001A, | ||||||
|  | 	CAPSETTYPE_LARGE_POINTER : 0x001B, | ||||||
|  | 	CAPSETTYPE_SURFACE_COMMANDS : 0x001C, | ||||||
|  | 	CAPSETTYPE_BITMAP_CODECS : 0x001D, | ||||||
|  | 	CAPSSETTYPE_FRAME_ACKNOWLEDGE : 0x001E | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
 | ||||||
|  |  */ | ||||||
|  | var MajorType = { | ||||||
|  | 	OSMAJORTYPE_UNSPECIFIED : 0x0000, | ||||||
|  | 	OSMAJORTYPE_WINDOWS : 0x0001, | ||||||
|  | 	OSMAJORTYPE_OS2 : 0x0002, | ||||||
|  | 	OSMAJORTYPE_MACINTOSH : 0x0003, | ||||||
|  | 	OSMAJORTYPE_UNIX : 0x0004, | ||||||
|  | 	OSMAJORTYPE_IOS : 0x0005, | ||||||
|  | 	OSMAJORTYPE_OSX : 0x0006, | ||||||
|  | 	OSMAJORTYPE_ANDROID : 0x0007 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
 | ||||||
|  |  */ | ||||||
|  | var MinorType = { | ||||||
|  | 	OSMINORTYPE_UNSPECIFIED : 0x0000, | ||||||
|  | 	OSMINORTYPE_WINDOWS_31X : 0x0001, | ||||||
|  | 	OSMINORTYPE_WINDOWS_95 : 0x0002, | ||||||
|  | 	OSMINORTYPE_WINDOWS_NT : 0x0003, | ||||||
|  | 	OSMINORTYPE_OS2_V21 : 0x0004, | ||||||
|  | 	OSMINORTYPE_POWER_PC : 0x0005, | ||||||
|  | 	OSMINORTYPE_MACINTOSH : 0x0006, | ||||||
|  | 	OSMINORTYPE_NATIVE_XSERVER : 0x0007, | ||||||
|  | 	OSMINORTYPE_PSEUDO_XSERVER : 0x0008, | ||||||
|  | 	OSMINORTYPE_WINDOWS_RT : 0x0009 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
 | ||||||
|  |  */ | ||||||
|  | var GeneralExtraFlag = { | ||||||
|  |     FASTPATH_OUTPUT_SUPPORTED : 0x0001, | ||||||
|  |     NO_BITMAP_COMPRESSION_HDR : 0x0400, | ||||||
|  |     LONG_CREDENTIALS_SUPPORTED : 0x0004, | ||||||
|  |     AUTORECONNECT_SUPPORTED : 0x0008, | ||||||
|  |     ENC_SALTED_CHECKSUM : 0x0010 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | var Boolean = { | ||||||
|  |     FALSE : 0x00, | ||||||
|  |     TRUE : 0x01 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
 | ||||||
|  |  */ | ||||||
|  | var OrderFlag = { | ||||||
|  |     NEGOTIATEORDERSUPPORT : 0x0002, | ||||||
|  |     ZEROBOUNDSDELTASSUPPORT : 0x0008, | ||||||
|  |     COLORINDEXSUPPORT : 0x0020, | ||||||
|  |     SOLIDPATTERNBRUSHONLY : 0x0040, | ||||||
|  |     ORDERFLAGS_EXTRA_FLAGS : 0x0080 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
 | ||||||
|  |  */ | ||||||
|  | var Order = { | ||||||
|  |     TS_NEG_DSTBLT_INDEX : 0x00, | ||||||
|  |     TS_NEG_PATBLT_INDEX : 0x01, | ||||||
|  |     TS_NEG_SCRBLT_INDEX : 0x02, | ||||||
|  |     TS_NEG_MEMBLT_INDEX : 0x03, | ||||||
|  |     TS_NEG_MEM3BLT_INDEX : 0x04, | ||||||
|  |     TS_NEG_DRAWNINEGRID_INDEX : 0x07, | ||||||
|  |     TS_NEG_LINETO_INDEX : 0x08, | ||||||
|  |     TS_NEG_MULTI_DRAWNINEGRID_INDEX : 0x09, | ||||||
|  |     TS_NEG_SAVEBITMAP_INDEX : 0x0B, | ||||||
|  |     TS_NEG_MULTIDSTBLT_INDEX : 0x0F, | ||||||
|  |     TS_NEG_MULTIPATBLT_INDEX : 0x10, | ||||||
|  |     TS_NEG_MULTISCRBLT_INDEX : 0x11, | ||||||
|  |     TS_NEG_MULTIOPAQUERECT_INDEX : 0x12, | ||||||
|  |     TS_NEG_FAST_INDEX_INDEX : 0x13, | ||||||
|  |     TS_NEG_POLYGON_SC_INDEX : 0x14, | ||||||
|  |     TS_NEG_POLYGON_CB_INDEX : 0x15, | ||||||
|  |     TS_NEG_POLYLINE_INDEX : 0x16, | ||||||
|  |     TS_NEG_FAST_GLYPH_INDEX : 0x18, | ||||||
|  |     TS_NEG_ELLIPSE_SC_INDEX : 0x19, | ||||||
|  |     TS_NEG_ELLIPSE_CB_INDEX : 0x1A, | ||||||
|  |     TS_NEG_INDEX_INDEX : 0x1B | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | var OrderEx = { | ||||||
|  |     ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT : 0x0002, | ||||||
|  |     ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT : 0x0004 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
 | ||||||
|  |  */ | ||||||
|  | var InputFlags = { | ||||||
|  |     INPUT_FLAG_SCANCODES : 0x0001, | ||||||
|  |     INPUT_FLAG_MOUSEX : 0x0004, | ||||||
|  |     INPUT_FLAG_FASTPATH_INPUT : 0x0008, | ||||||
|  |     INPUT_FLAG_UNICODE : 0x0010, | ||||||
|  |     INPUT_FLAG_FASTPATH_INPUT2 : 0x0020, | ||||||
|  |     INPUT_FLAG_UNUSED1 : 0x0040, | ||||||
|  |     INPUT_FLAG_UNUSED2 : 0x0080, | ||||||
|  |     TS_INPUT_FLAG_MOUSE_HWHEEL : 0x0100 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
 | ||||||
|  |  */ | ||||||
|  | var BrushSupport = { | ||||||
|  |     BRUSH_DEFAULT : 0x00000000, | ||||||
|  |     BRUSH_COLOR_8x8 : 0x00000001, | ||||||
|  |     BRUSH_COLOR_FULL : 0x00000002 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
 | ||||||
|  |  */ | ||||||
|  | var GlyphSupport = { | ||||||
|  |     GLYPH_SUPPORT_NONE : 0x0000, | ||||||
|  |     GLYPH_SUPPORT_PARTIAL : 0x0001, | ||||||
|  |     GLYPH_SUPPORT_FULL : 0x0002, | ||||||
|  |     GLYPH_SUPPORT_ENCODE : 0x0003 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
 | ||||||
|  |  */ | ||||||
|  | var OffscreenSupportLevel = { | ||||||
|  |     FALSE : 0x00000000, | ||||||
|  |     TRUE : 0x00000001 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
 | ||||||
|  |  */ | ||||||
|  | var VirtualChannelCompressionFlag = { | ||||||
|  |     VCCAPS_NO_COMPR : 0x00000000, | ||||||
|  |     VCCAPS_COMPR_SC : 0x00000001, | ||||||
|  |     VCCAPS_COMPR_CS_8K : 0x00000002 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240552.aspx
 | ||||||
|  |  */ | ||||||
|  | var SoundFlag = { | ||||||
|  |     NONE : 0x0000, | ||||||
|  |     SOUND_BEEPS_FLAG : 0x0001 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240549.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function generalCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_GENERAL, | ||||||
|  | 		osMajorType : new type.UInt16Le(), | ||||||
|  |         osMinorType : new type.UInt16Le(), | ||||||
|  |         protocolVersion : new type.UInt16Le(0x0200, {constant : true}), | ||||||
|  |         pad2octetsA : new type.UInt16Le(), | ||||||
|  |         generalCompressionTypes : new type.UInt16Le(0, {constant : true}), | ||||||
|  |         extraFlags : new type.UInt16Le(), | ||||||
|  |         updateCapabilityFlag : new type.UInt16Le(0, {constant : true}), | ||||||
|  |         remoteUnshareFlag : new type.UInt16Le(0, {constant : true}), | ||||||
|  |         generalCompressionLevel : new type.UInt16Le(0, {constant : true}), | ||||||
|  |         refreshRectSupport : new type.UInt8(), | ||||||
|  |         suppressOutputSupport : new type.UInt8() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240554.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function bitmapCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_BITMAP, | ||||||
|  | 		preferredBitsPerPixel : new type.UInt16Le(), | ||||||
|  |         receive1BitPerPixel : new type.UInt16Le(0x0001), | ||||||
|  |         receive4BitsPerPixel : new type.UInt16Le(0x0001), | ||||||
|  |         receive8BitsPerPixel : new type.UInt16Le(0x0001), | ||||||
|  |         desktopWidth : new type.UInt16Le(), | ||||||
|  |         desktopHeight : new type.UInt16Le(), | ||||||
|  |         pad2octets : new type.UInt16Le(), | ||||||
|  |         desktopResizeFlag : new type.UInt16Le(), | ||||||
|  |         bitmapCompressionFlag : new type.UInt16Le(0x0001, {constant : true}), | ||||||
|  |         highColorFlags : new type.UInt8(0), | ||||||
|  |         drawingFlags : new type.UInt8(), | ||||||
|  |         multipleRectangleSupport : new type.UInt16Le(0x0001, {constant : true}), | ||||||
|  |         pad2octetsB : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240556.aspx
 | ||||||
|  |  * @param orders {type.BinaryString|null} list of available orders | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function orderCapability(orders, opt) { | ||||||
|  | 	if(orders && orders.size() !== 32) { | ||||||
|  | 		throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_CAPS_BAD_ORDERS_SIZE'); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_ORDER, | ||||||
|  | 		terminalDescriptor : new type.BinaryString(Buffer.from(Array(16 + 1).join('\x00'), 'binary'), {readLength : new type.CallableValue(16)}), | ||||||
|  |         pad4octetsA : new type.UInt32Le(0), | ||||||
|  |         desktopSaveXGranularity : new type.UInt16Le(1), | ||||||
|  |         desktopSaveYGranularity : new type.UInt16Le(20), | ||||||
|  |         pad2octetsA : new type.UInt16Le(0), | ||||||
|  |         maximumOrderLevel : new type.UInt16Le(1), | ||||||
|  |         numberFonts : new type.UInt16Le(), | ||||||
|  |         orderFlags : new type.UInt16Le(OrderFlag.NEGOTIATEORDERSUPPORT), | ||||||
|  |         orderSupport : orders || new type.Factory(function(s) { | ||||||
|  |         	self.orderSupport = new type.BinaryString(null, {readLength : new type.CallableValue(32)}).read(s); | ||||||
|  |         }), | ||||||
|  |         textFlags : new type.UInt16Le(), | ||||||
|  |         orderSupportExFlags : new type.UInt16Le(), | ||||||
|  |         pad4octetsB : new type.UInt32Le(), | ||||||
|  |         desktopSaveSize : new type.UInt32Le(480 * 480), | ||||||
|  |         pad2octetsC : new type.UInt16Le(), | ||||||
|  |         pad2octetsD : new type.UInt16Le(), | ||||||
|  |         textANSICodePage : new type.UInt16Le(0), | ||||||
|  |         pad2octetsE : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240559.aspx
 | ||||||
|  |  * @param opt type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function bitmapCacheCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_BITMAPCACHE, | ||||||
|  | 		pad1 : new type.UInt32Le(), | ||||||
|  |         pad2 : new type.UInt32Le(), | ||||||
|  |         pad3 : new type.UInt32Le(), | ||||||
|  |         pad4 : new type.UInt32Le(), | ||||||
|  |         pad5 : new type.UInt32Le(), | ||||||
|  |         pad6 : new type.UInt32Le(), | ||||||
|  |         cache0Entries : new type.UInt16Le(), | ||||||
|  |         cache0MaximumCellSize : new type.UInt16Le(), | ||||||
|  |         cache1Entries : new type.UInt16Le(), | ||||||
|  |         cache1MaximumCellSize : new type.UInt16Le(), | ||||||
|  |         cache2Entries : new type.UInt16Le(), | ||||||
|  |         cache2MaximumCellSize : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  *  | ||||||
|  |  * @param isServer {boolean} true if in server mode | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function pointerCapability(isServer, opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_POINTER, | ||||||
|  | 		colorPointerFlag : new type.UInt16Le(), | ||||||
|  |         colorPointerCacheSize : new type.UInt16Le(20), | ||||||
|  |         //old version of rdp doesn't support ...
 | ||||||
|  |         pointerCacheSize : new type.UInt16Le(null, {conditional : function() { | ||||||
|  |         	return isServer || false; | ||||||
|  |         }}) | ||||||
|  |     }; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240563.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function inputCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_INPUT, | ||||||
|  | 		inputFlags : new type.UInt16Le(), | ||||||
|  |         pad2octetsA : new type.UInt16Le(), | ||||||
|  |         // same value as gcc.ClientCoreSettings.kbdLayout
 | ||||||
|  |         keyboardLayout : new type.UInt32Le(), | ||||||
|  |         // same value as gcc.ClientCoreSettings.keyboardType
 | ||||||
|  |         keyboardType : new type.UInt32Le(), | ||||||
|  |         // same value as gcc.ClientCoreSettings.keyboardSubType
 | ||||||
|  |         keyboardSubType : new type.UInt32Le(), | ||||||
|  |         // same value as gcc.ClientCoreSettings.keyboardFnKeys
 | ||||||
|  |         keyboardFunctionKey : new type.UInt32Le(), | ||||||
|  |         // same value as gcc.ClientCoreSettingrrs.imeFileName
 | ||||||
|  |         imeFileName : new type.BinaryString(Buffer.from(Array(64 + 1).join('\x00'), 'binary'), {readLength : new type.CallableValue(64)}) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240564.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function brushCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_BRUSH, | ||||||
|  | 		brushSupportLevel : new type.UInt32Le(BrushSupport.BRUSH_DEFAULT) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240566.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function cacheEntry(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		cacheEntries : new type.UInt16Le(), | ||||||
|  |         cacheMaximumCellSize : new type.UInt16Le()	 | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240565.aspx
 | ||||||
|  |  * @param entries {type.Component} cache entries | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function glyphCapability(entries, opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_GLYPHCACHE, | ||||||
|  | 		glyphCache : entries || new type.Factory(function(s) { | ||||||
|  | 			self.glyphCache = new type.Component([]); | ||||||
|  | 			for(var i = 0; i < 10; i++) { | ||||||
|  | 				self.glyphCache.obj.push(cacheEntry().read(s)); | ||||||
|  | 			} | ||||||
|  | 		}), | ||||||
|  |         fragCache : new type.UInt32Le(), | ||||||
|  |         // all fonts are sent with bitmap format (very expensive)
 | ||||||
|  |         glyphSupportLevel : new type.UInt16Le(GlyphSupport.GLYPH_SUPPORT_NONE), | ||||||
|  |         pad2octets : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240550.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function offscreenBitmapCacheCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_OFFSCREENCACHE, | ||||||
|  | 		offscreenSupportLevel : new type.UInt32Le(OffscreenSupportLevel.FALSE), | ||||||
|  |         offscreenCacheSize : new type.UInt16Le(), | ||||||
|  |         offscreenCacheEntries : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240551.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function virtualChannelCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_VIRTUALCHANNEL, | ||||||
|  | 		flags : new type.UInt32Le(VirtualChannelCompressionFlag.VCCAPS_NO_COMPR), | ||||||
|  |         VCChunkSize : new type.UInt32Le(null, {optional : true})	 | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240552.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function soundCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_SOUND, | ||||||
|  | 		soundFlags : new type.UInt16Le(SoundFlag.NONE), | ||||||
|  | 	    pad2octetsA : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240568.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function controlCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_CONTROL, | ||||||
|  | 		controlFlags : new type.UInt16Le(), | ||||||
|  | 		remoteDetachFlag : new type.UInt16Le(), | ||||||
|  | 		controlInterest : new type.UInt16Le(0x0002), | ||||||
|  | 		detachInterest : new type.UInt16Le(0x0002) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240569.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function windowActivationCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_ACTIVATION, | ||||||
|  | 		helpKeyFlag : new type.UInt16Le(), | ||||||
|  |         helpKeyIndexFlag : new type.UInt16Le(), | ||||||
|  |         helpExtendedKeyFlag : new type.UInt16Le(), | ||||||
|  |         windowManagerKeyFlag : new type.UInt16Le()	 | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240571.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function fontCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_FONT, | ||||||
|  | 		fontSupportFlags : new type.UInt16Le(0x0001), | ||||||
|  | 		pad2octets : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241564.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function colorCacheCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_COLORCACHE, | ||||||
|  | 		colorTableCacheSize : new type.UInt16Le(0x0006), | ||||||
|  | 		pad2octets : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240570.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function shareCapability(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSTYPE_SHARE, | ||||||
|  | 		nodeId : new type.UInt16Le(), | ||||||
|  | 		pad2octets : new type.UInt16Le()	 | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240649.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function multiFragmentUpdate(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE, | ||||||
|  | 		MaxRequestSize : new type.UInt32Le(0) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Capability wrapper packet | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240486.aspx
 | ||||||
|  |  * @param cap {type.Component} | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function capability(cap, opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		capabilitySetType : new type.UInt16Le(function() { | ||||||
|  | 			return self.capability.obj.__TYPE__; | ||||||
|  | 		}), | ||||||
|  | 		lengthCapability : new type.UInt16Le(function() { | ||||||
|  | 			return new type.Component(self).size(); | ||||||
|  | 		}), | ||||||
|  | 		capability : cap || new type.Factory(function(s) { | ||||||
|  | 			switch(self.capabilitySetType.value) { | ||||||
|  | 			case CapsType.CAPSTYPE_GENERAL: | ||||||
|  | 				self.capability = generalCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_BITMAP: | ||||||
|  | 				self.capability = bitmapCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_ORDER: | ||||||
|  | 				self.capability = orderCapability(null, {readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_BITMAPCACHE: | ||||||
|  | 				self.capability = bitmapCacheCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_POINTER: | ||||||
|  | 				self.capability = pointerCapability(false, {readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_INPUT: | ||||||
|  | 				self.capability = inputCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_BRUSH: | ||||||
|  | 				self.capability = brushCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_GLYPHCACHE: | ||||||
|  | 				self.capability = glyphCapability(null, {readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_OFFSCREENCACHE: | ||||||
|  | 				self.capability = offscreenBitmapCacheCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_VIRTUALCHANNEL: | ||||||
|  | 				self.capability = virtualChannelCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_SOUND: | ||||||
|  | 				self.capability = soundCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_CONTROL: | ||||||
|  | 				self.capability = controlCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_ACTIVATION: | ||||||
|  | 				self.capability = windowActivationCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_FONT: | ||||||
|  | 				self.capability = fontCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_COLORCACHE: | ||||||
|  | 				self.capability = colorCacheCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSTYPE_SHARE: | ||||||
|  | 				self.capability = shareCapability({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			case CapsType.CAPSETTYPE_MULTIFRAGMENTUPDATE: | ||||||
|  | 				self.capability = multiFragmentUpdate({readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				log.debug('unknown capability ' + self.capabilitySetType.value); | ||||||
|  | 				self.capability = new type.BinaryString(null, {readLength : new type.CallableValue(function() { | ||||||
|  | 					return self.lengthCapability.value - 4; | ||||||
|  | 				})}).read(s); | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	CapsType : CapsType, | ||||||
|  | 	MajorType : MajorType, | ||||||
|  | 	MinorType : MinorType, | ||||||
|  | 	GeneralExtraFlag : GeneralExtraFlag, | ||||||
|  | 	Boolean : Boolean, | ||||||
|  | 	OrderFlag : OrderFlag, | ||||||
|  | 	Order : Order, | ||||||
|  | 	OrderEx : OrderEx, | ||||||
|  | 	InputFlags : InputFlags, | ||||||
|  | 	BrushSupport : BrushSupport, | ||||||
|  | 	GlyphSupport : GlyphSupport, | ||||||
|  | 	OffscreenSupportLevel : OffscreenSupportLevel, | ||||||
|  | 	VirtualChannelCompressionFlag : VirtualChannelCompressionFlag, | ||||||
|  | 	SoundFlag : SoundFlag, | ||||||
|  | 	generalCapability : generalCapability, | ||||||
|  | 	bitmapCapability : bitmapCapability, | ||||||
|  | 	orderCapability : orderCapability, | ||||||
|  | 	bitmapCacheCapability : bitmapCacheCapability, | ||||||
|  | 	pointerCapability : pointerCapability, | ||||||
|  | 	inputCapability : inputCapability, | ||||||
|  | 	brushCapability : brushCapability, | ||||||
|  | 	cacheEntry : cacheEntry, | ||||||
|  | 	glyphCapability : glyphCapability, | ||||||
|  | 	offscreenBitmapCacheCapability : offscreenBitmapCacheCapability, | ||||||
|  | 	virtualChannelCapability : virtualChannelCapability, | ||||||
|  | 	soundCapability : soundCapability, | ||||||
|  | 	controlCapability : controlCapability, | ||||||
|  | 	windowActivationCapability : windowActivationCapability, | ||||||
|  | 	fontCapability : fontCapability, | ||||||
|  | 	colorCacheCapability : colorCacheCapability, | ||||||
|  | 	shareCapability : shareCapability, | ||||||
|  | 	multiFragmentUpdate : multiFragmentUpdate, | ||||||
|  | 	capability : capability | ||||||
|  | }; | ||||||
							
								
								
									
										1151
									
								
								rdp/protocol/pdu/data.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1151
									
								
								rdp/protocol/pdu/data.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										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 | ||||||
|  | }; | ||||||
							
								
								
									
										30
									
								
								rdp/protocol/pdu/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								rdp/protocol/pdu/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | /* | ||||||
|  |  * 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 lic = require('./lic'); | ||||||
|  | var sec = require('./sec'); | ||||||
|  | var global = require('./global'); | ||||||
|  | var data = require('./data'); | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  | 	lic : lic, | ||||||
|  | 	sec : sec, | ||||||
|  | 	global : global, | ||||||
|  | 	data : data | ||||||
|  | }; | ||||||
							
								
								
									
										309
									
								
								rdp/protocol/pdu/lic.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								rdp/protocol/pdu/lic.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,309 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../../core').type; | ||||||
|  | 
 | ||||||
|  | var MessageType = { | ||||||
|  |     LICENSE_REQUEST : 0x01, | ||||||
|  |     PLATFORM_CHALLENGE : 0x02, | ||||||
|  |     NEW_LICENSE : 0x03, | ||||||
|  |     UPGRADE_LICENSE : 0x04, | ||||||
|  |     LICENSE_INFO : 0x12, | ||||||
|  |     NEW_LICENSE_REQUEST : 0x13, | ||||||
|  |     PLATFORM_CHALLENGE_RESPONSE : 0x15, | ||||||
|  |     ERROR_ALERT : 0xFF | ||||||
|  | }; | ||||||
|  |      | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
 | ||||||
|  |  */ | ||||||
|  | var ErrorCode = { | ||||||
|  |     ERR_INVALID_SERVER_CERTIFICATE : 0x00000001, | ||||||
|  |     ERR_NO_LICENSE : 0x00000002, | ||||||
|  |     ERR_INVALID_SCOPE : 0x00000004, | ||||||
|  |     ERR_NO_LICENSE_SERVER : 0x00000006, | ||||||
|  |     STATUS_VALID_CLIENT : 0x00000007, | ||||||
|  |     ERR_INVALID_CLIENT : 0x00000008, | ||||||
|  |     ERR_INVALID_PRODUCTID : 0x0000000B, | ||||||
|  |     ERR_INVALID_MESSAGE_LEN : 0x0000000C, | ||||||
|  |     ERR_INVALID_MAC : 0x00000003 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
 | ||||||
|  |  */ | ||||||
|  | var StateTransition = { | ||||||
|  |     ST_TOTAL_ABORT : 0x00000001, | ||||||
|  |     ST_NO_TRANSITION : 0x00000002, | ||||||
|  |     ST_RESET_PHASE_TO_START : 0x00000003, | ||||||
|  |     ST_RESEND_LAST_MESSAGE : 0x00000004 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240481.aspx
 | ||||||
|  |  */ | ||||||
|  | var BinaryBlobType = { | ||||||
|  |     BB_ANY_BLOB : 0x0000, | ||||||
|  |     BB_DATA_BLOB : 0x0001, | ||||||
|  |     BB_RANDOM_BLOB : 0x0002, | ||||||
|  |     BB_CERTIFICATE_BLOB : 0x0003, | ||||||
|  |     BB_ERROR_BLOB : 0x0004, | ||||||
|  |     BB_ENCRYPTED_DATA_BLOB : 0x0009, | ||||||
|  |     BB_KEY_EXCHG_ALG_BLOB : 0x000D, | ||||||
|  |     BB_SCOPE_BLOB : 0x000E, | ||||||
|  |     BB_CLIENT_USER_NAME_BLOB : 0x000F, | ||||||
|  |     BB_CLIENT_MACHINE_NAME_BLOB : 0x0010 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | var Preambule = { | ||||||
|  |     PREAMBLE_VERSION_2_0 : 0x2, | ||||||
|  |     PREAMBLE_VERSION_3_0 : 0x3, | ||||||
|  |     EXTENDED_ERROR_MSG_SUPPORTED : 0x80 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Binary blob to emcompass license information | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240481.aspx
 | ||||||
|  |  * @param blobType {BinaryBlobType.*} | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function licenseBinaryBlob(blobType) { | ||||||
|  | 	blobType = blobType || BinaryBlobType.BB_ANY_BLOB; | ||||||
|  | 	var self = { | ||||||
|  | 		wBlobType : new type.UInt16Le(blobType, { constant : (blobType === BinaryBlobType.BB_ANY_BLOB)?false:true }), | ||||||
|  |         wBlobLen : new type.UInt16Le(function() { | ||||||
|  |         	return self.blobData.size(); | ||||||
|  |         }), | ||||||
|  |         blobData : new type.BinaryString(null, { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.wBlobLen.value; | ||||||
|  |         })}) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Error message in license PDU automata | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240482.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function licensingErrorMessage(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.ERROR_ALERT, | ||||||
|  | 		dwErrorCode : new type.UInt32Le(), | ||||||
|  |         dwStateTransition : new type.UInt32Le(), | ||||||
|  |         blob : licenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * License product informations | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241915.aspx
 | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function productInformation() { | ||||||
|  | 	var self = { | ||||||
|  | 		dwVersion : new type.UInt32Le(), | ||||||
|  |         cbCompanyName : new type.UInt32Le(function() { | ||||||
|  |         	return self.pbCompanyName.size(); | ||||||
|  |         }), | ||||||
|  |         // may contain "Microsoft Corporation" from server microsoft
 | ||||||
|  |         pbCompanyName : new type.BinaryString(Buffer.from('Microsoft Corporation', 'ucs2'), { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.cbCompanyName.value; | ||||||
|  |         })}), | ||||||
|  |         cbProductId : new type.UInt32Le(function() { | ||||||
|  |         	return self.pbProductId.size(); | ||||||
|  |         }), | ||||||
|  |         // may contain "A02" from microsoft license server
 | ||||||
|  |         pbProductId : new type.BinaryString(Buffer.from('A02', 'ucs2'), { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.cbProductId.value; | ||||||
|  |         })}) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Use in license negotiation | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241917.aspx
 | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function scope() { | ||||||
|  | 	var self = { | ||||||
|  | 		scope : licenseBinaryBlob(BinaryBlobType.BB_SCOPE_BLOB) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241916.aspx
 | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function scopeList() { | ||||||
|  | 	var self = { | ||||||
|  | 		scopeCount : new type.UInt32Le(function() { | ||||||
|  | 			return self.scopeArray.length; | ||||||
|  | 		}), | ||||||
|  | 		scopeArray : new type.Factory(function(s) { | ||||||
|  | 			self.scopeArray = new type.Component([]); | ||||||
|  | 			for(var i = 0; i < self.scopeCount.value; i++) { | ||||||
|  | 				self.scopeArray.obj.push(scope().read(s)); | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241914.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function serverLicenseRequest(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.LICENSE_REQUEST, | ||||||
|  | 		serverRandom : new type.BinaryString(Buffer.from(Array(32 + 1).join('\x00')), { readLength : new type.CallableValue(32) } ), | ||||||
|  |         productInfo : productInformation(), | ||||||
|  |         keyExchangeList : licenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB), | ||||||
|  |         serverCertificate : licenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB), | ||||||
|  |         scopeList : scopeList() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241918.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function clientNewLicenseRequest(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.NEW_LICENSE_REQUEST, | ||||||
|  | 		preferredKeyExchangeAlg : new type.UInt32Le(0x00000001, { constant : true }), | ||||||
|  |         // pure microsoft client ;-)
 | ||||||
|  |         // http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10
 | ||||||
|  |         platformId : new type.UInt32Le(0x04000000 | 0x00010000), | ||||||
|  |         clientRandom : new type.BinaryString(Buffer.from(Array(32 + 1).join('\x00')), { readLength : new type.CallableValue(32) }), | ||||||
|  |         encryptedPreMasterSecret : licenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB), | ||||||
|  |         ClientUserName : licenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB), | ||||||
|  |         ClientMachineName : licenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241921.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function serverPlatformChallenge(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.PLATFORM_CHALLENGE, | ||||||
|  | 		connectFlags : new type.UInt32Le(), | ||||||
|  |         encryptedPlatformChallenge : licenseBinaryBlob(BinaryBlobType.BB_ANY_BLOB), | ||||||
|  |         MACData : new type.BinaryString(Buffer.from(Array(16 + 1).join('\x00')), { readLength : new type.CallableValue(16) }) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241922.aspx
 | ||||||
|  |  * @param opt {object} type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function clientPLatformChallengeResponse(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.PLATFORM_CHALLENGE_RESPONSE, | ||||||
|  | 		encryptedPlatformChallengeResponse : licenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB), | ||||||
|  |         encryptedHWID : licenseBinaryBlob(BinaryBlobType.BB_DATA_BLOB), | ||||||
|  |         MACData : new type.BinaryString(Buffer.from(Array(16 + 1).join('\x00'), 'binary'), { readLength : new type.CallableValue(16) }) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Global license packet | ||||||
|  |  * @param packet {type.* | null} send packet | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function licensePacket(message) { | ||||||
|  | 	var self = { | ||||||
|  | 		bMsgtype : new type.UInt8(function() { | ||||||
|  | 			return self.licensingMessage.obj.__TYPE__; | ||||||
|  | 		}), | ||||||
|  |         flag : new type.UInt8(Preambule.PREAMBLE_VERSION_3_0), | ||||||
|  |         wMsgSize : new type.UInt16Le(function() { | ||||||
|  |         	return new type.Component(self).size(); | ||||||
|  |         }), | ||||||
|  |         licensingMessage : message || new type.Factory(function(s) { | ||||||
|  |         	switch(self.bMsgtype.value) { | ||||||
|  |         	case MessageType.ERROR_ALERT: | ||||||
|  |         		self.licensingMessage = licensingErrorMessage({ readLength : new type.CallableValue(function() { | ||||||
|  |         			return self.wMsgSize.value - 4; | ||||||
|  |         		})}).read(s); | ||||||
|  |         		break; | ||||||
|  |         	case MessageType.LICENSE_REQUEST: | ||||||
|  |         		self.licensingMessage = serverLicenseRequest({ readLength : new type.CallableValue(function() { | ||||||
|  |         			return self.wMsgSize.value - 4; | ||||||
|  |         		})}).read(s); | ||||||
|  |         		break; | ||||||
|  |         	case MessageType.NEW_LICENSE_REQUEST: | ||||||
|  |         		self.licensingMessage = clientNewLicenseRequest({ readLength : new type.CallableValue(function() { | ||||||
|  |         			return self.wMsgSize.value - 4; | ||||||
|  |         		})}).read(s); | ||||||
|  |         		break; | ||||||
|  |         	case MessageType.PLATFORM_CHALLENGE: | ||||||
|  |         		self.licensingMessage = serverPlatformChallenge({ readLength : new type.CallableValue(function() { | ||||||
|  |         			return self.wMsgSize.value - 4; | ||||||
|  |         		})}).read(s); | ||||||
|  |         		break; | ||||||
|  |         	case MessageType.PLATFORM_CHALLENGE_RESPONSE: | ||||||
|  |         		self.licensingMessage = clientPLatformChallengeResponse({ readLength : new type.CallableValue(function() { | ||||||
|  |         			return self.wMsgSize.value - 4; | ||||||
|  |         		})}).read(s); | ||||||
|  |         		break; | ||||||
|  |         	default: | ||||||
|  |         		log.error('unknown license message type ' + self.bMsgtype.value); | ||||||
|  |         	} | ||||||
|  |         }) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 		MessageType : MessageType, | ||||||
|  | 		ErrorCode : ErrorCode, | ||||||
|  | 		StateTransition : StateTransition, | ||||||
|  | 		licensePacket : licensePacket, | ||||||
|  | 		clientNewLicenseRequest : clientNewLicenseRequest, | ||||||
|  | 		clientPLatformChallengeResponse : clientPLatformChallengeResponse | ||||||
|  | }; | ||||||
							
								
								
									
										519
									
								
								rdp/protocol/pdu/sec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										519
									
								
								rdp/protocol/pdu/sec.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,519 @@ | |||||||
|  | /* | ||||||
|  |  * 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 crypto = require('crypto'); | ||||||
|  | var events = require('events'); | ||||||
|  | var type = require('../../core').type; | ||||||
|  | var error = require('../../core').error; | ||||||
|  | var log = require('../../core').log; | ||||||
|  | var gcc = require('../t125/gcc'); | ||||||
|  | var lic = require('./lic'); | ||||||
|  | var cert = require('../cert'); | ||||||
|  | var rsa = require('../../security').rsa; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240579.aspx
 | ||||||
|  |  */ | ||||||
|  | var SecurityFlag = { | ||||||
|  |     SEC_EXCHANGE_PKT : 0x0001, | ||||||
|  |     SEC_TRANSPORT_REQ : 0x0002, | ||||||
|  |     RDP_SEC_TRANSPORT_RSP : 0x0004, | ||||||
|  |     SEC_ENCRYPT : 0x0008, | ||||||
|  |     SEC_RESET_SEQNO : 0x0010, | ||||||
|  |     SEC_IGNORE_SEQNO : 0x0020, | ||||||
|  |     SEC_INFO_PKT : 0x0040, | ||||||
|  |     SEC_LICENSE_PKT : 0x0080, | ||||||
|  |     SEC_LICENSE_ENCRYPT_CS : 0x0200, | ||||||
|  |     SEC_LICENSE_ENCRYPT_SC : 0x0200, | ||||||
|  |     SEC_REDIRECTION_PKT : 0x0400, | ||||||
|  |     SEC_SECURE_CHECKSUM : 0x0800, | ||||||
|  |     SEC_AUTODETECT_REQ : 0x1000, | ||||||
|  |     SEC_AUTODETECT_RSP : 0x2000, | ||||||
|  |     SEC_HEARTBEAT : 0x4000, | ||||||
|  |     SEC_FLAGSHI_VALID : 0x8000 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://msdn.microsoft.com/en-us/library/cc240475.aspx
 | ||||||
|  |  */ | ||||||
|  | var InfoFlag = { | ||||||
|  |     INFO_MOUSE : 0x00000001, | ||||||
|  |     INFO_DISABLECTRLALTDEL : 0x00000002, | ||||||
|  |     INFO_AUTOLOGON : 0x00000008, | ||||||
|  |     INFO_UNICODE : 0x00000010, | ||||||
|  |     INFO_MAXIMIZESHELL : 0x00000020, | ||||||
|  |     INFO_LOGONNOTIFY : 0x00000040, | ||||||
|  |     INFO_COMPRESSION : 0x00000080, | ||||||
|  |     INFO_ENABLEWINDOWSKEY : 0x00000100, | ||||||
|  |     INFO_REMOTECONSOLEAUDIO : 0x00002000, | ||||||
|  |     INFO_FORCE_ENCRYPTED_CS_PDU : 0x00004000, | ||||||
|  |     INFO_RAIL : 0x00008000, | ||||||
|  |     INFO_LOGONERRORS : 0x00010000, | ||||||
|  |     INFO_MOUSE_HAS_WHEEL : 0x00020000, | ||||||
|  |     INFO_PASSWORD_IS_SC_PIN : 0x00040000, | ||||||
|  |     INFO_NOAUDIOPLAYBACK : 0x00080000, | ||||||
|  |     INFO_USING_SAVED_CREDS : 0x00100000, | ||||||
|  |     INFO_AUDIOCAPTURE : 0x00200000, | ||||||
|  |     INFO_VIDEO_DISABLE : 0x00400000, | ||||||
|  |     INFO_CompressionTypeMask : 0x00001E00 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://msdn.microsoft.com/en-us/library/cc240476.aspx
 | ||||||
|  |  */ | ||||||
|  | var AfInet = { | ||||||
|  |     AfInet : 0x00002, | ||||||
|  |     AF_INET6 : 0x0017 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://msdn.microsoft.com/en-us/library/cc240476.aspx
 | ||||||
|  |  */ | ||||||
|  | var PerfFlag = { | ||||||
|  |     PERF_DISABLE_WALLPAPER : 0x00000001, | ||||||
|  |     PERF_DISABLE_FULLWINDOWDRAG : 0x00000002, | ||||||
|  |     PERF_DISABLE_MENUANIMATIONS : 0x00000004, | ||||||
|  |     PERF_DISABLE_THEMING : 0x00000008, | ||||||
|  |     PERF_DISABLE_CURSOR_SHADOW : 0x00000020, | ||||||
|  |     PERF_DISABLE_CURSORSETTINGS : 0x00000040, | ||||||
|  |     PERF_ENABLE_FONT_SMOOTHING : 0x00000080, | ||||||
|  |     PERF_ENABLE_DESKTOP_COMPOSITION : 0x00000100 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241992.aspx
 | ||||||
|  |  * @param input {Buffer} Binary data | ||||||
|  |  * @param salt {Buffer} salt for context call | ||||||
|  |  * @param salt1 {Buffer} another salt (ex : client random) | ||||||
|  |  * @param salt2 {Buffer} another salt (ex : server random) | ||||||
|  |  * @return {Buffer} | ||||||
|  |  */ | ||||||
|  | function saltedHash(input, salt, salt1, salt2) { | ||||||
|  | 	var sha1Digest = crypto.createHash('sha1'); | ||||||
|  | 	sha1Digest.update(input); | ||||||
|  | 	sha1Digest.update(salt.slice(0, 48)); | ||||||
|  | 	sha1Digest.update(salt1); | ||||||
|  | 	sha1Digest.update(salt2); | ||||||
|  | 	 | ||||||
|  | 	var sha1Sig = sha1Digest.digest(); | ||||||
|  | 	 | ||||||
|  | 	var md5Digest = crypto.createHash('md5'); | ||||||
|  | 	md5Digest.update(salt.slice(0, 48)); | ||||||
|  | 	md5Digest.update(sha1Sig); | ||||||
|  | 	return md5Digest.digest(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param key {Buffer} secret | ||||||
|  |  * @param random1 {Buffer} client random | ||||||
|  |  * @param random2 {Buffer} server random | ||||||
|  |  * @returns {Buffer} | ||||||
|  |  */ | ||||||
|  | function finalHash (key, random1, random2) { | ||||||
|  | 	var md5Digest = crypto.createHash('md5'); | ||||||
|  | 	md5Digest.update(key); | ||||||
|  | 	md5Digest.update(random1); | ||||||
|  | 	md5Digest.update(random2); | ||||||
|  | 	return md5Digest.digest(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241992.aspx
 | ||||||
|  |  * @param secret {Buffer} secret | ||||||
|  |  * @param random1 {Buffer} client random | ||||||
|  |  * @param random2 {Buffer} server random | ||||||
|  |  * @returns {Buffer} | ||||||
|  |  */ | ||||||
|  | function masterSecret (secret, random1, random2) { | ||||||
|  | 	var sh1 = saltedHash(Buffer.from('A'), secret, random1, random2); | ||||||
|  | 	var sh2 = saltedHash(Buffer.from('BB'), secret, random1, random2); | ||||||
|  | 	var sh3 = saltedHash(Buffer.from('CCC'), secret, random1, random2); | ||||||
|  | 	 | ||||||
|  | 	var ms = Buffer.alloc(sh1.length + sh2.length + sh3.length); | ||||||
|  | 	sh1.copy(ms); | ||||||
|  | 	sh2.copy(ms, sh1.length); | ||||||
|  | 	sh3.copy(ms, sh1.length + sh2.length); | ||||||
|  | 	return ms; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc241995.aspx
 | ||||||
|  |  * @param macSaltKey {Buffer} key | ||||||
|  |  * @param data {Buffer} data | ||||||
|  |  * @returns {Buffer} | ||||||
|  |  */ | ||||||
|  | function macData(macSaltKey, data) { | ||||||
|  | 	var salt1 = Buffer.alloc(40); | ||||||
|  | 	salt1.fill(0x36); | ||||||
|  | 	 | ||||||
|  | 	var salt2 = Buffer.alloc(48); | ||||||
|  | 	salt2.fill(0x5c); | ||||||
|  | 
 | ||||||
|  | 	var dataLength = new type.UInt32Le(data.length).toStream().buffer; | ||||||
|  | 	 | ||||||
|  | 	var sha1 = crypto.createHash('sha1'); | ||||||
|  | 	sha1.update(macSaltKey); | ||||||
|  | 	sha1.update(salt1); | ||||||
|  | 	sha1.update(dataLength); | ||||||
|  | 	sha1.update(data); | ||||||
|  | 	var sha1Digest = sha1.digest(); | ||||||
|  | 	 | ||||||
|  | 	var md5 = crypto.createHash('md5'); | ||||||
|  | 	md5.update(macSaltKey); | ||||||
|  | 	md5.update(salt2); | ||||||
|  | 	md5.update(sha1Digest); | ||||||
|  | 	 | ||||||
|  | 	return md5.digest(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * RDP client informations | ||||||
|  |  * @param extendedInfoConditional {boolean} true if RDP5+ | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function rdpInfos(extendedInfoConditional) { | ||||||
|  | 	var self = { | ||||||
|  | 		codePage : new type.UInt32Le(), | ||||||
|  |         flag : new type.UInt32Le(InfoFlag.INFO_MOUSE | InfoFlag.INFO_UNICODE | InfoFlag.INFO_LOGONNOTIFY | InfoFlag.INFO_LOGONERRORS | InfoFlag.INFO_DISABLECTRLALTDEL | InfoFlag.INFO_ENABLEWINDOWSKEY), | ||||||
|  |         cbDomain : new type.UInt16Le(function() { | ||||||
|  |         	return self.domain.size() - 2; | ||||||
|  |         }), | ||||||
|  |         cbUserName : new type.UInt16Le(function() { | ||||||
|  |         	return self.userName.size() - 2; | ||||||
|  |         }), | ||||||
|  |         cbPassword : new type.UInt16Le(function() { | ||||||
|  |         	return self.password.size() - 2; | ||||||
|  |         }), | ||||||
|  |         cbAlternateShell : new type.UInt16Le(function() { | ||||||
|  |         	return self.alternateShell.size() - 2; | ||||||
|  |         }), | ||||||
|  |         cbWorkingDir : new type.UInt16Le(function() { | ||||||
|  |         	return self.workingDir.size() - 2; | ||||||
|  |         }), | ||||||
|  |         domain : new type.BinaryString(Buffer.from('\x00', 'ucs2'),{ readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.cbDomain.value + 2; | ||||||
|  |         })}), | ||||||
|  |         userName : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.cbUserName.value + 2; | ||||||
|  |         })}), | ||||||
|  |         password : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function () { | ||||||
|  |         	return self.cbPassword.value + 2; | ||||||
|  |         })}), | ||||||
|  |         alternateShell : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.cbAlternateShell.value + 2; | ||||||
|  |         })}), | ||||||
|  |         workingDir : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function() { | ||||||
|  |         	return self.cbWorkingDir.value + 2; | ||||||
|  |         })}), | ||||||
|  |         extendedInfo : rdpExtendedInfos({ conditional : extendedInfoConditional }) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * RDP client extended informations present in RDP5+ | ||||||
|  |  * @param opt | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function rdpExtendedInfos(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		clientAddressFamily : new type.UInt16Le(AfInet.AfInet), | ||||||
|  | 	    cbClientAddress : new type.UInt16Le(function() { | ||||||
|  |         	return self.clientAddress.size(); | ||||||
|  |         }), | ||||||
|  | 	    clientAddress : new type.BinaryString(Buffer.from('\x00', 'ucs2'),{ readLength : new type.CallableValue(function() { | ||||||
|  | 	    	return self.cbClientAddress; | ||||||
|  | 	    }) }), | ||||||
|  | 	    cbClientDir : new type.UInt16Le(function() { | ||||||
|  |         	return self.clientDir.size(); | ||||||
|  |         }), | ||||||
|  | 	    clientDir : new type.BinaryString(Buffer.from('\x00', 'ucs2'), { readLength : new type.CallableValue(function() { | ||||||
|  | 	    	return self.cbClientDir; | ||||||
|  | 	    }) }), | ||||||
|  | 	    clientTimeZone : new type.BinaryString(Buffer.from(Array(172 + 1).join("\x00"))), | ||||||
|  | 	    clientSessionId : new type.UInt32Le(), | ||||||
|  | 	    performanceFlags : new type.UInt32Le() | ||||||
|  | 	}; | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Header of security header | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function securityHeader() { | ||||||
|  | 	var self = { | ||||||
|  | 		securityFlag : new type.UInt16Le(), | ||||||
|  | 		securityFlagHi : new type.UInt16Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Security layer | ||||||
|  |  * @param transport {events.EventEmitter} | ||||||
|  |  */ | ||||||
|  | function Sec(transport, fastPathTransport) { | ||||||
|  | 	this.transport = transport; | ||||||
|  | 	this.fastPathTransport = fastPathTransport; | ||||||
|  | 	// init at connect event from transport layer
 | ||||||
|  | 	this.gccClient = null; | ||||||
|  | 	this.gccServer = null; | ||||||
|  | 	var self = this; | ||||||
|  | 	this.infos = rdpInfos(function() { | ||||||
|  | 		return self.gccClient.core.rdpVersion.value === gcc.VERSION.RDP_VERSION_5_PLUS; | ||||||
|  | 	}); | ||||||
|  | 	this.machineName = ''; | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  | 	// basic encryption
 | ||||||
|  | 	this.enableEncryption = false; | ||||||
|  | 	 | ||||||
|  | 	if (this.fastPathTransport) { | ||||||
|  | 		this.fastPathTransport.on('fastPathData', function (secFlag, s) { | ||||||
|  | 			self.recvFastPath(secFlag, s); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | //inherit from Layer
 | ||||||
|  | inherits(Sec, events.EventEmitter); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send message with security header | ||||||
|  |  * @param flag {integer} security flag | ||||||
|  |  * @param data {type.*} message | ||||||
|  |  */ | ||||||
|  | Sec.prototype.sendFlagged = function(flag, data) { | ||||||
|  |     this.transport.send('global', new type.Component([ | ||||||
|  | 	    new type.UInt16Le(flag),  | ||||||
|  | 	    new type.UInt16Le(),  | ||||||
|  | 	    data | ||||||
|  | 	])); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Main send function | ||||||
|  |  * @param message {type.*} message to send | ||||||
|  |  */ | ||||||
|  | Sec.prototype.send = function(message) { | ||||||
|  | 	if (this.enableEncryption) { | ||||||
|  | 		throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_SEC_ENCRYPT_NOT_IMPLEMENTED'); | ||||||
|  | 	} | ||||||
|  | 	this.transport.send('global', message); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Main receive function | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Sec.prototype.recv = function(s) { | ||||||
|  | 	if (this.enableEncryption) { | ||||||
|  | 		throw new error.FatalError('NODE_RDP_PROTOCOL_PDU_SEC_ENCRYPT_NOT_IMPLEMENTED'); | ||||||
|  | 	} | ||||||
|  | 	// not support yet basic RDP security layer
 | ||||||
|  | 	this.emit('data', s); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive fast path data | ||||||
|  |  * @param secFlag {integer} security flag | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Sec.prototype.recvFastPath = function (secFlag, s) { | ||||||
|  | 	// transparent because basic RDP security layer not implemented
 | ||||||
|  | 	this.emit('fastPathData', secFlag, s); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Client security layer | ||||||
|  |  * @param transport {events.EventEmitter} | ||||||
|  |  */ | ||||||
|  | function Client(transport, fastPathTransport) { | ||||||
|  | 	Sec.call(this, transport, fastPathTransport); | ||||||
|  | 	// for basic RDP layer (in futur)
 | ||||||
|  | 	this.enableSecureCheckSum = false; | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.on('connect', function(gccClient, gccServer, userId, channels) { | ||||||
|  | 		self.connect(gccClient, gccServer, userId, channels); | ||||||
|  | 	}).on('close', function() { | ||||||
|  | 		self.emit('close'); | ||||||
|  | 	}).on('error', function (err) { | ||||||
|  | 		self.emit('error', err); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | //inherit from Layer
 | ||||||
|  | inherits(Client, Sec); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Connect event | ||||||
|  |  */ | ||||||
|  | Client.prototype.connect = function(gccClient, gccServer, userId, channels) { | ||||||
|  | 	//init gcc information
 | ||||||
|  | 	this.gccClient = gccClient; | ||||||
|  | 	this.gccServer = gccServer; | ||||||
|  | 	this.userId = userId; | ||||||
|  | 	this.channelId = channels.find(function(e) { | ||||||
|  | 		if(e.name === 'global') return true; | ||||||
|  | 	}).id; | ||||||
|  | 	this.sendInfoPkt(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * close stack | ||||||
|  |  */ | ||||||
|  | Client.prototype.close = function() { | ||||||
|  | 	this.transport.close(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send main information packet | ||||||
|  |  * VIP (very important packet) because contain credentials | ||||||
|  |  */ | ||||||
|  | Client.prototype.sendInfoPkt = function() { | ||||||
|  | 	this.sendFlagged(SecurityFlag.SEC_INFO_PKT, this.infos); | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('global', function(s) { | ||||||
|  | 		self.recvLicense(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | function reverse(buffer) { | ||||||
|  | 	var result = Buffer.alloc(buffer.length); | ||||||
|  | 	for(var i = 0; i < buffer.length; i++) { | ||||||
|  | 		result.writeUInt8(buffer.readUInt8(buffer.length - 1 - i), i); | ||||||
|  | 	} | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send a valid license request | ||||||
|  |  * @param licenseRequest {object(lic.serverLicenseRequest)} license requets infos | ||||||
|  |  */ | ||||||
|  | Client.prototype.sendClientNewLicenseRequest = function(licenseRequest) { | ||||||
|  | 	log.debug('new license request'); | ||||||
|  | 	var serverRandom = licenseRequest.serverRandom.value; | ||||||
|  | 	 | ||||||
|  | 	// read server certificate
 | ||||||
|  | 	var s = new type.Stream(licenseRequest.serverCertificate.obj.blobData.value); | ||||||
|  | 	var certificate = cert.certificate().read(s).obj; | ||||||
|  | 	var publicKey = certificate.certData.obj.getPublicKey(); | ||||||
|  | 	 | ||||||
|  | 	var clientRandom = crypto.randomBytes(32); | ||||||
|  | 	var preMasterSecret = crypto.randomBytes(48); | ||||||
|  | 	var mSecret = masterSecret(preMasterSecret, clientRandom, serverRandom); | ||||||
|  | 	var sessionKeyBlob = masterSecret(mSecret, serverRandom, clientRandom); | ||||||
|  | 	 | ||||||
|  | 	this.licenseMacSalt = sessionKeyBlob.slice(0, 16) | ||||||
|  | 	this.licenseKey = finalHash(sessionKeyBlob.slice(16, 32), clientRandom, serverRandom); | ||||||
|  | 	 | ||||||
|  | 	var request = lic.clientNewLicenseRequest(); | ||||||
|  | 	request.obj.clientRandom.value = clientRandom; | ||||||
|  | 	 | ||||||
|  | 	var preMasterSecretEncrypted = reverse(rsa.encrypt(reverse(preMasterSecret), publicKey)); | ||||||
|  | 	var preMasterSecretEncryptedPadded = Buffer.alloc(preMasterSecretEncrypted.length + 8); | ||||||
|  | 	preMasterSecretEncryptedPadded.fill(0); | ||||||
|  | 	preMasterSecretEncrypted.copy(preMasterSecretEncryptedPadded); | ||||||
|  | 	request.obj.encryptedPreMasterSecret.obj.blobData.value = preMasterSecretEncryptedPadded; | ||||||
|  | 	 | ||||||
|  | 	request.obj.ClientMachineName.obj.blobData.value = this.infos.obj.userName.value; | ||||||
|  | 	request.obj.ClientUserName.obj.blobData.value = Buffer.from(this.machineName + '\x00'); | ||||||
|  | 	 | ||||||
|  | 	this.sendFlagged(SecurityFlag.SEC_LICENSE_PKT, lic.licensePacket(request)); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send a valid license request | ||||||
|  |  * @param platformChallenge {object(lic.serverPlatformChallenge)} platform challenge | ||||||
|  |  */ | ||||||
|  | Client.prototype.sendClientChallengeResponse = function(platformChallenge) { | ||||||
|  | 	log.debug('challenge license'); | ||||||
|  | 	var serverEncryptedChallenge = platformChallenge.encryptedPlatformChallenge.obj.blobData.value; | ||||||
|  | 	var serverChallenge = crypto.createDecipheriv('rc4', this.licenseKey, '').update(serverEncryptedChallenge); | ||||||
|  | 	if (serverChallenge.toString('ucs2') !== 'TEST\x00') { | ||||||
|  | 		throw new error.ProtocolError('NODE_RDP_PROTOCOL_PDU_SEC_INVALID_LICENSE_CHALLENGE'); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	var hwid = new type.Component([new type.UInt32Le(2), new type.BinaryString(crypto.randomBytes(16))]).toStream().buffer; | ||||||
|  | 	 | ||||||
|  | 	var response = lic.clientPLatformChallengeResponse(); | ||||||
|  | 	response.obj.encryptedPlatformChallengeResponse.obj.blobData.value = serverEncryptedChallenge; | ||||||
|  | 	response.obj.encryptedHWID.obj.blobData.value = crypto.createCipheriv('rc4', this.licenseKey, '').update(hwid); | ||||||
|  | 	 | ||||||
|  | 	var sig = Buffer.alloc(serverChallenge.length + hwid.length); | ||||||
|  | 	serverChallenge.copy(sig); | ||||||
|  | 	hwid.copy(sig, serverChallenge.length); | ||||||
|  | 	response.obj.MACData.value = macData(this.licenseMacSalt, sig); | ||||||
|  | 	 | ||||||
|  | 	this.sendFlagged(SecurityFlag.SEC_LICENSE_PKT, lic.licensePacket(response)); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive license informations | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Sec.prototype.recvLicense = function(s) { | ||||||
|  |     var header = securityHeader().read(s).obj; | ||||||
|  |     if (!(header.securityFlag.value & SecurityFlag.SEC_LICENSE_PKT)) { | ||||||
|  |     	throw new error.ProtocolError('NODE_RDP_PROTOCOL_PDU_SEC_BAD_LICENSE_HEADER'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     var message = lic.licensePacket().read(s).obj; | ||||||
|  |     // i'm accepted
 | ||||||
|  |     if (message.bMsgtype.value === lic.MessageType.NEW_LICENSE ||  | ||||||
|  |     		(message.bMsgtype.value === lic.MessageType.ERROR_ALERT | ||||||
|  |     		&& message.licensingMessage.obj.dwErrorCode.value === lic.ErrorCode.STATUS_VALID_CLIENT | ||||||
|  |     		&& message.licensingMessage.obj.dwStateTransition.value === lic.StateTransition.ST_NO_TRANSITION)) { | ||||||
|  |     	this.emit('connect', this.gccClient.core, this.userId, this.channelId); | ||||||
|  |     	var self = this; | ||||||
|  |     	this.transport.on('global', function(s) { | ||||||
|  |     		self.recv(s); | ||||||
|  |     	}); | ||||||
|  |     	return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // server ask license request
 | ||||||
|  |     if (message.bMsgtype.value === lic.MessageType.LICENSE_REQUEST) { | ||||||
|  |     	this.sendClientNewLicenseRequest(message.licensingMessage.obj); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // server send challenge
 | ||||||
|  |     if (message.bMsgtype.value === lic.MessageType.PLATFORM_CHALLENGE) { | ||||||
|  |     	this.sendClientChallengeResponse(message.licensingMessage.obj); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     var self = this; | ||||||
|  |     this.emit('connect', this.gccClient.core); | ||||||
|  |     this.transport.once('global', function (s) { | ||||||
|  | 		self.recvLicense(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 		PerfFlag : PerfFlag, | ||||||
|  | 		InfoFlag : InfoFlag, | ||||||
|  | 		Client : Client | ||||||
|  | }; | ||||||
							
								
								
									
										361
									
								
								rdp/protocol/rdp.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										361
									
								
								rdp/protocol/rdp.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,361 @@ | |||||||
|  | /* | ||||||
|  |  * 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 net = require('net'); | ||||||
|  | var inherits = require('util').inherits; | ||||||
|  | var events = require('events'); | ||||||
|  | var layer = require('../core').layer; | ||||||
|  | var error = require('../core').error; | ||||||
|  | var rle = require('../core').rle; | ||||||
|  | var log = require('../core').log; | ||||||
|  | var TPKT = require('./tpkt'); | ||||||
|  | var x224 = require('./x224'); | ||||||
|  | var t125 = require('./t125'); | ||||||
|  | var pdu = require('./pdu'); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * decompress bitmap from RLE algorithm | ||||||
|  |  * @param	bitmap	{object} bitmap object of bitmap event of node-rdpjs | ||||||
|  |  */ | ||||||
|  | function decompress (bitmap) { | ||||||
|  | 	var fName = null; | ||||||
|  | 	switch (bitmap.bitsPerPixel.value) { | ||||||
|  | 	case 15: | ||||||
|  | 		fName = 'bitmap_decompress_15'; | ||||||
|  | 		break; | ||||||
|  | 	case 16: | ||||||
|  | 		fName = 'bitmap_decompress_16'; | ||||||
|  | 		break; | ||||||
|  | 	case 24: | ||||||
|  | 		fName = 'bitmap_decompress_24'; | ||||||
|  | 		break; | ||||||
|  | 	case 32: | ||||||
|  | 		fName = 'bitmap_decompress_32'; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		throw 'invalid bitmap data format'; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	var input = new Uint8Array(bitmap.bitmapDataStream.value); | ||||||
|  | 	var inputPtr = rle._malloc(input.length); | ||||||
|  | 	var inputHeap = new Uint8Array(rle.HEAPU8.buffer, inputPtr, input.length); | ||||||
|  | 	inputHeap.set(input); | ||||||
|  | 	 | ||||||
|  | 	var ouputSize = bitmap.width.value * bitmap.height.value * 4; | ||||||
|  | 	var outputPtr = rle._malloc(ouputSize); | ||||||
|  | 
 | ||||||
|  | 	var outputHeap = new Uint8Array(rle.HEAPU8.buffer, outputPtr, ouputSize); | ||||||
|  | 
 | ||||||
|  | 	var res = rle.ccall(fName, | ||||||
|  | 		'number', | ||||||
|  | 		['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number'], | ||||||
|  | 		[outputHeap.byteOffset, bitmap.width.value, bitmap.height.value, bitmap.width.value, bitmap.height.value, inputHeap.byteOffset, input.length] | ||||||
|  | 	); | ||||||
|  | 	 | ||||||
|  | 	var output = new Uint8ClampedArray(outputHeap.buffer, outputHeap.byteOffset, ouputSize); | ||||||
|  | 	 | ||||||
|  | 	rle._free(inputPtr); | ||||||
|  | 	rle._free(outputPtr); | ||||||
|  | 	 | ||||||
|  | 	return output; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Main RDP module | ||||||
|  |  */ | ||||||
|  | function RdpClient(config) { | ||||||
|  | 	config = config || {}; | ||||||
|  | 	this.connected = false; | ||||||
|  | 	this.bufferLayer = new layer.BufferLayer(new net.Socket()); | ||||||
|  | 	this.tpkt = new TPKT(this.bufferLayer); | ||||||
|  | 	this.x224 = new x224.Client(this.tpkt, config); | ||||||
|  | 	this.mcs = new t125.mcs.Client(this.x224); | ||||||
|  | 	this.sec = new pdu.sec.Client(this.mcs, this.tpkt); | ||||||
|  | 	this.global = new pdu.global.Client(this.sec, this.sec); | ||||||
|  | 	 | ||||||
|  | 	// config log level
 | ||||||
|  | 	log.level = log.Levels[config.logLevel || 'INFO'] || log.Levels.INFO; | ||||||
|  | 	 | ||||||
|  | 	// credentials
 | ||||||
|  | 	if (config.domain) { | ||||||
|  | 		this.sec.infos.obj.domain.value = Buffer.from(config.domain + '\x00', 'ucs2'); | ||||||
|  | 	} | ||||||
|  | 	if (config.userName) { | ||||||
|  | 		this.sec.infos.obj.userName.value = Buffer.from(config.userName + '\x00', 'ucs2'); | ||||||
|  | 	} | ||||||
|  | 	if (config.password) { | ||||||
|  | 		this.sec.infos.obj.password.value = Buffer.from(config.password + '\x00', 'ucs2'); | ||||||
|  | 	} | ||||||
|  | 	if(config.workingDir) { | ||||||
|  | 		this.sec.infos.obj.workingDir.value = Buffer.from(config.workingDir + '\x00', 'ucs2'); | ||||||
|  | 	} | ||||||
|  | 	if(config.alternateShell) { | ||||||
|  | 		this.sec.infos.obj.alternateShell.value = Buffer.from(config.alternateShell + '\x00', 'ucs2'); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (config.enablePerf) { | ||||||
|  | 		this.sec.infos.obj.extendedInfo.obj.performanceFlags.value =  | ||||||
|  | 				pdu.sec.PerfFlag.PERF_DISABLE_WALLPAPER  | ||||||
|  | 			| 	pdu.sec.PerfFlag.PERF_DISABLE_MENUANIMATIONS  | ||||||
|  | 			| 	pdu.sec.PerfFlag.PERF_DISABLE_CURSOR_SHADOW  | ||||||
|  | 			| 	pdu.sec.PerfFlag.PERF_DISABLE_THEMING  | ||||||
|  | 			| 	pdu.sec.PerfFlag.PERF_DISABLE_FULLWINDOWDRAG; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (config.autoLogin) { | ||||||
|  | 		this.sec.infos.obj.flag.value |= pdu.sec.InfoFlag.INFO_AUTOLOGON; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if (config.screen && config.screen.width && config.screen.height) { | ||||||
|  | 		this.mcs.clientCoreData.obj.desktopWidth.value = config.screen.width; | ||||||
|  | 		this.mcs.clientCoreData.obj.desktopHeight.value = config.screen.height; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	log.debug('screen ' + this.mcs.clientCoreData.obj.desktopWidth.value + 'x' + this.mcs.clientCoreData.obj.desktopHeight.value); | ||||||
|  | 	 | ||||||
|  | 	// config keyboard layout
 | ||||||
|  | 	switch (config.locale) { | ||||||
|  | 	case 'fr': | ||||||
|  | 		log.debug('french keyboard layout'); | ||||||
|  | 		this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.FRENCH; | ||||||
|  | 		break; | ||||||
|  | 	case 'en': | ||||||
|  | 	default: | ||||||
|  | 		log.debug('english keyboard layout'); | ||||||
|  | 		this.mcs.clientCoreData.obj.kbdLayout.value = t125.gcc.KeyboardLayout.US; | ||||||
|  | 	} | ||||||
|  | 		 | ||||||
|  | 	 | ||||||
|  | 	//bind all events
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.global.on('connect', function () { | ||||||
|  | 		self.connected = true; | ||||||
|  | 		self.emit('connect'); | ||||||
|  | 	}).on('session', function () { | ||||||
|  | 		self.emit('session'); | ||||||
|  | 	}).on('close', function () { | ||||||
|  | 		self.connected = false; | ||||||
|  | 		self.emit('close'); | ||||||
|  | 	}).on('bitmap', function (bitmaps) { | ||||||
|  | 		for(var bitmap in bitmaps) { | ||||||
|  | 			var bitmapData = bitmaps[bitmap].obj.bitmapDataStream.value; | ||||||
|  | 			var isCompress = bitmaps[bitmap].obj.flags.value & pdu.data.BitmapFlag.BITMAP_COMPRESSION; | ||||||
|  | 			 | ||||||
|  | 			if (isCompress && config.decompress) { | ||||||
|  | 				bitmapData = decompress(bitmaps[bitmap].obj); | ||||||
|  | 				isCompress = false; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			self.emit('bitmap', {  | ||||||
|  | 				destTop : bitmaps[bitmap].obj.destTop.value, | ||||||
|  | 				destLeft : bitmaps[bitmap].obj.destLeft.value,  | ||||||
|  | 				destBottom : bitmaps[bitmap].obj.destBottom.value,  | ||||||
|  | 				destRight : bitmaps[bitmap].obj.destRight.value,  | ||||||
|  | 				width : bitmaps[bitmap].obj.width.value, | ||||||
|  | 				height : bitmaps[bitmap].obj.height.value, | ||||||
|  | 				bitsPerPixel : bitmaps[bitmap].obj.bitsPerPixel.value, | ||||||
|  | 				isCompress : isCompress, | ||||||
|  | 				data : bitmapData | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	}).on('error', function (err) { | ||||||
|  | 		log.warn(err.code + '(' + err.message + ')\n' + err.stack); | ||||||
|  | 		if (err instanceof error.FatalError) { | ||||||
|  | 			throw err; | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			self.emit('error', err); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(RdpClient, events.EventEmitter); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Connect RDP client | ||||||
|  |  * @param host {string} destination host | ||||||
|  |  * @param port {integer} destination port | ||||||
|  |  */ | ||||||
|  | RdpClient.prototype.connect = function (host, port) { | ||||||
|  | 	log.debug('connect to ' + host + ':' + port); | ||||||
|  | 	var self = this; | ||||||
|  | 	this.bufferLayer.socket.connect(port, host, function () { | ||||||
|  | 		// in client mode connection start from x224 layer
 | ||||||
|  | 		self.x224.connect(); | ||||||
|  | 	}); | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Close RDP client | ||||||
|  |  */ | ||||||
|  | RdpClient.prototype.close = function () { | ||||||
|  | 	if(this.connected) { | ||||||
|  | 		this.global.close(); | ||||||
|  | 	} | ||||||
|  | 	this.connected = false; | ||||||
|  | 	return this; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send pointer event to server | ||||||
|  |  * @param x {integer} mouse x position | ||||||
|  |  * @param y {integer} mouse y position | ||||||
|  |  * @param button {integer} button number of mouse | ||||||
|  |  * @param isPressed {boolean} state of button | ||||||
|  |  */ | ||||||
|  | RdpClient.prototype.sendPointerEvent = function (x, y, button, isPressed) { | ||||||
|  | 	if (!this.connected) | ||||||
|  | 		return; | ||||||
|  | 	 | ||||||
|  | 	var event = pdu.data.pointerEvent(); | ||||||
|  | 	if (isPressed) { | ||||||
|  | 		event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_DOWN; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	switch(button) { | ||||||
|  | 	case 1: | ||||||
|  | 		event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON1; | ||||||
|  | 		break; | ||||||
|  | 	case 2: | ||||||
|  | 		event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON2; | ||||||
|  | 		break; | ||||||
|  | 	case 3: | ||||||
|  | 		event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_BUTTON3 | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_MOVE; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  |     event.obj.xPos.value = x; | ||||||
|  |     event.obj.yPos.value = y; | ||||||
|  |      | ||||||
|  |     this.global.sendInputEvents([event]); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * send scancode event | ||||||
|  |  * @param code {integer} | ||||||
|  |  * @param isPressed {boolean} | ||||||
|  |  * @param extended {boolenan} extended keys | ||||||
|  |  */ | ||||||
|  | RdpClient.prototype.sendKeyEventScancode = function (code, isPressed, extended) { | ||||||
|  | 	if (!this.connected) | ||||||
|  | 		return; | ||||||
|  | 	extended = extended || false; | ||||||
|  | 	var event = pdu.data.scancodeKeyEvent(); | ||||||
|  | 	event.obj.keyCode.value = code; | ||||||
|  | 	 | ||||||
|  | 	if (!isPressed) { | ||||||
|  | 		event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE; | ||||||
|  | 	} | ||||||
|  |      | ||||||
|  |     if (extended) { | ||||||
|  |     	event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_EXTENDED; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     this.global.sendInputEvents([event]); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send key event as unicode | ||||||
|  |  * @param code {integer} | ||||||
|  |  * @param isPressed {boolean} | ||||||
|  |  */ | ||||||
|  | RdpClient.prototype.sendKeyEventUnicode = function (code, isPressed) { | ||||||
|  | 	if (!this.connected) | ||||||
|  | 		return; | ||||||
|  | 	 | ||||||
|  | 	var event = pdu.data.unicodeKeyEvent(); | ||||||
|  | 	event.obj.unicode.value = code; | ||||||
|  | 	 | ||||||
|  | 	if (!isPressed) { | ||||||
|  | 		event.obj.keyboardFlags.value |= pdu.data.KeyboardFlag.KBDFLAGS_RELEASE; | ||||||
|  | 	} | ||||||
|  | 	this.global.sendInputEvents([event]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Wheel mouse event | ||||||
|  |  * @param x {integer} mouse x position | ||||||
|  |  * @param y {integer} mouse y position | ||||||
|  |  * @param step {integer} wheel step | ||||||
|  |  * @param isNegative {boolean} | ||||||
|  |  * @param isHorizontal {boolean} | ||||||
|  |  */ | ||||||
|  | RdpClient.prototype.sendWheelEvent = function (x, y, step, isNegative, isHorizontal) { | ||||||
|  | 	if (!this.connected) | ||||||
|  | 		return; | ||||||
|  | 	 | ||||||
|  | 	var event = pdu.data.pointerEvent(); | ||||||
|  | 	if (isHorizontal) { | ||||||
|  |         event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_HWHEEL; | ||||||
|  | 	} | ||||||
|  |     else { | ||||||
|  |     	event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL; | ||||||
|  |     } | ||||||
|  |          | ||||||
|  | 	 | ||||||
|  | 	if (isNegative) { | ||||||
|  |         event.obj.pointerFlags.value |= pdu.data.PointerFlag.PTRFLAGS_WHEEL_NEGATIVE; | ||||||
|  | 	} | ||||||
|  |          | ||||||
|  |     event.obj.pointerFlags.value |= (step & pdu.data.PointerFlag.WheelRotationMask) | ||||||
|  | 	 | ||||||
|  |     event.obj.xPos.value = x; | ||||||
|  |     event.obj.yPos.value = y; | ||||||
|  |      | ||||||
|  |     this.global.sendInputEvents([event]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function createClient(config) { | ||||||
|  | 	return new RdpClient(config); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * RDP server side protocol | ||||||
|  |  * @param config {object} configuration | ||||||
|  |  * @param socket {net.Socket} | ||||||
|  |  */ | ||||||
|  | function RdpServer(config, socket) { | ||||||
|  | 	if (!(config.key && config.cert)) { | ||||||
|  | 		throw new error.FatalError('NODE_RDP_PROTOCOL_RDP_SERVER_CONFIG_MISSING', 'missing cryptographic tools') | ||||||
|  | 	} | ||||||
|  | 	this.connected = false; | ||||||
|  | 	this.bufferLayer = new layer.BufferLayer(socket); | ||||||
|  | 	this.tpkt = new TPKT(this.bufferLayer); | ||||||
|  | 	this.x224 = new x224.Server(this.tpkt, config.key, config.cert); | ||||||
|  | 	this.mcs = new t125.mcs.Server(this.x224); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | inherits(RdpServer, events.EventEmitter); | ||||||
|  | 
 | ||||||
|  | function createServer (config, next) { | ||||||
|  | 	return net.createServer(function (socket) { | ||||||
|  | 		next(new RdpServer(config, socket)); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 		createClient : createClient, | ||||||
|  | 		createServer : createServer | ||||||
|  | }; | ||||||
							
								
								
									
										540
									
								
								rdp/protocol/t125/gcc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								rdp/protocol/t125/gcc.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,540 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../../core').type; | ||||||
|  | var log = require('../../core').log; | ||||||
|  | var error = require('../../core').error; | ||||||
|  | var per = require('./per'); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | var t124_02_98_oid = [ 0, 0, 20, 124, 0, 1 ]; | ||||||
|  | var h221_cs_key = "Duca"; | ||||||
|  | var h221_sc_key = "McDn"; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240509.aspx
 | ||||||
|  |  */ | ||||||
|  | var MessageType = { | ||||||
|  |     //server -> client
 | ||||||
|  |     SC_CORE : 0x0C01, | ||||||
|  |     SC_SECURITY : 0x0C02, | ||||||
|  |     SC_NET : 0x0C03, | ||||||
|  |     //client -> server
 | ||||||
|  |     CS_CORE : 0xC001, | ||||||
|  |     CS_SECURITY : 0xC002, | ||||||
|  |     CS_NET : 0xC003, | ||||||
|  |     CS_CLUSTER : 0xC004, | ||||||
|  |     CS_MONITOR : 0xC005 | ||||||
|  | }; | ||||||
|  |      | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
 | ||||||
|  |  */ | ||||||
|  | var ColorDepth = { | ||||||
|  |     RNS_UD_COLOR_8BPP : 0xCA01, | ||||||
|  |     RNS_UD_COLOR_16BPP_555 : 0xCA02, | ||||||
|  |     RNS_UD_COLOR_16BPP_565 : 0xCA03, | ||||||
|  |     RNS_UD_COLOR_24BPP : 0xCA04 | ||||||
|  | }; | ||||||
|  |     | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
 | ||||||
|  |  */ | ||||||
|  | var HighColor = { | ||||||
|  |     HIGH_COLOR_4BPP : 0x0004, | ||||||
|  |     HIGH_COLOR_8BPP : 0x0008, | ||||||
|  |     HIGH_COLOR_15BPP : 0x000f, | ||||||
|  |     HIGH_COLOR_16BPP : 0x0010, | ||||||
|  |     HIGH_COLOR_24BPP : 0x0018 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
 | ||||||
|  |  */ | ||||||
|  | var Support = { | ||||||
|  |     RNS_UD_24BPP_SUPPORT : 0x0001, | ||||||
|  |     RNS_UD_16BPP_SUPPORT : 0x0002, | ||||||
|  |     RNS_UD_15BPP_SUPPORT : 0x0004, | ||||||
|  |     RNS_UD_32BPP_SUPPORT : 0x0008 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
 | ||||||
|  |  */ | ||||||
|  | var CapabilityFlag = { | ||||||
|  |     RNS_UD_CS_SUPPORT_ERRINFO_PDU : 0x0001, | ||||||
|  |     RNS_UD_CS_WANT_32BPP_SESSION : 0x0002, | ||||||
|  |     RNS_UD_CS_SUPPORT_STATUSINFO_PDU : 0x0004, | ||||||
|  |     RNS_UD_CS_STRONG_ASYMMETRIC_KEYS : 0x0008, | ||||||
|  |     RNS_UD_CS_UNUSED : 0x0010, | ||||||
|  |     RNS_UD_CS_VALID_CONNECTION_TYPE : 0x0020, | ||||||
|  |     RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU : 0x0040, | ||||||
|  |     RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT : 0x0080, | ||||||
|  |     RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL : 0x0100, | ||||||
|  |     RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE : 0x0200, | ||||||
|  |     RNS_UD_CS_SUPPORT_HEARTBEAT_PDU : 0x0400 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
 | ||||||
|  |  */ | ||||||
|  | var ConnectionType = { | ||||||
|  |     CONNECTION_TYPE_MODEM : 0x01, | ||||||
|  |     CONNECTION_TYPE_BROADBAND_LOW : 0x02, | ||||||
|  |     CONNECTION_TYPE_SATELLITE : 0x03, | ||||||
|  |     CONNECTION_TYPE_BROADBAND_HIGH : 0x04, | ||||||
|  |     CONNECTION_TYPE_WAN : 0x05, | ||||||
|  |     CONNECTION_TYPE_LAN : 0x06, | ||||||
|  |     CONNECTION_TYPE_AUTODETECT : 0x07 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
 | ||||||
|  |  */ | ||||||
|  | var VERSION = { | ||||||
|  |     RDP_VERSION_4 : 0x00080001, | ||||||
|  |     RDP_VERSION_5_PLUS : 0x00080004 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | var Sequence = { | ||||||
|  |     RNS_UD_SAS_DEL : 0xAA03 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240511.aspx
 | ||||||
|  |  */ | ||||||
|  | var EncryptionMethod = { | ||||||
|  |     ENCRYPTION_FLAG_40BIT : 0x00000001, | ||||||
|  |     ENCRYPTION_FLAG_128BIT : 0x00000002, | ||||||
|  |     ENCRYPTION_FLAG_56BIT : 0x00000008, | ||||||
|  |     FIPS_ENCRYPTION_FLAG : 0x00000010 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240518.aspx
 | ||||||
|  |  */ | ||||||
|  | var EncryptionLevel = { | ||||||
|  |     ENCRYPTION_LEVEL_NONE : 0x00000000, | ||||||
|  |     ENCRYPTION_LEVEL_LOW : 0x00000001, | ||||||
|  |     ENCRYPTION_LEVEL_CLIENT_COMPATIBLE : 0x00000002, | ||||||
|  |     ENCRYPTION_LEVEL_HIGH : 0x00000003, | ||||||
|  |     ENCRYPTION_LEVEL_FIPS : 0x00000004 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240513.aspx
 | ||||||
|  |  */ | ||||||
|  | var ChannelOptions = { | ||||||
|  |     CHANNEL_OPTION_INITIALIZED : 0x80000000, | ||||||
|  |     CHANNEL_OPTION_ENCRYPT_RDP : 0x40000000, | ||||||
|  |     CHANNEL_OPTION_ENCRYPT_SC : 0x20000000, | ||||||
|  |     CHANNEL_OPTION_ENCRYPT_CS : 0x10000000, | ||||||
|  |     CHANNEL_OPTION_PRI_HIGH : 0x08000000, | ||||||
|  |     CHANNEL_OPTION_PRI_MED : 0x04000000, | ||||||
|  |     CHANNEL_OPTION_PRI_LOW : 0x02000000, | ||||||
|  |     CHANNEL_OPTION_COMPRESS_RDP : 0x00800000, | ||||||
|  |     CHANNEL_OPTION_COMPRESS : 0x00400000, | ||||||
|  |     CHANNEL_OPTION_SHOW_PROTOCOL : 0x00200000, | ||||||
|  |     REMOTE_CONTROL_PERSISTENT : 0x00100000 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * IBM_101_102_KEYS is the most common keyboard type | ||||||
|  |  */ | ||||||
|  | var KeyboardType = { | ||||||
|  |     IBM_PC_XT_83_KEY : 0x00000001, | ||||||
|  |     OLIVETTI : 0x00000002, | ||||||
|  |     IBM_PC_AT_84_KEY : 0x00000003, | ||||||
|  |     IBM_101_102_KEYS : 0x00000004, | ||||||
|  |     NOKIA_1050 : 0x00000005, | ||||||
|  |     NOKIA_9140 : 0x00000006, | ||||||
|  |     JAPANESE : 0x00000007 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://technet.microsoft.com/en-us/library/cc766503%28WS.10%29.aspx
 | ||||||
|  |  */ | ||||||
|  | var KeyboardLayout = { | ||||||
|  |     ARABIC : 0x00000401, | ||||||
|  |     BULGARIAN : 0x00000402, | ||||||
|  |     CHINESE_US_KEYBOARD : 0x00000404, | ||||||
|  |     CZECH : 0x00000405, | ||||||
|  |     DANISH : 0x00000406, | ||||||
|  |     GERMAN : 0x00000407, | ||||||
|  |     GREEK : 0x00000408, | ||||||
|  |     US : 0x00000409, | ||||||
|  |     SPANISH : 0x0000040a, | ||||||
|  |     FINNISH : 0x0000040b, | ||||||
|  |     FRENCH : 0x0000040c, | ||||||
|  |     HEBREW : 0x0000040d, | ||||||
|  |     HUNGARIAN : 0x0000040e, | ||||||
|  |     ICELANDIC : 0x0000040f, | ||||||
|  |     ITALIAN : 0x00000410, | ||||||
|  |     JAPANESE : 0x00000411, | ||||||
|  |     KOREAN : 0x00000412, | ||||||
|  |     DUTCH : 0x00000413, | ||||||
|  |     NORWEGIAN : 0x00000414 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240521.aspx
 | ||||||
|  |  */ | ||||||
|  | var CertificateType = { | ||||||
|  |     CERT_CHAIN_VERSION_1 : 0x00000001, | ||||||
|  |     CERT_CHAIN_VERSION_2 : 0x00000002 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param {type.Type} data  | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function block(data) { | ||||||
|  | 	var self = { | ||||||
|  | 		// type of data block
 | ||||||
|  | 		type : new type.UInt16Le(function() { | ||||||
|  | 			return self.data.obj.__TYPE__; | ||||||
|  | 		}), | ||||||
|  | 		// length of entire packet
 | ||||||
|  | 	    length : new type.UInt16Le(function() { | ||||||
|  | 	    	return new type.Component(self).size(); | ||||||
|  | 	    }), | ||||||
|  | 	    // data block
 | ||||||
|  | 	    data : data || new type.Factory(function(s){ | ||||||
|  | 	    	var options = { | ||||||
|  | 	    		readLength : new type.CallableValue( function () { | ||||||
|  | 	    			return self.length.value - 4; | ||||||
|  | 	    		}) | ||||||
|  | 	    	}; | ||||||
|  | 	    	switch(self.type.value) { | ||||||
|  | 	    	case MessageType.SC_CORE: | ||||||
|  | 	    		self.data = serverCoreData(options).read(s); | ||||||
|  | 	    		break; | ||||||
|  | 	    	case MessageType.SC_SECURITY: | ||||||
|  | 	    		self.data = serverSecurityData(options).read(s); | ||||||
|  | 	    		break; | ||||||
|  | 	    	case MessageType.SC_NET: | ||||||
|  | 	    		self.data = serverNetworkData(null, options).read(s); | ||||||
|  | 	    		break; | ||||||
|  | 	    	case MessageType.CS_CORE: | ||||||
|  | 	    		self.data = clientCoreData(options).read(s); | ||||||
|  | 	    		break; | ||||||
|  | 	    	case MessageType.CS_SECURITY: | ||||||
|  | 	    		self.data = clientSecurityData(options).read(s); | ||||||
|  | 	    		break; | ||||||
|  | 	    	case MessageType.CS_NET: | ||||||
|  | 	    		self.data = clientNetworkData(null, options).read(s); | ||||||
|  | 	    		break; | ||||||
|  | 	    	default: | ||||||
|  | 	    		log.debug("unknown gcc block type " + self.type.value); | ||||||
|  | 	    		self.data = new type.BinaryString(null, options).read(s); | ||||||
|  | 	    	} | ||||||
|  | 	    }) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Main client informations | ||||||
|  |  * 	keyboard | ||||||
|  |  * 	screen definition | ||||||
|  |  * 	color depth | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240510.aspx
 | ||||||
|  |  * @param opt {object} Classic type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function clientCoreData(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.CS_CORE, | ||||||
|  | 		rdpVersion : new type.UInt32Le(VERSION.RDP_VERSION_5_PLUS), | ||||||
|  | 		desktopWidth : new type.UInt16Le(1280), | ||||||
|  | 		desktopHeight : new type.UInt16Le(800), | ||||||
|  | 		colorDepth : new type.UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP), | ||||||
|  | 		sasSequence : new type.UInt16Le(Sequence.RNS_UD_SAS_DEL), | ||||||
|  | 		kbdLayout : new type.UInt32Le(KeyboardLayout.FRENCH), | ||||||
|  | 		clientBuild : new type.UInt32Le(3790), | ||||||
|  | 		clientName : new type.BinaryString(Buffer.from('node-rdpjs\x00\x00\x00\x00\x00\x00', 'ucs2'), { readLength : new type.CallableValue(32) }), | ||||||
|  | 		keyboardType : new type.UInt32Le(KeyboardType.IBM_101_102_KEYS), | ||||||
|  | 		keyboardSubType : new type.UInt32Le(0), | ||||||
|  | 		keyboardFnKeys : new type.UInt32Le(12), | ||||||
|  | 		imeFileName : new type.BinaryString(Buffer.from(Array(64 + 1).join('\x00')), { readLength : new type.CallableValue(64), optional : true }), | ||||||
|  | 		postBeta2ColorDepth : new type.UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP, { optional : true }), | ||||||
|  | 		clientProductId : new type.UInt16Le(1, { optional : true }), | ||||||
|  | 		serialNumber : new type.UInt32Le(0, { optional : true }), | ||||||
|  | 		highColorDepth : new type.UInt16Le(HighColor.HIGH_COLOR_24BPP, { optional : true }), | ||||||
|  | 		supportedColorDepths : new type.UInt16Le(Support.RNS_UD_15BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_32BPP_SUPPORT, { optional : true }), | ||||||
|  | 		earlyCapabilityFlags : new type.UInt16Le(CapabilityFlag.RNS_UD_CS_SUPPORT_ERRINFO_PDU, { optional : true }), | ||||||
|  | 		clientDigProductId : new type.BinaryString(Buffer.from(Array(64 + 1).join('\x00')), { optional : true, readLength : new type.CallableValue(64) }), | ||||||
|  | 		connectionType : new type.UInt8(0, { optional : true }), | ||||||
|  | 		pad1octet : new type.UInt8(0, { optional : true }), | ||||||
|  | 		serverSelectedProtocol : new type.UInt32Le(0, { optional : true }) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240517.aspx
 | ||||||
|  |  * @param opt {object} Classic type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function serverCoreData(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.SC_CORE, | ||||||
|  | 		rdpVersion : new type.UInt32Le(VERSION.RDP_VERSION_5_PLUS), | ||||||
|  | 		clientRequestedProtocol : new type.UInt32Le(null, { optional : true }), | ||||||
|  | 		earlyCapabilityFlags : new type.UInt32Le(null, { optional : true })	 | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240511.aspx
 | ||||||
|  |  * @param opt {object} Classic type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function clientSecurityData(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.CS_SECURITY, | ||||||
|  | 		encryptionMethods : new type.UInt32Le(EncryptionMethod.ENCRYPTION_FLAG_40BIT | EncryptionMethod.ENCRYPTION_FLAG_56BIT | EncryptionMethod.ENCRYPTION_FLAG_128BIT), | ||||||
|  | 		extEncryptionMethods : new type.UInt32Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Only use for SSL (RDP security layer TODO) | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240518.aspx
 | ||||||
|  |  * @param opt {object} Classic type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function serverSecurityData(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.SC_SECURITY, | ||||||
|  | 		encryptionMethod : new type.UInt32Le(), | ||||||
|  | 		encryptionLevel : new type.UInt32Le()  | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Channel definition | ||||||
|  |  * @param opt {object} Classic type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function channelDef (opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		name : new type.BinaryString(null, { readLength : new type.CallableValue(8) }), | ||||||
|  | 		options : new type.UInt32Le() | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Optional channel requests (sound, clipboard ...) | ||||||
|  |  * @param opt {object} Classic type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function clientNetworkData(channelDefArray, opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.CS_NET, | ||||||
|  | 		channelCount : new type.UInt32Le( function () { | ||||||
|  | 			return self.channelDefArray.obj.length; | ||||||
|  | 		}), | ||||||
|  | 		channelDefArray : channelDefArray || new type.Factory( function (s) { | ||||||
|  | 			self.channelDefArray = new type.Component([]); | ||||||
|  | 			 | ||||||
|  | 			for (var i = 0; i < self.channelCount.value; i++) { | ||||||
|  | 				self.channelDefArray.obj.push(channelDef().read(s)); | ||||||
|  | 			} | ||||||
|  | 		}) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param channelIds {type.Component} list of available channels | ||||||
|  |  * @param opt {object} Classic type options | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function serverNetworkData (channelIds, opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		__TYPE__ : MessageType.SC_NET, | ||||||
|  | 		MCSChannelId : new type.UInt16Le(1003, { constant : true }), | ||||||
|  | 		channelCount : new type.UInt16Le(function () { | ||||||
|  | 			return self.channelIdArray.obj.length; | ||||||
|  | 		}), | ||||||
|  | 		channelIdArray : channelIds || new type.Factory( function (s) { | ||||||
|  | 			self.channelIdArray = new type.Component([]); | ||||||
|  | 			for (var i = 0; i < self.channelCount.value; i++) { | ||||||
|  | 				self.channelIdArray.obj.push(new type.UInt16Le().read(s)); | ||||||
|  | 			} | ||||||
|  | 		}), | ||||||
|  | 		pad : new type.UInt16Le(null, { conditional : function () { | ||||||
|  | 			return (self.channelCount.value % 2) === 1; | ||||||
|  | 		}}) | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Client or server GCC settings block | ||||||
|  |  * @param blocks {type.Component} array of gcc blocks | ||||||
|  |  * @param opt {object} options to component type | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function settings(blocks, opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		blocks : blocks || new type.Factory(function(s) { | ||||||
|  | 			self.blocks = new type.Component([]); | ||||||
|  | 			// read until end of stream
 | ||||||
|  | 			while(s.availableLength() > 0) { | ||||||
|  | 				self.blocks.obj.push(block().read(s)); | ||||||
|  | 			} | ||||||
|  | 		}), | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read GCC response from server | ||||||
|  |  * @param s {type.Stream} current stream | ||||||
|  |  * @returns {Array(type.Component)} list of server block | ||||||
|  |  */ | ||||||
|  | function readConferenceCreateResponse(s) { | ||||||
|  | 	per.readChoice(s); | ||||||
|  | 	 | ||||||
|  | 	if(!per.readObjectIdentifier(s, t124_02_98_oid)) { | ||||||
|  | 		throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_OBJECT_IDENTIFIER_T124'); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	per.readLength(s); | ||||||
|  | 	per.readChoice(s); | ||||||
|  | 	per.readInteger16(s, 1001); | ||||||
|  | 	per.readInteger(s); | ||||||
|  | 	per.readEnumerates(s); | ||||||
|  | 	per.readNumberOfSet(s); | ||||||
|  | 	per.readChoice(s); | ||||||
|  | 	 | ||||||
|  | 	if (!per.readOctetStream(s, h221_sc_key, 4)) { | ||||||
|  | 		throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_H221_SC_KEY'); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	length = per.readLength(s); | ||||||
|  | 	serverSettings = settings(null, { readLength : new type.CallableValue(length) }); | ||||||
|  | 	 | ||||||
|  | 	// Object magic
 | ||||||
|  | 	return serverSettings.read(s).obj.blocks.obj.map(function(e) { | ||||||
|  | 		return e.obj.data; | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read GCC request | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @returns {Array(type.Component)} list of client block | ||||||
|  |  */ | ||||||
|  | function readConferenceCreateRequest (s) { | ||||||
|  | 	per.readChoice(s); | ||||||
|  | 	if (!per.readObjectIdentifier(s, t124_02_98_oid)) { | ||||||
|  | 		throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_H221_SC_KEY'); | ||||||
|  | 	} | ||||||
|  | 	per.readLength(s); | ||||||
|  | 	per.readChoice(s); | ||||||
|  | 	per.readSelection(s); | ||||||
|  | 	per.readNumericString(s, 1); | ||||||
|  | 	per.readPadding(s, 1); | ||||||
|  | 
 | ||||||
|  | 	if (per.readNumberOfSet(s) !== 1) { | ||||||
|  | 		throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_SET'); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (per.readChoice(s) !== 0xc0) { | ||||||
|  | 		throw new error.ProtocolError('NODE_RDP_PROTOCOL_T125_GCC_BAD_CHOICE'); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	per.readOctetStream(s, h221_cs_key, 4); | ||||||
|  | 	 | ||||||
|  | 	length = per.readLength(s); | ||||||
|  | 	var clientSettings = settings(null, { readLength : new type.CallableValue(length) }); | ||||||
|  | 	 | ||||||
|  | 	// Object magic
 | ||||||
|  | 	return clientSettings.read(s).obj.blocks.obj.map(function(e) { | ||||||
|  | 		return e.obj.data; | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Built {type.Componen} from gcc user data | ||||||
|  |  * @param userData {type.Component} GCC data from client | ||||||
|  |  * @returns {type.Component} GCC encoded client user data | ||||||
|  |  */ | ||||||
|  | function writeConferenceCreateRequest (userData) { | ||||||
|  |     var userDataStream = new type.Stream(userData.size()); | ||||||
|  |     userData.write(userDataStream); | ||||||
|  |      | ||||||
|  |     return new type.Component([ | ||||||
|  | 	    per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), | ||||||
|  | 	    per.writeLength(userData.size() + 14), per.writeChoice(0), | ||||||
|  | 	    per.writeSelection(0x08), per.writeNumericString("1", 1), per.writePadding(1), | ||||||
|  | 	    per.writeNumberOfSet(1), per.writeChoice(0xc0), | ||||||
|  | 	    per.writeOctetStream(Buffer.from(h221_cs_key), 4), per.writeOctetStream(userDataStream.getValue()) | ||||||
|  |     ]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function writeConferenceCreateResponse (userData) { | ||||||
|  | 	 var userDataStream = new type.Stream(userData.size()); | ||||||
|  | 	 userData.write(userDataStream); | ||||||
|  | 	  | ||||||
|  | 	 return new type.Component([ | ||||||
|  | 	    per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), | ||||||
|  | 	    per.writeLength(userData.size() + 14), per.writeChoice(0x14), | ||||||
|  | 	    per.writeInteger16(0x79F3, 1001), per.writeInteger(1), per.writeEnumerates(0), | ||||||
|  | 	    per.writeNumberOfSet(1), per.writeChoice(0xc0), | ||||||
|  | 	    per.writeOctetStream(Buffer.from(h221_sc_key), 4), per.writeOctetStream(userDataStream.getValue()) | ||||||
|  |     ]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	MessageType : MessageType, | ||||||
|  | 	VERSION : VERSION, | ||||||
|  | 	KeyboardLayout : KeyboardLayout, | ||||||
|  | 	block : block, | ||||||
|  | 	clientCoreData : clientCoreData, | ||||||
|  | 	clientNetworkData : clientNetworkData, | ||||||
|  | 	clientSecurityData : clientSecurityData, | ||||||
|  | 	serverCoreData : serverCoreData, | ||||||
|  | 	serverSecurityData : serverSecurityData, | ||||||
|  | 	serverNetworkData : serverNetworkData, | ||||||
|  | 	readConferenceCreateResponse : readConferenceCreateResponse, | ||||||
|  | 	readConferenceCreateRequest : readConferenceCreateRequest, | ||||||
|  | 	writeConferenceCreateRequest : writeConferenceCreateRequest, | ||||||
|  | 	writeConferenceCreateResponse : writeConferenceCreateResponse | ||||||
|  | }; | ||||||
							
								
								
									
										26
									
								
								rdp/protocol/t125/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								rdp/protocol/t125/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | /* | ||||||
|  |  * 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 mcs = require('./mcs'); | ||||||
|  | var gcc = require('./gcc'); | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  | 	mcs : mcs, | ||||||
|  | 	gcc : gcc | ||||||
|  | }; | ||||||
							
								
								
									
										490
									
								
								rdp/protocol/t125/mcs.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										490
									
								
								rdp/protocol/t125/mcs.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,490 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../../core').type; | ||||||
|  | var log = require('../../core').log; | ||||||
|  | var error = require('../../core').error; | ||||||
|  | var gcc = require('./gcc'); | ||||||
|  | var per = require('./per'); | ||||||
|  | var asn1 = require('../../asn1'); | ||||||
|  | 
 | ||||||
|  | var Message = { | ||||||
|  | 	MCS_TYPE_CONNECT_INITIAL : 0x65, | ||||||
|  | 	MCS_TYPE_CONNECT_RESPONSE : 0x66 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | var DomainMCSPDU = { | ||||||
|  |     ERECT_DOMAIN_REQUEST : 1, | ||||||
|  |     DISCONNECT_PROVIDER_ULTIMATUM : 8, | ||||||
|  |     ATTACH_USER_REQUEST : 10, | ||||||
|  |     ATTACH_USER_CONFIRM : 11, | ||||||
|  |     CHANNEL_JOIN_REQUEST : 14, | ||||||
|  |     CHANNEL_JOIN_CONFIRM : 15, | ||||||
|  |     SEND_DATA_REQUEST : 25, | ||||||
|  |     SEND_DATA_INDICATION : 26 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | var Channel = { | ||||||
|  |     MCS_GLOBAL_CHANNEL : 1003, | ||||||
|  |     MCS_USERCHANNEL_BASE : 1001 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function DomainParameters(maxChannelIds, maxUserIds, maxTokenIds,  | ||||||
|  | 		numPriorities, minThoughput, maxHeight, maxMCSPDUsize, protocolVersion) { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		maxChannelIds : new asn1.univ.Integer(maxChannelIds), | ||||||
|  | 		maxUserIds : new asn1.univ.Integer(maxUserIds), | ||||||
|  | 		maxTokenIds : new asn1.univ.Integer(maxTokenIds), | ||||||
|  | 		numPriorities : new asn1.univ.Integer(numPriorities), | ||||||
|  | 		minThoughput : new asn1.univ.Integer(minThoughput), | ||||||
|  | 		maxHeight : new asn1.univ.Integer(maxHeight), | ||||||
|  | 		maxMCSPDUsize : new asn1.univ.Integer(maxMCSPDUsize), | ||||||
|  | 		protocolVersion : new asn1.univ.Integer(protocolVersion) | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
 | ||||||
|  |  * @param userData {Buffer} | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function ConnectInitial (userData) { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		callingDomainSelector : new asn1.univ.OctetString(Buffer.from('\x01', 'binary')), | ||||||
|  | 		calledDomainSelector : new asn1.univ.OctetString(Buffer.from('\x01', 'binary')), | ||||||
|  | 		upwardFlag : new asn1.univ.Boolean(true), | ||||||
|  | 		targetParameters : DomainParameters(34, 2, 0, 1, 0, 1, 0xffff, 2), | ||||||
|  | 		minimumParameters : DomainParameters(1, 1, 1, 1, 0, 1, 0x420, 2), | ||||||
|  | 		maximumParameters : DomainParameters(0xffff, 0xfc17, 0xffff, 1, 0, 1, 0xffff, 2), | ||||||
|  | 		userData : new asn1.univ.OctetString(userData) | ||||||
|  | 	}).implicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Application, asn1.spec.TagFormat.Constructed, 101)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://www.itu.int/rec/T-REC-T.125-199802-I/en page 25
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function ConnectResponse (userData) { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		result : new asn1.univ.Enumerate(0), | ||||||
|  | 		calledConnectId : new asn1.univ.Integer(0), | ||||||
|  | 		domainParameters : DomainParameters(22, 3, 0, 1, 0, 1,0xfff8, 2), | ||||||
|  | 		userData : new asn1.univ.OctetString(userData) | ||||||
|  | 	}).implicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Application, asn1.spec.TagFormat.Constructed, 102)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Format MCS PDU header packet | ||||||
|  |  * @param mcsPdu {integer} | ||||||
|  |  * @param options {integer} | ||||||
|  |  * @returns {type.UInt8} headers | ||||||
|  |  */ | ||||||
|  | function writeMCSPDUHeader(mcsPdu, options) { | ||||||
|  | 	options = options || 0; | ||||||
|  |     return new type.UInt8((mcsPdu << 2) | options); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read MCS PDU header | ||||||
|  |  * @param opcode | ||||||
|  |  * @param mcsPdu | ||||||
|  |  * @returns {Boolean} | ||||||
|  |  */ | ||||||
|  | function readMCSPDUHeader(opcode, mcsPdu) { | ||||||
|  | 	return (opcode >> 2) === mcsPdu; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Multi-Channel Services | ||||||
|  |  * @param transport {events.EventEmitter} transport layer listen (connect, data) events | ||||||
|  |  * @param recvOpCode {DomainMCSPDU} opcode use in receive automata | ||||||
|  |  * @param sendOpCode {DomainMCSPDU} opcode use to send message | ||||||
|  |  */ | ||||||
|  | function MCS(transport, recvOpCode, sendOpCode) { | ||||||
|  | 	this.transport = transport; | ||||||
|  | 	this.recvOpCode = recvOpCode; | ||||||
|  | 	this.sendOpCode = sendOpCode; | ||||||
|  | 	this.channels = [{id : Channel.MCS_GLOBAL_CHANNEL, name : 'global'}]; | ||||||
|  | 	this.channels.find = function(callback) { | ||||||
|  | 		for(var i in this) { | ||||||
|  | 			if(callback(this[i])) return this[i]; | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	// bind events
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.on('close', function () { | ||||||
|  | 		self.emit('close'); | ||||||
|  | 	}).on('error', function (err) { | ||||||
|  | 		self.emit('error', err); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from Layer
 | ||||||
|  | inherits(MCS, events.EventEmitter); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send message to a specific channel | ||||||
|  |  * @param channelName {string} name of channel | ||||||
|  |  * @param data {type.*} message to send | ||||||
|  |  */ | ||||||
|  | MCS.prototype.send = function(channelName, data) { | ||||||
|  | 	var channelId = this.channels.find(function(element) { | ||||||
|  | 		if (element.name === channelName) return true; | ||||||
|  | 	}).id; | ||||||
|  | 	 | ||||||
|  | 	this.transport.send(new type.Component([ | ||||||
|  | 	    writeMCSPDUHeader(this.sendOpCode), | ||||||
|  | 	    per.writeInteger16(this.userId, Channel.MCS_USERCHANNEL_BASE), | ||||||
|  | 	    per.writeInteger16(channelId), | ||||||
|  | 	    new type.UInt8(0x70), | ||||||
|  | 	    per.writeLength(data.size()),  | ||||||
|  | 	    data | ||||||
|  | 	])); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Main receive function | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | MCS.prototype.recv = function(s) { | ||||||
|  | 	opcode = new type.UInt8().read(s).value; | ||||||
|  | 	 | ||||||
|  | 	if (readMCSPDUHeader(opcode, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM)) { | ||||||
|  | 		log.info("MCS DISCONNECT_PROVIDER_ULTIMATUM"); | ||||||
|  | 		this.transport.close(); | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	else if(!readMCSPDUHeader(opcode, this.recvOpCode)) { | ||||||
|  | 		throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_BAD_RECEIVE_OPCODE'); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE); | ||||||
|  | 	 | ||||||
|  | 	var channelId = per.readInteger16(s); | ||||||
|  | 	 | ||||||
|  | 	per.readEnumerates(s);  | ||||||
|  | 	per.readLength(s); | ||||||
|  | 	 | ||||||
|  | 	var channelName = this.channels.find(function(e) { | ||||||
|  | 		if (e.id === channelId) return true; | ||||||
|  | 	}).name; | ||||||
|  | 	 | ||||||
|  | 	this.emit(channelName, s); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Only main channels handle actually | ||||||
|  |  * @param transport {event.EventEmitter} bind connect and data events | ||||||
|  |  * @returns | ||||||
|  |  */ | ||||||
|  | function Client(transport) { | ||||||
|  | 	MCS.call(this, transport, DomainMCSPDU.SEND_DATA_INDICATION, DomainMCSPDU.SEND_DATA_REQUEST); | ||||||
|  | 	 | ||||||
|  | 	// channel context automata
 | ||||||
|  | 	this.channelsConnected = 0; | ||||||
|  | 	 | ||||||
|  | 	// init gcc information
 | ||||||
|  | 	this.clientCoreData = gcc.clientCoreData(); | ||||||
|  | 	this.clientNetworkData = gcc.clientNetworkData(new type.Component([])); | ||||||
|  | 	this.clientSecurityData = gcc.clientSecurityData(); | ||||||
|  | 	 | ||||||
|  | 	// must be readed from protocol
 | ||||||
|  | 	this.serverCoreData = null; | ||||||
|  | 	this.serverSecurityData = null; | ||||||
|  | 	this.serverNetworkData = null; | ||||||
|  | 	 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.on('connect', function(s) { | ||||||
|  | 		self.connect(s); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Client, MCS); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Connect event layer | ||||||
|  |  */ | ||||||
|  | Client.prototype.connect = function(selectedProtocol) { | ||||||
|  | 	this.clientCoreData.obj.serverSelectedProtocol.value = selectedProtocol; | ||||||
|  | 	this.sendConnectInitial(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * close stack | ||||||
|  |  */ | ||||||
|  | Client.prototype.close = function() { | ||||||
|  | 	this.transport.close(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * MCS connect response (server->client) | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Client.prototype.recvConnectResponse = function(s) { | ||||||
|  |     var userData = new type.Stream(ConnectResponse().decode(s, asn1.ber).value.userData.value); | ||||||
|  |     var serverSettings = gcc.readConferenceCreateResponse(userData); | ||||||
|  |     // record server gcc block
 | ||||||
|  |     for(var i in serverSettings) { | ||||||
|  |     	if(!serverSettings[i].obj) { | ||||||
|  |     		continue; | ||||||
|  |     	} | ||||||
|  |     	switch(serverSettings[i].obj.__TYPE__) { | ||||||
|  |     	case gcc.MessageType.SC_CORE: | ||||||
|  |     		this.serverCoreData = serverSettings[i]; | ||||||
|  |     		break; | ||||||
|  |     	case gcc.MessageType.SC_SECURITY: | ||||||
|  |     		this.serverSecurityData = serverSettings[i]; | ||||||
|  |     		break; | ||||||
|  |     	case gcc.MessageType.SC_NET: | ||||||
|  |     		this.serverNetworkData = serverSettings[i]; | ||||||
|  |     		break; | ||||||
|  |     	default: | ||||||
|  |     		log.warn('unhandle server gcc block : ' + serverSettings[i].obj.__TYPE__); | ||||||
|  |     	} | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // send domain request
 | ||||||
|  |     this.sendErectDomainRequest(); | ||||||
|  |     // send attach user request
 | ||||||
|  |     this.sendAttachUserRequest(); | ||||||
|  |     // now wait user confirm from server
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvAttachUserConfirm(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * MCS connection automata step | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Client.prototype.recvAttachUserConfirm = function(s) { | ||||||
|  |     if (!readMCSPDUHeader(new type.UInt8().read(s).value, DomainMCSPDU.ATTACH_USER_CONFIRM)) { | ||||||
|  |     	throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_BAD_HEADER'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (per.readEnumerates(s) !== 0) { | ||||||
|  |     	throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_REJECT_USER'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     this.userId = per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE); | ||||||
|  |     //ask channel for specific user
 | ||||||
|  |     this.channels.push({ id : this.userId, name : 'user' }); | ||||||
|  |     // channel connect automata
 | ||||||
|  |     this.connectChannels(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Last state in channel connection automata | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Client.prototype.recvChannelJoinConfirm = function(s) { | ||||||
|  |     var opcode = new type.UInt8().read(s).value; | ||||||
|  |      | ||||||
|  |     if (!readMCSPDUHeader(opcode, DomainMCSPDU.CHANNEL_JOIN_CONFIRM)) { | ||||||
|  |     	throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_WAIT_CHANNEL_JOIN_CONFIRM'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     var confirm = per.readEnumerates(s); | ||||||
|  |      | ||||||
|  |     var userId = per.readInteger16(s, Channel.MCS_USERCHANNEL_BASE); | ||||||
|  |     if (this.userId !== userId) { | ||||||
|  |     	throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_INVALID_USER_ID'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     var channelId = per.readInteger16(s); | ||||||
|  | 
 | ||||||
|  |     if ((confirm !== 0) && (channelId === Channel.MCS_GLOBAL_CHANNEL || channelId === this.userId)) { | ||||||
|  |     	throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_MCS_SERVER_MUST_CONFIRM_STATIC_CHANNEL'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     this.connectChannels(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * First MCS message | ||||||
|  |  */ | ||||||
|  | Client.prototype.sendConnectInitial = function() { | ||||||
|  | 	 | ||||||
|  | 	var ccReq = gcc.writeConferenceCreateRequest(new type.Component([ | ||||||
|  | 	    gcc.block(this.clientCoreData),  | ||||||
|  | 	    gcc.block(this.clientNetworkData),  | ||||||
|  | 	    gcc.block(this.clientSecurityData) | ||||||
|  | 	])).toStream().getValue(); | ||||||
|  | 	 | ||||||
|  | 	this.transport.send(ConnectInitial(ccReq).encode(asn1.ber)); | ||||||
|  | 	 | ||||||
|  | 	// next event is connect response
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvConnectResponse(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * MCS connection automata step | ||||||
|  |  */ | ||||||
|  | Client.prototype.sendErectDomainRequest = function() { | ||||||
|  |     this.transport.send(new type.Component([ | ||||||
|  | 	    writeMCSPDUHeader(DomainMCSPDU.ERECT_DOMAIN_REQUEST), | ||||||
|  | 	    per.writeInteger(0), | ||||||
|  | 	    per.writeInteger(0) | ||||||
|  |     ])); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * MCS connection automata step | ||||||
|  |  */ | ||||||
|  | Client.prototype.sendAttachUserRequest = function() { | ||||||
|  |     this.transport.send(writeMCSPDUHeader(DomainMCSPDU.ATTACH_USER_REQUEST)); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send a channel join request | ||||||
|  |  * @param channelId {integer} channel id | ||||||
|  |  */ | ||||||
|  | Client.prototype.sendChannelJoinRequest = function(channelId) { | ||||||
|  | 	this.transport.send(new type.Component([ | ||||||
|  | 	    writeMCSPDUHeader(DomainMCSPDU.CHANNEL_JOIN_REQUEST), | ||||||
|  | 	    per.writeInteger16(this.userId, Channel.MCS_USERCHANNEL_BASE), | ||||||
|  | 	    per.writeInteger16(channelId) | ||||||
|  |     ])); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Connect channels automata | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Client.prototype.connectChannels = function(s) { | ||||||
|  | 	if(this.channelsConnected == this.channels.length) { | ||||||
|  | 		var self = this; | ||||||
|  | 		this.transport.on('data', function(s) { | ||||||
|  | 			self.recv(s); | ||||||
|  | 		}); | ||||||
|  | 		 | ||||||
|  | 		// send client and sever gcc informations
 | ||||||
|  | 		this.emit('connect',  | ||||||
|  | 				{ | ||||||
|  | 					core : this.clientCoreData.obj,  | ||||||
|  | 					security : this.clientSecurityData.obj,  | ||||||
|  | 					net : this.clientNetworkData.obj | ||||||
|  | 				}, | ||||||
|  | 				{ | ||||||
|  | 					core : this.serverCoreData.obj, | ||||||
|  | 					security : this.serverSecurityData.obj | ||||||
|  | 				}, this.userId, this.channels); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	this.sendChannelJoinRequest(this.channels[this.channelsConnected++].id); | ||||||
|  | 	 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvChannelJoinConfirm(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Server side of MCS layer | ||||||
|  |  * @param transport | ||||||
|  |  */ | ||||||
|  | function Server (transport) { | ||||||
|  | 	MCS.call(this, transport, DomainMCSPDU.SEND_DATA_REQUEST, DomainMCSPDU.SEND_DATA_INDICATION); | ||||||
|  | 	 | ||||||
|  | 	// must be readed from protocol
 | ||||||
|  | 	this.clientCoreData = null; | ||||||
|  | 	this.clientNetworkData = null; | ||||||
|  | 	this.clientSecurityData = null; | ||||||
|  | 	 | ||||||
|  | 	// init gcc information
 | ||||||
|  | 	this.serverCoreData = gcc.serverCoreData(); | ||||||
|  | 	this.serverSecurityData = gcc.serverSecurityData(); | ||||||
|  | 	this.serverNetworkData = gcc.serverNetworkData(new type.Component([])); | ||||||
|  | 	 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.on('connect', function (selectedProtocol) { | ||||||
|  | 		self.serverCoreData.obj.clientRequestedProtocol.value = selectedProtocol; | ||||||
|  | 	}).once('data', function (s) { | ||||||
|  | 		self.recvConnectInitial(s); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inherits(Server, MCS); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * First state of server automata | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Server.prototype.recvConnectInitial = function (s) { | ||||||
|  | 	var userData = new type.Stream(ConnectInitial().decode(s, asn1.ber).value.userData.value); | ||||||
|  | 	var clientSettings = gcc.readConferenceCreateRequest(userData); | ||||||
|  |     // record server gcc block
 | ||||||
|  |     for(var i in clientSettings) { | ||||||
|  |     	if(!clientSettings[i].obj) { | ||||||
|  |     		continue; | ||||||
|  |     	} | ||||||
|  |     	switch(clientSettings[i].obj.__TYPE__) { | ||||||
|  |     	case gcc.MessageType.CS_CORE: | ||||||
|  |     		this.clientCoreData = clientSettings[i]; | ||||||
|  |     		break; | ||||||
|  |     	case gcc.MessageType.CS_SECURITY: | ||||||
|  |     		this.clientSecurityData = clientSettings[i]; | ||||||
|  |     		break; | ||||||
|  |     	case gcc.MessageType.CS_NET: | ||||||
|  |     		this.clientNetworkData = clientSettings[i]; | ||||||
|  |     		for (var i = 0; i < this.clientNetworkData.obj.channelCount.value; i++) { | ||||||
|  |     			this.serverNetworkData.obj.channelIdArray.obj.push(new type.UInt16Le( i + 1 + Channel.MCS_GLOBAL_CHANNEL)); | ||||||
|  |     		} | ||||||
|  |     		break; | ||||||
|  |     	default: | ||||||
|  |     		log.debug('unhandle client gcc block : ' + clientSettings[i].obj.__TYPE__); | ||||||
|  |     	} | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     this.sendConnectResponse(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * State 2 in mcs server connetion automata | ||||||
|  |  */ | ||||||
|  | Server.prototype.sendConnectResponse = function () { | ||||||
|  | 	var ccReq = gcc.writeConferenceCreateResponse(new type.Component([ | ||||||
|  |  	    gcc.block(this.serverCoreData),  | ||||||
|  |  	    gcc.block(this.serverSecurityData), | ||||||
|  |  	    gcc.block(this.serverNetworkData), | ||||||
|  |  	])).toStream().getValue(); | ||||||
|  |  	 | ||||||
|  |  	this.transport.send(ConnectResponse(ccReq).encode(asn1.ber)); | ||||||
|  |  	 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 		Client : Client, | ||||||
|  | 		Server : Server | ||||||
|  | }; | ||||||
							
								
								
									
										338
									
								
								rdp/protocol/t125/per.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										338
									
								
								rdp/protocol/t125/per.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,338 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../../core').type; | ||||||
|  | var error = require('../../core').error; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} read value from stream | ||||||
|  |  * @returns read length from per format | ||||||
|  |  */ | ||||||
|  | function readLength(s) { | ||||||
|  | 	var byte = new type.UInt8().read(s).value; | ||||||
|  | 	var size = 0; | ||||||
|  | 	if(byte & 0x80) { | ||||||
|  | 		byte &= ~0x80; | ||||||
|  | 		size = byte << 8; | ||||||
|  | 		size += new type.UInt8().read(s).value; | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		size = byte; | ||||||
|  | 	} | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param value {raw} value to convert to per format | ||||||
|  |  * @returns type objects per encoding value | ||||||
|  |  */ | ||||||
|  | function writeLength(value) { | ||||||
|  | 	if(value > 0x7f) { | ||||||
|  | 		return new type.UInt16Be(value | 0x8000); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		return new type.UInt8(value); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @returns {integer} choice decoding from per encoding | ||||||
|  |  */ | ||||||
|  | function readChoice(s) { | ||||||
|  | 	return new type.UInt8().read(s).value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param choice {integer} | ||||||
|  |  * @returns {type.UInt8} choice per encoded | ||||||
|  |  */ | ||||||
|  | function writeChoice(choice) { | ||||||
|  | 	return new type.UInt8(choice); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @returns {integer} number represent selection | ||||||
|  |  */ | ||||||
|  | function readSelection(s) { | ||||||
|  | 	return new type.UInt8().read(s).value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param selection {integer} | ||||||
|  |  * @returns {type.UInt8} per encoded selection | ||||||
|  |  */ | ||||||
|  | function writeSelection(selection) { | ||||||
|  | 	return new type.UInt8(selection); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @returns {integer} number of sets | ||||||
|  |  */ | ||||||
|  | function readNumberOfSet(s) { | ||||||
|  | 	return new type.UInt8().read(s).value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param numberOfSet {integer} | ||||||
|  |  * @returns {type.UInt8} per encoded nuimber of sets | ||||||
|  |  */ | ||||||
|  | function writeNumberOfSet(numberOfSet) { | ||||||
|  | 	return new type.UInt8(numberOfSet); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @returns {integer} enumerates number | ||||||
|  |  */ | ||||||
|  | function readEnumerates(s) { | ||||||
|  | 	return new type.UInt8().read(s).value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param enumerate {integer} | ||||||
|  |  * @returns {type.UInt8} per encoded enumerate | ||||||
|  |  */ | ||||||
|  | function writeEnumerates(enumerate) { | ||||||
|  | 	return new type.UInt8(enumerate); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @returns {integer} integer per decoded | ||||||
|  |  */ | ||||||
|  | function readInteger(s) { | ||||||
|  | 	var result; | ||||||
|  | 	var size = readLength(s); | ||||||
|  | 	switch(size) { | ||||||
|  | 	case 1: | ||||||
|  | 		result = new type.UInt8(); | ||||||
|  | 		break; | ||||||
|  | 	case 2: | ||||||
|  | 		result = new type.UInt16Be(); | ||||||
|  | 		break; | ||||||
|  | 	case 4: | ||||||
|  | 		result = new type.UInt32Be(); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		throw new error.UnexpectedFatalError('NODE_RDP_PROTOCOL_T125_PER_BAD_INTEGER_LENGTH'); | ||||||
|  | 	} | ||||||
|  | 	return result.read(s).value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param value {integer} | ||||||
|  |  * @returns {type.Component} per encoded integer | ||||||
|  |  */ | ||||||
|  | function writeInteger(value) { | ||||||
|  | 	if(value <= 0xff) { | ||||||
|  | 		return new type.Component([writeLength(1), new type.UInt8(value)]); | ||||||
|  | 	} | ||||||
|  | 	else if(value < 0xffff) { | ||||||
|  | 		return new type.Component([writeLength(2), new type.UInt16Be(value)]); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		return new type.Component([writeLength(4), new type.UInt32Be(value)]); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param minimum {integer} increment (default 0) | ||||||
|  |  * @returns {integer} per decoded integer 16 bits | ||||||
|  |  */ | ||||||
|  | function readInteger16(s, minimum) { | ||||||
|  | 	return new type.UInt16Be().read(s).value + (minimum || 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param value {integer} | ||||||
|  |  * @param minimum {integer} decrement (default 0) | ||||||
|  |  * @returns {type.UInt16Be} per encoded integer 16 bits | ||||||
|  |  */ | ||||||
|  | function writeInteger16(value, minimum) { | ||||||
|  | 	return new type.UInt16Be(value - (minimum || 0)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Check object identifier | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param oid {array} object identifier to check | ||||||
|  |  */ | ||||||
|  | function readObjectIdentifier(s, oid) { | ||||||
|  | 	var size = readLength(s); | ||||||
|  | 	if(size !== 5) { | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var a_oid = [0, 0, 0, 0, 0, 0]; | ||||||
|  | 	var t12 = new type.UInt8().read(s).value; | ||||||
|  | 	a_oid[0] = t12 >> 4; | ||||||
|  | 	a_oid[1] = t12 & 0x0f; | ||||||
|  | 	a_oid[2] = new type.UInt8().read(s).value; | ||||||
|  | 	a_oid[3] = new type.UInt8().read(s).value; | ||||||
|  | 	a_oid[4] = new type.UInt8().read(s).value; | ||||||
|  | 	a_oid[5] = new type.UInt8().read(s).value; | ||||||
|  | 
 | ||||||
|  | 	for(var i in oid) { | ||||||
|  | 		if(oid[i] !== a_oid[i]) return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param oid {array} oid to write | ||||||
|  |  * @returns {type.Component} per encoded object identifier | ||||||
|  |  */ | ||||||
|  | function writeObjectIdentifier(oid) { | ||||||
|  | 	return new type.Component([new type.UInt8(5), new type.UInt8((oid[0] << 4) & (oid[1] & 0x0f)), new type.UInt8(oid[2]), new type.UInt8(oid[3]), new type.UInt8(oid[4]), new type.UInt8(oid[5])]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read as padding... | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param minValue | ||||||
|  |  */ | ||||||
|  | function readNumericString(s, minValue) { | ||||||
|  |     var length = readLength(s); | ||||||
|  |     length = (length + minValue + 1) / 2; | ||||||
|  |     s.readPadding(length); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param nStr {String} | ||||||
|  |  * @param minValue {integer} | ||||||
|  |  * @returns {type.Component} per encoded numeric string | ||||||
|  |  */ | ||||||
|  | function writeNumericString(nStr, minValue) { | ||||||
|  |     var length = nStr.length; | ||||||
|  |     var mlength = minValue; | ||||||
|  |     if(length - minValue >= 0) { | ||||||
|  |         mlength = length - minValue; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     var result = []; | ||||||
|  |      | ||||||
|  |     for(var i = 0; i < length; i += 2) { | ||||||
|  |         var c1 = nStr.charCodeAt(i); | ||||||
|  |     	var c2 = 0; | ||||||
|  |         if(i + 1 < length) { | ||||||
|  |             c2 = nStr.charCodeAt(i + 1); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             c2 = 0x30; | ||||||
|  |         } | ||||||
|  |         c1 = (c1 - 0x30) % 10; | ||||||
|  |         c2 = (c2 - 0x30) % 10; | ||||||
|  |          | ||||||
|  |         result[result.length] = new type.UInt8((c1 << 4) | c2); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return new type.Component([writeLength(mlength), new type.Component(result)]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param length {integer} length of padding | ||||||
|  |  */ | ||||||
|  | function readPadding(s, length) { | ||||||
|  |     s.readPadding(length); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param length {integer} length of padding | ||||||
|  |  * @returns {type.BinaryString} per encoded padding | ||||||
|  |  */ | ||||||
|  | function writePadding(length) { | ||||||
|  |     return new type.BinaryString(Buffer.from(Array(length + 1).join("\x00"))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  * @param octetStream {String} | ||||||
|  |  * @param minValue {integer} default 0 | ||||||
|  |  * @returns {Boolean} true if read octectStream is equal to octetStream | ||||||
|  |  */ | ||||||
|  | function readOctetStream(s, octetStream, minValue) { | ||||||
|  |     var size = readLength(s) + (minValue || 0); | ||||||
|  |     if(size !== octetStream.length) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     for(var i = 0; i < size; i++) { | ||||||
|  |         var c = new type.UInt8().read(s); | ||||||
|  |         if(octetStream.charCodeAt(i) !== c.value) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param oStr {String} | ||||||
|  |  * @param minValue {integer} default 0 | ||||||
|  |  * @returns {type.Component} per encoded octet stream | ||||||
|  |  */ | ||||||
|  | function writeOctetStream(oStr, minValue) { | ||||||
|  | 	minValue = minValue || 0; | ||||||
|  |     var length = oStr.length; | ||||||
|  |     var mlength = minValue; | ||||||
|  |      | ||||||
|  |     if(length - minValue >= 0) { | ||||||
|  |         mlength = length - minValue; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     result = []; | ||||||
|  |     for(var i = 0; i < length; i++) { | ||||||
|  |         result[result.length] = new type.UInt8(oStr[i]); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return new type.Component([writeLength(mlength), new type.Component(result)]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	readLength : readLength, | ||||||
|  | 	writeLength : writeLength, | ||||||
|  | 	readChoice : readChoice, | ||||||
|  | 	writeChoice : writeChoice, | ||||||
|  | 	readSelection : readSelection, | ||||||
|  | 	writeSelection : writeSelection, | ||||||
|  | 	readNumberOfSet : readNumberOfSet, | ||||||
|  | 	writeNumberOfSet : writeNumberOfSet, | ||||||
|  | 	readEnumerates : readEnumerates, | ||||||
|  | 	writeEnumerates : writeEnumerates, | ||||||
|  | 	readInteger : readInteger, | ||||||
|  | 	writeInteger : writeInteger, | ||||||
|  | 	readInteger16 : readInteger16, | ||||||
|  | 	writeInteger16 : writeInteger16, | ||||||
|  | 	readObjectIdentifier : readObjectIdentifier, | ||||||
|  | 	writeObjectIdentifier : writeObjectIdentifier, | ||||||
|  | 	readNumericString : readNumericString, | ||||||
|  | 	writeNumericString : writeNumericString, | ||||||
|  | 	readPadding : readPadding, | ||||||
|  | 	writePadding : writePadding, | ||||||
|  | 	readOctetStream : readOctetStream, | ||||||
|  | 	writeOctetStream : writeOctetStream | ||||||
|  | }; | ||||||
							
								
								
									
										171
									
								
								rdp/protocol/tpkt.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								rdp/protocol/tpkt.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,171 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../core').type; | ||||||
|  | var events = require('events'); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Type of tpkt packet | ||||||
|  |  * Fastpath is use to shortcut RDP stack | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240621.aspx
 | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240589.aspx
 | ||||||
|  |  */ | ||||||
|  | var Action = { | ||||||
|  | 	FASTPATH_ACTION_FASTPATH : 0x0, | ||||||
|  |     FASTPATH_ACTION_X224 : 0x3 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * TPKT layer of rdp stack | ||||||
|  |  */ | ||||||
|  | function TPKT(transport) { | ||||||
|  | 	this.transport = transport; | ||||||
|  | 	// wait 2 bytes
 | ||||||
|  | 	this.transport.expect(2); | ||||||
|  | 	// next state is receive header
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvHeader(s); | ||||||
|  | 	}).on('close', function() { | ||||||
|  | 		self.emit('close'); | ||||||
|  | 	}).on('error', function (err) { | ||||||
|  | 		self.emit('error', err); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * inherit from a packet layer | ||||||
|  |  */ | ||||||
|  | inherits(TPKT, events.EventEmitter); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive correct packet as expected | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | TPKT.prototype.recvHeader = function (s) { | ||||||
|  | 	var version = new type.UInt8().read(s).value; | ||||||
|  | 	var self = this; | ||||||
|  | 	if(version === Action.FASTPATH_ACTION_X224) { | ||||||
|  | 		new type.UInt8().read(s); | ||||||
|  | 		this.transport.expect(2); | ||||||
|  | 		this.transport.once('data', function(s) { | ||||||
|  | 			self.recvExtendedHeader(s); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		this.secFlag = ((version >> 6) & 0x3); | ||||||
|  | 		var length = new type.UInt8().read(s).value; | ||||||
|  | 		if (length & 0x80) { | ||||||
|  | 			this.transport.expect(1); | ||||||
|  | 			this.transport.once('data', function(s) { | ||||||
|  | 				self.recvExtendedFastPathHeader(s, length); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			this.transport.expect(length - 2); | ||||||
|  | 			this.transport.once('data', function(s) { | ||||||
|  | 				self.recvFastPath(s); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive second part of header packet | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | TPKT.prototype.recvExtendedHeader = function (s) { | ||||||
|  | 	var size = new type.UInt16Be().read(s); | ||||||
|  | 	this.transport.expect(size.value - 4); | ||||||
|  | 	//next state receive packet
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvData(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive data available for presentation layer | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | TPKT.prototype.recvData = function (s) { | ||||||
|  | 	this.emit('data', s); | ||||||
|  | 	this.transport.expect(2); | ||||||
|  | 	//next state receive header
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvHeader(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read extended fastpath header | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | TPKT.prototype.recvExtendedFastPathHeader = function (s, length) { | ||||||
|  | 	var rightPart = new type.UInt8().read(s).value; | ||||||
|  | 	var leftPart = length & ~0x80; | ||||||
|  | 	var packetSize = (leftPart << 8) + rightPart; | ||||||
|  | 
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.expect(packetSize - 3); | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvFastPath(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Read fast path data | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | TPKT.prototype.recvFastPath = function (s) { | ||||||
|  | 	this.emit('fastPathData', this.secFlag, s); | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.expect(2); | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvHeader(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Send message throught TPKT layer | ||||||
|  |  * @param message {type.*} | ||||||
|  |  */ | ||||||
|  | TPKT.prototype.send = function(message) { | ||||||
|  | 	this.transport.send(new type.Component([ | ||||||
|  | 	    new type.UInt8(Action.FASTPATH_ACTION_X224), | ||||||
|  | 	    new type.UInt8(0), | ||||||
|  | 	    new type.UInt16Be(message.size() + 4), | ||||||
|  | 	    message | ||||||
|  | 	])); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * close stack | ||||||
|  |  */ | ||||||
|  | TPKT.prototype.close = function() { | ||||||
|  | 	this.transport.close(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = TPKT; | ||||||
|  | 
 | ||||||
							
								
								
									
										346
									
								
								rdp/protocol/x224.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								rdp/protocol/x224.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,346 @@ | |||||||
|  | /* | ||||||
|  |  * 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 type = require('../core').type; | ||||||
|  | var log = require('../core').log; | ||||||
|  | var error = require('../core').error; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Message type present in X224 packet header | ||||||
|  |  */ | ||||||
|  | var MessageType = { | ||||||
|  | 	X224_TPDU_CONNECTION_REQUEST : 0xE0, | ||||||
|  | 	X224_TPDU_CONNECTION_CONFIRM : 0xD0, | ||||||
|  | 	X224_TPDU_DISCONNECT_REQUEST : 0x80, | ||||||
|  | 	X224_TPDU_DATA : 0xF0, | ||||||
|  | 	X224_TPDU_ERROR : 0x70 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Type of negotiation present in negotiation packet | ||||||
|  |  */ | ||||||
|  | var NegotiationType = { | ||||||
|  | 	TYPE_RDP_NEG_REQ : 0x01, | ||||||
|  | 	TYPE_RDP_NEG_RSP : 0x02, | ||||||
|  | 	TYPE_RDP_NEG_FAILURE : 0x03	 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Protocols available for x224 layer | ||||||
|  |  */ | ||||||
|  | var Protocols = { | ||||||
|  | 	PROTOCOL_RDP : 0x00000000, | ||||||
|  | 	PROTOCOL_SSL : 0x00000001, | ||||||
|  | 	PROTOCOL_HYBRID : 0x00000002, | ||||||
|  | 	PROTOCOL_HYBRID_EX : 0x00000008	 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Use to negotiate security layer of RDP stack | ||||||
|  |  * In node-rdpjs only ssl is available | ||||||
|  |  * @param opt {object} component type options | ||||||
|  |  * @see request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
 | ||||||
|  |  * @see response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
 | ||||||
|  |  * @see failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
 | ||||||
|  |  */ | ||||||
|  | function negotiation(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		type : new type.UInt8(), | ||||||
|  | 		flag : new type.UInt8(), | ||||||
|  | 		length : new type.UInt16Le(0x0008, { constant : true }), | ||||||
|  | 		result : new type.UInt32Le() | ||||||
|  | 	}; | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * X224 client connection request | ||||||
|  |  * @param opt {object} component type options | ||||||
|  |  * @see	http://msdn.microsoft.com/en-us/library/cc240470.aspx
 | ||||||
|  |  */ | ||||||
|  | function clientConnectionRequestPDU(opt, cookie) { | ||||||
|  | 	var self = { | ||||||
|  | 		len : new type.UInt8(function() {  | ||||||
|  | 			return new type.Component(self).size() - 1;  | ||||||
|  | 		}), | ||||||
|  | 		code : new type.UInt8(MessageType.X224_TPDU_CONNECTION_REQUEST, { constant : true }), | ||||||
|  | 		padding : new type.Component([new type.UInt16Le(), new type.UInt16Le(), new type.UInt8()]), | ||||||
|  | 		cookie : cookie || new type.Factory( function (s) { | ||||||
|  | 			var offset = 0; | ||||||
|  | 			while (true) { | ||||||
|  | 				var token = s.buffer.readUInt16LE(s.offset + offset); | ||||||
|  | 				if (token === 0x0a0d) { | ||||||
|  | 					self.cookie = new type.BinaryString(null, { readLength : new type.CallableValue(offset + 2) }).read(s); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  | 				else { | ||||||
|  | 					offset += 1; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}, { conditional : function () { | ||||||
|  | 			return self.len.value > 14; | ||||||
|  | 		}}), | ||||||
|  | 		protocolNeg : negotiation({ optional : true }) | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * X224 Server connection confirm | ||||||
|  |  * @param opt {object} component type options | ||||||
|  |  * @see	http://msdn.microsoft.com/en-us/library/cc240506.aspx
 | ||||||
|  |  */ | ||||||
|  | function serverConnectionConfirm(opt) { | ||||||
|  | 	var self = { | ||||||
|  | 		len : new type.UInt8(function() {  | ||||||
|  | 			return new type.Component(self).size() - 1;  | ||||||
|  | 		}), | ||||||
|  | 		code : new type.UInt8(MessageType.X224_TPDU_CONNECTION_CONFIRM, { constant : true }), | ||||||
|  | 		padding : new type.Component([new type.UInt16Le(), new type.UInt16Le(), new type.UInt8()]), | ||||||
|  | 		protocolNeg : negotiation({ optional : true }) | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	return new type.Component(self, opt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Header of each data message from x224 layer | ||||||
|  |  * @returns {type.Component} | ||||||
|  |  */ | ||||||
|  | function x224DataHeader() { | ||||||
|  | 	var self = { | ||||||
|  | 		header : new type.UInt8(2), | ||||||
|  | 		messageType : new type.UInt8(MessageType.X224_TPDU_DATA, { constant : true }), | ||||||
|  | 		separator : new type.UInt8(0x80, { constant : true })	 | ||||||
|  | 	}; | ||||||
|  | 	return new type.Component(self); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Common X224 Automata | ||||||
|  |  * @param presentation {Layer} presentation layer | ||||||
|  |  */ | ||||||
|  | function X224(transport) { | ||||||
|  | 	this.transport = transport; | ||||||
|  |     this.requestedProtocol = Protocols.PROTOCOL_SSL | Protocols.PROTOCOL_HYBRID; | ||||||
|  |     this.selectedProtocol = Protocols.PROTOCOL_SSL | Protocols.PROTOCOL_HYBRID; | ||||||
|  | 	 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.on('close', function() { | ||||||
|  | 		self.emit('close'); | ||||||
|  | 	}).on('error', function (err) { | ||||||
|  | 		self.emit('error', err); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from Layer
 | ||||||
|  | inherits(X224, events.EventEmitter); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Main data received function  | ||||||
|  |  * after connection sequence | ||||||
|  |  * @param s {type.Stream} stream formated from transport layer | ||||||
|  |  */ | ||||||
|  | X224.prototype.recvData = function(s) { | ||||||
|  |     // check header
 | ||||||
|  | 	x224DataHeader().read(s); | ||||||
|  | 	this.emit('data', s); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Format message from x224 layer to transport layer | ||||||
|  |  * @param message {type} | ||||||
|  |  * @returns {type.Component} x224 formated message | ||||||
|  |  */ | ||||||
|  | X224.prototype.send = function(message) { | ||||||
|  | 	this.transport.send(new type.Component([x224DataHeader(), message])); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Client x224 automata | ||||||
|  |  * @param transport {events.EventEmitter} (bind data events) | ||||||
|  |  */ | ||||||
|  | function Client(transport, config) { | ||||||
|  |     this.config = config; | ||||||
|  |     X224.call(this, transport); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from X224 automata
 | ||||||
|  | inherits(Client, X224); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Client automata connect event | ||||||
|  |  */ | ||||||
|  | Client.prototype.connect = function() { | ||||||
|  | 	var message = clientConnectionRequestPDU(null, new type.BinaryString()); | ||||||
|  | 	message.obj.protocolNeg.obj.type.value = NegotiationType.TYPE_RDP_NEG_REQ; | ||||||
|  | 	message.obj.protocolNeg.obj.result.value = this.requestedProtocol; | ||||||
|  | 	this.transport.send(message); | ||||||
|  | 
 | ||||||
|  | 	// next state wait connection confirm packet
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('data', function(s) { | ||||||
|  | 		self.recvConnectionConfirm(s); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * close stack | ||||||
|  |  */ | ||||||
|  | Client.prototype.close = function() { | ||||||
|  | 	this.transport.close(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Receive connection from server | ||||||
|  |  * @param s {Stream} | ||||||
|  |  */ | ||||||
|  | Client.prototype.recvConnectionConfirm = function(s) { | ||||||
|  | 	var message = serverConnectionConfirm().read(s); | ||||||
|  | 
 | ||||||
|  | 	if (message.obj.protocolNeg.obj.type.value == NegotiationType.TYPE_RDP_NEG_FAILURE) { | ||||||
|  | 		throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NEG_FAILURE', | ||||||
|  | 			'Failure code:' + message.obj.protocolNeg.obj.result.value + " (see https://msdn.microsoft.com/en-us/library/cc240507.aspx)"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (message.obj.protocolNeg.obj.type.value == NegotiationType.TYPE_RDP_NEG_RSP) { | ||||||
|  | 		this.selectedProtocol = message.obj.protocolNeg.obj.result.value; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     if ([Protocols.PROTOCOL_HYBRID_EX].indexOf(this.selectedProtocol) !== -1) { | ||||||
|  |         throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NLA_NOT_SUPPORTED'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 	if (this.selectedProtocol == Protocols.PROTOCOL_RDP) { | ||||||
|  | 		log.debug("RDP standard security selected"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |     if (this.selectedProtocol == Protocols.PROTOCOL_HYBRID) { | ||||||
|  |         log.debug("NLA security layer selected"); | ||||||
|  |         var self = this; | ||||||
|  |         var transportEx = this.transport.transport; | ||||||
|  |         this.transport.transport.startTLS(function () { | ||||||
|  |             //console.log('TLS connected, start cssp_connect()');
 | ||||||
|  |             var NLA = require('./nla'); | ||||||
|  |             self.nla = new NLA(transportEx, function () { self.nlaCompleted(); }, self.config.domain, self.config.userName, self.config.password); | ||||||
|  |             self.nla.sendNegotiateMessage(); | ||||||
|  |         }); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 	// finish connection sequence
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.on('data', function(s) { | ||||||
|  | 		self.recvData(s); | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  |     if (this.selectedProtocol == Protocols.PROTOCOL_SSL) { | ||||||
|  | 		log.debug("SSL standard security selected"); | ||||||
|  | 		this.transport.transport.startTLS(function() { | ||||||
|  | 			self.emit('connect', self.selectedProtocol); | ||||||
|  | 		}); | ||||||
|  | 		return; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Called when NLA is completed | ||||||
|  |  */ | ||||||
|  | Client.prototype.nlaCompleted = function () { | ||||||
|  |     const self = this; | ||||||
|  |     delete self.nla; | ||||||
|  |     this.transport.on('data', function (s) { self.recvData(s); }); | ||||||
|  |     this.emit('connect', this.selectedProtocol); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Server x224 automata | ||||||
|  |  */ | ||||||
|  | function Server(transport, keyFilePath, crtFilePath) { | ||||||
|  | 	X224.call(this, transport); | ||||||
|  | 	this.keyFilePath = keyFilePath; | ||||||
|  | 	this.crtFilePath = crtFilePath; | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.once('data', function (s) { | ||||||
|  | 		self.recvConnectionRequest(s); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //inherit from X224 automata
 | ||||||
|  | inherits(Server, X224); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240470.aspx
 | ||||||
|  |  * @param s {type.Stream} | ||||||
|  |  */ | ||||||
|  | Server.prototype.recvConnectionRequest = function (s) { | ||||||
|  | 	var request = clientConnectionRequestPDU().read(s); | ||||||
|  | 	if (!request.obj.protocolNeg.isReaded) { | ||||||
|  | 		throw new Error('NODE_RDP_PROTOCOL_X224_NO_BASIC_SECURITY_LAYER'); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	this.requestedProtocol = request.obj.protocolNeg.obj.result.value; | ||||||
|  | 	this.selectedProtocol = this.requestedProtocol & Protocols.PROTOCOL_SSL; | ||||||
|  | 	 | ||||||
|  | 	if (!(this.selectedProtocol & Protocols.PROTOCOL_SSL)) { | ||||||
|  | 		var confirm = serverConnectionConfirm(); | ||||||
|  | 		confirm.obj.protocolNeg.obj.type.value = NegociationType.TYPE_RDP_NEG_FAILURE; | ||||||
|  | 		confirm.obj.protocolNeg.obj.result.value = NegotiationFailureCode.SSL_REQUIRED_BY_SERVER; | ||||||
|  | 		this.transport.send(confirm); | ||||||
|  | 		this.close(); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		this.sendConnectionConfirm(); | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Start SSL connection if needed | ||||||
|  |  * @see http://msdn.microsoft.com/en-us/library/cc240501.aspx
 | ||||||
|  |  */ | ||||||
|  | Server.prototype.sendConnectionConfirm = function () { | ||||||
|  | 	var confirm = serverConnectionConfirm(); | ||||||
|  | 	confirm.obj.protocolNeg.obj.type.value = NegotiationType.TYPE_RDP_NEG_RSP; | ||||||
|  | 	confirm.obj.protocolNeg.obj.result.value = this.selectedProtocol; | ||||||
|  | 	this.transport.send(confirm); | ||||||
|  | 	 | ||||||
|  | 	// finish connection sequence
 | ||||||
|  | 	var self = this; | ||||||
|  | 	this.transport.on('data', function(s) { | ||||||
|  | 		self.recvData(s); | ||||||
|  | 	}); | ||||||
|  | 	 | ||||||
|  | 	this.transport.transport.listenTLS(this.keyFilePath, this.crtFilePath, function() { | ||||||
|  | 		log.debug('start SSL connection'); | ||||||
|  | 		self.emit('connect', self.requestedProtocol); | ||||||
|  | 	}); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module exports | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 		Client : Client, | ||||||
|  | 		Server : Server | ||||||
|  | }; | ||||||
							
								
								
									
										26
									
								
								rdp/security/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								rdp/security/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | /* | ||||||
|  |  * 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 x509 = require('./x509'); | ||||||
|  | var rsa = require('./rsa'); | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  | 	x509 : x509, | ||||||
|  | 	rsa : rsa | ||||||
|  | }; | ||||||
							
								
								
									
										1543
									
								
								rdp/security/jsbn.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1543
									
								
								rdp/security/jsbn.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										43
									
								
								rdp/security/rsa.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								rdp/security/rsa.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | /* | ||||||
|  |  * 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 BigInteger = require('./jsbn'); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @param modulus {Buffer} | ||||||
|  |  * @param pubExp {integer} | ||||||
|  |  */ | ||||||
|  | function publicKey(modulus, pubExp) { | ||||||
|  | 	return { | ||||||
|  | 		n : modulus, | ||||||
|  | 		e : pubExp | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function encrypt(data, publicKey) { | ||||||
|  | 	return new BigInteger(data).modPowInt(publicKey.e, new BigInteger(publicKey.n)).toBuffer(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module Export | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	publicKey : publicKey, | ||||||
|  | 	encrypt : encrypt | ||||||
|  | }; | ||||||
							
								
								
									
										216
									
								
								rdp/security/x509.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								rdp/security/x509.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,216 @@ | |||||||
|  | /* | ||||||
|  |  * 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/>.
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | // https://tools.ietf.org/html/rfc5280
 | ||||||
|  | 
 | ||||||
|  | var asn1 = require('../asn1'); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 20
 | ||||||
|  |  * @returns {asn1.univ.Choice} | ||||||
|  |  */ | ||||||
|  | function DirectoryString() { | ||||||
|  | 	return new asn1.univ.Choice({ | ||||||
|  | 		teletexString : new asn1.univ.T61String(), | ||||||
|  | 		printableString : new asn1.univ.PrintableString(), | ||||||
|  | 		universalString : new asn1.univ.UniversalString(), | ||||||
|  | 		utf8String : new asn1.univ.UTF8String(), | ||||||
|  | 		bmpString : new asn1.univ.BMPString(), | ||||||
|  | 		ia5String : new asn1.univ.IA5String() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * https://tools.ietf.org/html/rfc5280 page 20
 | ||||||
|  |  * @returns {asn1.univ.Choice} | ||||||
|  |  */ | ||||||
|  | function AttributeValue() { | ||||||
|  | 	return DirectoryString(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 20
 | ||||||
|  |  * @returns {asn1.univ.ObjectIdentifier} | ||||||
|  |  */ | ||||||
|  | function AttributeType() { | ||||||
|  | 	return new asn1.univ.ObjectIdentifier(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 20
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function AttributeTypeAndValue() { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		type : AttributeType(), | ||||||
|  | 		value : AttributeValue() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * https://tools.ietf.org/html/rfc5280 page 116
 | ||||||
|  |  * @returns {asn1.univ.SetOf} | ||||||
|  |  */ | ||||||
|  | function RelativeDistinguishedName() { | ||||||
|  | 	return new asn1.univ.SetOf(AttributeTypeAndValue); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * https://tools.ietf.org/html/rfc5280 page 116
 | ||||||
|  |  * @returns {asn1.univ.SequenceOf} | ||||||
|  |  */ | ||||||
|  | function RDNSequence() { | ||||||
|  | 	return new asn1.univ.SequenceOf(RelativeDistinguishedName); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 116
 | ||||||
|  |  * @returns {asn1.univ.Choice} | ||||||
|  |  */ | ||||||
|  | function Name() { | ||||||
|  | 	return new asn1.univ.Choice({ | ||||||
|  | 		rdnSequence : RDNSequence() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 18
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function AlgorithmIdentifier() { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		algorithm : new asn1.univ.ObjectIdentifier(), | ||||||
|  | 		parameters : new asn1.univ.Null() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function Extension() { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		extnID : new asn1.univ.ObjectIdentifier(), | ||||||
|  | 		critical : new asn1.univ.Boolean(), | ||||||
|  | 		extnValue : new asn1.univ.OctetString() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.SequenceOf} | ||||||
|  |  */ | ||||||
|  | function Extensions() { | ||||||
|  | 	return new asn1.univ.SequenceOf(Extension); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.Choice} | ||||||
|  |  */ | ||||||
|  | function Time() { | ||||||
|  | 	return new asn1.univ.Choice({ | ||||||
|  | 		utcTime : new asn1.univ.UTCTime(), | ||||||
|  | 		generalTime : new asn1.univ.GeneralizedTime() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function Validity() { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		notBefore : Time(), | ||||||
|  | 		notAfter : Time() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.Integer} | ||||||
|  |  */ | ||||||
|  | function CertificateSerialNumber() { | ||||||
|  | 	return new asn1.univ.Integer(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function SubjectPublicKeyInfo() { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		algorithm : AlgorithmIdentifier(), | ||||||
|  | 		subjectPublicKey : new asn1.univ.BitString() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.BitString} | ||||||
|  |  */ | ||||||
|  | function UniqueIdentifier() { | ||||||
|  | 	return new asn1.univ.BitString(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function TbsCertificate() { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		version : CertificateSerialNumber().explicitTag(new asn1.spec.Asn1Tag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Constructed, 0)), | ||||||
|  | 		serialNumber : new asn1.univ.Integer(), | ||||||
|  | 		signature : AlgorithmIdentifier(), | ||||||
|  | 		issuer : Name(), | ||||||
|  | 		validity : Validity(), | ||||||
|  | 		subject : Name(), | ||||||
|  | 		subjectPublicKeyInfo : SubjectPublicKeyInfo(), | ||||||
|  | 		issuerUniqueID : UniqueIdentifier().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 1).optional(), | ||||||
|  | 		subjectUniqueID : UniqueIdentifier().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 2).optional(), | ||||||
|  | 		extensions : Extensions().implicitTag(asn1.spec.TagClass.Context, asn1.spec.TagFormat.Primitive, 3).optional() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @see https://tools.ietf.org/html/rfc5280 page 117
 | ||||||
|  |  * @returns {asn1.univ.Sequence} | ||||||
|  |  */ | ||||||
|  | function X509Certificate() { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		tbsCertificate : TbsCertificate(), | ||||||
|  | 		signatureAlgorithm : AlgorithmIdentifier(), | ||||||
|  | 		signatureValue : new asn1.univ.BitString() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function RSAPublicKey() { | ||||||
|  | 	return new asn1.univ.Sequence({ | ||||||
|  | 		modulus : new asn1.univ.Integer(), | ||||||
|  | 		publicExponent : new asn1.univ.Integer() | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module Export | ||||||
|  |  */ | ||||||
|  | module.exports = { | ||||||
|  | 	X509Certificate : X509Certificate, | ||||||
|  | 	RSAPublicKey : RSAPublicKey | ||||||
|  | }; | ||||||
| @ -2931,7 +2931,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||||||
|         if (domain.sessionrecording != null) { features += 0x08000000; } // Server recordings enabled
 |         if (domain.sessionrecording != null) { features += 0x08000000; } // Server recordings enabled
 | ||||||
|         if (domain.urlswitching === false) { features += 0x10000000; } // Disables the URL switching feature
 |         if (domain.urlswitching === false) { features += 0x10000000; } // Disables the URL switching feature
 | ||||||
|         if (domain.novnc === false) { features += 0x20000000; } // Disables noVNC
 |         if (domain.novnc === false) { features += 0x20000000; } // Disables noVNC
 | ||||||
|         if (domain.mstsc !== true) { features += 0x40000000; } // Disables MSTSC.js
 |         if (domain.mstsc === false) { features += 0x40000000; } // Disables MSTSC.js
 | ||||||
|         if (obj.isTrustedCert(domain) == false) { features += 0x80000000; } // Indicate we are not using a trusted certificate
 |         if (obj.isTrustedCert(domain) == false) { features += 0x80000000; } // Indicate we are not using a trusted certificate
 | ||||||
|         if (obj.parent.amtManager != null) { features2 += 0x00000001; } // Indicates that the Intel AMT manager is active
 |         if (obj.parent.amtManager != null) { features2 += 0x00000001; } // Indicates that the Intel AMT manager is active
 | ||||||
|         if (obj.parent.firebase != null) { features2 += 0x00000002; } // Indicates the server supports Firebase push messaging
 |         if (obj.parent.firebase != null) { features2 += 0x00000002; } // Indicates the server supports Firebase push messaging
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user