using System; using System.Collections.Generic; using System.Linq; using System.Text; using Disco.Models.ClientServices; using System.Security.Cryptography.X509Certificates; using System.IO; using System.Diagnostics; using Microsoft.Win32; using System.Text.RegularExpressions; namespace Disco.Client.Extensions { public static class EnrolExtensions { public static void Build(this Enrol enrol) { enrol.DeviceUUID = Interop.SystemAudit.DeviceUUID; enrol.DeviceSerialNumber = Interop.SystemAudit.DeviceSerialNumber; enrol.DeviceComputerName = Interop.LocalAuthentication.ComputerName; enrol.DeviceManufacturer = Interop.SystemAudit.DeviceManufacturer; enrol.DeviceModel = Interop.SystemAudit.DeviceModel; enrol.DeviceModelType = Interop.SystemAudit.DeviceType; enrol.DeviceIsPartOfDomain = Interop.SystemAudit.DeviceIsPartOfDomain; // LAN enrol.DeviceLanMacAddress = Interop.Network.PrimaryLanMacAddress; // WAN enrol.DeviceWlanMacAddress = Interop.Network.PrimaryWlanMacAddress; // Certificates enrol.DeviceCertificates = Interop.Certificates.GetCertificateSubjects(StoreName.My, StoreLocation.LocalMachine); } public static void Process(this EnrolResponse enrolResponse) { if (enrolResponse == null) throw new ClientServiceException("Enrolment", "Server denied enrolment (Empty Response)"); ErrorReporting.EnrolmentSessionId = enrolResponse.SessionId; if (!string.IsNullOrEmpty(enrolResponse.ErrorMessage)) throw new ClientServiceException("Enrolment", enrolResponse.ErrorMessage); // Offline Domain Join bool requireReboot = enrolResponse.ApplyOfflineDomainJoin(); // Certificates enrolResponse.ApplyDeviceCertificates(); // Device Owner enrolResponse.ApplyDeviceAssignedUser(); Presentation.UpdateStatus("Enrolling Device", "Device Enrolment Successfully Completed", false, 0, 1500); Program.RebootRequired = requireReboot; Program.AllowUninstall = enrolResponse.AllowBootstrapperUninstall; } /// /// Processes a Client Service Enrol Response for Offline Domain Join Actions /// /// /// Boolean indicating whether a reboot is required. private static bool ApplyOfflineDomainJoin(this EnrolResponse enrolResponse) { if (!string.IsNullOrWhiteSpace(enrolResponse.OfflineDomainJoin)) { Presentation.UpdateStatus("Enrolling Device", string.Format("Performing Offline Domain Join:{0}Renaming Computer: {1} -> {2}", Environment.NewLine, Interop.LocalAuthentication.ComputerName, enrolResponse.DeviceComputerName), true, -1, 1500); string odjFile = Path.GetTempFileName(); File.WriteAllBytes(odjFile, Convert.FromBase64String(enrolResponse.OfflineDomainJoin)); string odjWindowsPath = Environment.GetEnvironmentVariable("SystemRoot"); string odjProcessArguments = string.Format("/REQUESTODJ /LOADFILE \"{0}\" /WINDOWSPATH \"{1}\" /LOCALOS", odjFile, odjWindowsPath); ProcessStartInfo odjProcessStartInfo = new ProcessStartInfo("DJOIN.EXE", odjProcessArguments) { CreateNoWindow = true, ErrorDialog = false, LoadUserProfile = true, RedirectStandardOutput = true, UseShellExecute = false }; string odjResult; using (Process odjProcess = System.Diagnostics.Process.Start(odjProcessStartInfo)) { odjResult = odjProcess.StandardOutput.ReadToEnd(); odjProcess.WaitForExit(20000); // 20 Seconds } Presentation.UpdateStatus("Enrolling Device", string.Format("Offline Domain Join Result:{0}{1}", Environment.NewLine, odjResult), true, -1, 3000); if (File.Exists(odjFile)) File.Delete(odjFile); // Flush Logged-On History if (!string.IsNullOrEmpty(enrolResponse.DeviceDomainName)) { using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true)){ regWinlogon.SetValue("DefaultDomainName", enrolResponse.DeviceDomainName, RegistryValueKind.String); regWinlogon.SetValue("DefaultUserName", String.Empty, RegistryValueKind.String); } using (RegistryKey regLogonUI = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI", true)) { regLogonUI.DeleteValue("LastLoggedOnUser", false); } } return true; // Reboot required } else { // No Domain Join return false; // Reboot not required } } /// /// Processes a Client Service Enrol Response for Device Assigned User Actions /// /// private static void ApplyDeviceAssignedUser(this EnrolResponse enrolResponse) { // Only run task if Assigned User was specified if (!string.IsNullOrWhiteSpace(enrolResponse.DeviceAssignedUserSID)) { Presentation.UpdateStatus("Enrolling Device", string.Format(@"Configuring permissions for the device owner:{0}{1} ({2}\{3})", Environment.NewLine, enrolResponse.DeviceAssignedUserName, enrolResponse.DeviceAssignedUserDomain, enrolResponse.DeviceAssignedUserUsername), true, -1, 3000); Interop.LocalAuthentication.AddLocalGroupMembership("Administrators", enrolResponse.DeviceAssignedUserSID, enrolResponse.DeviceAssignedUserUsername, enrolResponse.DeviceAssignedUserDomain); // Make Windows think this user was the last to logon using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true)) { regWinlogon.SetValue("DefaultDomainName", enrolResponse.DeviceAssignedUserDomain, RegistryValueKind.String); regWinlogon.SetValue("DefaultUserName", enrolResponse.DeviceAssignedUserUsername, RegistryValueKind.String); } using (RegistryKey regLogonUI = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI", true)) { regLogonUI.SetValue("LastLoggedOnUser", string.Format(@"{0}\{1}", enrolResponse.DeviceAssignedUserDomain, enrolResponse.DeviceAssignedUserUsername), RegistryValueKind.String); } } } /// /// Processes a Client Service Enrol Response for Device Certificate Actions /// /// private static void ApplyDeviceCertificates(this EnrolResponse enrolResponse) { // Only run if a Certificate was supplied if (!string.IsNullOrEmpty(enrolResponse.DeviceCertificate)) { Presentation.UpdateStatus("Enrolling Device", "Configuring Wireless Certificates", true, -1, 1000); var certPersonalBytes = Convert.FromBase64String(enrolResponse.DeviceCertificate); var certPersonal = new X509Certificate2(certPersonalBytes, "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); if (certPersonal == null) throw new ClientServiceException("Enrolment > Device Certificate", "Unable to Import Device Certificate Provided, possibly check password."); // Certificate Removal if (enrolResponse.DeviceCertificateRemoveExisting != null && enrolResponse.DeviceCertificateRemoveExisting.Count > 0) { List regExMatchesSubject = new List(); foreach (var subjectRegEx in enrolResponse.DeviceCertificateRemoveExisting) regExMatchesSubject.Add(new Regex(subjectRegEx, RegexOptions.IgnoreCase)); // Remove from 'My' Store Interop.Certificates.RemoveCertificates(StoreName.My, StoreLocation.LocalMachine, regExMatchesSubject, certPersonal); // Remove from 'Root' Store Interop.Certificates.RemoveCertificates(StoreName.Root, StoreLocation.LocalMachine, regExMatchesSubject, certPersonal); // Remove from 'CertificateAuthority' Store Interop.Certificates.RemoveCertificates(StoreName.CertificateAuthority, StoreLocation.LocalMachine, regExMatchesSubject, certPersonal); } // Add Certificate Presentation.UpdateStatus("Enrolling Device", string.Format("Configuring Wireless Certificates{0}Installing Certificate: {1}", Environment.NewLine, Interop.Certificates.GetCertificateFriendlyName(certPersonal)), true, -1); Interop.Certificates.AddCertificate(StoreName.My, StoreLocation.LocalMachine, certPersonal); } } } }