mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 14:07:46 +08:00
397 lines
13 KiB
C#
397 lines
13 KiB
C#
using System.Collections.Generic;
|
|
using System;
|
|
using AxWFICALib;
|
|
using System.Drawing;
|
|
using System.Diagnostics;
|
|
using System.Data;
|
|
using AxMSTSCLib;
|
|
using Microsoft.VisualBasic;
|
|
using System.Collections;
|
|
using System.Windows.Forms;
|
|
using System.Xml;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using mRemoteNG.Connection.Protocol;
|
|
using mRemoteNG.App;
|
|
using mRemoteNG.Connection.Protocol.RDP;
|
|
using mRemoteNG.Images;
|
|
using mRemoteNG.Connection;
|
|
using mRemoteNG.Container;
|
|
|
|
|
|
namespace mRemoteNG.Config.Import
|
|
{
|
|
public class RemoteDesktopConnectionManager
|
|
{
|
|
public static void Import(string fileName, TreeNode parentTreeNode)
|
|
{
|
|
XmlDocument xmlDocument = new XmlDocument();
|
|
xmlDocument.Load(fileName);
|
|
|
|
XmlNode rdcManNode = xmlDocument.SelectSingleNode("/RDCMan");
|
|
int schemaVersion = System.Convert.ToInt32(rdcManNode.Attributes["schemaVersion"].Value);
|
|
if (!(schemaVersion == 1))
|
|
{
|
|
throw (new FileFormatException(string.Format("Unsupported schema version ({0}).", schemaVersion)));
|
|
}
|
|
|
|
XmlNode versionNode = rdcManNode.SelectSingleNode("./version");
|
|
Version version = new Version(versionNode.InnerText);
|
|
if (!(version == new Version(2, 2)))
|
|
{
|
|
throw (new FileFormatException(string.Format("Unsupported file version ({0}).", version)));
|
|
}
|
|
|
|
XmlNode fileNode = rdcManNode.SelectSingleNode("./file");
|
|
ImportFileOrGroup(fileNode, parentTreeNode);
|
|
}
|
|
|
|
private static void ImportFileOrGroup(XmlNode xmlNode, TreeNode parentTreeNode)
|
|
{
|
|
XmlNode propertiesNode = xmlNode.SelectSingleNode("./properties");
|
|
string name = propertiesNode.SelectSingleNode("./name").InnerText;
|
|
|
|
TreeNode treeNode = new TreeNode(name);
|
|
parentTreeNode.Nodes.Add(treeNode);
|
|
|
|
Container.ContainerInfo containerInfo = new Container.ContainerInfo();
|
|
containerInfo.TreeNode = treeNode;
|
|
containerInfo.Name = name;
|
|
|
|
Connection.ConnectionInfo connectionInfo = ConnectionInfoFromXml(propertiesNode);
|
|
connectionInfo.Parent = containerInfo;
|
|
connectionInfo.IsContainer = true;
|
|
containerInfo.ConnectionInfo = connectionInfo;
|
|
|
|
// We can only inherit from a container node, not the root node or connection nodes
|
|
if (Tree.Node.GetNodeType(parentTreeNode) == Tree.TreeNodeType.Container)
|
|
{
|
|
containerInfo.Parent = parentTreeNode.Tag;
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Inherit.TurnOffInheritanceCompletely();
|
|
}
|
|
|
|
treeNode.Name = name;
|
|
treeNode.Tag = containerInfo;
|
|
treeNode.ImageIndex = (int)TreeImageType.Container;
|
|
treeNode.SelectedImageIndex = (int)TreeImageType.Container;
|
|
|
|
foreach (XmlNode childNode in xmlNode.SelectNodes("./group|./server"))
|
|
{
|
|
switch (childNode.Name)
|
|
{
|
|
case "group":
|
|
ImportFileOrGroup(childNode, treeNode);
|
|
break;
|
|
case "server":
|
|
ImportServer(childNode, treeNode);
|
|
break;
|
|
}
|
|
}
|
|
|
|
containerInfo.IsExpanded = bool.Parse(propertiesNode.SelectSingleNode("./expanded").InnerText);
|
|
if (containerInfo.IsExpanded)
|
|
{
|
|
treeNode.Expand();
|
|
}
|
|
|
|
Runtime.ContainerList.Add(containerInfo);
|
|
}
|
|
|
|
private static void ImportServer(XmlNode serverNode, TreeNode parentTreeNode)
|
|
{
|
|
string name = serverNode.SelectSingleNode("./displayName").InnerText;
|
|
TreeNode treeNode = new TreeNode(name);
|
|
parentTreeNode.Nodes.Add(treeNode);
|
|
|
|
ConnectionInfo connectionInfo = ConnectionInfoFromXml(serverNode);
|
|
connectionInfo.TreeNode = treeNode;
|
|
connectionInfo.Parent = (ContainerInfo)parentTreeNode.Tag;
|
|
|
|
treeNode.Name = name;
|
|
treeNode.Tag = connectionInfo;
|
|
treeNode.ImageIndex = (int)TreeImageType.ConnectionClosed;
|
|
treeNode.SelectedImageIndex = (int)TreeImageType.ConnectionClosed;
|
|
|
|
Runtime.ConnectionList.Add(connectionInfo);
|
|
}
|
|
|
|
private static ConnectionInfo ConnectionInfoFromXml(XmlNode xmlNode)
|
|
{
|
|
ConnectionInfo connectionInfo = new ConnectionInfo();
|
|
connectionInfo.Inherit = new ConnectionInfoInheritance(connectionInfo);
|
|
|
|
string name = xmlNode.SelectSingleNode("./name").InnerText;
|
|
|
|
string displayName = "";
|
|
XmlNode displayNameNode = xmlNode.SelectSingleNode("./displayName");
|
|
if (displayNameNode == null)
|
|
{
|
|
displayName = name;
|
|
}
|
|
else
|
|
{
|
|
displayName = displayNameNode.InnerText;
|
|
}
|
|
|
|
connectionInfo.Name = displayName;
|
|
connectionInfo.Description = xmlNode.SelectSingleNode("./comment").InnerText;
|
|
connectionInfo.Hostname = name;
|
|
|
|
XmlNode logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
|
|
if (logonCredentialsNode.Attributes["inherit"].Value == "None")
|
|
{
|
|
connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName").InnerText;
|
|
|
|
XmlNode passwordNode = logonCredentialsNode.SelectSingleNode("./password");
|
|
if (passwordNode.Attributes["storeAsClearText"].Value == "True")
|
|
{
|
|
connectionInfo.Password = passwordNode.InnerText;
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Password = DecryptPassword(passwordNode.InnerText);
|
|
}
|
|
|
|
connectionInfo.Domain = logonCredentialsNode.SelectSingleNode("./domain").InnerText;
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Inherit.Username = true;
|
|
connectionInfo.Inherit.Password = true;
|
|
connectionInfo.Inherit.Domain = true;
|
|
}
|
|
|
|
XmlNode connectionSettingsNode = xmlNode.SelectSingleNode("./connectionSettings");
|
|
if (connectionSettingsNode.Attributes["inherit"].Value == "None")
|
|
{
|
|
connectionInfo.UseConsoleSession = bool.Parse(connectionSettingsNode.SelectSingleNode("./connectToConsole").InnerText);
|
|
// ./startProgram
|
|
// ./workingDir
|
|
connectionInfo.Port = Convert.ToInt32(connectionSettingsNode.SelectSingleNode("./port").InnerText);
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Inherit.UseConsoleSession = true;
|
|
connectionInfo.Inherit.Port = true;
|
|
}
|
|
|
|
XmlNode gatewaySettingsNode = xmlNode.SelectSingleNode("./gatewaySettings");
|
|
if (gatewaySettingsNode.Attributes["inherit"].Value == "None")
|
|
{
|
|
if (gatewaySettingsNode.SelectSingleNode("./enabled").InnerText == "True")
|
|
{
|
|
connectionInfo.RDGatewayUsageMethod = ProtocolRDP.RDGatewayUsageMethod.Always;
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.RDGatewayUsageMethod = ProtocolRDP.RDGatewayUsageMethod.Never;
|
|
}
|
|
|
|
connectionInfo.RDGatewayHostname = gatewaySettingsNode.SelectSingleNode("./hostName").InnerText;
|
|
connectionInfo.RDGatewayUsername = gatewaySettingsNode.SelectSingleNode("./userName").InnerText;
|
|
|
|
XmlNode passwordNode = logonCredentialsNode.SelectSingleNode("./password");
|
|
if (passwordNode.Attributes["storeAsClearText"].Value == "True")
|
|
{
|
|
connectionInfo.RDGatewayPassword = passwordNode.InnerText;
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Password = DecryptPassword(passwordNode.InnerText);
|
|
}
|
|
|
|
connectionInfo.RDGatewayDomain = gatewaySettingsNode.SelectSingleNode("./domain").InnerText;
|
|
// ./logonMethod
|
|
// ./localBypass
|
|
// ./credSharing
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Inherit.RDGatewayUsageMethod = true;
|
|
connectionInfo.Inherit.RDGatewayHostname = true;
|
|
connectionInfo.Inherit.RDGatewayUsername = true;
|
|
connectionInfo.Inherit.RDGatewayPassword = true;
|
|
connectionInfo.Inherit.RDGatewayDomain = true;
|
|
}
|
|
|
|
XmlNode remoteDesktopNode = xmlNode.SelectSingleNode("./remoteDesktop");
|
|
if (remoteDesktopNode.Attributes["inherit"].Value == "None")
|
|
{
|
|
string resolutionString = Convert.ToString(remoteDesktopNode.SelectSingleNode("./size").InnerText.Replace(" ", ""));
|
|
try
|
|
{
|
|
connectionInfo.Resolution = (ProtocolRDP.RDPResolutions)Enum.Parse(typeof(ProtocolRDP.RDPResolutions), "Res" + resolutionString);
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
connectionInfo.Resolution = ProtocolRDP.RDPResolutions.FitToWindow;
|
|
}
|
|
|
|
if (remoteDesktopNode.SelectSingleNode("./sameSizeAsClientArea").InnerText == "True")
|
|
{
|
|
connectionInfo.Resolution = ProtocolRDP.RDPResolutions.FitToWindow;
|
|
}
|
|
|
|
if (remoteDesktopNode.SelectSingleNode("./fullScreen").InnerText == "True")
|
|
{
|
|
connectionInfo.Resolution = ProtocolRDP.RDPResolutions.Fullscreen;
|
|
}
|
|
|
|
|
|
connectionInfo.Colors = (ProtocolRDP.RDPColors)Enum.Parse(typeof(ProtocolRDP.RDPColors), remoteDesktopNode.SelectSingleNode("./colorDepth").InnerText);
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Inherit.Resolution = true;
|
|
connectionInfo.Inherit.Colors = true;
|
|
}
|
|
|
|
XmlNode localResourcesNode = xmlNode.SelectSingleNode("./localResources");
|
|
if (localResourcesNode.Attributes["inherit"].Value == "None")
|
|
{
|
|
switch (localResourcesNode.SelectSingleNode("./audioRedirection").InnerText)
|
|
{
|
|
case "0": // Bring to this computer
|
|
connectionInfo.RedirectSound = ProtocolRDP.RDPSounds.BringToThisComputer;
|
|
break;
|
|
case "1": // Leave at remote computer
|
|
connectionInfo.RedirectSound = ProtocolRDP.RDPSounds.LeaveAtRemoteComputer;
|
|
break;
|
|
case "2": // Do not play
|
|
connectionInfo.RedirectSound = ProtocolRDP.RDPSounds.DoNotPlay;
|
|
break;
|
|
}
|
|
|
|
// ./audioRedirectionQuality
|
|
// ./audioCaptureRedirection
|
|
|
|
switch (localResourcesNode.SelectSingleNode("./keyboardHook").InnerText)
|
|
{
|
|
case "0": // On the local computer
|
|
connectionInfo.RedirectKeys = false;
|
|
break;
|
|
case "1": // On the remote computer
|
|
connectionInfo.RedirectKeys = true;
|
|
break;
|
|
case "2": // In full screen mode only
|
|
connectionInfo.RedirectKeys = false;
|
|
break;
|
|
}
|
|
|
|
// ./redirectClipboard
|
|
connectionInfo.RedirectDiskDrives = bool.Parse(localResourcesNode.SelectSingleNode("./redirectDrives").InnerText);
|
|
connectionInfo.RedirectPorts = bool.Parse(localResourcesNode.SelectSingleNode("./redirectPorts").InnerText);
|
|
connectionInfo.RedirectPrinters = bool.Parse(localResourcesNode.SelectSingleNode("./redirectPrinters").InnerText);
|
|
connectionInfo.RedirectSmartCards = bool.Parse(localResourcesNode.SelectSingleNode("./redirectSmartCards").InnerText);
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Inherit.RedirectSound = true;
|
|
connectionInfo.Inherit.RedirectKeys = true;
|
|
connectionInfo.Inherit.RedirectDiskDrives = true;
|
|
connectionInfo.Inherit.RedirectPorts = true;
|
|
connectionInfo.Inherit.RedirectPrinters = true;
|
|
connectionInfo.Inherit.RedirectSmartCards = true;
|
|
}
|
|
|
|
XmlNode securitySettingsNode = xmlNode.SelectSingleNode("./securitySettings");
|
|
if (securitySettingsNode.Attributes["inherit"].Value == "None")
|
|
{
|
|
switch (securitySettingsNode.SelectSingleNode("./authentication").InnerText)
|
|
{
|
|
case "0": // No authentication
|
|
connectionInfo.RDPAuthenticationLevel = ProtocolRDP.AuthenticationLevel.NoAuth;
|
|
break;
|
|
case "1": // Do not connect if authentication fails
|
|
connectionInfo.RDPAuthenticationLevel = ProtocolRDP.AuthenticationLevel.AuthRequired;
|
|
break;
|
|
case "2": // Warn if authentication fails
|
|
connectionInfo.RDPAuthenticationLevel = ProtocolRDP.AuthenticationLevel.WarnOnFailedAuth;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
connectionInfo.Inherit.RDPAuthenticationLevel = true;
|
|
}
|
|
|
|
// ./displaySettings/thumbnailScale
|
|
// ./displaySettings/liveThumbnailUpdates
|
|
// ./displaySettings/showDisconnectedThumbnails
|
|
|
|
return connectionInfo;
|
|
}
|
|
|
|
private static string DecryptPassword(string ciphertext)
|
|
{
|
|
if (string.IsNullOrEmpty(ciphertext))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
GCHandle gcHandle = new GCHandle();
|
|
Win32.DATA_BLOB plaintextData = new Win32.DATA_BLOB();
|
|
try
|
|
{
|
|
byte[] ciphertextArray = Convert.FromBase64String(ciphertext);
|
|
gcHandle = System.Runtime.InteropServices.GCHandle.Alloc(ciphertextArray, GCHandleType.Pinned);
|
|
|
|
Win32.DATA_BLOB ciphertextData = new Win32.DATA_BLOB();
|
|
ciphertextData.cbData = ciphertextArray.Length;
|
|
ciphertextData.pbData = gcHandle.AddrOfPinnedObject();
|
|
|
|
Win32.DATA_BLOB temp_optionalEntropy = new Win32.DATA_BLOB();
|
|
IntPtr temp_promptStruct = IntPtr.Zero;
|
|
if (!Win32.CryptUnprotectData(ref ciphertextData, null, ref temp_optionalEntropy, IntPtr.Zero, ref temp_promptStruct, 0, ref plaintextData))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
int plaintextLength = (int) ((double) plaintextData.cbData / 2); // Char = 2 bytes
|
|
char[] plaintextArray = new char[plaintextLength - 1 + 1];
|
|
Marshal.Copy(plaintextData.pbData, plaintextArray, 0, plaintextLength);
|
|
|
|
return new string(plaintextArray);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Runtime.MessageCollector.AddExceptionMessage(message: "RemoteDesktopConnectionManager.DecryptPassword() failed.", ex: ex, logOnly: true);
|
|
return null;
|
|
}
|
|
finally
|
|
{
|
|
if (gcHandle.IsAllocated)
|
|
{
|
|
gcHandle.Free();
|
|
}
|
|
if (!(plaintextData.pbData == IntPtr.Zero))
|
|
{
|
|
Win32.LocalFree(plaintextData.pbData);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ReSharper disable once ClassNeverInstantiated.Local
|
|
private class Win32
|
|
{
|
|
// ReSharper disable InconsistentNaming
|
|
// ReSharper disable IdentifierTypo
|
|
// ReSharper disable StringLiteralTypo
|
|
[DllImport("crypt32.dll", CharSet = CharSet.Unicode)]public static extern bool CryptUnprotectData(ref DATA_BLOB dataIn, string description, ref DATA_BLOB optionalEntropy, IntPtr reserved, ref IntPtr promptStruct, int flags, ref DATA_BLOB dataOut);
|
|
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]public static extern void LocalFree(IntPtr ptr);
|
|
|
|
public struct DATA_BLOB
|
|
{
|
|
public int cbData;
|
|
public IntPtr pbData;
|
|
}
|
|
// ReSharper restore StringLiteralTypo
|
|
// ReSharper restore IdentifierTypo
|
|
// ReSharper restore InconsistentNaming
|
|
}
|
|
}
|
|
} |