Skip to content

Commit

Permalink
Merge pull request #5 from webmd-health-services/feature/privileges
Browse files Browse the repository at this point in the history
Migrating Get/Grant/Revoke/Test-CPrivilege functions from Carbon
  • Loading branch information
splatteredbits authored Apr 11, 2024
2 parents af2eab3 + 17a3683 commit ef323b7
Show file tree
Hide file tree
Showing 15 changed files with 740 additions and 9 deletions.
15 changes: 12 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

### Upgrade Instructions

This is not the upgrade path you want, if switching from Carbon. The `Get-CPermission`, `Grant-CPermission`,
`Revoke-CPermission`, and `Test-CPermission` functions were migrated to the following provider-specific modules with the
following function names:
If switching from Carbon, the `Get-CPermission`, `Grant-CPermission`, `Revoke-CPermission`, and `Test-CPermission`
functions were migrated to the following provider-specific modules with the following function names:

`Carbon.FileSystem`:

Expand All @@ -30,8 +29,18 @@ following function names:
* `Resolve-CPrivateKeyPath`
* `Revoke-CPrivateKeyPermission`
* `Test-CPrivateKeyPath`
* `Test-CPrivateKeyPermission`

### Added

* Function `Get-CAcl` to get the access control (i.e. security descriptor) for a registry key, file, or directory.
Supports getting only specific sections/parts of the security descriptor, too. Works across PowerShell editions.
* Function `Get-CPrivilege` (migrated from Carbon), which gets a user/group's rights/privileges.
* Function `Grant-CPrivilege` (migrated from Carbon), which grants a user/group rights/privileges.
* Function `Revoke-CPrivilege` (migrated from Carbon), which removes a user/group's rights/privileges.
* Function `Test-CPrivilege` (migrated from Carbon), which tests a user/group's rights/privileges.
* Function `Test-CPrivilegeName`, which tests if rights/privileges are supported on the current operating system.

### Changed

* The `Privilege` parameters on the `Grant-CPrivilege` and `Revoke-CPrivilege` functions are now case-insensitive.
7 changes: 6 additions & 1 deletion Carbon.Security/Carbon.Security.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,14 @@
FunctionsToExport = @(
'Get-CAcl',
'Get-CPermission',
'Get-CPrivilege',
'Grant-CPermission',
'Grant-CPrivilege',
'Revoke-CPermission',
'Test-CPermission'
'Revoke-CPrivilege',
'Test-CPermission',
'Test-CPrivilege',
'Test-CPrivilegeName'
)

