mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 12:50:22 -07:00
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:
parent
d79027b77f
commit
9259f31fee
18 changed files with 708 additions and 298 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ###
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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[]]@()
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue