├── .gitignore ├── COPYING ├── README.md ├── img ├── adbl.png └── help.png ├── maclocker.sln └── maclocker ├── App.config ├── Program.cs ├── Properties └── AssemblyInfo.cs └── maclocker.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.user 3 | maclocker/bin/* 4 | maclocker/obj/* 5 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Berke Viktor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MacLocker 2 | 3 | ## What is it 4 | 5 | It's a utility to save FileVault recovery keys as BitLocker passwords in Active Directory 6 | 7 | ## Usage 8 | 9 | 10 | 11 | ## Result 12 | 13 | 14 | -------------------------------------------------------------------------------- /img/adbl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bviktor/maclocker/453ae08821079c48c505aa4973604fb9ffac0feb/img/adbl.png -------------------------------------------------------------------------------- /img/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bviktor/maclocker/453ae08821079c48c505aa4973604fb9ffac0feb/img/help.png -------------------------------------------------------------------------------- /maclocker.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "maclocker", "maclocker\maclocker.csproj", "{5871F3FB-F2CD-44E5-B449-03B31448BA70}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {5871F3FB-F2CD-44E5-B449-03B31448BA70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {5871F3FB-F2CD-44E5-B449-03B31448BA70}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {5871F3FB-F2CD-44E5-B449-03B31448BA70}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {5871F3FB-F2CD-44E5-B449-03B31448BA70}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /maclocker/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /maclocker/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.DirectoryServices; 7 | using System.Configuration; 8 | 9 | namespace maclocker 10 | { 11 | class Program 12 | { 13 | public static String GenerateDateString() 14 | { 15 | DateTime date = DateTime.Now; 16 | return date.ToString("yyyy-MM-ddTHH:mm:ss\\\\K"); 17 | } 18 | 19 | public static String GenerateGuid(int mode) 20 | { 21 | Guid guid = Guid.NewGuid(); 22 | 23 | switch (mode) 24 | { 25 | case 1: 26 | return guid.ToString("D"); 27 | 28 | case 2: 29 | string guidString = guid.ToString("N"); 30 | char[] guidChar = guidString.ToCharArray(); 31 | String buf = ""; 32 | 33 | for (int i = 0; i < 32; i++) 34 | { 35 | buf += "0x" + guidChar[i] + guidChar[++i] + " "; 36 | } 37 | 38 | return buf; 39 | 40 | case 3: 41 | return guid.ToString("N"); 42 | 43 | default: 44 | return ""; 45 | } 46 | } 47 | 48 | public static String GenerateKeyCN() 49 | { 50 | return GenerateDateString() + "{" + GenerateGuid(1) + "}"; 51 | } 52 | 53 | public static bool ComputerExists(String ouPath, String objName) 54 | { 55 | if (DirectoryEntry.Exists("LDAP://CN=" + objName + "," + ouPath)) 56 | { 57 | return true; 58 | } 59 | else 60 | { 61 | return false; 62 | } 63 | } 64 | 65 | public static bool CreateComputer(String ouPath, String objName, bool useOsAuth, String adminUser, String adminPass) 66 | { 67 | try 68 | { 69 | DirectoryEntry comp; 70 | 71 | if (useOsAuth) 72 | { 73 | comp = new DirectoryEntry("LDAP://" + ouPath); 74 | } 75 | else 76 | { 77 | comp = new DirectoryEntry("LDAP://" + ouPath, adminUser, adminPass); 78 | } 79 | 80 | DirectoryEntry group = comp.Children.Add("CN=" + objName, "computer"); 81 | group.Properties["sAmAccountName"].Value = objName; 82 | group.CommitChanges(); 83 | return true; 84 | } 85 | catch (Exception e) 86 | { 87 | Console.WriteLine(e.ToString()); 88 | return false; 89 | } 90 | } 91 | 92 | public static bool AddRecoveryKey(String ouPath, String objName, String recoveryPassword, bool useOsAuth, String adminUser, String adminPass) 93 | { 94 | try 95 | { 96 | DirectoryEntry comp; 97 | 98 | if (useOsAuth) 99 | { 100 | comp = new DirectoryEntry("LDAP://CN=" + objName + "," + ouPath); 101 | } 102 | else 103 | { 104 | comp = new DirectoryEntry("LDAP://CN=" + objName + "," + ouPath, adminUser, adminPass); 105 | } 106 | 107 | DirectoryEntry recKey = comp.Children.Add("CN=" + GenerateKeyCN(), "msFVE-RecoveryInformation"); 108 | recKey.Properties["msFVE-RecoveryPassword"].Value = recoveryPassword; 109 | recKey.Properties["msFVE-RecoveryGuid"].Value = GenerateGuid(2); 110 | recKey.CommitChanges(); 111 | return true; 112 | } 113 | catch (Exception e) 114 | { 115 | Console.WriteLine(e.ToString()); 116 | return false; 117 | } 118 | } 119 | 120 | public static void WriteDashes() 121 | { 122 | Console.Write("--------------------------------------------------------------------------------"); 123 | } 124 | 125 | public static void FinishUp() 126 | { 127 | WriteDashes(); 128 | Console.WriteLine("End of execution, press any key to close..."); 129 | Console.ReadKey(true); 130 | } 131 | 132 | static void PrintHelp() 133 | { 134 | Console.WriteLine("MacLocker - utility to save FileVault recovery keys as BitLocker passwords in Active Directory. Requires your AD schema to be prepared to store BitLocker info."); 135 | Console.WriteLine(); 136 | Console.WriteLine("Usage:"); 137 | Console.WriteLine("\tmaclocker "); 138 | Console.WriteLine("\tmaclocker "); 139 | Console.WriteLine("\tmaclocker "); 140 | Console.WriteLine(); 141 | Console.WriteLine("\tcomp:\tCN of the computer object"); 142 | Console.WriteLine("\tkey:\tFileVault recovery key to store as BitLocker key"); 143 | Console.WriteLine("\tOU DN:\tdistinguishedName of the OU containing the computer"); 144 | Console.WriteLine("\tuser:\tsAMAccountName of the account to write the changes with"); 145 | Console.WriteLine("\tpass:\tpassword of this account"); 146 | Console.WriteLine(); 147 | Console.WriteLine("Example:"); 148 | Console.WriteLine(); 149 | Console.WriteLine("maclocker mac01 UIER-IASD-U2DM-78DG-NM23-91DT OU=Mac,DC=xy,DC=lan admin1 P@ss"); 150 | Console.WriteLine(); 151 | Console.WriteLine("If OU DN or user/pass are omitted, the App.config values are used."); 152 | Console.WriteLine("If you set useOsAuth to true in App.config, user and pass are ignored."); 153 | } 154 | 155 | static void Main(string[] args) 156 | { 157 | String computerName; 158 | String recoveryKey; 159 | String adminUser; 160 | String adminPass; 161 | String ouPath; 162 | bool useOsAuth; 163 | ConsoleKeyInfo key; 164 | 165 | adminUser = ConfigurationManager.AppSettings["adminUser"]; 166 | adminPass = ConfigurationManager.AppSettings["adminPass"]; 167 | ouPath = ConfigurationManager.AppSettings["ouPath"]; 168 | 169 | if (ConfigurationManager.AppSettings["useOsAuth"].Equals("true")) 170 | { 171 | useOsAuth = true; 172 | } 173 | else 174 | { 175 | useOsAuth = false; 176 | } 177 | 178 | switch (args.Length) 179 | { 180 | case 2: 181 | computerName = args[0]; 182 | recoveryKey = args[1]; 183 | break; 184 | case 3: 185 | computerName = args[0]; 186 | recoveryKey = args[1]; 187 | ouPath = args[2]; 188 | break; 189 | case 5: 190 | computerName = args[0]; 191 | recoveryKey = args[1]; 192 | ouPath = args[2]; 193 | adminUser = args[3]; 194 | adminPass = args[4]; 195 | break; 196 | default: 197 | PrintHelp(); 198 | return; 199 | } 200 | 201 | Console.WriteLine("DN of the computer object:\tCN=" + computerName + "," + ouPath); 202 | Console.WriteLine("FileVault recovery password:\t" + recoveryKey); 203 | Console.WriteLine("Using OS authentication:\t" + useOsAuth.ToString()); 204 | Console.Write("Store this key under this object? [y/n]\t"); 205 | key = Console.ReadKey(); 206 | Console.WriteLine(); 207 | 208 | if (!key.Key.Equals(ConsoleKey.Y)) 209 | { 210 | FinishUp(); 211 | return; 212 | } 213 | 214 | WriteDashes(); 215 | 216 | Console.Write("Checking for computer object: \t\t"); 217 | 218 | if (ComputerExists(ouPath, computerName)) 219 | { 220 | Console.WriteLine("exists"); 221 | } 222 | else 223 | { 224 | Console.WriteLine("does not exist"); 225 | Console.Write("Create computer object? [y/n]\t\t"); 226 | 227 | key = Console.ReadKey(); 228 | Console.WriteLine(); 229 | 230 | if (key.Key.Equals(ConsoleKey.Y)) 231 | { 232 | Console.Write("Creating computer object:\t\t"); 233 | 234 | if (!CreateComputer(ouPath, computerName, useOsAuth, adminUser, adminPass)) 235 | { 236 | Console.WriteLine("failure"); 237 | FinishUp(); 238 | return; 239 | } 240 | else 241 | { 242 | Console.WriteLine("success"); 243 | } 244 | } 245 | else 246 | { 247 | FinishUp(); 248 | return; 249 | } 250 | } 251 | 252 | Console.Write("Adding recovery key:\t\t\t"); 253 | 254 | if (AddRecoveryKey(ouPath, computerName, recoveryKey, useOsAuth, adminUser, adminPass)) 255 | { 256 | Console.WriteLine("success"); 257 | } 258 | else 259 | { 260 | Console.WriteLine("failure"); 261 | FinishUp(); 262 | return; 263 | } 264 | 265 | FinishUp(); 266 | } 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /maclocker/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("maclocker")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("maclocker")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ed42de6c-1dfb-4fc2-814f-2769c468ed82")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /maclocker/maclocker.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5871F3FB-F2CD-44E5-B449-03B31448BA70} 8 | Exe 9 | Properties 10 | maclocker 11 | maclocker 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 60 | --------------------------------------------------------------------------------