# Cmdlets to export from this module. By default, you get a script module, so there are no cmdlets.
Expand Down
13 changes: 12 additions & 1 deletion Carbon.Security/Carbon.Security.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,18 @@ Import-Module -Name (Join-Path -Path $psModulesRoot -ChildPath 'Carbon.Core') `
-Function @('Get-CPathProvider') `
-Verbose:$false
Import-Module -Name (Join-Path -Path $psModulesRoot -ChildPath 'Carbon.Accounts') `
-Function @('Resolve-CIdentityName', 'Test-CIdentity') `
-Function @('Resolve-CIdentity', 'Resolve-CIdentityName', 'Test-CIdentity') `
-Verbose:$false
Import-Module -Name (Join-Path -Path $psModulesRoot -ChildPath 'PureInvoke' -Resolve) `
-Function @(
'Invoke-AdvApiLookupPrivilegeName'
'Invoke-AdvApiLookupPrivilegeValue',
'Invoke-AdvApiLsaAddAccountRights',
'Invoke-AdvApiLsaClose',
'Invoke-AdvApiLsaEnumerateAccountRights',
'Invoke-AdvApiLsaOpenPolicy',
'Invoke-AdvApiLsaRemoveAccountRights'
) `
-Verbose:$false

if (-not (Test-Path -Path 'variable:IsWindows'))
Expand Down
63 changes: 63 additions & 0 deletions Carbon.Security/Functions/Get-CPrivilege.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

function Get-CPrivilege
{
<#
.SYNOPSIS
Gets an account's rights and privileges.
.DESCRIPTION
The `Get-CPrivilege` function gets an account's rights and privileges. These privileges are usually managed by Group
Policy and control the system operations and types of logons an account can perform.
.OUTPUTS
System.String
.LINK
Grant-CPrivilege
.LINK
Revoke-CPrivilege
.LINK
Test-CPrivilege
.LINK
Test-CPrivilegeName
.EXAMPLE
Get-CPrivilege -Identity TheBeast
Gets `TheBeast` account's privileges as an array of strings.
#>
[CmdletBinding()]
[OutputType([String])]
param(
# The user/group name whose privileges to return.
[Parameter(Mandatory)]
[String] $Identity
)

Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState

$account = Resolve-CIdentity -Name $Identity
if (-not $account)
{
return
}

$pHandle = Invoke-AdvApiLsaOpenPolicy -DesiredAccess LookupNames
if (-not $pHandle)
{
return
}

try
{
Invoke-AdvApiLsaEnumerateAccountRights -PolicyHandle $pHandle -Sid $account.Sid | Write-Output
}
finally
{
Invoke-AdvApiLsaClose -PolicyHandle $pHandle | Out-Null
}
}
162 changes: 162 additions & 0 deletions Carbon.Security/Functions/Grant-CPrivilege.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@

function Grant-CPrivilege
{
<#
.SYNOPSIS
Grants an account privileges to perform system operations.
.DESCRIPTION
The `Grant-CPrivilege` function grants a user/group rights and privileges. Pass the name of the user/group to the
`Identity` parameter. Pass the list of account rights and/or privileges to grant to the `Privilege` parameter. The
account is granted any rights/privileges it doesn't currently have.
Rights and privilege names are documented on Microsoft's website, duplicated below. These lists may be out-of-date.
[Privilege Constants](https://learn.microsoft.com/en-us/windows/win32/secauthz/privilege-constants):
* SeAssignPrimaryTokenPrivilege
* SeAuditPrivilege
* SeBackupPrivilege
* SeChangeNotifyPrivilege
* SeCreateGlobalPrivilege
* SeCreatePagefilePrivilege
* SeCreatePermanentPrivilege
* SeCreateSymbolicLinkPrivilege
* SeCreateTokenPrivilege
* SeDebugPrivilege
* SeDelegateSessionUserImpersonatePrivilege
* SeEnableDelegationPrivilege
* SeImpersonatePrivilege
* SeIncreaseBasePriorityPrivilege
* SeIncreaseQuotaPrivilege
* SeIncreaseWorkingSetPrivilege
* SeLoadDriverPrivilege
* SeLockMemoryPrivilege
* SeMachineAccountPrivilege
* SeManageVolumePrivilege
* SeProfileSingleProcessPrivilege
* SeRelabelPrivilege
* SeRemoteInteractiveLogonRight
* SeRemoteShutdownPrivilege
* SeRestorePrivilege
* SeSecurityPrivilege
* SeShutdownPrivilege
* SeSyncAgentPrivilege
* SeSystemEnvironmentPrivilege
* SeSystemProfilePrivilege
* SeSystemtimePrivilege
* SeTakeOwnershipPrivilege
* SeTcbPrivilege
* SeTimeZonePrivilege
* SeTrustedCredManAccessPrivilege
* SeUndockPrivilege
* SeUnsolicitedInputPrivilege
[Account Right Constants](https://learn.microsoft.com/en-us/windows/win32/secauthz/account-rights-constants):
* SeBatchLogonRight
* SeDenyBatchLogonRight
* SeDenyInteractiveLogonRight
* SeDenyNetworkLogonRight
* SeDenyRemoteInteractiveLogonRight
* SeDenyServiceLogonRight
* SeInteractiveLogonRight
* SeNetworkLogonRight
* SeServiceLogonRight
.LINK
Get-CPrivilege
.LINK
Revoke-CPrivilege
.LINK
Test-CPrivilege
.LINK
Test-CPrivilegeName
.LINK
https://learn.microsoft.com/en-us/windows/win32/secauthz/privilege-constants
.LINK
https://learn.microsoft.com/en-us/windows/win32/secauthz/account-rights-constants
.EXAMPLE
Grant-CPrivilege -Identity Batcomputer -Privilege SeServiceLogonRight
Grants the Batcomputer account the ability to logon as a service.
#>
[CmdletBinding()]
param(
# The user/group name to grant rights/privileges.
[Parameter(Mandatory)]
[String] $Identity,

# The rights/privileges to grant.
#
# [Privilege names are documented on the "Privilege Constants"
# page.](https://learn.microsoft.com/en-us/windows/win32/secauthz/privilege-constants)
#
# [Rights names are documented on the "Account Rights Constants"
# page.](https://learn.microsoft.com/en-us/windows/win32/secauthz/account-rights-constants)
[Parameter(Mandatory)]
[String[]] $Privilege
)

Set-StrictMode -Version 'Latest'
Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState

$account = Resolve-CIdentity -Name $Identity
if( -not $account )
{
return
}

$privilegesToGrant = $Privilege | Where-Object { -not (Test-CPrivilege -Identity $account.FullName -Privilege $_) }
if (-not $privilegesToGrant)
{
return
}

$unknownPrivileges = $privilegesToGrant | Where-Object { -not (Test-CPrivilegeName -Name $_) }
if ($unknownPrivileges)
{
$privileges = 'privilege'
$thatThose = 'that'
$isAre = 'is'
if (($unknownPrivileges | Measure-Object).Count -gt 1)
{
$privileges = 'privileges'
$thatThose = 'those'
$isAre = 'are'
}
$msg = "Failed to grant the $($account.FullName) account $($unknownPrivileges -join ', ') ${privileges} " +
"because ${thatThose} ${privileges} ${isAre} unknown."
Write-Error -Message $msg -ErrorAction $ErrorActionPreference
}

# Privilege names are case-sensitive when granting, so get the actual value of the privilege names.
$privilegesToGrant = $privilegesToGrant | Test-CPrivilegeName -PassThru | Where-Object { $_ }
if (-not $privilegesToGrant)
{
return
}

$pHandle = Invoke-AdvApiLsaOpenPolicy -DesiredAccess CreateAccount,LookupNames
if (-not $pHandle)
{
return
}

try
{
Write-Information "$($account.FullName) + $($privilegesToGrant -join ',')"
Invoke-AdvApiLsaAddAccountRights -PolicyHandle $pHandle -Sid $account.Sid -Privilege $privilegesToGrant |
Out-Null
}
finally
{
Invoke-AdvApiLsaClose -PolicyHandle $pHandle | Out-Null
}
}
Loading

0 comments on commit ef323b7

Please sign in to comment.