source: trunk/eraser6/Eraser.Util/AdvApi.cs @ 1675

Revision 1675, 18.2 KB checked in by lowjoel, 5 years ago (diff)

Updated copyright information: since Eraser is still under development we should update our copyright status.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25using System.ComponentModel;
26using System.Security.Principal;
27using System.Runtime.InteropServices;
28
29namespace Eraser.Util
30{
31    public static class AdvApi
32    {
33        /// <summary>
34        /// Checks whether the current process is running with administrative
35        /// privileges.
36        /// </summary>
37        /// <returns>True if the user is an administrator. This only returns
38        /// true under Vista when UAC is enabled and the process is elevated.</returns>
39        public static bool IsAdministrator()
40        {
41            WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
42            return principal.IsInRole(WindowsBuiltInRole.Administrator);
43        }
44
45        /// <summary>
46        /// Checks whether the current process is running with administrative privileges.
47        /// </summary>
48        /// <returns>Returns true if UAC is enabled under Vista. Will return false
49        /// under pre-Vista OSes</returns>
50        public static bool UacEnabled()
51        {
52            //Check whether we're on Vista
53            if (Environment.OSVersion.Platform != PlatformID.Win32NT ||
54                Environment.OSVersion.Version < new Version(6, 0))
55            {
56                //UAC doesn't exist on these platforms.
57                return false;
58            }
59
60            //Get the process token.
61            SafeTokenHandle hToken = new SafeTokenHandle();
62            bool result = NativeMethods.OpenProcessToken(KernelApi.NativeMethods.GetCurrentProcess(),
63                NativeMethods.TOKEN_QUERY, out hToken);
64            if (!result || hToken.IsInvalid)
65                throw KernelApi.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
66
67            IntPtr pElevationType = Marshal.AllocHGlobal(Marshal.SizeOf(
68                typeof(NativeMethods.TOKEN_ELEVATION_TYPE)));
69            try
70            {
71                //Get the token information for our current process.
72                uint returnSize = 0;
73                result = NativeMethods.GetTokenInformation(hToken,
74                    NativeMethods.TOKEN_INFORMATION_CLASS.TokenElevationType,
75                    pElevationType, sizeof(NativeMethods.TOKEN_ELEVATION_TYPE),
76                    out returnSize);
77
78                //Check the return code
79                if (!result)
80                    throw KernelApi.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
81
82                NativeMethods.TOKEN_ELEVATION_TYPE elevationType =
83                    (NativeMethods.TOKEN_ELEVATION_TYPE)Marshal.PtrToStructure(
84                        pElevationType, typeof(NativeMethods.TOKEN_ELEVATION_TYPE));
85                return elevationType != NativeMethods.TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;
86            }
87            finally
88            {
89                Marshal.FreeHGlobal(pElevationType);
90            }
91        }
92
93        /// <summary>
94        /// Stores functions, structs and constants from Advapi32.dll
95        /// </summary>
96        internal static class NativeMethods
97        {
98            /// <summary>
99            /// The CryptAcquireContext function is used to acquire a handle to a
100            /// particular key container within a particular cryptographic service
101            /// provider (CSP). This returned handle is used in calls to CryptoAPI
102            /// functions that use the selected CSP.
103            ///
104            /// This function first attempts to find a CSP with the characteristics
105            /// described in the dwProvType and pszProvider parameters. If the CSP
106            /// is found, the function attempts to find a key container within the
107            /// CSP that matches the name specified by the pszContainer parameter.
108            /// To acquire the context and the key container of a private key
109            /// associated with the public key of a certificate, use
110            /// CryptAcquireCertificatePrivateKey.
111            ///
112            /// With the appropriate setting of dwFlags, this function can also create
113            /// and destroy key containers and can provide access to a CSP with a
114            /// temporary key container if access to a private key is not required.
115            /// </summary>
116            /// <param name="phProv">A pointer to a handle of a CSP. When you have
117            /// finished using the CSP, release the handle by calling the
118            /// CryptReleaseContext function.</param>
119            /// <param name="pszContainer">The key container name. This is a
120            /// null-terminated string that identifies the key container to the CSP.
121            /// This name is independent of the method used to store the keys.
122            /// Some CSPs store their key containers internally (in hardware),
123            /// some use the system registry, and others use the file system. When
124            /// dwFlags is set to CRYPT_VERIFYCONTEXT, pszContainer must be set to NULL.
125            ///
126            /// When pszContainer is NULL, a default key container name is used. For
127            /// example, the Microsoft Base Cryptographic Provider uses the logon name
128            /// of the currently logged on user as the key container name. Other CSPs
129            /// can also have default key containers that can be acquired in this way.
130            ///
131            /// Applications must not use the default key container to store private
132            /// keys. When multiple applications use the same container, one application
133            /// can change or destroy the keys that another application needs to have
134            /// available. If applications use key containers linked to the application,
135            /// the risk is reduced of other applications tampering with keys necessary
136            /// for proper function.
137            ///
138            /// An application can obtain the name of the key container in use by
139            /// reading the PP_CONTAINER value with the CryptGetProvParam function.</param>
140            /// <param name="pszProvider">A null-terminated string that specifies the
141            /// name of the CSP to be used.
142            ///
143            /// If this parameter is NULL, the user default provider is used. For more
144            /// information, see Cryptographic Service Provider Contexts. For a list
145            /// of available cryptographic providers, see Cryptographic Provider Names.
146            ///
147            /// An application can obtain the name of the CSP in use by using the
148            /// CryptGetProvParam function to read the PP_NAME CSP value in the dwParam
149            /// parameter.
150            ///
151            /// Due to changing export control restrictions, the default CSP can change
152            /// between operating system releases. To ensure interoperability on
153            /// different operating system platforms, the CSP should be explicitly
154            /// set by using this parameter instead of using the default CSP.</param>
155            /// <param name="dwProvType">Specifies the type of provider to acquire.
156            /// Defined provider types are discussed in Cryptographic Provider Types.</param>
157            /// <param name="dwFlags">Flag values. This parameter is usually set to zero,
158            /// but some applications set one or more flags.</param>
159            /// <returns> If the function succeeds, the function returns nonzero (TRUE).
160            /// If the function fails, it returns zero (FALSE). For extended error
161            /// information, call Marshal.GetLastWin32Error.</returns>
162            [DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
163            [return: MarshalAs(UnmanagedType.Bool)]
164            public static extern bool CryptAcquireContext(out SafeCryptHandle phProv,
165                string pszContainer, string pszProvider, uint dwProvType, uint dwFlags);
166
167            /// <summary>
168            /// The CryptGenRandom function fills a buffer with cryptographically random bytes.
169            /// </summary>
170            /// <param name="hProv">Handle of a cryptographic service provider (CSP)
171            /// created by a call to CryptAcquireContext.</param>
172            /// <param name="dwLen">Number of bytes of random data to be generated.</param>
173            /// <param name="pbBuffer">Buffer to receive the returned data. This buffer
174            /// must be at least dwLen bytes in length.
175            ///
176            /// Optionally, the application can fill this buffer with data to use as
177            /// an auxiliary random seed.</param>
178            [DllImport("Advapi32.dll", SetLastError = true)]
179            [return: MarshalAs(UnmanagedType.Bool)]
180            public static extern bool CryptGenRandom(SafeCryptHandle hProv, uint dwLen,
181                byte[] pbBuffer);
182
183            /// <summary>
184            /// The CryptReleaseContext function releases the handle of a cryptographic
185            /// service provider (CSP) and a key container. At each call to this function,
186            /// the reference count on the CSP is reduced by one. When the reference
187            /// count reaches zero, the context is fully released and it can no longer
188            /// be used by any function in the application.
189            ///
190            /// An application calls this function after finishing the use of the CSP.
191            /// After this function is called, the released CSP handle is no longer
192            /// valid. This function does not destroy key containers or key pairs</summary>
193            /// <param name="hProv">Handle of a cryptographic service provider (CSP)
194            /// created by a call to CryptAcquireContext.</param>
195            /// <param name="dwFlags">Reserved for future use and must be zero. If
196            /// dwFlags is not set to zero, this function returns FALSE but the CSP
197            /// is released.</param>
198            /// <returns>If the function succeeds, the return value is nonzero (TRUE).
199            ///
200            /// If the function fails, the return value is zero (FALSE). For extended
201            /// error information, call Marshal.GetLastWin32Error.</returns>
202            [DllImport("Advapi32.dll", SetLastError = true)]
203            [return: MarshalAs(UnmanagedType.Bool)]
204            public static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
205
206            public const uint PROV_RSA_FULL = 1;
207            public const uint PROV_RSA_SIG = 2;
208            public const uint PROV_DSS = 3;
209            public const uint PROV_FORTEZZA = 4;
210            public const uint PROV_MS_EXCHANGE = 5;
211            public const uint PROV_SSL = 6;
212            public const uint PROV_RSA_SCHANNEL = 12;
213            public const uint PROV_DSS_DH = 13;
214            public const uint PROV_EC_ECDSA_SIG = 14;
215            public const uint PROV_EC_ECNRA_SIG = 15;
216            public const uint PROV_EC_ECDSA_FULL = 16;
217            public const uint PROV_EC_ECNRA_FULL = 17;
218            public const uint PROV_DH_SCHANNEL = 18;
219            public const uint PROV_SPYRUS_LYNKS = 20;
220            public const uint PROV_RNG = 21;
221            public const uint PROV_INTEL_SEC = 22;
222
223            public const int NTE_BAD_KEYSET = unchecked((int)0x80090016);
224
225            public const uint CRYPT_VERIFYCONTEXT = 0xF0000000;
226            public const uint CRYPT_NEWKEYSET = 0x00000008;
227            public const uint CRYPT_DELETEKEYSET = 0x00000010;
228            public const uint CRYPT_MACHINE_KEYSET = 0x00000020;
229            public const uint CRYPT_SILENT = 0x00000040;
230
231            /// <summary>
232            /// The GetTokenInformation function retrieves a specified type of information
233            /// about an access token. The calling process must have appropriate access
234            /// rights to obtain the information.
235            /// </summary>
236            /// <param name="TokenHandle">A handle to an access token from which
237            /// information is retrieved. If TokenInformationClass specifies TokenSource,
238            /// the handle must have TOKEN_QUERY_SOURCE access. For all other
239            /// TokenInformationClass values, the handle must have TOKEN_QUERY access.</param>
240            /// <param name="TokenInformationClass">Specifies a value from the
241            /// TOKEN_INFORMATION_CLASS enumerated type to identify the type of
242            /// information the function retrieves.</param>
243            /// <param name="TokenInformation">A pointer to a buffer the function
244            /// fills with the requested information. The structure put into this
245            /// buffer depends upon the type of information specified by the
246            /// TokenInformationClass parameter.</param>
247            /// <param name="TokenInformationLength">Specifies the size, in bytes,
248            /// of the buffer pointed to by the TokenInformation parameter.
249            /// If TokenInformation is NULL, this parameter must be zero.</param>
250            /// <param name="ReturnLength">A pointer to a variable that receives the
251            /// number of bytes needed for the buffer pointed to by the TokenInformation
252            /// parameter. If this value is larger than the value specified in the
253            /// TokenInformationLength parameter, the function fails and stores no
254            /// data in the buffer.
255            ///
256            /// If the value of the TokenInformationClass parameter is TokenDefaultDacl
257            /// and the token has no default DACL, the function sets the variable pointed
258            /// to by ReturnLength to sizeof(TOKEN_DEFAULT_DACL) and sets the
259            /// DefaultDacl member of the TOKEN_DEFAULT_DACL structure to NULL.</param>
260            /// <returns> If the function succeeds, the return value is true. To get
261            /// extended error information, call Marshal.GetLastWin32Error().</returns>
262            [DllImport("Advapi32.dll", SetLastError = true)]
263            [return: MarshalAs(UnmanagedType.Bool)]
264            public static extern bool GetTokenInformation(SafeTokenHandle TokenHandle,
265                TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation,
266                uint TokenInformationLength, out uint ReturnLength);
267
268            /// <summary>
269            /// The OpenProcessToken function opens the access token associated with a process.
270            /// </summary>
271            /// <param name="ProcessHandle">A handle to the process whose access token
272            /// is opened. The process must have the PROCESS_QUERY_INFORMATION access
273            /// permission.</param>
274            /// <param name="DesiredAccess">Specifies an access mask that specifies
275            /// the requested types of access to the access token. These requested
276            /// access types are compared with the discretionary access control
277            /// list (DACL) of the token to determine which accesses are granted or
278            /// denied.</param>
279            /// <param name="TokenHandle">A pointer to a handle that identifies the
280            /// newly opened access token when the function returns.</param>
281            /// <returns> If the function succeeds, the return value is true. To get
282            /// extended error information, call Marshal.GetLastWin32Error().</returns>
283            [DllImport("Advapi32.dll", SetLastError = true)]
284            [return: MarshalAs(UnmanagedType.Bool)]
285            public static extern bool OpenProcessToken(IntPtr ProcessHandle,
286                UInt32 DesiredAccess, out SafeTokenHandle TokenHandle);
287
288            public const uint STANDARD_RIGHTS_REQUIRED = 0xF0000;
289            public const uint TOKEN_ASSIGN_PRIMARY = 0x00001;
290            public const uint TOKEN_DUPLICATE = 0x00002;
291            public const uint TOKEN_IMPERSONATE = 0x00004;
292            public const uint TOKEN_QUERY = 0x00008;
293            public const uint TOKEN_QUERY_SOURCE = 0x00010;
294            public const uint TOKEN_ADJUST_PRIVILEGES = 0x00020;
295            public const uint TOKEN_ADJUST_GROUPS = 0x00040;
296            public const uint TOKEN_ADJUST_DEFAULT = 0x00080;
297            public const uint TOKEN_ADJUST_SESSIONID = 0x00100;
298            public const uint TOKEN_ALL_ACCESS_P = (STANDARD_RIGHTS_REQUIRED |
299                TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY |
300                TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS |
301                TOKEN_ADJUST_DEFAULT);
302
303            public enum TOKEN_INFORMATION_CLASS
304            {
305                TokenUser = 1,
306                TokenGroups = 2,
307                TokenPrivileges = 3,
308                TokenOwner = 4,
309                TokenPrimaryGroup = 5,
310                TokenDefaultDacl = 6,
311                TokenSource = 7,
312                TokenType = 8,
313                TokenImpersonationLevel = 9,
314                TokenStatistics = 10,
315                TokenRestrictedSids = 11,
316                TokenSessionId = 12,
317                TokenGroupsAndPrivileges = 13,
318                TokenSessionReference = 14,
319                TokenSandBoxInert = 15,
320                TokenAuditPolicy = 16,
321                TokenOrigin = 17,
322                TokenElevationType = 18,
323                TokenLinkedToken = 19,
324                TokenElevation = 20,
325                TokenHasRestrictions = 21,
326                TokenAccessInformation = 22,
327                TokenVirtualizationAllowed = 23,
328                TokenVirtualizationEnabled = 24,
329                TokenIntegrityLevel = 25,
330                TokenUIAccess = 26,
331                TokenMandatoryPolicy = 27,
332                TokenLogonSid = 28,
333                MaxTokenInfoClass = 29  // MaxTokenInfoClass should always be the last enum
334            }
335
336            public enum TOKEN_ELEVATION_TYPE
337            {
338                TokenElevationTypeDefault = 1,
339                TokenElevationTypeFull = 2,
340                TokenElevationTypeLimited = 3,
341            }
342        }
343    }
344
345    public sealed class CryptApi : IDisposable
346    {
347        /// <summary>
348        /// Constructor.
349        /// </summary>
350        private CryptApi()
351        {
352            /* Intel i8xx (82802 Firmware Hub Device) hardware random number generator */
353            const string IntelDefaultProvider = "Intel Hardware Cryptographic Service Provider";
354
355            handle = new SafeCryptHandle();
356            if (AdvApi.NativeMethods.CryptAcquireContext(out handle, string.Empty,
357                IntelDefaultProvider, AdvApi.NativeMethods.PROV_INTEL_SEC, 0))
358            {
359                return;
360            }
361            else if (AdvApi.NativeMethods.CryptAcquireContext(out handle, string.Empty,
362                string.Empty, AdvApi.NativeMethods.PROV_RSA_FULL, 0))
363            {
364                return;
365            }
366            else if (Marshal.GetLastWin32Error() == AdvApi.NativeMethods.NTE_BAD_KEYSET)
367            {
368                //Default keyset doesn't exist, attempt to create a new one
369                if (AdvApi.NativeMethods.CryptAcquireContext(out handle, string.Empty,
370                    string.Empty, AdvApi.NativeMethods.PROV_RSA_FULL,
371                    AdvApi.NativeMethods.CRYPT_NEWKEYSET))
372                {
373                    return;
374                }
375            }
376
377            throw new NotSupportedException("Unable to acquire a cryptographic service provider.");
378        }
379
380        #region IDisposable Members
381        ~CryptApi()
382        {
383            Dispose(false);
384        }
385
386        public void Dispose(bool disposing)
387        {
388            if (disposing)
389                handle.Close();
390        }
391
392        public void Dispose()
393        {
394            Dispose(true);
395            GC.SuppressFinalize(this);
396        }
397        #endregion
398
399        /// <summary>
400        /// The GenRandom function fills a buffer with cryptographically random bytes.
401        /// </summary>
402        /// <param name="buffer">Buffer to receive the returned data. This buffer
403        /// must be at least dwLen bytes in length.
404        ///
405        /// Optionally, the application can fill this buffer with data to use as
406        /// an auxiliary random seed.</param>
407        public static bool CryptGenRandom(byte[] buffer)
408        {
409            return AdvApi.NativeMethods.CryptGenRandom(instance.handle,
410                (uint)buffer.Length, buffer);
411        }
412
413        /// <summary>
414        /// The HCRYPTPROV handle.
415        /// </summary>
416        private SafeCryptHandle handle;
417
418        /// <summary>
419        /// The global CryptAPI instance.
420        /// </summary>
421        private static CryptApi instance = new CryptApi();
422    }
423
424    internal class SafeCryptHandle : SafeHandle
425    {
426        public SafeCryptHandle()
427            : base(IntPtr.Zero, true)
428        {
429        }
430
431        public override bool IsInvalid
432        {
433            get { return handle == IntPtr.Zero; }
434        }
435
436        protected override bool ReleaseHandle()
437        {
438            AdvApi.NativeMethods.CryptReleaseContext(handle, 0u);
439            handle = IntPtr.Zero;
440            return true;
441        }
442    }
443
444    internal class SafeTokenHandle : SafeHandle
445    {
446        public SafeTokenHandle()
447            : base(IntPtr.Zero, true)
448        {
449        }
450
451        public override bool IsInvalid
452        {
453            get { return handle == IntPtr.Zero; }
454        }
455
456        protected override bool ReleaseHandle()
457        {
458            KernelApi.NativeMethods.CloseHandle(handle);
459            handle = IntPtr.Zero;
460            return true;
461        }
462    }
463}
Note: See TracBrowser for help on using the repository browser.