Browse Source

fix(access): don't warn for a name of this computer in Get-NTFSEffectiveAccess

Where a computer doesn't offer the remote interface of the authorization
manager, the cmdlet calculates the result with the local one and warns
that the result might be inaccurate. Only localhost in lowercase counted
as this computer, so the cmdlet warned that the computer couldn't be
reached for ., LOCALHOST, or the computer name, although the local result
is the result of that computer. A name of this computer is now localhost
in any case, ., the NetBIOS name, the DNS host name, or the fully
qualified domain name.

From the security-reviewer pass over be04cb7..4ee01e5 (Nit 7),
reproduced in Windows PowerShell 5.1 and PowerShell 7 on a workstation
without the remote interface.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
pull/116/head
Raimund Andree 3 days ago
parent
commit
dc6e9f5359
  1. 4
      CHANGELOG.md
  2. 4
      Docs/Cmdlets/Get-NTFSEffectiveAccess.md
  3. 4
      NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
  4. 35
      Security2/Win32/Lib.cs
  5. 22
      Tests/Access.Tests.ps1

4
CHANGELOG.md

@ -363,5 +363,9 @@ The format is based on
missing `-Target`, and of `New-NTFSHardLink` for a folder as `-Target`,
which named no path. `New-NTFSSymbolicLink` now checks `-Path` first,
like `New-NTFSHardLink`
- Fix `Get-NTFSEffectiveAccess`, which warned that the result might be
inaccurate for every name of this computer in `-ServerName` except
`localhost` in lowercase, such as `.`, `LOCALHOST`, or the computer name,
where the computer doesn't offer the remote access check
[Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD

4
Docs/Cmdlets/Get-NTFSEffectiveAccess.md

@ -31,7 +31,7 @@ Calculates the rights an account really has on a file or a folder and writes the
The calculation covers the NTFS permissions of the item only. Share permissions are stored in a separate security descriptor and are not part of the result, so access over a network share can be more restrictive than this cmdlet reports.
When `-Account` is omitted, the account that runs the session is used. `-ServerName` selects the computer whose authorization manager resolves the group memberships of the account and defaults to `localhost`; when the remote authorization manager of the named computer cannot be reached, the cmdlet falls back to the local one and warns that the result is based on the group memberships known on this computer and may be inaccurate. The warning names the computer that couldn't be reached. The authorization manager of the named computer answers only the administrators of that computer and the members of its local group Access Control Assistance Operators; for any other account, the cmdlet writes an error and doesn't fall back. Reading effective access relies on the Security privilege, and the cmdlet warns when the account does not hold it or the privilege is disabled.
When `-Account` is omitted, the account that runs the session is used. `-ServerName` selects the computer whose authorization manager resolves the group memberships of the account and defaults to `localhost`; when the remote authorization manager of the named computer cannot be reached, the cmdlet falls back to the local one and warns that the result is based on the group memberships known on this computer and may be inaccurate. The warning names the computer that couldn't be reached. For a name of this computer, such as `localhost`, `.`, or its computer name, the local authorization manager gives the result of the named computer, so the cmdlet doesn't warn. The authorization manager of the named computer answers only the administrators of that computer and the members of its local group Access Control Assistance Operators; for any other account, the cmdlet writes an error and doesn't fall back. Reading effective access relies on the Security privilege, and the cmdlet warns when the account does not hold it or the privilege is disabled.
When `-Path` is omitted, the cmdlet calculates the effective access to the current location. In the `SecurityDescriptor` parameter set, it calculates the effective access from a `Security2.FileSystemSecurity2` object that `Get-NTFSSecurityDescriptor` returned, without reading the item again.
@ -184,7 +184,7 @@ Reading effective access needs the Security privilege. In a session that does no
Before 5.0.0, `-ExcludeNoneAccessEntries` had no effect, and the cmdlet returned nothing without `-Path` or for `-SecurityDescriptor`. When the computer of `-ServerName` couldn't be reached, the cmdlet warned that it had calculated the result on this computer, but returned no access instead of that result.
Before 5.0.0-rc7, the warning about a computer that couldn't be reached didn't name the computer.
Before 5.0.0-rc7, the warning about a computer that couldn't be reached didn't name the computer, and the cmdlet warned for every name of this computer except `localhost` in lowercase, such as `.`, `LOCALHOST`, or the computer name.
## RELATED LINKS

4
NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml

@ -4945,7 +4945,7 @@ PS C:\&gt; Get-NTFSAudit -SecurityDescriptor $sd</dev:code>
<maml:description>
<maml:para>Calculates the rights an account really has on a file or a folder and writes the result as a single `Security2.FileSystemAccessRule2` object per item. The cmdlet evaluates the complete discretionary access control list (DACL) of the item against the group memberships of the account with the Windows Authorization API, so allow entries, deny entries, and inherited entries are combined the same way the Windows access check combines them. This is the equivalent of the "Effective Access" tab of the advanced security dialog.</maml:para>
<maml:para>The calculation covers the NTFS permissions of the item only. Share permissions are stored in a separate security descriptor and are not part of the result, so access over a network share can be more restrictive than this cmdlet reports.</maml:para>
<maml:para>When `-Account` is omitted, the account that runs the session is used. `-ServerName` selects the computer whose authorization manager resolves the group memberships of the account and defaults to `localhost`; when the remote authorization manager of the named computer cannot be reached, the cmdlet falls back to the local one and warns that the result is based on the group memberships known on this computer and may be inaccurate. The warning names the computer that couldn't be reached. The authorization manager of the named computer answers only the administrators of that computer and the members of its local group Access Control Assistance Operators; for any other account, the cmdlet writes an error and doesn't fall back. Reading effective access relies on the Security privilege, and the cmdlet warns when the account does not hold it or the privilege is disabled.</maml:para>
<maml:para>When `-Account` is omitted, the account that runs the session is used. `-ServerName` selects the computer whose authorization manager resolves the group memberships of the account and defaults to `localhost`; when the remote authorization manager of the named computer cannot be reached, the cmdlet falls back to the local one and warns that the result is based on the group memberships known on this computer and may be inaccurate. The warning names the computer that couldn't be reached. For a name of this computer, such as `localhost`, `.`, or its computer name, the local authorization manager gives the result of the named computer, so the cmdlet doesn't warn. The authorization manager of the named computer answers only the administrators of that computer and the members of its local group Access Control Assistance Operators; for any other account, the cmdlet writes an error and doesn't fall back. Reading effective access relies on the Security privilege, and the cmdlet warns when the account does not hold it or the privilege is disabled.</maml:para>
<maml:para>When `-Path` is omitted, the cmdlet calculates the effective access to the current location. In the `SecurityDescriptor` parameter set, it calculates the effective access from a `Security2.FileSystemSecurity2` object that `Get-NTFSSecurityDescriptor` returned, without reading the item again.</maml:para>
</maml:description>
<command:syntax>
@ -5155,7 +5155,7 @@ PS C:\&gt; Get-NTFSAudit -SecurityDescriptor $sd</dev:code>
<maml:para>When the module setting `EnablePrivileges` is `$true` (the default in the `PrivateData` section of NTFSSecurity.psd1), this cmdlet tries to enable the Backup, Restore, Take Ownership, and Security privileges while it runs and disables the privileges it enabled when it finishes. These privileges are only available in an elevated session of an account that holds them, such as a member of the local Administrators group. If a privilege cannot be enabled, the cmdlet continues without it and writes a debug message.</maml:para>
<maml:para>Reading effective access needs the Security privilege. In a session that does not hold it, the cmdlet warns before it starts and the calculation may fail with an error. Use `Enable-Privileges` in an elevated session to enable the privilege, and `Get-Privileges` to see which privileges the session holds. When the calculation fails, the error names the cause that Windows reported, such as a security descriptor without an owner; before 5.0.0, it blamed a missing Security privilege whenever the privilege wasn't enabled.</maml:para>
<maml:para>Before 5.0.0, `-ExcludeNoneAccessEntries` had no effect, and the cmdlet returned nothing without `-Path` or for `-SecurityDescriptor`. When the computer of `-ServerName` couldn't be reached, the cmdlet warned that it had calculated the result on this computer, but returned no access instead of that result.</maml:para>
<maml:para>Before 5.0.0-rc7, the warning about a computer that couldn't be reached didn't name the computer.</maml:para>
<maml:para>Before 5.0.0-rc7, the warning about a computer that couldn't be reached didn't name the computer, and the cmdlet warned for every name of this computer except `localhost` in lowercase, such as `.`, `LOCALHOST`, or the computer name.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>

35
Security2/Win32/Lib.cs

@ -134,6 +134,36 @@ namespace Security2
}
#region Win32 Wrapper
// Whether a name of -ServerName names this computer: localhost in any case, ., the NetBIOS name, the DNS host
// name, or the fully qualified domain name. It must not throw, because GetEffectiveAccess hides every exception
// of the resource manager behind a result without access.
private static bool IsLocalComputer(string serverName)
{
if (string.IsNullOrEmpty(serverName))
{
return false;
}
if (serverName == "." ||
string.Equals(serverName, "localhost", StringComparison.OrdinalIgnoreCase) ||
string.Equals(serverName, Environment.MachineName, StringComparison.OrdinalIgnoreCase))
{
return true;
}
try
{
var properties = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties();
return string.Equals(serverName, properties.HostName, StringComparison.OrdinalIgnoreCase) ||
(!string.IsNullOrEmpty(properties.DomainName) &&
string.Equals(serverName, properties.HostName + "." + properties.DomainName, StringComparison.OrdinalIgnoreCase));
}
catch (System.Net.NetworkInformation.NetworkInformationException)
{
return false;
}
}
private void GetEffectivePermissions_AuthzInitializeResourceManager(string serverName, out bool remoteServerAvailable)
{
remoteServerAvailable = false;
@ -157,7 +187,10 @@ namespace Security2
throw new Win32Exception(error);
}
if (serverName == "localhost")
// The local authorization manager is the one of this computer, so its result is accurate for any name
// of this computer. Before 5.0.0-rc7, only localhost in lowercase counted, and the cmdlet warned for
// the others, such as ., the computer name, or LOCALHOST.
if (IsLocalComputer(serverName))
{
remoteServerAvailable = true;
}

