|
| 1 | +Add-Type @' |
| 2 | +using System; |
| 3 | +using System.Collections.Generic; |
| 4 | +using System.Text; |
| 5 | +
|
| 6 | +namespace LsaWrapper |
| 7 | +{ |
| 8 | + using System.Runtime.InteropServices; |
| 9 | + using System.Security; |
| 10 | + using System.Management; |
| 11 | + using System.Runtime.CompilerServices; |
| 12 | + using System.ComponentModel; |
| 13 | +
|
| 14 | + using LSA_HANDLE = IntPtr; |
| 15 | +
|
| 16 | + [StructLayout(LayoutKind.Sequential)] |
| 17 | + struct LSA_OBJECT_ATTRIBUTES |
| 18 | + { |
| 19 | + internal int Length; |
| 20 | + internal IntPtr RootDirectory; |
| 21 | + internal IntPtr ObjectName; |
| 22 | + internal int Attributes; |
| 23 | + internal IntPtr SecurityDescriptor; |
| 24 | + internal IntPtr SecurityQualityOfService; |
| 25 | + } |
| 26 | + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] |
| 27 | + struct LSA_UNICODE_STRING |
| 28 | + { |
| 29 | + internal ushort Length; |
| 30 | + internal ushort MaximumLength; |
| 31 | + [MarshalAs(UnmanagedType.LPWStr)] |
| 32 | + internal string Buffer; |
| 33 | + } |
| 34 | + sealed class Win32Sec |
| 35 | + { |
| 36 | + [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), |
| 37 | + SuppressUnmanagedCodeSecurityAttribute] |
| 38 | + internal static extern uint LsaOpenPolicy( |
| 39 | + LSA_UNICODE_STRING[] SystemName, |
| 40 | + ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, |
| 41 | + int AccessMask, |
| 42 | + out IntPtr PolicyHandle |
| 43 | + ); |
| 44 | +
|
| 45 | + [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), |
| 46 | + SuppressUnmanagedCodeSecurityAttribute] |
| 47 | + internal static extern uint LsaAddAccountRights( |
| 48 | + LSA_HANDLE PolicyHandle, |
| 49 | + IntPtr pSID, |
| 50 | + LSA_UNICODE_STRING[] UserRights, |
| 51 | + int CountOfRights |
| 52 | + ); |
| 53 | +
|
| 54 | + [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), |
| 55 | + SuppressUnmanagedCodeSecurityAttribute] |
| 56 | + internal static extern int LsaLookupNames2( |
| 57 | + LSA_HANDLE PolicyHandle, |
| 58 | + uint Flags, |
| 59 | + uint Count, |
| 60 | + LSA_UNICODE_STRING[] Names, |
| 61 | + ref IntPtr ReferencedDomains, |
| 62 | + ref IntPtr Sids |
| 63 | + ); |
| 64 | +
|
| 65 | + [DllImport("advapi32")] |
| 66 | + internal static extern int LsaNtStatusToWinError(int NTSTATUS); |
| 67 | +
|
| 68 | + [DllImport("advapi32")] |
| 69 | + internal static extern int LsaClose(IntPtr PolicyHandle); |
| 70 | +
|
| 71 | + [DllImport("advapi32")] |
| 72 | + internal static extern int LsaFreeMemory(IntPtr Buffer); |
| 73 | +
|
| 74 | + } |
| 75 | + /// <summary> |
| 76 | + /// This class is used to grant "Log on as a service", "Log on as a batchjob", "Log on localy" etc. |
| 77 | + /// to a user. |
| 78 | + /// </summary> |
| 79 | + public sealed class LsaWrapper : IDisposable |
| 80 | + { |
| 81 | + [StructLayout(LayoutKind.Sequential)] |
| 82 | + struct LSA_TRUST_INFORMATION |
| 83 | + { |
| 84 | + internal LSA_UNICODE_STRING Name; |
| 85 | + internal IntPtr Sid; |
| 86 | + } |
| 87 | + [StructLayout(LayoutKind.Sequential)] |
| 88 | + struct LSA_TRANSLATED_SID2 |
| 89 | + { |
| 90 | + internal SidNameUse Use; |
| 91 | + internal IntPtr Sid; |
| 92 | + internal int DomainIndex; |
| 93 | + uint Flags; |
| 94 | + } |
| 95 | +
|
| 96 | + [StructLayout(LayoutKind.Sequential)] |
| 97 | + struct LSA_REFERENCED_DOMAIN_LIST |
| 98 | + { |
| 99 | + internal uint Entries; |
| 100 | + internal LSA_TRUST_INFORMATION Domains; |
| 101 | + } |
| 102 | +
|
| 103 | + enum SidNameUse : int |
| 104 | + { |
| 105 | + User = 1, |
| 106 | + Group = 2, |
| 107 | + Domain = 3, |
| 108 | + Alias = 4, |
| 109 | + KnownGroup = 5, |
| 110 | + DeletedAccount = 6, |
| 111 | + Invalid = 7, |
| 112 | + Unknown = 8, |
| 113 | + Computer = 9 |
| 114 | + } |
| 115 | +
|
| 116 | + enum Access : int |
| 117 | + { |
| 118 | + POLICY_READ = 0x20006, |
| 119 | + POLICY_ALL_ACCESS = 0x00F0FFF, |
| 120 | + POLICY_EXECUTE = 0X20801, |
| 121 | + POLICY_WRITE = 0X207F8 |
| 122 | + } |
| 123 | + const uint STATUS_ACCESS_DENIED = 0xc0000022; |
| 124 | + const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a; |
| 125 | + const uint STATUS_NO_MEMORY = 0xc0000017; |
| 126 | +
|
| 127 | + IntPtr lsaHandle; |
| 128 | +
|
| 129 | + public LsaWrapper() |
| 130 | + : this(null) |
| 131 | + { } |
| 132 | + // // local system if systemName is null |
| 133 | + public LsaWrapper(string systemName) |
| 134 | + { |
| 135 | + LSA_OBJECT_ATTRIBUTES lsaAttr; |
| 136 | + lsaAttr.RootDirectory = IntPtr.Zero; |
| 137 | + lsaAttr.ObjectName = IntPtr.Zero; |
| 138 | + lsaAttr.Attributes = 0; |
| 139 | + lsaAttr.SecurityDescriptor = IntPtr.Zero; |
| 140 | + lsaAttr.SecurityQualityOfService = IntPtr.Zero; |
| 141 | + lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES)); |
| 142 | + lsaHandle = IntPtr.Zero; |
| 143 | + LSA_UNICODE_STRING[] system = null; |
| 144 | + if (systemName != null) |
| 145 | + { |
| 146 | + system = new LSA_UNICODE_STRING[1]; |
| 147 | + system[0] = InitLsaString(systemName); |
| 148 | + } |
| 149 | +
|
| 150 | + uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr, |
| 151 | + (int)Access.POLICY_ALL_ACCESS, out lsaHandle); |
| 152 | + if (ret == 0) |
| 153 | + return; |
| 154 | + if (ret == STATUS_ACCESS_DENIED) |
| 155 | + { |
| 156 | + throw new UnauthorizedAccessException(); |
| 157 | + } |
| 158 | + if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) |
| 159 | + { |
| 160 | + throw new OutOfMemoryException(); |
| 161 | + } |
| 162 | + throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret)); |
| 163 | + } |
| 164 | +
|
| 165 | + public void AddPrivileges(string account, string privilege) |
| 166 | + { |
| 167 | + IntPtr pSid = GetSIDInformation(account); |
| 168 | + LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1]; |
| 169 | + privileges[0] = InitLsaString(privilege); |
| 170 | + uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1); |
| 171 | + if (ret == 0) |
| 172 | + return; |
| 173 | + if (ret == STATUS_ACCESS_DENIED) |
| 174 | + { |
| 175 | + throw new UnauthorizedAccessException(); |
| 176 | + } |
| 177 | + if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) |
| 178 | + { |
| 179 | + throw new OutOfMemoryException(); |
| 180 | + } |
| 181 | + throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret)); |
| 182 | + } |
| 183 | +
|
| 184 | + public void Dispose() |
| 185 | + { |
| 186 | + if (lsaHandle != IntPtr.Zero) |
| 187 | + { |
| 188 | + Win32Sec.LsaClose(lsaHandle); |
| 189 | + lsaHandle = IntPtr.Zero; |
| 190 | + } |
| 191 | + GC.SuppressFinalize(this); |
| 192 | + } |
| 193 | + ~LsaWrapper() |
| 194 | + { |
| 195 | + Dispose(); |
| 196 | + } |
| 197 | + // helper functions |
| 198 | +
|
| 199 | + IntPtr GetSIDInformation(string account) |
| 200 | + { |
| 201 | + LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1]; |
| 202 | + LSA_TRANSLATED_SID2 lts; |
| 203 | + IntPtr tsids = IntPtr.Zero; |
| 204 | + IntPtr tdom = IntPtr.Zero; |
| 205 | + names[0] = InitLsaString(account); |
| 206 | + lts.Sid = IntPtr.Zero; |
| 207 | +
|
| 208 | + int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids); |
| 209 | + if (ret != 0) |
| 210 | + throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret)); |
| 211 | + lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids, |
| 212 | + typeof(LSA_TRANSLATED_SID2)); |
| 213 | + Win32Sec.LsaFreeMemory(tsids); |
| 214 | + Win32Sec.LsaFreeMemory(tdom); |
| 215 | + return lts.Sid; |
| 216 | + } |
| 217 | +
|
| 218 | + static LSA_UNICODE_STRING InitLsaString(string s) |
| 219 | + { |
| 220 | + // Unicode strings max. 32KB |
| 221 | + if (s.Length > 0x7ffe) |
| 222 | + throw new ArgumentException("String too long"); |
| 223 | + LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING(); |
| 224 | + lus.Buffer = s; |
| 225 | + lus.Length = (ushort)(s.Length * sizeof(char)); |
| 226 | + lus.MaximumLength = (ushort)(lus.Length + sizeof(char)); |
| 227 | + return lus; |
| 228 | + } |
| 229 | + } |
| 230 | + public class LsaWrapperCaller |
| 231 | + { |
| 232 | + public static void AddPrivileges(string account, string privilege) |
| 233 | + { |
| 234 | + using (LsaWrapper lsaWrapper = new LsaWrapper()) |
| 235 | + { |
| 236 | + lsaWrapper.AddPrivileges(account, privilege); |
| 237 | + } |
| 238 | + } |
| 239 | + } |
| 240 | +} |
| 241 | +'@ |
| 242 | + |
0 commit comments