Add Ansible.ModuleUtils.PrivilegeUtil and converted code to use it (#43179)

* Add Ansible.ModuleUtils.PrivilegeUtil and converted code to use it

* Changed namespace and class to be a better standard and fixed some typos

* Changes from review

* changes to avoid out of bound mem of server 2008

* changes to detect failure when setting a privileged not allowed
This commit is contained in:
Jordan Borean 2018-07-31 07:48:54 +10:00 committed by Matt Davis
commit 9259f31fee
18 changed files with 708 additions and 298 deletions

View file

@ -6,6 +6,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#Requires -Module Ansible.ModuleUtils.Legacy
#Requires -Module Ansible.ModuleUtils.PrivilegeUtil
#Requires -Module Ansible.ModuleUtils.SID
$ErrorActionPreference = "Stop"
@ -43,96 +44,7 @@ function Get-UserSID {
return $userSID
}
# Need to adjust token privs when executing Set-ACL in certain cases.
# e.g. d:\testdir is owned by group in which current user is not a member and no perms are inherited from d:\
# This also sets us up for setting the owner as a feature.
$AdjustTokenPrivileges = @"
using System;
using System.Runtime.InteropServices;
namespace Ansible {
public class TokenManipulator {
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc,
ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool AddPrivilege(string privilege) {
try {
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex) {
throw ex;
}
}
public static bool RemovePrivilege(string privilege) {
try {
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_DISABLED;
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
catch (Exception ex) {
throw ex;
}
}
}
}
"@
$params = Parse-Args $args
$_remote_tmp = Get-AnsibleParam $params "_ansible_remote_tmp" -type "path" -default $env:TMP
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
add-type $AdjustTokenPrivileges
$env:TMP = $original_tmp
$env:TEMP = $original_temp
Function SetPrivilegeTokens() {
# Set privilege tokens only if admin.
@ -144,13 +56,23 @@ Function SetPrivilegeTokens() {
if ($myWindowsPrincipal.IsInRole($adminRole)) {
# Need to adjust token privs when executing Set-ACL in certain cases.
# e.g. d:\testdir is owned by group in which current user is not a member and no perms are inherited from d:\
# This also sets us up for setting the owner as a feature.
# See the following for details of each privilege
# https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx
[void][Ansible.TokenManipulator]::AddPrivilege("SeRestorePrivilege") #Grants all write access control to any file, regardless of ACL.
[void][Ansible.TokenManipulator]::AddPrivilege("SeBackupPrivilege") #Grants all read access control to any file, regardless of ACL.
[void][Ansible.TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege") #Grants ability to take owernship of an object w/out being granted discretionary access
Import-PrivilegeUtil
$privileges = @(
"SeRestorePrivilege", # Grants all write access control to any file, regardless of ACL.
"SeBackupPrivilege", # Grants all read access control to any file, regardless of ACL.
"SeTakeOwnershipPrivilege" # Grants ability to take owernship of an object w/out being granted discretionary access
)
foreach ($privilege in $privileges) {
$state = Get-AnsiblePrivilege -Name $privilege
if ($state -eq $false) {
Set-AnsiblePrivilege -Name $privilege -Value $true
}
}
}
}

View file

@ -52,12 +52,9 @@ namespace Ansible.Command {
}
"@
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $symlink_util
$env:TMP = $original_tmp
$env:TEMP = $original_temp
# Used to delete directories and files with logic on handling symbolic links
function Remove-File($file, $checkmode) {

View file

@ -71,12 +71,9 @@ namespace Ansible.Command {
}
"@
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $symlink_util
$env:TMP = $original_tmp
$env:TEMP = $original_temp
Function Assert-Age($info) {
$valid_match = $true

View file

@ -30,12 +30,9 @@ $webclient_util = @"
}
"@
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $webclient_util
$env:TMP = $original_tmp
$env:TEMP = $original_temp
Function CheckModified-File($url, $dest, $headers, $credentials, $timeout, $use_proxy, $proxy) {

View file

@ -6,6 +6,7 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#Requires -Module Ansible.ModuleUtils.Legacy
#Requires -Module Ansible.ModuleUtils.PrivilegeUtil
$ErrorActionPreference = "Stop"
@ -39,23 +40,8 @@ using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Ansible
namespace Ansible.RegEdit
{
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public UInt32 LowPart;
public Int32 HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
public LUID Luid;
public UInt32 Attributes;
}
public enum HKEY : uint
{
LOCAL_MACHINE = 0x80000002,
@ -74,41 +60,8 @@ namespace Ansible
public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
}
public class RegistryUtil
public class Hive
{
public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public const int TOKEN_QUERY = 0x00000008;
public const int SE_PRIVILEGE_ENABLED = 0x00000002;
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(
IntPtr hObject);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
private static extern bool OpenProcessToken(
IntPtr ProcessHandle,
UInt32 DesiredAccess,
out IntPtr TokenHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
private static extern bool LookupPrivilegeValue(
string lpSystemName,
string lpName,
[MarshalAs(UnmanagedType.Struct)] out LUID lpLuid);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
private static extern bool AdjustTokenPrivileges(
IntPtr TokenHandle,
[MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges,
ref TOKEN_PRIVILEGES NewState,
UInt32 BufferLength,
IntPtr PreviousState,
IntPtr ReturnLength);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int RegLoadKey(
HKEY hKey,
@ -120,41 +73,6 @@ namespace Ansible
HKEY hKey,
string lpSubKey);
public static void EnablePrivileges()
{
List<String> privileges = new List<String>()
{
"SeRestorePrivilege",
"SeBackupPrivilege"
};
foreach (string privilege in privileges)
{
IntPtr hToken;
LUID luid;
TOKEN_PRIVILEGES tkpPrivileges;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken))
throw new Win32Exception("OpenProcessToken() failed");
try
{
if (!LookupPrivilegeValue(null, privilege, out luid))
throw new Win32Exception("LookupPrivilegeValue() failed");
tkpPrivileges.PrivilegeCount = 1;
tkpPrivileges.Luid = luid;
tkpPrivileges.Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, false, ref tkpPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
throw new Win32Exception(String.Format("AdjustTokenPrivileges() failed to adjust privilege {0}", privilege));
}
finally
{
CloseHandle(hToken);
}
}
}
public static void LoadHive(string lpSubKey, string lpFile)
{
int ret;
@ -373,29 +291,29 @@ if ($hive) {
}
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $registry_util
$env:TMP = $original_tmp
$env:TEMP = $original_temp
Import-PrivilegeUtil
try {
[Ansible.RegistryUtil]::EnablePrivileges()
Set-AnsiblePrivilege -Name SeBackupPrivilege -Value $true
Set-AnsiblePrivilege -Name SeRestorePrivilege -Value $true
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to enable SeRestorePrivilege and SeRestorePrivilege for the current process: $($_.Exception.Message)"
Fail-Json -obj $result -message "failed to enable SeBackupPrivilege and SeRestorePrivilege for the current process: $($_.Exception.Message)"
}
if (Test-Path -Path HKLM:\ANSIBLE) {
Add-Warning -obj $result -message "hive already loaded at HKLM:\ANSIBLE, had to unload hive for win_regedit to continue"
try {
[Ansible.RegistryUtil]::UnloadHive("ANSIBLE")
[Ansible.RegEdit.Hive]::UnloadHive("ANSIBLE")
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to unload registry hive HKLM:\ANSIBLE from $($hive): $($_.Exception.Message)"
}
}
try {
[Ansible.RegistryUtil]::LoadHive("ANSIBLE", $hive)
[Ansible.RegEdit.Hive]::LoadHive("ANSIBLE", $hive)
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to load registry hive from '$hive' to HKLM:\ANSIBLE: $($_.Exception.Message)"
}
@ -566,7 +484,7 @@ $key_prefix[$path]
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
try {
[Ansible.RegistryUtil]::UnloadHive("ANSIBLE")
[Ansible.RegEdit.Hive]::UnloadHive("ANSIBLE")
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to unload registry hive HKLM:\ANSIBLE from $($hive): $($_.Exception.Message)"
}

View file

@ -88,12 +88,9 @@ Function Set-CultureLegacy($culture) {
$reg_key = 'HKCU:\Control Panel\International'
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $lctype_util
$env:TMP = $original_tmp
$env:TEMP = $original_temp
$lookup = New-Object Ansible.LocaleHelper($culture)
# hex values are from http://www.pinvoke.net/default.aspx/kernel32/GetLocaleInfoEx.html

View file

@ -125,12 +125,9 @@ public enum TASK_TRIGGER_TYPE2 // https://msdn.microsoft.com/en-us/library/windo
"@
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $task_enums
$env:TMP = $original_tmp
$env:TEMP = $original_temp
########################
### HELPER FUNCTIONS ###

View file

@ -70,12 +70,9 @@ public enum TASK_TRIGGER_TYPE2
"@
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $task_enums
$env:TMP = $original_tmp
$env:TEMP = $original_temp
Function Get-PropertyValue($task_property, $com, $property) {
$raw_value = $com.$property

View file

@ -70,12 +70,9 @@ namespace Ansible
'@
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $platform_util
$env:TMP = $original_tmp
$env:TEMP = $original_temp
$handle = [IntPtr]::Zero
$logon_res = [Ansible.WinUserPInvoke]::LogonUser($Username, $null, $Password,

View file

@ -267,12 +267,9 @@ namespace Ansible
"@
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $sec_helper_util
$env:TMP = $original_tmp
$env:TEMP = $original_temp
Function Compare-UserList($existing_users, $new_users) {
$added_users = [String[]]@()

View file

@ -783,12 +783,9 @@ namespace Ansible
'@
$original_tmp = $env:TMP
$original_temp = $env:TEMP
$env:TMP = $_remote_tmp
$env:TEMP = $_remote_tmp
Add-Type -TypeDefinition $session_util
$env:TMP = $original_tmp
$env:TEMP = $original_temp
$session_info = [Ansible.SessionUtil]::GetSessionInfo()