Example #1
0
        public AuthorizationResponse GetAuthorizationResponse(IUser user, IComputer computer, AccessMask requestedAccess)
        {
            try
            {
                requestedAccess.ValidateAccessMask();

                var info = this.authzBuilder.GetAuthorizationInformation(user, computer);

                if (info.MatchedComputerTargets.Count == 0)
                {
                    this.logger.LogTrace($"User {user.MsDsPrincipalName} is denied access to the password for computer {computer.MsDsPrincipalName} because the computer did not match any of the configured targets");
                    return(BuildAuthZResponseFailed(requestedAccess, AuthorizationResponseCode.NoMatchingRuleForComputer));
                }

                IList <SecurityDescriptorTarget> successTargets;

                if (requestedAccess.HasFlag(AccessMask.LocalAdminPassword))
                {
                    successTargets = info.SuccessfulLapsTargets;
                }
                else if (requestedAccess.HasFlag(AccessMask.LocalAdminPasswordHistory))
                {
                    successTargets = info.SuccessfulLapsHistoryTargets;
                }
                else if (requestedAccess.HasFlag(AccessMask.Jit))
                {
                    successTargets = info.SuccessfulJitTargets;
                }
                else
                {
                    throw new AccessManagerException($"An invalid access mask combination was requested: {requestedAccess}");
                }

                if (successTargets.Count == 0 || !(info.EffectiveAccess.HasFlag(requestedAccess)))
                {
                    this.logger.LogTrace($"User {user.MsDsPrincipalName} is denied {requestedAccess} access for computer {computer.MsDsPrincipalName}");

                    return(BuildAuthZResponseFailed(
                               requestedAccess,
                               AuthorizationResponseCode.NoMatchingRuleForUser,
                               GetNotificationRecipients(info.FailedTargets, false)));
                }
                else
                {
                    var matchedTarget = successTargets[0];
                    this.logger.LogTrace($"User {user.MsDsPrincipalName} is authorized for {requestedAccess} access to computer {computer.MsDsPrincipalName} from target {matchedTarget.Id}");

                    return(BuildAuthZResponseSuccess(requestedAccess, matchedTarget, computer));
                }
            }
            finally
            {
                this.authzBuilder.ClearCache(user, computer);
            }
        }
        private PowerShellAuthorizationResponse AccessMaskToPowerShellAuthorizationResponse(AccessMask allowedAccessMask, AccessMask deniedAccessMask)
        {
            PowerShellAuthorizationResponse response = new PowerShellAuthorizationResponse
            {
                IsLocalAdminPasswordAllowed        = allowedAccessMask.HasFlag(AccessMask.LocalAdminPassword),
                IsLocalAdminPasswordHistoryAllowed = allowedAccessMask.HasFlag(AccessMask.LocalAdminPasswordHistory),
                IsJitAllowed = allowedAccessMask.HasFlag(AccessMask.Jit),
                IsLocalAdminPasswordDenied        = deniedAccessMask.HasFlag(AccessMask.LocalAdminPassword),
                IsLocalAdminPasswordHistoryDenied = deniedAccessMask.HasFlag(AccessMask.LocalAdminPasswordHistory),
                IsJitDenied = deniedAccessMask.HasFlag(AccessMask.Jit)
            };

            return(response);
        }
        /// <summary>
        /// Check the status code of create response
        /// </summary>
        /// <param name="isNonAdmin">true for non admin credential</param>
        /// <param name="createOption">The create option set in create request</param>
        /// <param name="accessMask">The access mark set in create request</param>
        /// <param name="header">Header of create response</param>
        /// <param name="response">create response</param>
        /// <param name="fileNameType">file name type</param>
        private void CheckCreateResponse(bool isNonAdmin, CreateOptions_Values createOption, AccessMask accessMask, Packet_Header header, CREATE_Response response, FileNameType fileNameType)
        {
            switch (fileNameType)
            {
            case FileNameType.SymbolicLinkInMiddle:
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                    header.Status,
                    "3.3.5.9: If any intermediate component of the path specified in the create request is a symbolic link, " +
                    "the server MUST return an error as specified in section 2.2.2.1. " +
                    "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                break;
            }

            case FileNameType.SymbolicLinkAtLast:
            {
                if (!createOption.HasFlag(CreateOptions_Values.FILE_OPEN_REPARSE_POINT))
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                        header.Status,
                        "3.3.5.9: If the final component of the path is a symbolic link, the server behavior depends on whether the flag FILE_OPEN_REPARSE_POINT was specified in the CreateOptions field of the request. " +
                        "If FILE_OPEN_REPARSE_POINT was specified, the server MUST open the underlying file or directory and return a handle to it. " +
                        "Otherwise, the server MUST return an error as specified in section 2.2.2.1. " +
                        "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                }
                break;
            }

            case FileNameType.InvalidSymbolicLink:
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                    header.Status,
                    "3.3.5.9: If the underlying object store returns a failure indicating that the attempted open operation failed due to the presence of a symbolic link in the target path name, " +
                    "the server MUST fail the create operation with the error code STATUS_STOPPED_ON_SYMLINK. " +
                    "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                break;
            }

            case FileNameType.NotExistedValidFileName:
            {
                if (createOption.HasFlag(CreateOptions_Values.FILE_DELETE_ON_CLOSE) &&
                    !(accessMask.HasFlag(AccessMask.DELETE) || accessMask.HasFlag(AccessMask.GENERIC_ALL)))
                {
                    if (testConfig.Platform == Platform.NonWindows)
                    {
                        BaseTestSite.Assert.AreNotEqual(
                            Smb2Status.STATUS_SUCCESS,
                            header.Status,
                            "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and Treeconnect.MaximalAccess does not include DELETE or GENERIC, the server SHOULD<283> fail the request with STATUS_ACCESS_DENIED. " +
                            "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                    }
                    else if (testConfig.Platform == Platform.WindowsServer2008 ||
                             testConfig.Platform == Platform.WindowsServer2008R2)
                    {
                        //TD does not specify the behavior of windows 2008 and 2008R2, not check here
                    }
                    else if (testConfig.Platform == Platform.WindowsServer2012)
                    {
                        //For platform windows 2012
                        BaseTestSite.Assert.AreEqual(
                            Smb2Status.STATUS_INVALID_PARAMETER,
                            header.Status,
                            "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and Treeconnect.MaximalAccess does not include DELETE or GENERIC, the server SHOULD<283> fail the request with STATUS_ACCESS_DENIED. " +
                            "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                    }
                    else
                    {
                        //For platform windows 2012R2 and above
                        BaseTestSite.Assert.AreEqual(
                            Smb2Status.STATUS_ACCESS_DENIED,
                            header.Status,
                            "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and Treeconnect.MaximalAccess does not include DELETE or GENERIC, the server SHOULD<283> fail the request with STATUS_ACCESS_DENIED. " +
                            "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                    }
                }
                else if (createOption.HasFlag(CreateOptions_Values.FILE_DELETE_ON_CLOSE) && isNonAdmin)
                {
                    //NonAdminAccountCredential does not include DELETE or GENERIC_ALL in MaximalAccess
                    if (testConfig.Platform == Platform.NonWindows)
                    {
                        BaseTestSite.Assert.AreNotEqual(
                            Smb2Status.STATUS_SUCCESS,
                            header.Status,
                            "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and Treeconnect.MaximalAccess does not include DELETE or GENERIC, the server SHOULD<283> fail the request with STATUS_ACCESS_DENIED. " +
                            "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                    }
                    else if (testConfig.Platform == Platform.WindowsServer2008 ||
                             testConfig.Platform == Platform.WindowsServer2008R2)
                    {
                        //TD does not specify te behavior of windows 2008 and 2008R2, not check here
                    }
                    else
                    {
                        //For platform win2012 and 2012R2
                        BaseTestSite.Assert.AreEqual(
                            Smb2Status.STATUS_ACCESS_DENIED,
                            header.Status,
                            "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and Treeconnect.MaximalAccess does not include DELETE or GENERIC, the server SHOULD<283> fail the request with STATUS_ACCESS_DENIED. " +
                            "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                    }
                }
                else
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        header.Status,
                        "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));
                }
                break;
            }

            case FileNameType.ExistedValidFileName:
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_SUCCESS,
                    header.Status,
                    "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));
            }
            break;

            case FileNameType.NotExistedValidFileNameWithDotDirectoryName:
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_SUCCESS,
                    header.Status,
                    "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));
            }
            break;

            case FileNameType.NotExistedValidFileNameWithDoubleDotDirectoryName:
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_INVALID_PARAMETER,
                    header.Status,
                    "3.3.5.9: Windows-based servers accept the path names containing Dot Directory Names specified in [MS-FSCC] section 2.1.5.1 and attempt to normalize the path name by removing the pathname components of \".\"  and \"..\"." +
                    "Windows-based servers fail the CREATE request with STATUS_INVALID_PARAMETER if the file name in the Buffer field of the request begins in the form \"subfolder\\..\\\", for example \"x\\..\\y.txt\". " +
                    "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
            }
            break;

            default:
                throw new ArgumentException("fileNameType");
            }
        }
 /// <summary>
 /// Check the status code of create response
 /// </summary>
 /// <param name="isNonAdmin">true for non admin credential</param>
 /// <param name="createOption">The create option set in create request</param>
 /// <param name="accessMask">The access mark set in create request</param>
 /// <param name="header">Header of create response</param>
 /// <param name="response">create response</param>
 /// <param name="fileNameType">file name type</param>
 private void CheckCreateResponse(bool isNonAdmin, CreateOptions_Values createOption, AccessMask accessMask, Packet_Header header, CREATE_Response response, FileNameType fileNameType)
 {
     switch (fileNameType)
     {
         case FileNameType.SymbolicLinkInMiddle:
             {
                 BaseTestSite.Assert.AreEqual(
                     Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                     header.Status,
                     "3.3.5.9: If any intermediate component of the path specified in the create request is a symbolic link, " +
                     "the server MUST return an error as specified in section 2.2.2.1. " +
                     "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                 break;
             }
         case FileNameType.SymbolicLinkAtLast:
             {
                 if (!createOption.HasFlag(CreateOptions_Values.FILE_OPEN_REPARSE_POINT))
                 {
                     BaseTestSite.Assert.AreEqual(
                         Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                         header.Status,
                         "3.3.5.9: If the final component of the path is a symbolic link, the server behavior depends on whether the flag FILE_OPEN_REPARSE_POINT was specified in the CreateOptions field of the request. " +
                         "If FILE_OPEN_REPARSE_POINT was specified, the server MUST open the underlying file or directory and return a handle to it. " +
                         "Otherwise, the server MUST return an error as specified in section 2.2.2.1. " +
                         "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                 }
                 break;
             }
         case FileNameType.InvalidSymbolicLink:
             {
                 BaseTestSite.Assert.AreEqual(
                     Smb2Status.STATUS_STOPPED_ON_SYMLINK,
                     header.Status,
                     "3.3.5.9: If the underlying object store returns a failure indicating that the attempted open operation failed due to the presence of a symbolic link in the target path name, " +
                     "the server MUST fail the create operation with the error code STATUS_STOPPED_ON_SYMLINK. " +
                     "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                 break;
             }
         case FileNameType.NotExistedValidFileName:
             {
                 if (createOption.HasFlag(CreateOptions_Values.FILE_DELETE_ON_CLOSE)
                     && !(accessMask.HasFlag(AccessMask.DELETE) || accessMask.HasFlag(AccessMask.GENERIC_ALL)))
                 {
                     if (testConfig.Platform == Platform.NonWindows)
                     {
                         BaseTestSite.Assert.AreNotEqual(
                             Smb2Status.STATUS_SUCCESS,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "DesiredAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                     else if (testConfig.Platform == Platform.WindowsServer2008
                         || testConfig.Platform == Platform.WindowsServer2008R2)
                     {
                         //TD does not specify the behavior of windows 2008 and 2008R2, not check here
                     }
                     else if(testConfig.Platform == Platform.WindowsServer2012)
                     {
                         //For platform windows 2012
                         BaseTestSite.Assert.AreEqual(
                             Smb2Status.STATUS_INVALID_PARAMETER,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "DesiredAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                     else
                     {
                         //For platform windows 2012R2 and above
                         BaseTestSite.Assert.AreEqual(
                             Smb2Status.STATUS_ACCESS_DENIED,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "DesiredAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                 }
                 else if (createOption.HasFlag(CreateOptions_Values.FILE_DELETE_ON_CLOSE) && isNonAdmin)
                 {
                     //NonAdminAccountCredential does not include DELETE or GENERIC_ALL in MaximalAccess
                     if (testConfig.Platform == Platform.NonWindows)
                     {
                         BaseTestSite.Assert.AreNotEqual(
                             Smb2Status.STATUS_SUCCESS,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                     else if (testConfig.Platform == Platform.WindowsServer2008
                         || testConfig.Platform == Platform.WindowsServer2008R2)
                     {
                         //TD does not specify te behavior of windows 2008 and 2008R2, not check here
                     }
                     else
                     {
                         //For platform win2012 and 2012R2
                         BaseTestSite.Assert.AreEqual(
                             Smb2Status.STATUS_ACCESS_DENIED,
                             header.Status,
                             "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " +
                             "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL. " +
                             "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                     }
                 }
                 else
                 {
                     BaseTestSite.Assert.AreEqual(
                         Smb2Status.STATUS_SUCCESS,
                         header.Status,
                         "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));
                 }
                 break;
             }
         case FileNameType.ExistedValidFileName:
             {
                 BaseTestSite.Assert.AreEqual(
                         Smb2Status.STATUS_SUCCESS,
                         header.Status,
                         "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));
             }
             break;
         default:
             throw new ArgumentException("fileNameType");
     }
 }
        public async Task <AuthorizationResponse> GetAuthorizationResponse(IUser user, IComputer computer, AccessMask requestedAccess, IPAddress ip)
        {
            try
            {
                requestedAccess.ValidateAccessMask();

                var info = this.authzBuilder.GetAuthorizationInformation(user, computer);

                if (info.MatchedComputerTargets.Count == 0)
                {
                    this.logger.LogTrace($"User {user.MsDsPrincipalName} is denied {requestedAccess} access to the computer {computer.MsDsPrincipalName} because the computer did not match any of the configured targets");
                    return(BuildAuthZResponseFailed(requestedAccess, AuthorizationResponseCode.NoMatchingRuleForComputer));
                }

                IList <SecurityDescriptorTarget> successTargets;

                if (requestedAccess.HasFlag(AccessMask.LocalAdminPassword))
                {
                    successTargets = info.SuccessfulLapsTargets;
                }
                else if (requestedAccess.HasFlag(AccessMask.LocalAdminPasswordHistory))
                {
                    successTargets = info.SuccessfulLapsHistoryTargets;
                }
                else if (requestedAccess.HasFlag(AccessMask.Jit))
                {
                    successTargets = info.SuccessfulJitTargets;
                }
                else if (requestedAccess.HasFlag(AccessMask.BitLocker))
                {
                    successTargets = info.SuccessfulBitLockerTargets;
                }
                else
                {
                    throw new AccessManagerException($"An invalid access mask combination was requested: {requestedAccess}");
                }

                var matchedTarget = successTargets?.FirstOrDefault(t => t.IsActive());

                if (!info.EffectiveAccess.HasFlag(requestedAccess) || matchedTarget == null)
                {
                    this.logger.LogTrace($"User {user.MsDsPrincipalName} is denied {requestedAccess} access for computer {computer.MsDsPrincipalName}");

                    return(BuildAuthZResponseFailed(
                               requestedAccess,
                               AuthorizationResponseCode.NoMatchingRuleForUser,
                               GetNotificationRecipients(info.FailedTargets, false)));
                }
                else
                {
                    var rateLimitResult = await this.rateLimiter.GetRateLimitResult(user.Sid, ip, requestedAccess);

                    if (rateLimitResult.IsRateLimitExceeded)
                    {
                        return(BuildAuthZResponseRateLimitExceeded(user, computer, requestedAccess, rateLimitResult, ip, matchedTarget));
                    }

                    this.logger.LogTrace($"User {user.MsDsPrincipalName} is authorized for {requestedAccess} access to computer {computer.MsDsPrincipalName} from target {matchedTarget.Id}");
                    return(BuildAuthZResponseSuccess(requestedAccess, matchedTarget, computer));
                }
            }
            finally
            {
                this.authzBuilder.ClearCache(user, computer);
            }
        }
Example #6
0
        public AuthorizationInformation BuildAuthorizationInformation(IUser user, IComputer computer, IList <SecurityDescriptorTarget> matchedComputerTargets)
        {
            AuthorizationInformation info = new AuthorizationInformation
            {
                MatchedComputerTargets = matchedComputerTargets,
                EffectiveAccess        = 0,
                Computer = computer,
                User     = user
            };

            if (info.MatchedComputerTargets.Count == 0)
            {
                return(info);
            }

            using AuthorizationContext c = authorizationContextProvider.GetAuthorizationContext(user, computer.Sid);

            DiscretionaryAcl masterDacl = new DiscretionaryAcl(false, false, info.MatchedComputerTargets.Count);

            int matchedTargetCount = 0;

            foreach (var target in info.MatchedComputerTargets)
            {
                CommonSecurityDescriptor sd;

                if (target.IsInactive())
                {
                    continue;
                }

                if (target.AuthorizationMode == AuthorizationMode.PowershellScript)
                {
                    if (!this.licenseManager.IsFeatureEnabled(LicensedFeatures.PowerShellAcl))
                    {
                        continue;
                    }

                    sd = this.powershell.GenerateSecurityDescriptor(user, computer, target.Script, 30);
                }
                else
                {
                    if (string.IsNullOrWhiteSpace(target.SecurityDescriptor))
                    {
                        this.logger.LogTrace($"Ignoring target {target.Id} with empty security descriptor");
                        continue;
                    }

                    sd = new CommonSecurityDescriptor(false, false, new RawSecurityDescriptor(target.SecurityDescriptor));
                }

                if (sd == null)
                {
                    this.logger.LogTrace($"Ignoring target {target.Id} with null security descriptor");
                    continue;
                }

                foreach (var ace in sd.DiscretionaryAcl.OfType <CommonAce>())
                {
                    AccessMask mask = (AccessMask)ace.AccessMask;

                    if (mask.HasFlag(AccessMask.LocalAdminPasswordHistory) && ace.AceType == AceType.AccessAllowed)
                    {
                        if (!this.licenseManager.IsFeatureEnabled(LicensedFeatures.LapsHistory))
                        {
                            mask &= ~AccessMask.LocalAdminPasswordHistory;
                        }
                    }

                    if (mask != 0)
                    {
                        masterDacl.AddAccess((AccessControlType)ace.AceType, ace.SecurityIdentifier, (int)mask, ace.InheritanceFlags, ace.PropagationFlags);
                    }
                }

                int i = matchedTargetCount;

                if (c.AccessCheck(sd, (int)AccessMask.LocalAdminPassword))
                {
                    info.SuccessfulLapsTargets.Add(target);
                    matchedTargetCount++;
                }

                if (c.AccessCheck(sd, (int)AccessMask.LocalAdminPasswordHistory))
                {
                    info.SuccessfulLapsHistoryTargets.Add(target);
                    matchedTargetCount++;
                }

                if (c.AccessCheck(sd, (int)AccessMask.Jit))
                {
                    info.SuccessfulJitTargets.Add(target);
                    matchedTargetCount++;
                }

                if (c.AccessCheck(sd, (int)AccessMask.BitLocker))
                {
                    info.SuccessfulBitLockerTargets.Add(target);
                    matchedTargetCount++;
                }

                // If the ACE did not grant any permissions to the user, consider it a failure response
                if (i == matchedTargetCount)
                {
                    info.FailedTargets.Add(target);
                }
            }

            if (matchedTargetCount > 0)
            {
                info.SecurityDescriptor = new CommonSecurityDescriptor(false, false, ControlFlags.DiscretionaryAclPresent, new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), null, null, masterDacl);

                this.logger.LogTrace($"Resultant security descriptor for computer {computer.MsDsPrincipalName}: {info.SecurityDescriptor.GetSddlForm(AccessControlSections.All)}");

                info.EffectiveAccess |= c.AccessCheck(info.SecurityDescriptor, (int)AccessMask.LocalAdminPassword) ? AccessMask.LocalAdminPassword : 0;
                info.EffectiveAccess |= c.AccessCheck(info.SecurityDescriptor, (int)AccessMask.Jit) ? AccessMask.Jit : 0;
                info.EffectiveAccess |= c.AccessCheck(info.SecurityDescriptor, (int)AccessMask.LocalAdminPasswordHistory) ? AccessMask.LocalAdminPasswordHistory : 0;
                info.EffectiveAccess |= c.AccessCheck(info.SecurityDescriptor, (int)AccessMask.BitLocker) ? AccessMask.BitLocker : 0;
            }

            this.logger.LogTrace($"User {user.MsDsPrincipalName} has effective access of {info.EffectiveAccess} on computer {computer.MsDsPrincipalName}");

            return(info);
        }