fe2a6db786
rust / build / test / clippy / fmt (push) Has been cancelled
Layout:
- src/ .NET 10 x64 reference: MxNativeCodec, MxNativeClient,
MxAsbClient, probes, tests, harnesses. Executable spec.
- design/ Architectural plan for the Rust port (M0–M6), error
model, protocol invariants, risks (R1–R16), adversarial
review log (review.md).
- rust/ Rust workspace. M0 skeleton + M1 codec parity.
mxaccess-codec: 215 unit tests + 2 cross-implementation
parity tests (byte-identical against .NET reference).
Other crates are M0 stubs awaiting M2+.
- captures/ Frida + netsh + pcap evidence per CLAUDE.md
("captures are evidence, not throwaway logs").
- analysis/ Decompiled C# (frida/proxy/decompiled-*),
Ghidra exports for native DLLs (`exports/` only —
working state at `projects/` and AVEVA's input
binaries at `input/` are gitignored).
- docs/ Reverse-engineering reference docs.
- tools/ Setup-LiveProbeEnv.ps1 (Infisical credential fetcher),
Compute-Crc.ps1 (.NET parity helper).
- .github/workflows/ Rust CI: fmt + build + test + clippy on Windows.
- LICENSE MIT (Joseph Doherty, 2026).
Verified:
- cargo test --workspace → 217 passed (215 unit + 2 .NET parity), 0 failed
- cargo clippy --workspace -- -D warnings → clean
- cargo fmt --all -- --check → clean
- cargo publish --dry-run -p mxaccess-codec → packages cleanly
Excluded from history (see .gitignore):
- **/bin, **/obj, **/target — build artifacts
- analysis/ghidra/projects/ — Ghidra working state (regenerable)
- analysis/ghidra/input/ — AVEVA proprietary DLLs (vendor IP)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
955 lines
29 KiB
C#
955 lines
29 KiB
C#
#define TRACE
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Security;
|
|
using System.Security.AccessControl;
|
|
using System.Text;
|
|
using System.Xml.Linq;
|
|
using Microsoft.Win32;
|
|
|
|
namespace ArchestrAServices.Common;
|
|
|
|
public class RegistryHandler
|
|
{
|
|
private static string asbInstallPath = string.Empty;
|
|
|
|
private static string asbCoreServicesInstallPath = string.Empty;
|
|
|
|
private static string managementServerAddress = string.Empty;
|
|
|
|
public static string ASBSolutionsSubkey = string.Empty;
|
|
|
|
public static string ASBRegistration = "NodeRegistration";
|
|
|
|
public static string LDSPort = "808";
|
|
|
|
public static string PGDSEndPoint = "PrimaryGlobalDiscovery";
|
|
|
|
public static string SGDSEndPoint = "SecondaryGlobalDiscovery";
|
|
|
|
public static string PUDSEndPoint = "PrimaryUniversalDiscovery";
|
|
|
|
public static string SUDSEndPoint = "SecondaryUniversalDiscovery";
|
|
|
|
public static string LDSEndPoint = "EndPointLocalDiscovery";
|
|
|
|
private static string Wow64OptionalLayer
|
|
{
|
|
get
|
|
{
|
|
if (!Environment.Is64BitProcess)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
return "Wow6432Node\\";
|
|
}
|
|
}
|
|
|
|
public static string RegistryPath => "SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\ArchestrAServices\\";
|
|
|
|
public static string Registry32Path => "SOFTWARE\\ArchestrA\\ArchestrAServices\\";
|
|
|
|
public static string ASBSolutionPath => RegistryPath + ASBSolutionsSubkey;
|
|
|
|
public static string ASBNodeRegistraion => $"{RegistryPath}{ASBRegistration}";
|
|
|
|
public static string ASBInstallPath
|
|
{
|
|
get
|
|
{
|
|
if (string.IsNullOrEmpty(asbInstallPath))
|
|
{
|
|
try
|
|
{
|
|
asbInstallPath = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\ArchestrAServices", "ASBInstallPath", string.Empty).ToString();
|
|
}
|
|
catch (NullReferenceException)
|
|
{
|
|
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "ParentKey for ASBInstallPath key was not found in registry");
|
|
}
|
|
}
|
|
return asbInstallPath;
|
|
}
|
|
}
|
|
|
|
public static string AsbCoreServicesInstallPath
|
|
{
|
|
get
|
|
{
|
|
if (!string.IsNullOrEmpty(asbCoreServicesInstallPath))
|
|
{
|
|
return asbCoreServicesInstallPath;
|
|
}
|
|
try
|
|
{
|
|
string text = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\ArchestrAServices", "FwkInstallPath", string.Empty).ToString();
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
asbCoreServicesInstallPath = Path.Combine(text, "CoreServices");
|
|
}
|
|
}
|
|
catch (NullReferenceException)
|
|
{
|
|
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "ParentKey for FwkInstallPath key was not found in registry");
|
|
}
|
|
return asbCoreServicesInstallPath;
|
|
}
|
|
}
|
|
|
|
public static SecureCommunicationModes SecureCommunicationMode
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
string text = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\ArchestrAServices", "SecureCommunicationMode", 0).ToString();
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
int.TryParse(text, out var result);
|
|
return (SecureCommunicationModes)result;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
return SecureCommunicationModes.Never;
|
|
}
|
|
set
|
|
{
|
|
try
|
|
{
|
|
Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\ArchestrAServices", "SecureCommunicationMode", (int)value, RegistryValueKind.DWord);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool AsbManagedCertificates
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
return Convert.ToBoolean(Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\ArchestrAServices", "ASBManagedCertificates", 1));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
return true;
|
|
}
|
|
set
|
|
{
|
|
Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\ArchestrAServices", "ASBManagedCertificates", value, RegistryValueKind.DWord);
|
|
}
|
|
}
|
|
|
|
public static int DefaultSslPort
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
return Convert.ToInt32(Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\WebApplications\\Default", "SslPort", 443));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
return 443;
|
|
}
|
|
set
|
|
{
|
|
Registry.SetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\WebApplications\\Default", "SslPort", value, RegistryValueKind.DWord);
|
|
}
|
|
}
|
|
|
|
public static string ManagementServerAddress
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(managementServerAddress))
|
|
{
|
|
managementServerAddress = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\" + Wow64OptionalLayer + "ArchestrA\\ArchestrAServices", "MSAddress", string.Empty).ToString();
|
|
}
|
|
return managementServerAddress;
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
public static Uri MakeLDSProbeEndpointAddress(string NodeName)
|
|
{
|
|
return new Uri("net.tcp://" + NodeName + "/LDS/Probe");
|
|
}
|
|
|
|
public static Uri MakeLDSEndpointAddress(string NodeName)
|
|
{
|
|
return new Uri("net.tcp://" + NodeName + "/LDS");
|
|
}
|
|
|
|
public static string DeleteFromRegistry(string solutionName)
|
|
{
|
|
string SRNodeName;
|
|
string srNode = GetSrNode(solutionName, out SRNodeName);
|
|
if (!string.IsNullOrEmpty(srNode))
|
|
{
|
|
return srNode;
|
|
}
|
|
if (SRNodeName.ToUpperInvariant() == Environment.MachineName.ToUpperInvariant())
|
|
{
|
|
return "Cannot delete the SR node solution.";
|
|
}
|
|
string subkey = RegistryPath;
|
|
if (!string.IsNullOrEmpty(solutionName))
|
|
{
|
|
subkey = ASBSolutionPath + solutionName;
|
|
}
|
|
try
|
|
{
|
|
Registry.LocalMachine.DeleteSubKeyTree(subkey);
|
|
return "Success";
|
|
}
|
|
catch (ArgumentNullException ex)
|
|
{
|
|
return "Node Does not exist to delete: " + ex.Message;
|
|
}
|
|
catch (SecurityException ex2)
|
|
{
|
|
return "Security Error: " + ex2.Message;
|
|
}
|
|
catch (ArgumentException ex3)
|
|
{
|
|
return "Node Does not exist to delete: " + ex3.Message;
|
|
}
|
|
catch (ObjectDisposedException ex4)
|
|
{
|
|
return ex4.Message;
|
|
}
|
|
catch (UnauthorizedAccessException ex5)
|
|
{
|
|
return "UnauthorizedAccessException: " + ex5.Message;
|
|
}
|
|
}
|
|
|
|
public static string CreateASBConfigInfoStructureInRegistry(ASBConfigurationInformation securityConfiguration, string srNode, bool isRegister)
|
|
{
|
|
try
|
|
{
|
|
if (securityConfiguration != null)
|
|
{
|
|
CreateSolutionKey(securityConfiguration);
|
|
CreateNodeRegistrationyKey(securityConfiguration, isRegister);
|
|
return "Success";
|
|
}
|
|
return "Cannot write security configuration to registry: Please provide SecurityConfiguration";
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
return "Cannot write security configuration to registry: " + ex.Message;
|
|
}
|
|
catch (SecurityException ex2)
|
|
{
|
|
return "Cannot write security configuration to registry: " + ex2.Message;
|
|
}
|
|
catch (IOException ex3)
|
|
{
|
|
return "Cannot write security configuration to registry: " + ex3.Message;
|
|
}
|
|
catch (ObjectDisposedException ex4)
|
|
{
|
|
return "Cannot write security configuration to registry: " + ex4.Message;
|
|
}
|
|
}
|
|
|
|
public static string ReadASBConfigInfoStructureFromRegistry(string solutionName, out ASBConfigurationInformation securityConfiguration)
|
|
{
|
|
string empty = string.Empty;
|
|
string text = solutionName;
|
|
string DefaultSolutionName;
|
|
string defaultSolutionName = GetDefaultSolutionName(out DefaultSolutionName);
|
|
if (string.IsNullOrEmpty(solutionName))
|
|
{
|
|
if (string.IsNullOrEmpty(defaultSolutionName))
|
|
{
|
|
securityConfiguration = null;
|
|
return "Read of default ASBSolution requested, but no default on local machine";
|
|
}
|
|
text = DefaultSolutionName;
|
|
}
|
|
RegistryKey registryKey = null;
|
|
using (RegistryKey registryKey2 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
|
|
{
|
|
registryKey = registryKey2.OpenSubKey(Registry32Path + "\\" + text);
|
|
registryKey2.Close();
|
|
if (registryKey == null)
|
|
{
|
|
securityConfiguration = null;
|
|
return "ASBSolution " + text + " does not exist local machine";
|
|
}
|
|
}
|
|
using (registryKey)
|
|
{
|
|
securityConfiguration = FillConfigurationFromRegistry(registryKey, text, DefaultSolutionName);
|
|
registryKey.Close();
|
|
return empty;
|
|
}
|
|
}
|
|
|
|
private static ASBConfigurationInformation FillConfigurationFromRegistry(RegistryKey asbSolutionKey, string solutionNameToRead, string defaultSolutionName)
|
|
{
|
|
if (asbSolutionKey == null)
|
|
{
|
|
return null;
|
|
}
|
|
ASBConfigurationInformation aSBConfigurationInformation = new ASBConfigurationInformation
|
|
{
|
|
SolutionName = solutionNameToRead
|
|
};
|
|
try
|
|
{
|
|
aSBConfigurationInformation.Generator = asbSolutionKey.GetValue("Generator", string.Empty).ToString();
|
|
aSBConfigurationInformation.Prime = asbSolutionKey.GetValue("Prime", string.Empty).ToString();
|
|
aSBConfigurationInformation.HashAlgorithm = asbSolutionKey.GetValue("HashAlgorthim", string.Empty).ToString();
|
|
aSBConfigurationInformation.InitializationVector = asbSolutionKey.GetValue("initailizationVector", string.Empty).ToString();
|
|
aSBConfigurationInformation.SaltValue = asbSolutionKey.GetValue("saltValue", string.Empty).ToString();
|
|
string s = asbSolutionKey.GetValue("passowordIterations", "0").ToString();
|
|
aSBConfigurationInformation.PasswordDerivationIterations = int.Parse(s);
|
|
string s2 = asbSolutionKey.GetValue("keySize", "0").ToString();
|
|
aSBConfigurationInformation.KeySize = int.Parse(s2);
|
|
try
|
|
{
|
|
DPUtility dPUtility = new DPUtility(DPUtility.Store.USE_MACHINE_STORE);
|
|
byte[] bytes = Encoding.Unicode.GetBytes("wonderware");
|
|
byte[] cipherText = (byte[])asbSolutionKey.GetValue("sharedsecret", RegistryValueKind.Binary);
|
|
byte[] bytes2 = dPUtility.Decrypt(cipherText, bytes);
|
|
aSBConfigurationInformation.EncryptedSharedSecret = Encoding.Unicode.GetString(bytes2);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "Reading and decrypting shared secret failed with exception {0}", ex.Message);
|
|
}
|
|
aSBConfigurationInformation.EncryptedCertificate = asbSolutionKey.GetValue("Certificate", RegistryValueKind.String).ToString();
|
|
aSBConfigurationInformation.IsDefault = ((string.Compare(solutionNameToRead, defaultSolutionName, ignoreCase: true) == 0) ? "true" : "false");
|
|
if (string.IsNullOrEmpty(GetSrNode(solutionNameToRead, out var SRNodeName)))
|
|
{
|
|
aSBConfigurationInformation.SRNodeName = SRNodeName;
|
|
}
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "Failed to read a solution element for ASB Solution {0} with exception {1}", solutionNameToRead, ex2.Message);
|
|
}
|
|
return aSBConfigurationInformation;
|
|
}
|
|
|
|
private static void CreateNodeRegistrationyKey(ASBConfigurationInformation securityConfiguration, bool isRegister)
|
|
{
|
|
RegistryKey registryKey = Registry.LocalMachine.CreateSubKey(ASBSolutionPath + securityConfiguration.SolutionName + "\\NodeRegistration", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None);
|
|
Uri uri = MakeLDSEndpointAddress(securityConfiguration.SRNodeName);
|
|
if (registryKey != null)
|
|
{
|
|
SetSecurityParameter(uri.AbsoluteUri, registryKey, LDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.PrimaryGlobalDiscovery, registryKey, PGDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.SecondaryGlobalDiscovery, registryKey, SGDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.PrimaryUniversalDiscovery, registryKey, PUDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.SecondaryUniversalDiscovery, registryKey, SUDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.SRNodeName, registryKey, "ServiceRepositoryNode");
|
|
registryKey.Close();
|
|
registryKey.Dispose();
|
|
}
|
|
if (isRegister && string.Compare(securityConfiguration.IsDefault, "true", StringComparison.OrdinalIgnoreCase) == 0)
|
|
{
|
|
RegistryKey registryKey2 = Registry.LocalMachine.CreateSubKey(RegistryPath + "NodeRegistration", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None);
|
|
Uri uri2 = MakeLDSEndpointAddress(Environment.MachineName);
|
|
if (registryKey2 != null)
|
|
{
|
|
SetSecurityParameter(uri2.AbsoluteUri, registryKey2, LDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.PrimaryGlobalDiscovery, registryKey2, PGDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.SecondaryGlobalDiscovery, registryKey2, SGDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.PrimaryUniversalDiscovery, registryKey2, PUDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.SecondaryUniversalDiscovery, registryKey2, SUDSEndPoint);
|
|
SetSecurityParameter(securityConfiguration.SRNodeName, registryKey2, "ServiceRepositoryNode");
|
|
CreateRootKey(securityConfiguration);
|
|
registryKey2.Close();
|
|
registryKey2.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void CreateRootKey(ASBConfigurationInformation securityConfiguration)
|
|
{
|
|
using RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegistryPath, RegistryKeyPermissionCheck.ReadWriteSubTree);
|
|
registryKey?.SetValue("DefaultASBSolution", securityConfiguration.SolutionName);
|
|
}
|
|
|
|
private static void CreateSolutionKey(ASBConfigurationInformation securityConfiguration)
|
|
{
|
|
RegistryKey registryKey = Registry.LocalMachine.CreateSubKey(ASBSolutionPath + securityConfiguration.SolutionName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None);
|
|
if (registryKey != null)
|
|
{
|
|
SetSecurityParameter(securityConfiguration.EncryptedCertificate, registryKey, "Certificate");
|
|
SetSecurityParameter(securityConfiguration.Generator, registryKey, "Generator");
|
|
SetSecurityParameter(securityConfiguration.HashAlgorithm, registryKey, "HashAlgorthim");
|
|
SetSecurityParameter(securityConfiguration.InitializationVector, registryKey, "initailizationVector");
|
|
SetSecurityParameter(securityConfiguration.SaltValue, registryKey, "saltValue");
|
|
SetSecurityParameter(securityConfiguration.Prime, registryKey, "Prime");
|
|
try
|
|
{
|
|
DPUtility dPUtility = new DPUtility(DPUtility.Store.USE_MACHINE_STORE);
|
|
byte[] bytes = Encoding.Unicode.GetBytes(securityConfiguration.EncryptedSharedSecret);
|
|
byte[] bytes2 = Encoding.Unicode.GetBytes("wonderware");
|
|
byte[] value = dPUtility.Encrypt(bytes, bytes2);
|
|
registryKey.SetValue("sharedsecret", value, RegistryValueKind.Binary);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Failed to write passphrase to registry: {0}", ex.Message);
|
|
}
|
|
registryKey.SetValue("passowordIterations", securityConfiguration.PasswordDerivationIterations);
|
|
registryKey.SetValue("keySize", securityConfiguration.KeySize);
|
|
registryKey.Close();
|
|
registryKey.Dispose();
|
|
}
|
|
}
|
|
|
|
private static void SetSecurityParameter(string securityConfiguration, RegistryKey solutionKey, string name)
|
|
{
|
|
if (!string.IsNullOrEmpty(securityConfiguration))
|
|
{
|
|
solutionKey.SetValue(name, securityConfiguration);
|
|
}
|
|
else
|
|
{
|
|
solutionKey.SetValue(name, string.Empty);
|
|
}
|
|
}
|
|
|
|
public static string CreateUniversalSolutionStructureInRegistry(ASBConfigurationInformation securityConfiguration)
|
|
{
|
|
string result = string.Empty;
|
|
try
|
|
{
|
|
if (securityConfiguration != null)
|
|
{
|
|
using RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(ASBSolutionPath, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.SetValue);
|
|
if (registryKey == null)
|
|
{
|
|
result = "Cannot open parent registry key for creating the Universal Solution.";
|
|
}
|
|
else
|
|
{
|
|
using (RegistryKey registryKey2 = registryKey.OpenSubKey(securityConfiguration.SolutionName))
|
|
{
|
|
if (registryKey2 == null)
|
|
{
|
|
CreateSolutionKey(securityConfiguration);
|
|
}
|
|
}
|
|
registryKey.SetValue("UniversalSolution", securityConfiguration.SolutionName, RegistryValueKind.String);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = "Please provide details for configuring the Universal Solution.";
|
|
}
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
result = ex.Message;
|
|
}
|
|
catch (SecurityException ex2)
|
|
{
|
|
result = ex2.Message;
|
|
}
|
|
catch (IOException ex3)
|
|
{
|
|
result = ex3.Message;
|
|
}
|
|
catch (ObjectDisposedException ex4)
|
|
{
|
|
result = ex4.Message;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static string GetSrNode(out string SRNodeName)
|
|
{
|
|
SRNodeName = string.Empty;
|
|
RegistryKey registryKey = null;
|
|
string result = string.Empty;
|
|
try
|
|
{
|
|
registryKey = Registry.LocalMachine.OpenSubKey(RegistryPath + "NodeRegistration");
|
|
object obj = null;
|
|
if (registryKey != null && (obj = registryKey.GetValue("ServiceRepositoryNode")) != null)
|
|
{
|
|
SRNodeName = obj.ToString();
|
|
if (string.IsNullOrEmpty(SRNodeName))
|
|
{
|
|
result = "Default SR Node name is empty";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = "Unable to open registry key " + RegistryPath + "NodeRegistration\\ServiceRepositoryNode";
|
|
}
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
result = ex.Message;
|
|
}
|
|
catch (SecurityException ex2)
|
|
{
|
|
result = ex2.Message;
|
|
}
|
|
catch (IOException ex3)
|
|
{
|
|
result = ex3.Message;
|
|
}
|
|
catch (ObjectDisposedException ex4)
|
|
{
|
|
result = ex4.Message;
|
|
}
|
|
finally
|
|
{
|
|
registryKey?.Close();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static bool GetSRInstalled()
|
|
{
|
|
bool result = false;
|
|
try
|
|
{
|
|
result = GetBinaryRegistryValue(RegistryPath, "SRInstalled");
|
|
}
|
|
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is SecurityException || ex is IOException || ex is ObjectDisposedException)
|
|
{
|
|
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "GetSRInstalled: Unable to read SR installation status from registry, assuming false: {0}", ex.Message);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static bool GetManagementServerInstalled()
|
|
{
|
|
bool result = false;
|
|
try
|
|
{
|
|
result = GetBinaryRegistryValue(RegistryPath, "MSInstalled");
|
|
}
|
|
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is SecurityException || ex is IOException || ex is ObjectDisposedException)
|
|
{
|
|
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "GetManagementServerInstalled: Unable to read Management Server installation status from registry, assuming false: {0}", ex.Message);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static string GetSrNode(string SolutionName, out string SRNodeName)
|
|
{
|
|
SRNodeName = string.Empty;
|
|
RegistryKey registryKey = null;
|
|
string result = string.Empty;
|
|
try
|
|
{
|
|
registryKey = Registry.LocalMachine.OpenSubKey(ASBSolutionPath + SolutionName + "\\NodeRegistration", writable: true);
|
|
object obj = null;
|
|
if (registryKey != null && (obj = registryKey.GetValue("ServiceRepositoryNode")) != null)
|
|
{
|
|
SRNodeName = obj.ToString();
|
|
if (string.IsNullOrEmpty(SRNodeName))
|
|
{
|
|
result = "Default SR Node name is empty";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = "Unable to open registry key " + ASBSolutionPath + SolutionName + "\\NodeRegistration\\ServiceRepositoryNode";
|
|
}
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
result = ex.Message;
|
|
}
|
|
catch (SecurityException ex2)
|
|
{
|
|
result = ex2.Message;
|
|
}
|
|
catch (IOException ex3)
|
|
{
|
|
result = ex3.Message;
|
|
}
|
|
catch (ObjectDisposedException ex4)
|
|
{
|
|
result = ex4.Message;
|
|
}
|
|
finally
|
|
{
|
|
registryKey?.Close();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static string GetDefaultSolutionName(out string DefaultSolutionName)
|
|
{
|
|
DefaultSolutionName = string.Empty;
|
|
RegistryKey registryKey = null;
|
|
string result = string.Empty;
|
|
try
|
|
{
|
|
registryKey = Registry.LocalMachine.OpenSubKey(RegistryPath, writable: false);
|
|
object obj = null;
|
|
if (registryKey != null && (obj = registryKey.GetValue("DefaultASBSolution")) != null)
|
|
{
|
|
DefaultSolutionName = obj.ToString();
|
|
result = string.Empty;
|
|
}
|
|
else
|
|
{
|
|
result = "Unable to open registry key " + RegistryPath + "\\DefaultASBSolution";
|
|
}
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
result = ex.Message;
|
|
}
|
|
catch (SecurityException ex2)
|
|
{
|
|
result = ex2.Message;
|
|
}
|
|
catch (IOException ex3)
|
|
{
|
|
result = ex3.Message;
|
|
}
|
|
catch (ObjectDisposedException ex4)
|
|
{
|
|
result = ex4.Message;
|
|
}
|
|
finally
|
|
{
|
|
registryKey?.Close();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static string GetSolutionPassphrase(string asbSolution, out string passphrase)
|
|
{
|
|
passphrase = string.Empty;
|
|
string result = string.Empty;
|
|
if (string.IsNullOrEmpty(asbSolution))
|
|
{
|
|
result = GetDefaultSolutionName(out asbSolution);
|
|
}
|
|
if (string.IsNullOrEmpty(asbSolution))
|
|
{
|
|
passphrase = string.Empty;
|
|
return result;
|
|
}
|
|
RegistryKey registryKey = null;
|
|
try
|
|
{
|
|
registryKey = Registry.LocalMachine.OpenSubKey(ASBSolutionPath + asbSolution, writable: false);
|
|
object obj = null;
|
|
if (registryKey != null && (obj = registryKey.GetValue("sharedsecret")) != null)
|
|
{
|
|
try
|
|
{
|
|
byte[] bytes = new DPUtility(DPUtility.Store.USE_MACHINE_STORE).Decrypt(optionalEntropy: Encoding.Unicode.GetBytes("wonderware"), cipherText: (byte[])obj);
|
|
passphrase = Encoding.Unicode.GetString(bytes);
|
|
result = string.Empty;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Failed to read passphrase from registry.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = string.Format("Unable to find the passphrase for the solution: '{0}'. Confirm that local galaxy and remote galaxy (whose solution name is '{0}') have been paired", asbSolution);
|
|
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Unable to open registry key {0}{1}\\sharedsecret", ASBSolutionPath, asbSolution);
|
|
}
|
|
}
|
|
catch (UnauthorizedAccessException ex2)
|
|
{
|
|
result = ex2.Message;
|
|
}
|
|
catch (SecurityException ex3)
|
|
{
|
|
result = ex3.Message;
|
|
}
|
|
catch (IOException ex4)
|
|
{
|
|
result = ex4.Message;
|
|
}
|
|
catch (ObjectDisposedException ex5)
|
|
{
|
|
result = ex5.Message;
|
|
}
|
|
finally
|
|
{
|
|
registryKey?.Close();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static List<string> EnumerateSolutionsAtThisNode()
|
|
{
|
|
_ = string.Empty;
|
|
List<string> list = new List<string>();
|
|
RegistryKey registryKey = null;
|
|
try
|
|
{
|
|
registryKey = Registry.LocalMachine.OpenSubKey(ASBSolutionPath, writable: true);
|
|
if (registryKey != null)
|
|
{
|
|
string[] subKeyNames = registryKey.GetSubKeyNames();
|
|
foreach (string text in subKeyNames)
|
|
{
|
|
if (string.Compare(text, ASBRegistration, ignoreCase: true) != 0)
|
|
{
|
|
list.Add(text);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_ = "Unable to open registry key " + ASBSolutionPath;
|
|
}
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
_ = ex.Message;
|
|
}
|
|
catch (SecurityException ex2)
|
|
{
|
|
_ = ex2.Message;
|
|
}
|
|
catch (IOException ex3)
|
|
{
|
|
_ = ex3.Message;
|
|
}
|
|
catch (ObjectDisposedException ex4)
|
|
{
|
|
_ = ex4.Message;
|
|
}
|
|
finally
|
|
{
|
|
registryKey?.Close();
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public static List<KeyValuePair<string, string>> ReadDiscoveryInfoFromRegistry(string asbSolutionName)
|
|
{
|
|
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
|
|
using (RegistryKey registryKey = Registry.LocalMachine.CreateSubKey(ASBSolutionPath + asbSolutionName + "\\" + ASBRegistration, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
|
|
{
|
|
if (registryKey != null)
|
|
{
|
|
list.Add(new KeyValuePair<string, string>(LDSEndPoint, registryKey.GetValue(LDSEndPoint, string.Empty).ToString()));
|
|
list.Add(new KeyValuePair<string, string>(PGDSEndPoint, registryKey.GetValue(PGDSEndPoint, string.Empty).ToString()));
|
|
list.Add(new KeyValuePair<string, string>(SGDSEndPoint, registryKey.GetValue(SGDSEndPoint, string.Empty).ToString()));
|
|
list.Add(new KeyValuePair<string, string>(PUDSEndPoint, registryKey.GetValue(PUDSEndPoint, string.Empty).ToString()));
|
|
list.Add(new KeyValuePair<string, string>(SUDSEndPoint, registryKey.GetValue(SUDSEndPoint, string.Empty).ToString()));
|
|
list.Add(new KeyValuePair<string, string>("ServiceRepositoryNode", registryKey.GetValue("ServiceRepositoryNode", string.Empty).ToString()));
|
|
registryKey.Close();
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public static bool SetDiscoveryInfoInRegistry(string solutionName, List<KeyValuePair<string, string>> extraInfo, string srNode = null)
|
|
{
|
|
if (extraInfo == null)
|
|
{
|
|
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "SetDiscoveryInfoInRegistry: Unable to proceed with no info to set, not setting Discovery information");
|
|
return false;
|
|
}
|
|
if (!string.IsNullOrEmpty(srNode))
|
|
{
|
|
extraInfo.Add(new KeyValuePair<string, string>("ServiceRepositoryNode", srNode));
|
|
}
|
|
string text = solutionName;
|
|
if (!string.IsNullOrEmpty(GetDefaultSolutionName(out var DefaultSolutionName)))
|
|
{
|
|
DefaultSolutionName = string.Empty;
|
|
}
|
|
if (string.IsNullOrEmpty(text))
|
|
{
|
|
text = DefaultSolutionName;
|
|
}
|
|
if (string.IsNullOrEmpty(text))
|
|
{
|
|
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, "SetDiscoveryInfoInRegistry: Default solution specified, but does not exist, not setting Discovery information");
|
|
return false;
|
|
}
|
|
using (RegistryKey registryKey = Registry.LocalMachine.CreateSubKey(ASBSolutionPath + solutionName + "\\NodeRegistration", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None))
|
|
{
|
|
if (registryKey != null)
|
|
{
|
|
foreach (KeyValuePair<string, string> item in extraInfo)
|
|
{
|
|
if (string.Compare(item.Key, LDSEndPoint) == 0 || string.Compare(item.Key, PGDSEndPoint) == 0 || string.Compare(item.Key, SGDSEndPoint) == 0 || string.Compare(item.Key, PUDSEndPoint) == 0 || string.Compare(item.Key, SUDSEndPoint) == 0 || string.Compare(item.Key, "ServiceRepositoryNode") == 0)
|
|
{
|
|
SetSecurityParameter(item.Value, registryKey, item.Key);
|
|
break;
|
|
}
|
|
}
|
|
registryKey.Close();
|
|
}
|
|
}
|
|
if (string.Compare(text, DefaultSolutionName, ignoreCase: true) == 0)
|
|
{
|
|
using RegistryKey registryKey2 = Registry.LocalMachine.CreateSubKey(RegistryPath + "NodeRegistration", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None);
|
|
if (registryKey2 != null)
|
|
{
|
|
foreach (KeyValuePair<string, string> item2 in extraInfo)
|
|
{
|
|
if (string.Compare(item2.Key, LDSEndPoint) == 0 || string.Compare(item2.Key, PGDSEndPoint) == 0 || string.Compare(item2.Key, SGDSEndPoint) == 0 || string.Compare(item2.Key, PUDSEndPoint) == 0 || string.Compare(item2.Key, SUDSEndPoint) == 0 || string.Compare(item2.Key, "ServiceRepositoryNode") == 0)
|
|
{
|
|
SetSecurityParameter(item2.Value, registryKey2, item2.Key);
|
|
break;
|
|
}
|
|
}
|
|
registryKey2.Close();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static void UpdateDiscoveryInfos(List<KeyValuePair<string, string>> discoveryInfos)
|
|
{
|
|
UpdateDiscoverySingleRegKey(string.Empty, discoveryInfos);
|
|
if (string.IsNullOrEmpty(GetDefaultSolutionName(out var DefaultSolutionName)))
|
|
{
|
|
UpdateDiscoverySingleRegKey(DefaultSolutionName, discoveryInfos);
|
|
}
|
|
}
|
|
|
|
private static void UpdateDiscoverySingleRegKey(string solutionName, List<KeyValuePair<string, string>> discoveryInfos)
|
|
{
|
|
if (solutionName == null)
|
|
{
|
|
solutionName = string.Empty;
|
|
}
|
|
if (!string.IsNullOrEmpty(solutionName))
|
|
{
|
|
solutionName += "\\";
|
|
}
|
|
RegistryKey registryKey = Registry.LocalMachine.CreateSubKey(ASBSolutionPath + solutionName + "NodeRegistration", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None);
|
|
if (registryKey == null)
|
|
{
|
|
return;
|
|
}
|
|
foreach (KeyValuePair<string, string> discoveryInfo in discoveryInfos)
|
|
{
|
|
switch (discoveryInfo.Key)
|
|
{
|
|
case "PrimaryGlobalDiscovery":
|
|
WriteRegistryValue(registryKey, PGDSEndPoint, discoveryInfo.Value);
|
|
break;
|
|
case "SecondaryGlobalDiscovery":
|
|
WriteRegistryValue(registryKey, SGDSEndPoint, discoveryInfo.Value);
|
|
break;
|
|
case "PrimaryUniversalDiscovery":
|
|
WriteRegistryValue(registryKey, PUDSEndPoint, discoveryInfo.Value);
|
|
break;
|
|
case "SecondaryUniversalDiscovery":
|
|
WriteRegistryValue(registryKey, SUDSEndPoint, discoveryInfo.Value);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void WriteRegistryValue(RegistryKey solutionKey, string key, string value)
|
|
{
|
|
if (solutionKey != null)
|
|
{
|
|
if (!string.IsNullOrEmpty(value))
|
|
{
|
|
solutionKey.SetValue(key, value);
|
|
}
|
|
else
|
|
{
|
|
solutionKey.SetValue(key, string.Empty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string GenerateXMLExtraInfo(List<KeyValuePair<string, string>> Parameters)
|
|
{
|
|
XElement xElement = new XElement("extrainfo");
|
|
if (Parameters != null)
|
|
{
|
|
foreach (KeyValuePair<string, string> Parameter in Parameters)
|
|
{
|
|
XElement xElement2 = new XElement("parameter");
|
|
xElement2.Add(new XAttribute("name", Parameter.Key));
|
|
xElement2.Add(new XAttribute("value", Parameter.Value));
|
|
xElement.Add(xElement2);
|
|
}
|
|
}
|
|
return xElement.ToString();
|
|
}
|
|
|
|
public static Dictionary<string, string> ParseXMLExtraInfo(string XMLExtraInfo)
|
|
{
|
|
Dictionary<string, string> dictionary = new Dictionary<string, string>();
|
|
if (!string.IsNullOrEmpty(XMLExtraInfo))
|
|
{
|
|
XElement xElement = null;
|
|
using StringReader stringReader = new StringReader(XMLExtraInfo);
|
|
if (stringReader != null)
|
|
{
|
|
xElement = XElement.Load(stringReader);
|
|
}
|
|
if (xElement != null)
|
|
{
|
|
foreach (XElement item in xElement.Elements("parameter"))
|
|
{
|
|
XAttribute xAttribute = item.Attribute("name");
|
|
XAttribute xAttribute2 = item.Attribute("value");
|
|
if (xAttribute != null && xAttribute2 != null)
|
|
{
|
|
dictionary.Add(xAttribute.Value, xAttribute2.Value);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SvcTrace.DiagException.TraceEvent(TraceEventType.Warning, 0, $"ParseXMLExtraInfo failed to parse XMLExtraInfo {XMLExtraInfo}");
|
|
}
|
|
}
|
|
return dictionary;
|
|
}
|
|
|
|
private static bool GetBinaryRegistryValue(string keyPath, string keyName)
|
|
{
|
|
bool result = false;
|
|
RegistryKey registryKey = null;
|
|
try
|
|
{
|
|
registryKey = Registry.LocalMachine.OpenSubKey(keyPath);
|
|
if (registryKey != null)
|
|
{
|
|
result = Convert.ToBoolean(registryKey.GetValue(keyName));
|
|
}
|
|
registryKey?.Close();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
registryKey?.Close();
|
|
throw;
|
|
}
|
|
return result;
|
|
}
|
|
}
|