File: System\Security\Principal\Win32.cs
Web Access
Project: src\src\runtime\src\libraries\System.Security.Principal.Windows\src\System.Security.Principal.Windows.csproj (System.Security.Principal.Windows)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace System.Security.Principal
{
    internal static class Win32
    {
        internal const int FALSE = 0;

        //
        // Wrapper around advapi32.LsaOpenPolicy
        //


        internal static SafeLsaPolicyHandle LsaOpenPolicy(
            string? systemName,
            Interop.Advapi32.PolicyRights rights)
        {

            Interop.OBJECT_ATTRIBUTES attributes = default;
            uint error = Interop.Advapi32.LsaOpenPolicy(systemName, ref attributes, (int)rights, out SafeLsaPolicyHandle policyHandle);
            if (error == 0)
            {
                return policyHandle;
            }

            policyHandle.Dispose();

            if (error == Interop.StatusOptions.STATUS_ACCESS_DENIED)
            {
                throw new UnauthorizedAccessException();
            }
            else if (error == Interop.StatusOptions.STATUS_INSUFFICIENT_RESOURCES ||
                      error == Interop.StatusOptions.STATUS_NO_MEMORY)
            {
                throw new OutOfMemoryException();
            }
            else
            {
                uint win32ErrorCode = Interop.Advapi32.LsaNtStatusToWinError(error);

                throw new Win32Exception(unchecked((int)win32ErrorCode));
            }
        }


        internal static byte[] ConvertIntPtrSidToByteArraySid(IntPtr binaryForm)
        {
            byte[] ResultSid;

            //
            // Verify the revision (just sanity, should never fail to be 1)
            //

            byte Revision = Marshal.ReadByte(binaryForm, 0);

            if (Revision != SecurityIdentifier.Revision)
            {
                throw new ArgumentException(SR.IdentityReference_InvalidSidRevision, nameof(binaryForm));
            }

            //
            // Need the subauthority count in order to figure out how many bytes to read
            //

            byte SubAuthorityCount = Marshal.ReadByte(binaryForm, 1);

            if (SubAuthorityCount < 0 ||
                SubAuthorityCount > SecurityIdentifier.MaxSubAuthorities)
            {
                throw new ArgumentException(SR.Format(SR.IdentityReference_InvalidNumberOfSubauthorities, SecurityIdentifier.MaxSubAuthorities), nameof(binaryForm));
            }

            //
            // Compute the size of the binary form of this SID and allocate the memory
            //

            int BinaryLength = 1 + 1 + 6 + SubAuthorityCount * 4;
            ResultSid = new byte[BinaryLength];

            //
            // Extract the data from the returned pointer
            //

            Marshal.Copy(binaryForm, ResultSid, 0, BinaryLength);

            return ResultSid;
        }

        //
        // Wrapper around advapi32.ConvertStringSidToSidW
        //


        internal static unsafe int CreateSidFromString(
            string stringSid,
            out byte[]? resultSid
            )
        {
            int ErrorCode;
            void* pSid = null;

            try
            {
                if (Interop.BOOL.FALSE == Interop.Advapi32.ConvertStringSidToSid(stringSid, out pSid))
                {
                    ErrorCode = Marshal.GetLastPInvokeError();
                    goto Error;
                }

                resultSid = ConvertIntPtrSidToByteArraySid((IntPtr)pSid);
            }
            finally
            {
                //
                // Now is a good time to get rid of the returned pointer
                //

                Marshal.FreeHGlobal((IntPtr)pSid);
            }

            //
            // Now invoke the SecurityIdentifier factory method to create the result
            //

            return Interop.Errors.ERROR_SUCCESS;

        Error:

            resultSid = null;
            return ErrorCode;
        }

        //
        // Wrapper around advapi32.CreateWellKnownSid
        //


        internal static int CreateWellKnownSid(
            WellKnownSidType sidType,
            SecurityIdentifier? domainSid,
            out byte[]? resultSid
            )
        {
            //
            // Passing an array as big as it can ever be is a small price to pay for
            // not having to P/Invoke twice (once to get the buffer, once to get the data)
            //

            uint length = (uint)SecurityIdentifier.MaxBinaryLength;
            resultSid = new byte[length];

            if (FALSE != Interop.Advapi32.CreateWellKnownSid((int)sidType, domainSid?.BinaryForm, resultSid, ref length))
            {
                return Interop.Errors.ERROR_SUCCESS;
            }
            else
            {
                resultSid = null;

                return Marshal.GetLastPInvokeError();
            }
        }

        //
        // Wrapper around advapi32.EqualDomainSid
        //


        internal static bool IsEqualDomainSid(SecurityIdentifier sid1, SecurityIdentifier sid2)
        {
            if (sid1 == null || sid2 == null)
            {
                return false;
            }
            else
            {
                byte[] BinaryForm1 = new byte[sid1.BinaryLength];
                sid1.GetBinaryForm(BinaryForm1, 0);

                byte[] BinaryForm2 = new byte[sid2.BinaryLength];
                sid2.GetBinaryForm(BinaryForm2, 0);

                return (Interop.Advapi32.IsEqualDomainSid(BinaryForm1, BinaryForm2, out bool result) == FALSE ? false : result);
            }
        }

        //
        // Wrapper around avdapi32.GetWindowsAccountDomainSid
        //
        internal static int GetWindowsAccountDomainSid(
            SecurityIdentifier sid,
            out SecurityIdentifier? resultSid
            )
        {
            //
            // Passing an array as big as it can ever be is a small price to pay for
            // not having to P/Invoke twice (once to get the buffer, once to get the data)
            //

            byte[] BinaryForm = new byte[sid.BinaryLength];
            sid.GetBinaryForm(BinaryForm, 0);
            uint sidLength = (uint)SecurityIdentifier.MaxBinaryLength;
            byte[] resultSidBinary = new byte[sidLength];

            if (FALSE != Interop.Advapi32.GetWindowsAccountDomainSid(BinaryForm, resultSidBinary, ref sidLength))
            {
                resultSid = new SecurityIdentifier(resultSidBinary, 0);

                return Interop.Errors.ERROR_SUCCESS;
            }
            else
            {
                resultSid = null;

                return Marshal.GetLastPInvokeError();
            }
        }

        //
        // Wrapper around advapi32.IsWellKnownSid
        //


        internal static bool IsWellKnownSid(
            SecurityIdentifier sid,
            WellKnownSidType type
            )
        {
            byte[] BinaryForm = new byte[sid.BinaryLength];
            sid.GetBinaryForm(BinaryForm, 0);

            if (FALSE == Interop.Advapi32.IsWellKnownSid(BinaryForm, (int)type))
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}