2
Original sources available at: https://bitbucket.org/splatteredbits/carbon
6
using System.Collections.Generic;
7
using System.ComponentModel;
8
using System.Runtime.InteropServices;
9
using System.Security.Principal;
14
public sealed class Lsa
16
// ReSharper disable InconsistentNaming
17
[StructLayout(LayoutKind.Sequential)]
18
internal struct LSA_UNICODE_STRING
20
internal LSA_UNICODE_STRING(string inputString)
22
if (inputString == null)
30
Buffer = Marshal.StringToHGlobalAuto(inputString);
31
Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize);
32
MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize);
36
internal ushort Length;
37
internal ushort MaximumLength;
38
internal IntPtr Buffer;
41
[StructLayout(LayoutKind.Sequential)]
42
internal struct LSA_OBJECT_ATTRIBUTES
45
internal IntPtr RootDirectory;
46
internal LSA_UNICODE_STRING ObjectName;
47
internal uint Attributes;
48
internal IntPtr SecurityDescriptor;
49
internal IntPtr SecurityQualityOfService;
52
[StructLayout(LayoutKind.Sequential)]
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
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,
81
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
82
private static extern uint LsaAddAccountRights(
85
LSA_UNICODE_STRING[] UserRights,
88
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)]
89
private static extern uint LsaClose(IntPtr ObjectHandle);
91
[DllImport("advapi32.dll", SetLastError = true)]
92
private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle,
94
out IntPtr UserRights,
95
out uint CountOfRights
98
[DllImport("advapi32.dll", SetLastError = true)]
99
private static extern uint LsaFreeMemory(IntPtr pBuffer);
101
[DllImport("advapi32.dll")]
102
private static extern int LsaNtStatusToWinError(long status);
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 );
107
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
108
static extern uint LsaRemoveAccountRights(
111
[MarshalAs(UnmanagedType.U1)]
113
LSA_UNICODE_STRING[] UserRights,
115
// ReSharper restore InconsistentNaming
117
private static IntPtr GetIdentitySid(string identity)
119
SecurityIdentifier sid =
120
new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier;
123
throw new ArgumentException(string.Format("Account {0} not found.", identity));
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);
132
private static IntPtr GetLsaPolicyHandle()
134
string computerName = Environment.MachineName;
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;
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);
150
public static string[] GetPrivileges(string identity)
152
IntPtr sidPtr = GetIdentitySid(identity);
153
IntPtr hPolicy = GetLsaPolicyHandle();
154
IntPtr rightsPtr = IntPtr.Zero;
159
List<string> privileges = new List<string>();
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 )
167
return new string[0];
169
HandleLsaResult(result);
171
LSA_UNICODE_STRING myLsaus = new LSA_UNICODE_STRING();
172
for (ulong i = 0; i < rightsCount; i++)
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);
181
return privileges.ToArray();
185
Marshal.FreeHGlobal(sidPtr);
186
uint result = LsaClose(hPolicy);
187
HandleLsaResult(result);
188
result = LsaFreeMemory(rightsPtr);
189
HandleLsaResult(result);
193
public static void GrantPrivileges(string identity, string[] privileges)
195
IntPtr sidPtr = GetIdentitySid(identity);
196
IntPtr hPolicy = GetLsaPolicyHandle();
200
LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges);
201
uint result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length);
202
HandleLsaResult(result);
206
Marshal.FreeHGlobal(sidPtr);
207
uint result = LsaClose(hPolicy);
208
HandleLsaResult(result);
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;
223
private static Dictionary<int, string> ErrorMessages = new Dictionary<int, string>();
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.");
236
private static void HandleLsaResult(uint returnCode)
238
int win32ErrorCode = LsaNtStatusToWinError(returnCode);
240
if( win32ErrorCode == STATUS_SUCCESS)
243
if( ErrorMessages.ContainsKey(win32ErrorCode) )
245
throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]);
248
throw new Win32Exception(win32ErrorCode);
251
public static void RevokePrivileges(string identity, string[] privileges)
253
IntPtr sidPtr = GetIdentitySid(identity);
254
IntPtr hPolicy = GetLsaPolicyHandle();
258
string[] currentPrivileges = GetPrivileges(identity);
259
if (currentPrivileges.Length == 0)
263
LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges);
264
uint result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length);
265
HandleLsaResult(result);
269
Marshal.FreeHGlobal(sidPtr);
270
uint result = LsaClose(hPolicy);
271
HandleLsaResult(result);
276
private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges)
278
LSA_UNICODE_STRING[] lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length];
279
for (int idx = 0; idx < privileges.Length; ++idx)
281
lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]);
283
return lsaPrivileges;