Skip to content

Commit 6efcf74

Browse files
committed
Reworked AccessCheckResult.
1 parent f0ae627 commit 6efcf74

5 files changed

Lines changed: 96 additions & 20 deletions

File tree

NtApiDotNet/AccessCheckResult.cs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@
1818
namespace NtApiDotNet
1919
{
2020
/// <summary>
21-
/// Result of an access check with specific access types. This is an extension with
22-
/// generic granted access masks.
21+
/// Result of an access check with specific access types.
2322
/// </summary>
24-
/// <typeparam name="T">The access rights type.</typeparam>
23+
/// <typeparam name="T">The access rights type, must be derived from an Enum.</typeparam>
2524
public class AccessCheckResult<T> where T : Enum
2625
{
2726
/// <summary>
@@ -49,13 +48,17 @@ public class AccessCheckResult<T> where T : Enum
4948
/// </summary>
5049
public T SpecificGenericGrantedAccess { get; }
5150
/// <summary>
51+
/// Object type associated with the access.
52+
/// </summary>
53+
public Guid ObjectType { get; }
54+
/// <summary>
5255
/// Get access check result as a specific access.
5356
/// </summary>
5457
/// <returns>The specific access results.</returns>
5558
public AccessCheckResult<U> ToSpecificAccess<U>() where U : Enum
5659
{
5760
return new AccessCheckResult<U>(Status, GrantedAccess, GenericGrantedAccess, PrivilegesRequired,
58-
GrantedAccess.ToSpecificAccess<U>(), GenericGrantedAccess.ToSpecificAccess<U>());
61+
GrantedAccess.ToSpecificAccess<U>(), GenericGrantedAccess.ToSpecificAccess<U>(), ObjectType);
5962
}
6063
/// <summary>
6164
/// Get access check result as a specific access.
@@ -65,17 +68,20 @@ public AccessCheckResult<Enum> ToSpecificAccess(Type specific_access_type)
6568
{
6669
return new AccessCheckResult<Enum>(Status, GrantedAccess, GenericGrantedAccess, PrivilegesRequired,
6770
GrantedAccess.ToSpecificAccess(specific_access_type),
68-
GenericGrantedAccess.ToSpecificAccess(specific_access_type));
71+
GenericGrantedAccess.ToSpecificAccess(specific_access_type),
72+
ObjectType);
6973
}
7074

7175
internal AccessCheckResult(NtStatus status,
7276
AccessMask granted_access,
7377
AccessMask generic_granted_access,
74-
IEnumerable<TokenPrivilege> privilege_required)
78+
IEnumerable<TokenPrivilege> privilege_required,
79+
Guid object_type)
7580
: this(status, granted_access,
7681
generic_granted_access, privilege_required,
7782
granted_access.ToSpecificAccess<T>(),
78-
generic_granted_access.ToSpecificAccess<T>())
83+
generic_granted_access.ToSpecificAccess<T>(),
84+
object_type)
7985
{
8086
}
8187

@@ -84,14 +90,16 @@ internal AccessCheckResult(NtStatus status,
8490
AccessMask generic_granted_access,
8591
IEnumerable<TokenPrivilege> privilege_required,
8692
T specific_granted_access,
87-
T specific_generic_granted_access)
93+
T specific_generic_granted_access,
94+
Guid object_type)
8895
{
8996
Status = status;
9097
GrantedAccess = granted_access;
9198
GenericGrantedAccess = generic_granted_access;
9299
PrivilegesRequired = privilege_required;
93100
SpecificGrantedAccess = specific_granted_access;
94101
SpecificGenericGrantedAccess = specific_generic_granted_access;
102+
ObjectType = object_type;
95103
}
96104
}
97105