22
Tests/Access.Tests.ps1

@ -13,6 +13,11 @@ BeforeDiscovery {
# Assigning an owner other than the user or one of its groups needs the Restore privilege.
$canAssignAnyOwner = Test-PrivilegeHeld -Name 'SeRestorePrivilege'
$holdsSecurityPrivilege = Test-PrivilegeHeld -Name 'SeSecurityPrivilege'
# Names of this computer for -ServerName of Get-NTFSEffectiveAccess: its NetBIOS name, its DNS host name, and, in a
# domain, its fully qualified name
$ipProperties = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
$localComputerNames = @(@('LOCALHOST', '.', $env:COMPUTERNAME, $ipProperties.HostName) +
@(if ($ipProperties.DomainName) { '{0}.{1}' -f $ipProperties.HostName, $ipProperties.DomainName }) | Sort-Object -Unique)
}
BeforeAll {
@ -151,6 +156,23 @@ Describe 'Get-NTFSEffectiveAccess' {
'For more accurate results, calculate effective access rights on that computer.')
}
}
# Not every computer offers the remote interface of the authorization manager; the cmdlet then calculates the result
# with the local one, which for a name of this computer is the result of that computer. Before 5.0.0-rc7, the cmdlet
# warned that the computer couldn't be reached for every name of this computer but localhost in lowercase.
Context 'When -ServerName names this computer' {
It 'Should return the result of localhost for <_> and warn no more than for localhost' -ForEach $localComputerNames {
$expected = Get-NTFSEffectiveAccess -Path $effectiveFile -WarningVariable expectedWarnings -WarningAction SilentlyContinue -ErrorAction Stop
$result = @(Get-NTFSEffectiveAccess -Path $effectiveFile -ServerName $_ -WarningVariable accessWarnings -WarningAction SilentlyContinue -ErrorVariable accessErrors -ErrorAction SilentlyContinue)
$accessErrors | Should -BeNullOrEmpty
$result | Should -HaveCount 1
$result[0].AccessRights | Should -Be $expected.AccessRights
# Without the Security privilege, the cmdlet warns about it for every name.
@($accessWarnings.Message) -join '|' | Should -Be (@($expectedWarnings.Message) -join '|')
}
}
}
Describe 'Get-NTFSOrphanedAccess' {

Loading…
Cancel
Save