From 99479b1f27a5f1a403d4c394924acf0508c3f5e2 Mon Sep 17 00:00:00 2001 From: dahall Date: Tue, 5 Jul 2022 09:44:38 -0600 Subject: [PATCH] Added overloads for LsaAddAccountRights and LsaRemoveAccountRights and optimized marshaling code --- PInvoke/Security/AdvApi32/NTSecApi.Lsa.cs | 133 ++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 17 deletions(-) diff --git a/PInvoke/Security/AdvApi32/NTSecApi.Lsa.cs b/PInvoke/Security/AdvApi32/NTSecApi.Lsa.cs index 64f2533a..b26ca487 100644 --- a/PInvoke/Security/AdvApi32/NTSecApi.Lsa.cs +++ b/PInvoke/Security/AdvApi32/NTSecApi.Lsa.cs @@ -283,6 +283,49 @@ namespace Vanara.PInvoke public static extern NTStatus LsaAddAccountRights(LSA_HANDLE PolicyHandle, PSID AccountSid, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(LsaUnicodeStringArrayMarshaler))] string[] UserRights, uint CountOfRights); + /// + /// The LsaAddAccountRights function assigns one or more privileges to an account. If the account does not exist, + /// LsaAddAccountRights creates it. + /// + /// + /// A handle to a Policy object. The handle must have the POLICY_LOOKUP_NAMES access right. If the account identified by the + /// AccountSid parameter does not exist, the handle must have the POLICY_CREATE_ACCOUNT access right. For more information, see + /// Opening a Policy Object Handle. + /// + /// Pointer to the SID of the account to which the function assigns privileges. + /// + /// Pointer to an array of LSA_UNICODE_STRING structures. Each structure contains the name of a privilege to add to the account. For + /// a list of privilege names, see Privilege Constants. + /// + /// + /// If the function succeeds, the return value is STATUS_SUCCESS. + /// + /// If the function fails, the return value is an NTSTATUS code, which can be the following value or one of the LSA Policy Function + /// Return Values. + /// + /// + /// + /// Return code + /// Description + /// + /// + /// STATUS_NO_SUCH_PRIVILEGE + /// One of the privilege names is not valid. + /// + /// + /// You can use the LsaNtStatusToWinError function to convert the NTSTATUS code to a Windows error code. + /// + /// + /// If you specify privileges already granted to the account, they are ignored. + /// For an example that demonstrates calling this function, see Managing Account Permissions. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-lsaaddaccountrights NTSTATUS LsaAddAccountRights( + // LSA_HANDLE PolicyHandle, PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); + [PInvokeData("ntsecapi.h", MSDNShortId = "66b78404-02c2-48e9-92c3-d27b68f77c23")] + public static NTStatus LsaAddAccountRights(LSA_HANDLE PolicyHandle, PSID AccountSid, + [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(LsaUnicodeStringArrayMarshaler))] params string[] UserRights) => + LsaAddAccountRights(PolicyHandle, AccountSid, UserRights, (uint)UserRights?.Length); + /// Undocumented function for creating an account. /// A handle to a Policy object. For more information, see Opening a Policy Object Handle. /// Pointer to the SID of the account for which to enumerate privileges. @@ -351,7 +394,8 @@ namespace Vanara.PInvoke // PTRUSTED_DOMAIN_AUTH_INFORMATION AuthenticationInformation, ACCESS_MASK DesiredAccess, PLSA_HANDLE TrustedDomainHandle ); [DllImport(Lib.AdvApi32, SetLastError = false, ExactSpelling = true)] [PInvokeData("ntsecapi.h", MSDNShortId = "2f458098-9498-4f08-bd13-ac572678d734")] - public static extern NTStatus LsaCreateTrustedDomainEx(LSA_HANDLE PolicyHandle, in TRUSTED_DOMAIN_INFORMATION_EX TrustedDomainInformation, in TRUSTED_DOMAIN_AUTH_INFORMATION AuthenticationInformation, ACCESS_MASK DesiredAccess, out SafeLSA_HANDLE TrustedDomainHandle); + public static extern NTStatus LsaCreateTrustedDomainEx(LSA_HANDLE PolicyHandle, in TRUSTED_DOMAIN_INFORMATION_EX TrustedDomainInformation, + in TRUSTED_DOMAIN_AUTH_INFORMATION AuthenticationInformation, ACCESS_MASK DesiredAccess, out SafeLSA_HANDLE TrustedDomainHandle); /// /// The LsaDeleteTrustedDomain function removes a trusted domain from the list of trusted domains for a system and deletes the @@ -1837,7 +1881,9 @@ namespace Vanara.PInvoke // InformationClass, PVOID *Buffer ); [DllImport(Lib.AdvApi32, SetLastError = false, ExactSpelling = true)] [PInvokeData("ntsecapi.h", MSDNShortId = "d33d6cee-bd8b-49f4-8e65-07cdc65bec7c")] - public static extern NTStatus LsaQueryTrustedDomainInfoByName(LSA_HANDLE PolicyHandle, [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(LsaUnicodeStringMarshaler))] string TrustedDomainName, TRUSTED_INFORMATION_CLASS InformationClass, out SafeLsaMemoryHandle Buffer); + public static extern NTStatus LsaQueryTrustedDomainInfoByName(LSA_HANDLE PolicyHandle, + [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(LsaUnicodeStringMarshaler))] string TrustedDomainName, + TRUSTED_INFORMATION_CLASS InformationClass, out SafeLsaMemoryHandle Buffer); /// /// @@ -1898,13 +1944,67 @@ namespace Vanara.PInvoke [PInvokeData("ntsecapi.h", MSDNShortId = "ad250a01-7a24-4fae-975c-aa3e65731c82")] // public static extern NTSTATUS LsaRemoveAccountRights(LSA_HANDLE PolicyHandle, PSID AccountSid, [MarshalAs(UnmanagedType.U1)] bool // AllRights, PLSA_UNICODE_STRING UserRights, uint CountOfRights); - public static extern NTStatus LsaRemoveAccountRights( - LSA_HANDLE PolicyHandle, - PSID AccountSid, - [MarshalAs(UnmanagedType.Bool)] bool AllRights, - [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(LsaUnicodeStringArrayMarshaler))] - string[] UserRights, - uint CountOfRights); + public static extern NTStatus LsaRemoveAccountRights( LSA_HANDLE PolicyHandle, PSID AccountSid, [MarshalAs(UnmanagedType.Bool)] bool AllRights, + [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(LsaUnicodeStringArrayMarshaler))] string[] UserRights, uint CountOfRights); + + /// + /// + /// The LsaRemoveAccountRights function removes one or more privileges from an account. You can specify the privileges to be + /// removed, or you can set a flag to remove all privileges. When you remove all privileges, the function deletes the account. If you + /// specify privileges not held by the account, the function ignores them. + /// + /// + /// + /// + /// A handle to a Policy object. The handle must have the POLICY_LOOKUP_NAMES access right. For more information, see Opening a + /// Policy Object Handle. + /// + /// + /// + /// Pointer to the security identifier (SID) of the account from which the privileges are removed. + /// + /// + /// + /// If TRUE, the function removes all privileges and deletes the account. In this case, the function ignores the UserRights + /// parameter. If FALSE, the function removes the privileges specified by the UserRights parameter. + /// + /// + /// + /// + /// Pointer to an array of LSA_UNICODE_STRING structures. Each structure contains the name of a privilege to be removed from the + /// account. For a list of privilege names, see Privilege Constants. + /// + /// + /// + /// If the function succeeds, the return value is STATUS_SUCCESS. + /// + /// If the function fails, the return value is an NTSTATUS code, which can be one of the following values or one of the LSA Policy + /// Function Return Values. + /// + /// + /// + /// Value + /// Description + /// + /// + /// STATUS_NO_SUCH_PRIVILEGE + /// One of the privilege names is not valid. + /// + /// + /// STATUS_INVALID_PARAMETER + /// Indicates the UserRights parameter was NULL and the AllRights parameter was FALSE. + /// + /// + /// You can use the LsaNtStatusToWinError function to convert the NTSTATUS code to a Windows error code. + /// + // https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-lsaremoveaccountrights NTSTATUS LsaRemoveAccountRights( + // LSA_HANDLE PolicyHandle, PSID AccountSid, BOOLEAN AllRights, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); + [PInvokeData("ntsecapi.h", MSDNShortId = "ad250a01-7a24-4fae-975c-aa3e65731c82")] + // public static extern NTSTATUS LsaRemoveAccountRights(LSA_HANDLE PolicyHandle, PSID AccountSid, [MarshalAs(UnmanagedType.U1)] bool + // AllRights, PLSA_UNICODE_STRING UserRights, uint CountOfRights); + public static NTStatus LsaRemoveAccountRights(LSA_HANDLE PolicyHandle, PSID AccountSid, [MarshalAs(UnmanagedType.Bool)] bool AllRights, + [In, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(LsaUnicodeStringArrayMarshaler))] params string[] UserRights) => + LsaRemoveAccountRights(PolicyHandle, AccountSid, AllRights, UserRights, (uint)UserRights?.Length); /// Do not use the LSA private data functions. Instead, use the CryptProtectData and CryptUnprotectData functions. /// @@ -3232,17 +3332,16 @@ namespace Vanara.PInvoke if (ManagedObj is string[] a) { var uma = Array.ConvertAll(a, p => new LSA_UNICODE_STRING { length = (ushort)StringHelper.GetByteCount(p, false, CharSet.Unicode) }); - var sz = Marshal.SizeOf(typeof(LSA_UNICODE_STRING)); - var strSz = uma.Sum(s => s.length + 2); - var result = Marshal.AllocCoTaskMem(sz * a.Length + strSz); - var strPtr = result.Offset(sz * a.Length); + var strSz = uma.Sum(s => s.length + UnicodeEncoding.CharSize); + var result = Marshal.AllocCoTaskMem(LsaUnicodeStringMarshaler.ssz * a.Length + strSz); + var strPtr = result.Offset(LsaUnicodeStringMarshaler.ssz * a.Length); for (var i = 0; i < uma.Length; i++) { uma[i].Buffer = strPtr; StringHelper.Write(a[i], (IntPtr)uma[i].Buffer, out var byteCnt, true, CharSet.Unicode); uma[i].MaximumLength = (ushort)byteCnt; strPtr = strPtr.Offset(byteCnt); - Marshal.StructureToPtr(uma[i], result.Offset(i * sz), false); + Marshal.StructureToPtr(uma[i], result.Offset(i * LsaUnicodeStringMarshaler.ssz), false); } return result; } @@ -3260,6 +3359,8 @@ namespace Vanara.PInvoke /// internal class LsaUnicodeStringMarshaler : ICustomMarshaler { + internal static readonly int ssz = Marshal.SizeOf(typeof(LSA_UNICODE_STRING)); + public static ICustomMarshaler GetInstance(string _) => new LsaUnicodeStringMarshaler(); public void CleanUpManagedData(object ManagedObj) @@ -3289,9 +3390,7 @@ namespace Vanara.PInvoke { if (value is null) return IntPtr.Zero; var lus = new LSA_UNICODE_STRING { length = (ushort)StringHelper.GetByteCount(value, false, CharSet.Unicode) }; - var chSz = StringHelper.GetCharSize(CharSet.Unicode); - lus.MaximumLength = (ushort)(lus.length + chSz); - var ssz = Marshal.SizeOf(typeof(LSA_UNICODE_STRING)); + lus.MaximumLength = (ushort)(lus.length + UnicodeEncoding.CharSize); var mem = Marshal.AllocCoTaskMem(ssz + lus.MaximumLength); lus.Buffer = mem.Offset(ssz); mem.Write(lus);