@@ -103,22 +111,25 @@ public class AccessCheckResult : AccessCheckResult<GenericAccessRights>
103111
internal AccessCheckResult(NtStatus status,
104112
AccessMask granted_access,
105113
SafePrivilegeSetBuffer privilege_set,
106-
GenericMapping generic_mapping)
114+
GenericMapping generic_mapping,
115+
Guid object_type)
107116
: this(status, granted_access,
108117
generic_mapping.UnmapMask(granted_access),
109-
privilege_set?.GetPrivileges() ?? new TokenPrivilege[0])
118+
privilege_set?.GetPrivileges() ?? new TokenPrivilege[0],
119+
object_type)
110120
{
111121
}
112122

113123
internal AccessCheckResult(
114124
NtStatus status,
115125
AccessMask granted_access,
116126
AccessMask generic_granted_access,
117-
IEnumerable<TokenPrivilege> privilege_required)
127+
IEnumerable<TokenPrivilege> privilege_required,
128+
Guid object_type)
118129
: base(status, granted_access, generic_granted_access, privilege_required,
119-
granted_access.ToGenericAccess(), generic_granted_access.ToGenericAccess())
130+
granted_access.ToGenericAccess(), generic_granted_access.ToGenericAccess(),
131+
object_type)
120132
{
121133
}
122134
}
123-
124135
}

NtApiDotNet/NtObjectUtils.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using NtApiDotNet.Win32;
1516
using System;
16-
using System.IO;
1717
using System.Collections.Generic;
18-
using System.Runtime.InteropServices;
18+
using System.IO;
1919
using System.Linq;
20-
using NtApiDotNet.Win32;
21-
using System.Threading.Tasks;
2220
using System.Reflection;
21+
using System.Runtime.InteropServices;
22+
using System.Threading.Tasks;
2323

2424
namespace NtApiDotNet
2525
{

NtApiDotNet/NtSecurity.cs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,8 @@ public static NtResult<AccessCheckResult> AccessCheck(SecurityDescriptor sd, NtT
391391

392392
if (desired_access.IsEmpty)
393393
{
394-
return new AccessCheckResult(NtStatus.STATUS_ACCESS_DENIED, 0, null, generic_mapping).CreateResult();
394+
return new AccessCheckResult(NtStatus.STATUS_ACCESS_DENIED, 0, null,
395+
generic_mapping, object_types.GetDefaultObjectType()).CreateResult();
395396
}
396397

397398
using (var list = new DisposableList())
@@ -416,7 +417,8 @@ public static NtResult<AccessCheckResult> AccessCheck(SecurityDescriptor sd, NtT
416417
if (repeat_count == 0 || status != NtStatus.STATUS_BUFFER_TOO_SMALL)
417418
{
418419
return status.CreateResult(throw_on_error, ()
419-
=> new AccessCheckResult(result_status, granted_access, privs, generic_mapping));
420+
=> new AccessCheckResult(result_status, granted_access,
421+
privs, generic_mapping, object_types.GetDefaultObjectType()));
420422
}
421423

422424
repeat_count--;
@@ -425,6 +427,23 @@ public static NtResult<AccessCheckResult> AccessCheck(SecurityDescriptor sd, NtT
425427
}
426428
}
427429

430+
/// <summary>
431+
/// Do an access check between a security descriptor and a token to determine the allowed access.
432+
/// </summary>
433+
/// <param name="sd">The security descriptor</param>
434+
/// <param name="token">The access token.</param>
435+
/// <param name="desired_access">The set of access rights to check against</param>
436+
/// <param name="principal">An optional principal SID used to replace the SELF SID in a security descriptor.</param>
437+
/// <param name="generic_mapping">The type specific generic mapping (get from corresponding NtType entry).</param>
438+
/// <param name="object_types">List of object types to check against.</param>
439+
/// <returns>The result of the access check.</returns>
440+
/// <exception cref="NtException">Thrown if an error occurred in the access check.</exception>
441+
public static AccessCheckResult AccessCheck(SecurityDescriptor sd, NtToken token,
442+
AccessMask desired_access, Sid principal, GenericMapping generic_mapping, IEnumerable<ObjectTypeEntry> object_types)
443+
{
444+
return AccessCheck(sd, token, desired_access, principal, generic_mapping, object_types, true).Result;
445+
}
446+
428447
/// <summary>
429448
/// Do an access check between a security descriptor and a token to determine the allowed access.
430449
/// </summary>
@@ -445,6 +464,24 @@ public static NtResult<AccessCheckResult<T>> AccessCheck<T>(SecurityDescriptor s
445464
generic_mapping, object_types, throw_on_error).Map(r => r.ToSpecificAccess<T>());
446465
}
447466

