github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cloudconfig/windowsuserdatafiles/Carbon.cs (about) 1 /* 2 Original sources available at: https://bitbucket.org/splatteredbits/carbon 3 */ 4 5 using System; 6 using System.Collections.Generic; 7 using System.ComponentModel; 8 using System.Runtime.InteropServices; 9 using System.Security.Principal; 10 using System.Text; 11 12 namespace PSCarbon 13 { 14 public sealed class Lsa 15 { 16 // ReSharper disable InconsistentNaming 17 [StructLayout(LayoutKind.Sequential)] 18 internal struct LSA_UNICODE_STRING 19 { 20 internal LSA_UNICODE_STRING(string inputString) 21 { 22 if (inputString == null) 23 { 24 Buffer = IntPtr.Zero; 25 Length = 0; 26 MaximumLength = 0; 27 } 28 else 29 { 30 Buffer = Marshal.StringToHGlobalAuto(inputString); 31 Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize); 32 MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize); 33 } 34 } 35 36 internal ushort Length; 37 internal ushort MaximumLength; 38 internal IntPtr Buffer; 39 } 40 41 [StructLayout(LayoutKind.Sequential)] 42 internal struct LSA_OBJECT_ATTRIBUTES 43 { 44 internal uint Length; 45 internal IntPtr RootDirectory; 46 internal LSA_UNICODE_STRING ObjectName; 47 internal uint Attributes; 48 internal IntPtr SecurityDescriptor; 49 internal IntPtr SecurityQualityOfService; 50 } 51 52 [StructLayout(LayoutKind.Sequential)] 53 public struct LUID 54 { 55 public uint LowPart; 56 public int HighPart; 57 } 58 59 // ReSharper disable UnusedMember.Local 60 private const uint POLICY_VIEW_LOCAL_INFORMATION = 0x00000001; 61 private const uint POLICY_VIEW_AUDIT_INFORMATION = 0x00000002; 62 private const uint POLICY_GET_PRIVATE_INFORMATION = 0x00000004; 63 private const uint POLICY_TRUST_ADMIN = 0x00000008; 64 private const uint POLICY_CREATE_ACCOUNT = 0x00000010; 65 private const uint POLICY_CREATE_SECRET = 0x00000014; 66 private const uint POLICY_CREATE_PRIVILEGE = 0x00000040; 67 private const uint POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080; 68 private const uint POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100; 69 private const uint POLICY_AUDIT_LOG_ADMIN = 0x00000200; 70 private const uint POLICY_SERVER_ADMIN = 0x00000400; 71 private const uint POLICY_LOOKUP_NAMES = 0x00000800; 72 private const uint POLICY_NOTIFICATION = 0x00001000; 73 // ReSharper restore UnusedMember.Local 74 75 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 76 public static extern bool LookupPrivilegeValue( 77 [MarshalAs(UnmanagedType.LPTStr)] string lpSystemName, 78 [MarshalAs(UnmanagedType.LPTStr)] string lpName, 79 out LUID lpLuid); 80 81 [DllImport("advapi32.dll", CharSet = CharSet.Unicode)] 82 private static extern uint LsaAddAccountRights( 83 IntPtr PolicyHandle, 84 IntPtr AccountSid, 85 LSA_UNICODE_STRING[] UserRights, 86 uint CountOfRights); 87 88 [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)] 89 private static extern uint LsaClose(IntPtr ObjectHandle); 90 91 [DllImport("advapi32.dll", SetLastError = true)] 92 private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle, 93 IntPtr AccountSid, 94 out IntPtr UserRights, 95 out uint CountOfRights 96 ); 97 98 [DllImport("advapi32.dll", SetLastError = true)] 99 private static extern uint LsaFreeMemory(IntPtr pBuffer); 100 101 [DllImport("advapi32.dll")] 102 private static extern int LsaNtStatusToWinError(long status); 103 104 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 105 private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle ); 106 107 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 108 static extern uint LsaRemoveAccountRights( 109 IntPtr PolicyHandle, 110 IntPtr AccountSid, 111 [MarshalAs(UnmanagedType.U1)] 112 bool AllRights, 113 LSA_UNICODE_STRING[] UserRights, 114 uint CountOfRights); 115 // ReSharper restore InconsistentNaming 116 117 private static IntPtr GetIdentitySid(string identity) 118 { 119 SecurityIdentifier sid = 120 new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier; 121 if (sid == null) 122 { 123 throw new ArgumentException(string.Format("Account {0} not found.", identity)); 124 } 125 byte[] sidBytes = new byte[sid.BinaryLength]; 126 sid.GetBinaryForm(sidBytes, 0); 127 System.IntPtr sidPtr = Marshal.AllocHGlobal(sidBytes.Length); 128 Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length); 129 return sidPtr; 130 } 131 132 private static IntPtr GetLsaPolicyHandle() 133 { 134 string computerName = Environment.MachineName; 135 IntPtr hPolicy; 136 LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES(); 137 objectAttributes.Length = 0; 138 objectAttributes.RootDirectory = IntPtr.Zero; 139 objectAttributes.Attributes = 0; 140 objectAttributes.SecurityDescriptor = IntPtr.Zero; 141 objectAttributes.SecurityQualityOfService = IntPtr.Zero; 142 143 const uint ACCESS_MASK = POLICY_CREATE_SECRET | POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION; 144 LSA_UNICODE_STRING machineNameLsa = new LSA_UNICODE_STRING(computerName); 145 uint result = LsaOpenPolicy(ref machineNameLsa, ref objectAttributes, ACCESS_MASK, out hPolicy); 146 HandleLsaResult(result); 147 return hPolicy; 148 } 149 150 public static string[] GetPrivileges(string identity) 151 { 152 IntPtr sidPtr = GetIdentitySid(identity); 153 IntPtr hPolicy = GetLsaPolicyHandle(); 154 IntPtr rightsPtr = IntPtr.Zero; 155 156 try 157 { 158 159 List<string> privileges = new List<string>(); 160 161 uint rightsCount; 162 uint result = LsaEnumerateAccountRights(hPolicy, sidPtr, out rightsPtr, out rightsCount); 163 int win32ErrorCode = LsaNtStatusToWinError(result); 164 // the user has no privileges 165 if( win32ErrorCode == STATUS_OBJECT_NAME_NOT_FOUND ) 166 { 167 return new string[0]; 168 } 169 HandleLsaResult(result); 170 171 LSA_UNICODE_STRING myLsaus = new LSA_UNICODE_STRING(); 172 for (ulong i = 0; i < rightsCount; i++) 173 { 174 IntPtr itemAddr = new IntPtr(rightsPtr.ToInt64() + (long) (i*(ulong) Marshal.SizeOf(myLsaus))); 175 myLsaus = (LSA_UNICODE_STRING) Marshal.PtrToStructure(itemAddr, myLsaus.GetType()); 176 char[] cvt = new char[myLsaus.Length/UnicodeEncoding.CharSize]; 177 Marshal.Copy(myLsaus.Buffer, cvt, 0, myLsaus.Length/UnicodeEncoding.CharSize); 178 string thisRight = new string(cvt); 179 privileges.Add(thisRight); 180 } 181 return privileges.ToArray(); 182 } 183 finally 184 { 185 Marshal.FreeHGlobal(sidPtr); 186 uint result = LsaClose(hPolicy); 187 HandleLsaResult(result); 188 result = LsaFreeMemory(rightsPtr); 189 HandleLsaResult(result); 190 } 191 } 192 193 public static void GrantPrivileges(string identity, string[] privileges) 194 { 195 IntPtr sidPtr = GetIdentitySid(identity); 196 IntPtr hPolicy = GetLsaPolicyHandle(); 197 198 try 199 { 200 LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges); 201 uint result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length); 202 HandleLsaResult(result); 203 } 204 finally 205 { 206 Marshal.FreeHGlobal(sidPtr); 207 uint result = LsaClose(hPolicy); 208 HandleLsaResult(result); 209 } 210 } 211 212 const int STATUS_SUCCESS = 0x0; 213 const int STATUS_OBJECT_NAME_NOT_FOUND = 0x00000002; 214 const int STATUS_ACCESS_DENIED = 0x00000005; 215 const int STATUS_INVALID_HANDLE = 0x00000006; 216 const int STATUS_UNSUCCESSFUL = 0x0000001F; 217 const int STATUS_INVALID_PARAMETER = 0x00000057; 218 const int STATUS_NO_SUCH_PRIVILEGE = 0x00000521; 219 const int STATUS_INVALID_SERVER_STATE = 0x00000548; 220 const int STATUS_INTERNAL_DB_ERROR = 0x00000567; 221 const int STATUS_INSUFFICIENT_RESOURCES = 0x000005AA; 222 223 private static Dictionary<int, string> ErrorMessages = new Dictionary<int, string>(); 224 public Lsa () { 225 ErrorMessages.Add(STATUS_ACCESS_DENIED, "Access denied. Caller does not have the appropriate access to complete the operation."); 226 ErrorMessages.Add(STATUS_INVALID_HANDLE, "Invalid handle. Indicates an object or RPC handle is not valid in the context used."); 227 ErrorMessages.Add(STATUS_UNSUCCESSFUL, "Unsuccessful. Generic failure, such as RPC connection failure."); 228 ErrorMessages.Add(STATUS_INVALID_PARAMETER, "Invalid parameter. One of the parameters is not valid."); 229 ErrorMessages.Add(STATUS_NO_SUCH_PRIVILEGE, "No such privilege. Indicates a specified privilege does not exist."); 230 ErrorMessages.Add(STATUS_INVALID_SERVER_STATE, "Invalid server state. Indicates the LSA server is currently disabled."); 231 ErrorMessages.Add(STATUS_INTERNAL_DB_ERROR, "Internal database error. The LSA database contains an internal inconsistency."); 232 ErrorMessages.Add(STATUS_INSUFFICIENT_RESOURCES, "Insufficient resources. There are not enough system resources (such as memory to allocate buffers) to complete the call."); 233 ErrorMessages.Add(STATUS_OBJECT_NAME_NOT_FOUND, "Object name not found. An object in the LSA policy database was not found. The object may have been specified either by SID or by name, depending on its type."); 234 } 235 236 private static void HandleLsaResult(uint returnCode) 237 { 238 int win32ErrorCode = LsaNtStatusToWinError(returnCode); 239 240 if( win32ErrorCode == STATUS_SUCCESS) 241 return; 242 243 if( ErrorMessages.ContainsKey(win32ErrorCode) ) 244 { 245 throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]); 246 } 247 248 throw new Win32Exception(win32ErrorCode); 249 } 250 251 public static void RevokePrivileges(string identity, string[] privileges) 252 { 253 IntPtr sidPtr = GetIdentitySid(identity); 254 IntPtr hPolicy = GetLsaPolicyHandle(); 255 256 try 257 { 258 string[] currentPrivileges = GetPrivileges(identity); 259 if (currentPrivileges.Length == 0) 260 { 261 return; 262 } 263 LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges); 264 uint result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length); 265 HandleLsaResult(result); 266 } 267 finally 268 { 269 Marshal.FreeHGlobal(sidPtr); 270 uint result = LsaClose(hPolicy); 271 HandleLsaResult(result); 272 } 273 274 } 275 276 private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges) 277 { 278 LSA_UNICODE_STRING[] lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length]; 279 for (int idx = 0; idx < privileges.Length; ++idx) 280 { 281 lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]); 282 } 283 return lsaPrivileges; 284 } 285 } 286 }