Completed unit testing and fixes for aclapi.h functions

pull/83/head
David Hall 2019-08-02 13:42:47 -06:00
parent 8dee73c55c
commit c09b2ec246
3 changed files with 203 additions and 7 deletions

View File

@ -18,6 +18,41 @@ namespace Vanara.PInvoke
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)]
public delegate void FN_PROGRESS(string pObjectName, uint Status, ref PROG_INVOKE_SETTING pInvokeSetting, IntPtr Args, [MarshalAs(UnmanagedType.Bool)] bool SecuritySet);
/// <summary>Flags to control the behavior of <see cref="TreeSetNamedSecurityInfo"/>.</summary>
[PInvokeData("aclapi.h", MSDNShortId = "caa711c3-301b-4ed7-b1f4-dc6a48563905")]
public enum TREE_SEC_INFO
{
/// <summary>
/// The security information is set on the object specified by the pObjectName parameter and the tree of child objects of that
/// object. If ACLs are specified in either the pDacl or pSacl parameters, the security descriptors are associated with the
/// object. The security descriptors are propagated to the tree of child objects based on their inheritance properties.
/// </summary>
TREE_SEC_INFO_SET = 0x00000001,
/// <summary>
/// The security information is reset on the object specified by the pObjectName parameter and the tree of child objects of that
/// object. Any existing security information is removed from all objects on the tree.
/// <para>
/// If any object in the tree does not grant appropriate permissions to the caller to modify the security descriptor on the
/// object, then the propagation of security information on that particular node of the tree and its objects is skipped. The
/// operation continues on the rest of the tree under the object specified by the pObjectName parameter.
/// </para>
/// </summary>
TREE_SEC_INFO_RESET = 0x00000002,
/// <summary>
/// The security information is reset on the object specified by the pObjectName parameter and the tree of child objects of that
/// object. Any existing inherited security information is removed from all objects on the tree. Security information that was
/// explicitly set on objects in the tree is unchanged.
/// <para>
/// If any object in the tree does not grant appropriate permissions to the caller to modify the security descriptor on the
/// object, then the propagation of security information on that particular node of the tree and its objects is skipped. The
/// operation continues on the rest of the tree under the object specified by the pObjectName parameter.
/// </para>
/// </summary>
TREE_SEC_INFO_RESET_KEEP_EXPLICIT = 0x00000003,
}
/// <summary>
/// <para>
/// The <c>BuildExplicitAccessWithName</c> function initializes an EXPLICIT_ACCESS structure with data specified by the caller. The
@ -903,8 +938,7 @@ namespace Vanara.PInvoke
// https://docs.microsoft.com/en-us/windows/desktop/api/aclapi/nf-aclapi-gettrusteenamea LPSTR GetTrusteeNameA( PTRUSTEE_A pTrustee );
[DllImport(Lib.AdvApi32, SetLastError = false, CharSet = CharSet.Auto)]
[PInvokeData("aclapi.h", MSDNShortId = "9d3ce528-fb28-4e2e-bf7f-7d84c697fcb6")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetTrusteeName(in TRUSTEE pTrustee);
public static extern StrPtrAuto GetTrusteeName(in TRUSTEE pTrustee);
/// <summary>
/// <para>
@ -1143,8 +1177,8 @@ namespace Vanara.PInvoke
/// </returns>
[DllImport(Lib.AdvApi32, CharSet = CharSet.Auto)]
[PInvokeData("Aclapi.h", MSDNShortId = "aa379579")]
public static extern Win32Error SetNamedSecurityInfo(string pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID ppsidOwner,
PSID ppsidGroup, PACL ppDacl, PACL ppSacl);
public static extern Win32Error SetNamedSecurityInfo(string pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, [Optional] PSID ppsidOwner,
[Optional] PSID ppsidGroup, [Optional] PACL ppDacl, [Optional] PACL ppSacl);
/// <summary>
/// <para>
@ -1256,7 +1290,7 @@ namespace Vanara.PInvoke
// SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl );
[DllImport(Lib.AdvApi32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("aclapi.h", MSDNShortId = "f1781ba9-81eb-46f9-b530-c390b67d65de")]
public static extern Win32Error SetSecurityInfo(IntPtr handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl);
public static extern Win32Error SetSecurityInfo(IntPtr handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, [Optional] PSID psidOwner, [Optional] PSID psidGroup, [Optional] PACL pDacl, [Optional] PACL pSacl);
/// <summary>
/// <para>
@ -1374,7 +1408,7 @@ namespace Vanara.PInvoke
[DllImport(Lib.AdvApi32, SetLastError = false, CharSet = CharSet.Auto)]
[PInvokeData("aclapi.h", MSDNShortId = "adae7d07-a452-409e-b1a1-e9f86f873e39")]
public static extern Win32Error TreeResetNamedSecurityInfo(string pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID pOwner, PSID pGroup, PACL pDacl, PACL pSacl,
[MarshalAs(UnmanagedType.Bool)] bool KeepExplicit, FN_PROGRESS fnProgress, PROG_INVOKE_SETTING ProgressInvokeSetting, IntPtr Args);
[MarshalAs(UnmanagedType.Bool)] bool KeepExplicit, [Optional] FN_PROGRESS fnProgress, PROG_INVOKE_SETTING ProgressInvokeSetting, [Optional] IntPtr Args);
/// <summary>
/// <para>
@ -1527,7 +1561,7 @@ namespace Vanara.PInvoke
[DllImport(Lib.AdvApi32, SetLastError = false, CharSet = CharSet.Auto)]
[PInvokeData("aclapi.h", MSDNShortId = "caa711c3-301b-4ed7-b1f4-dc6a48563905")]
public static extern Win32Error TreeSetNamedSecurityInfo(string pObjectName, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID pOwner, PSID pGroup,
PACL pDacl, PACL pSacl, uint dwAction, FN_PROGRESS fnProgress, PROG_INVOKE_SETTING ProgressInvokeSetting, IntPtr Args);
PACL pDacl, PACL pSacl, TREE_SEC_INFO dwAction, [Optional] FN_PROGRESS fnProgress, PROG_INVOKE_SETTING ProgressInvokeSetting, [Optional] IntPtr Args);
/// <summary>A <see cref="SafeHandle"/> to hold the array of <see cref="INHERITED_FROM"/> instances returned from <see cref="GetInheritanceSource"/>.</summary>
public class SafeInheritedFromArray : SafeHGlobalHandle