467+
/// <summary>
468+
/// Do an access check between a security descriptor and a token to determine the allowed access.
469+
/// </summary>
470+
/// <param name="sd">The security descriptor</param>
471+
/// <param name="token">The access token.</param>
472+
/// <param name="desired_access">The set of access rights to check against</param>
473+
/// <param name="principal">An optional principal SID used to replace the SELF SID in a security descriptor.</param>
474+
/// <param name="generic_mapping">The type specific generic mapping (get from corresponding NtType entry).</param>
475+
/// <param name="object_types">List of object types to check against.</param>
476+
/// <returns>The result of the access check.</returns>
477+
/// <exception cref="NtException">Thrown if an error occurred in the access check.</exception>
478+
public static AccessCheckResult<T> AccessCheck<T>(SecurityDescriptor sd, NtToken token,
479+
T desired_access, Sid principal, GenericMapping generic_mapping, IEnumerable<ObjectTypeEntry> object_types)
480+
where T : Enum
481+
{
482+
return AccessCheck(sd, token, desired_access, principal, generic_mapping, object_types, true).Result;
483+
}
484+
448485
/// <summary>
449486
/// Do an access check between a security descriptor and a token to determine the allowed access.
450487
/// </summary>
@@ -1372,6 +1409,13 @@ private static void GetCapabilitySids(string capability_name, out Sid capability
13721409
}
13731410
}
13741411

1412+
private static Guid GetDefaultObjectType(this IEnumerable<ObjectTypeEntry> object_types)
1413+
{
1414+
if (object_types == null)
1415+
return Guid.Empty;
1416+
return object_types.Select(e => e.ObjectType).FirstOrDefault();
1417+
}
1418+
13751419
#endregion
13761420
}
13771421
}

NtApiDotNet/NtSecurityNative.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,21 @@ public class ObjectTypeEntry
555555
public int Level { get; set; }
556556
public Guid ObjectType { get; set; }
557557

558+
public ObjectTypeEntry()
559+
{
560+
}
561+
562+
public ObjectTypeEntry(Guid object_type, int level)
563+
{
564+
ObjectType = object_type;
565+
Level = level;
566+
}
567+
568+
public ObjectTypeEntry(Guid object_type)
569+
: this(object_type, 0)
570+
{
571+
}
572+
558573
internal ObjectTypeList ToStruct(DisposableList resources)
559574
{
560575
return new ObjectTypeList()

NtObjectManager/NtSecurityCmdlets.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,12 @@ public class GetNtGrantedAccessCmdlet : Cmdlet
675675
[Parameter]
676676
public SwitchParameter PassResult { get; set; }
677677

678+
/// <summary>
679+
/// <para type="description">Specify object types for access check..</para>
680+
/// </summary>
681+
[Parameter]
682+
public ObjectTypeEntry[] ObjectType { get; set; }
683+
678684
/// <summary>
679685
/// Constructor.
680686
/// </summary>
@@ -739,7 +745,7 @@ protected override void ProcessRecord()
739745
if (type == null)
740746
throw new ArgumentException("Must specify a type.");
741747
var result = NtSecurity.AccessCheck(GetSecurityDescriptor(),
742-
token, AccessMask, Principal, type.GenericMapping).ToSpecificAccess(type.AccessRightsType);
748+
token, AccessMask, Principal, type.GenericMapping, ObjectType).ToSpecificAccess(type.AccessRightsType);
743749
if (PassResult)
744750
{
745751
WriteObject(result);

0 commit comments

Comments
 (0)