@@ -494,26 +494,27 @@ public static Sid SidFromSddl(string sddl)
494494 return SidFromSddl ( sddl , true ) . Result ;
495495 }
496496
497- private static NtToken DuplicateForAccessCheck ( NtToken token )
497+ private static NtResult < NtToken > DuplicateForAccessCheck ( NtToken token , bool throw_on_error )
498498 {
499499 if ( token . IsPseudoToken )
500500 {
501501 // This is a pseudo token, pass along as no need to duplicate.
502- return token ;
502+ return token . CreateResult ( ) ;
503503 }
504504
505505 if ( token . TokenType == TokenType . Primary )
506506 {
507- return token . DuplicateToken ( TokenType . Impersonation , SecurityImpersonationLevel . Identification , TokenAccessRights . Query ) ;
507+ return token . DuplicateToken ( TokenType . Impersonation ,
508+ SecurityImpersonationLevel . Identification , TokenAccessRights . Query , throw_on_error ) ;
508509 }
509510 else if ( ! token . IsAccessGranted ( TokenAccessRights . Query ) )
510511 {
511- return token . Duplicate ( TokenAccessRights . Query ) ;
512+ return token . Duplicate ( TokenAccessRights . Query , throw_on_error ) ;
512513 }
513514 else
514515 {
515516 // If we've got query access rights already just create a shallow clone.
516- return token . ShallowClone ( ) ;
517+ return token . ShallowClone ( ) . CreateResult ( ) ;
517518 }
518519 }
519520
@@ -525,10 +526,12 @@ private static NtToken DuplicateForAccessCheck(NtToken token)
525526 /// <param name="access_rights">The set of access rights to check against</param>
526527 /// <param name="principal">An optional principal SID used to replace the SELF SID in a security descriptor.</param>
527528 /// <param name="generic_mapping">The type specific generic mapping (get from corresponding NtType entry).</param>
528- /// <returns>The allowed access mask as a unsigned integer.</returns>
529+ /// <param name="throw_on_error">True to throw on error.</param>
530+ /// <returns>The result of the access check.</returns>
529531 /// <exception cref="NtException">Thrown if an error occurred in the access check.</exception>
530- public static AccessMask GetAllowedAccess ( SecurityDescriptor sd , NtToken token ,
531- AccessMask access_rights , Sid principal , GenericMapping generic_mapping )
532+ public static NtResult < AccessCheckResult > AccessCheck ( SecurityDescriptor sd , NtToken token ,
533+ AccessMask access_rights , Sid principal , GenericMapping generic_mapping ,
534+ bool throw_on_error )
532535 {
533536 if ( sd == null )
534537 {
@@ -542,33 +545,71 @@ public static AccessMask GetAllowedAccess(SecurityDescriptor sd, NtToken token,
542545
543546 if ( access_rights . IsEmpty )
544547 {
545- return AccessMask . Empty ;
548+ return new AccessCheckResult ( NtStatus . STATUS_ACCESS_DENIED , 0 , null ) . CreateResult ( ) ;
546549 }
547550
548- using ( SafeBuffer sd_buffer = sd . ToSafeBuffer ( ) )
551+ using ( var list = new DisposableList ( ) )
549552 {
550- using ( NtToken imp_token = DuplicateForAccessCheck ( token ) )
553+ var sd_buffer = list . AddResource ( sd . ToSafeBuffer ( ) ) ;
554+ var imp_token = list . AddResource ( DuplicateForAccessCheck ( token , throw_on_error ) ) ;
555+ if ( ! imp_token . IsSuccess )
551556 {
552- using ( var privs = new SafePrivilegeSetBuffer ( ) )
553- {
554- int buffer_length = privs . Length ;
557+ return imp_token . Cast < AccessCheckResult > ( ) ;
558+ }
559+ var self_sid = list . AddResource ( principal ? . ToSafeBuffer ( ) ?? SafeSidBufferHandle . Null ) ;
560+ var privs = list . AddResource ( new SafePrivilegeSetBuffer ( ) ) ;
561+ int repeat_count = 1 ;
555562
556- using ( var self_sid = principal != null ? principal . ToSafeBuffer ( ) : SafeSidBufferHandle . Null )
557- {
558- NtSystemCalls . NtAccessCheckByType ( sd_buffer , self_sid , imp_token . Handle , access_rights ,
559- SafeHGlobalBuffer . Null , 0 , ref generic_mapping , privs ,
560- ref buffer_length , out AccessMask granted_access , out NtStatus result_status ) . ToNtException ( ) ;
561- if ( result_status . IsSuccess ( ) )
562- {
563- return granted_access ;
564- }
565- return AccessMask . Empty ;
566- }
563+ while ( true )
564+ {
565+ int buffer_length = privs . Length ;
566+ NtStatus status = NtSystemCalls . NtAccessCheckByType ( sd_buffer , self_sid , imp_token . Result . Handle , access_rights ,
567+ SafeHGlobalBuffer . Null , 0 , ref generic_mapping , privs ,
568+ ref buffer_length , out AccessMask granted_access , out NtStatus result_status ) ;
569+ if ( repeat_count == 0 || status != NtStatus . STATUS_BUFFER_TOO_SMALL )
570+ {
571+ return status . CreateResult ( throw_on_error , ( )
572+ => new AccessCheckResult ( result_status , granted_access , privs ) ) ;
567573 }
574+
575+ repeat_count -- ;
576+ privs = list . AddResource ( new SafePrivilegeSetBuffer ( buffer_length ) ) ;
568577 }
569578 }
570579 }
571580
581+ /// <summary>
582+ /// Do an access check between a security descriptor and a token to determine the allowed access.
583+ /// </summary>
584+ /// <param name="sd">The security descriptor</param>
585+ /// <param name="token">The access token.</param>
586+ /// <param name="access_rights">The set of access rights to check against</param>
587+ /// <param name="principal">An optional principal SID used to replace the SELF SID in a security descriptor.</param>
588+ /// <param name="generic_mapping">The type specific generic mapping (get from corresponding NtType entry).</param>
589+ /// <returns>The result of the access check.</returns>
590+ /// <exception cref="NtException">Thrown if an error occurred in the access check.</exception>
591+ public static AccessCheckResult AccessCheck ( SecurityDescriptor sd , NtToken token ,
592+ AccessMask access_rights , Sid principal , GenericMapping generic_mapping )
593+ {
594+ return AccessCheck ( sd , token , access_rights , principal , generic_mapping , true ) . Result ;
595+ }
596+
597+ /// <summary>
598+ /// Do an access check between a security descriptor and a token to determine the allowed access.
599+ /// </summary>
600+ /// <param name="sd">The security descriptor</param>
601+ /// <param name="token">The access token.</param>
602+ /// <param name="access_rights">The set of access rights to check against</param>
603+ /// <param name="principal">An optional principal SID used to replace the SELF SID in a security descriptor.</param>
604+ /// <param name="generic_mapping">The type specific generic mapping (get from corresponding NtType entry).</param>
605+ /// <returns>The allowed access mask as a unsigned integer.</returns>
606+ /// <exception cref="NtException">Thrown if an error occurred in the access check.</exception>
607+ public static AccessMask GetAllowedAccess ( SecurityDescriptor sd , NtToken token ,
608+ AccessMask access_rights , Sid principal , GenericMapping generic_mapping )
609+ {
610+ return AccessCheck ( sd , token , access_rights , principal , generic_mapping , true ) . Result . GrantedAccess ;
611+ }
612+
572613 /// <summary>
573614 /// Do an access check between a security descriptor and a token to determine the allowed access.
574615 /// </summary>
0 commit comments