View File

@ -0,0 +1,161 @@
using NUnit.Framework;
using System;
using static Vanara.PInvoke.AdvApi32;
namespace Vanara.PInvoke.Tests
{
[TestFixture()]
public class AclApiTests
{
public const SECURITY_INFORMATION SecInfoAll = SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION | SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION | SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.SACL_SECURITY_INFORMATION;
public static readonly string localAdmins = $"{Environment.MachineName}\\Administrators";
public static readonly SafePSECURITY_DESCRIPTOR pSd;
public static readonly string userName = $"{Environment.UserDomainName}\\{Environment.UserName}";
static AclApiTests()
{
using (new PrivBlock("SeSecurityPrivilege"))
pSd = AdvApi32Tests.GetSD(AdvApi32Tests.fn, SecInfoAll);
}
[Test]
public void BuildExplicitAccessWithNameTest()
{
EXPLICIT_ACCESS ea = default;
Assert.That(() => BuildExplicitAccessWithName(out ea, userName, 0x10000000, ACCESS_MODE.SET_ACCESS, INHERIT_FLAGS.SUB_CONTAINERS_AND_OBJECTS_INHERIT), Throws.Nothing);
Assert.That(ea.grfAccessMode, Is.Not.Zero);
ea.WriteValues();
}
[Test]
public void BuildSecurityDescriptorTest()
{
SafePSECURITY_DESCRIPTOR pSd = null;
Assert.That(() =>
{
BuildTrusteeWithName(out var trustee, userName);
BuildTrusteeWithName(out var grpTrustee, localAdmins);
BuildExplicitAccessWithName(out var ea, userName, 0x10000000, ACCESS_MODE.SET_ACCESS, INHERIT_FLAGS.SUB_CONTAINERS_AND_OBJECTS_INHERIT);
BuildSecurityDescriptor(trustee, grpTrustee, 1, new[] { ea }, 0, null, PSECURITY_DESCRIPTOR.NULL, out var sz, out pSd);
}, Throws.Nothing);
Assert.That(pSd, Is.Not.Null);
Assert.That(pSd.IsInvalid, Is.False);
pSd.Dispose();
}
[Test]
public void BuildTrusteeWithObjectsAndNameTest()
{
Assert.That(() => BuildTrusteeWithObjectsAndName(out var t, default, SE_OBJECT_TYPE.SE_FILE_OBJECT, "", "", "Name"), Throws.Nothing);
}
[Test]
public void BuildTrusteeWithObjectsAndSidTest()
{
Assert.That(() => BuildTrusteeWithObjectsAndSid(out var t, default, default, default, PSID.NULL), Throws.Nothing);
}
[Test]
public void BuildTrusteeWithSidTest()
{
Assert.That(() => BuildTrusteeWithSid(out var t, PSID.NULL), Throws.Nothing);
}
[Test]
public void GetAuditedPermissionsFromAclTest()
{
Assert.That(GetSecurityDescriptorSacl(pSd, out var ok, out var pSacl, out _), ResultIs.Successful);
BuildTrusteeWithName(out var trustee, userName);
Assert.That(GetAuditedPermissionsFromAcl(pSacl, trustee, out var smask, out var fmask), ResultIs.Successful);
(smask, fmask).WriteValues();
}
[Test]
public void GetExplicitEntriesFromAclTest()
{
Assert.That(GetSecurityDescriptorDacl(pSd, out var ok, out var pDacl, out _), ResultIs.Successful);
Assert.That(GetExplicitEntriesFromAcl(pDacl, out var cnt, out var memList), ResultIs.Successful);
using (memList)
Assert.That(() => memList.ToArray<EXPLICIT_ACCESS>((int)cnt).WriteValues(), Throws.Nothing);
}
[Test]
public void GetSetSecurityInfoTest()
{
using (var tmp = new TempFile(Kernel32.FileAccess.FILE_ALL_ACCESS, System.IO.FileShare.Read))
{
Assert.That(GetSecurityInfo(tmp.hFile.DangerousGetHandle(), SE_OBJECT_TYPE.SE_FILE_OBJECT, SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION, out var owner, out _, out _, out _, out var plsd), ResultIs.Successful);
Assert.That(SetSecurityInfo(tmp.hFile.DangerousGetHandle(), SE_OBJECT_TYPE.SE_FILE_OBJECT, SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION, owner), ResultIs.Successful);
}
}
[Test]
public void GetTrusteeFormTest()
{
BuildTrusteeWithName(out var trustee, userName);
Assert.That(GetTrusteeForm(trustee), ResultIs.Value(TRUSTEE_FORM.TRUSTEE_IS_NAME));
}
[Test]
public void GetTrusteeNameTest()
{
BuildTrusteeWithName(out var trustee, userName);
var s = GetTrusteeName(trustee);
Assert.That(s.ToString(), ResultIs.Value(userName));
}
[Test]
public void GetTrusteeTypeTest()
{
BuildTrusteeWithName(out var trustee, userName);
Assert.That(GetTrusteeType(trustee), ResultIs.Value(TRUSTEE_TYPE.TRUSTEE_IS_UNKNOWN));
}
[Test]
public void LookupSecurityDescriptorPartsTest()
{
Assert.That(LookupSecurityDescriptorParts(out var ptOwner, out var ptGrp, out var cnt, out var plEntries, out var acnt, out var plAEntries, pSd), ResultIs.Successful);
ptOwner.ToStructure<TRUSTEE>().WriteValues();
ptGrp.ToStructure<TRUSTEE>().WriteValues();
plEntries.ToArray<EXPLICIT_ACCESS>((int)cnt).WriteValues();
plAEntries.ToArray<EXPLICIT_ACCESS>((int)acnt).WriteValues();
}
[Test]
public void SetEntriesInAclTest()
{
Assert.That(GetSecurityDescriptorDacl(pSd, out _, out var pDacl, out _), ResultIs.Successful);
BuildExplicitAccessWithName(out var ea, $"{Environment.MachineName}\\Invalid", 0x10000000, ACCESS_MODE.SET_ACCESS, 0);
var entries = new[] { ea };
Assert.That(SetEntriesInAcl((uint)entries.Length, entries, pDacl, out var pNewAcl), ResultIs.FailureCode(Win32Error.ERROR_NONE_MAPPED));
}
[Test]
public void TreeResetNamedSecurityInfoTest()
{
var counter = 0;
using (new PrivBlock("SeSecurityPrivilege"))
{
Assert.That(GetNamedSecurityInfo(AdvApi32Tests.fn, SE_OBJECT_TYPE.SE_FILE_OBJECT, SecInfoAll, out var pOwnSid, out var pGrpSid, out var dacl, out var sacl, out var plsd), ResultIs.Successful);
Assert.That(TreeResetNamedSecurityInfo(@"C:\Temp\Temp\", SE_OBJECT_TYPE.SE_FILE_OBJECT, SecInfoAll, pOwnSid, pGrpSid, dacl, sacl, false, OnProgress, PROG_INVOKE_SETTING.ProgressInvokeEveryObject), ResultIs.Successful);
}
Assert.That(counter, Is.GreaterThan(0));
void OnProgress(string pObjectName, uint Status, ref PROG_INVOKE_SETTING pInvokeSetting, IntPtr Args, bool SecuritySet) { counter++; }
}
[Test]
public void TreeSetNamedSecurityInfoTest()
{
var counter = 0;
using (new PrivBlock("SeSecurityPrivilege"))
{
Assert.That(GetNamedSecurityInfo(AdvApi32Tests.fn, SE_OBJECT_TYPE.SE_FILE_OBJECT, SecInfoAll, out var pOwnSid, out var pGrpSid, out var dacl, out var sacl, out var plsd), ResultIs.Successful);
Assert.That(TreeSetNamedSecurityInfo(@"C:\Temp\Temp\", SE_OBJECT_TYPE.SE_FILE_OBJECT, SecInfoAll, pOwnSid, pGrpSid, dacl, sacl, TREE_SEC_INFO.TREE_SEC_INFO_SET, OnProgress, PROG_INVOKE_SETTING.ProgressInvokeEveryObject), ResultIs.Successful);
}
Assert.That(counter, Is.GreaterThan(0));
void OnProgress(string pObjectName, uint Status, ref PROG_INVOKE_SETTING pInvokeSetting, IntPtr Args, bool SecuritySet) { counter++; }
}
}
}

View File

@ -40,6 +40,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AdvApi32\AdvApi32Tests.cs" />
<Compile Include="AdvApi32\AclApiTests.cs" />
<Compile Include="AdvApi32\AuditTests.cs" />
<Compile Include="AdvApi32\AppMgmtTests.cs" />
<Compile Include="AdvApi32\SecurityBaseApiTests.cs" />