Server IP : 85.214.239.14 / Your IP : 18.227.26.84 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /lib/python3/dist-packages/ansible_collections/community/windows/plugins/modules/ |
Upload File : |
#!powershell # Copyright: (c) 2019, Prasoon Karunan V (@prasoonkarunan) <kvprasoon@Live.in> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # All helper methods are written in a binary module and has to be loaded for consuming them. #AnsibleRequires -CSharpUtil Ansible.Basic #Requires -Module Ansible.ModuleUtils.AddType Set-StrictMode -Version 2.0 $spec = @{ options = @{ logon_count = @{ type = "int" } password = @{ type = "str"; no_log = $true } state = @{ type = "str"; choices = "absent", "present"; default = "present" } username = @{ type = "str" } } required_if = @( , @("state", "present", @("username", "password")) ) supports_check_mode = $true } $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) $logonCount = $module.Params.logon_count $password = $module.Params.password $state = $module.Params.state $username = $module.Params.username $domain = $null if ($username) { # Try and get the Netlogon form of the username specified. Translating to and from a SID gives us an NTAccount # in the Netlogon form that we desire. $ntAccount = New-Object -TypeName System.Security.Principal.NTAccount -ArgumentList $username try { $accountSid = $ntAccount.Translate([System.Security.Principal.SecurityIdentifier]) } catch [System.Security.Principal.IdentityNotMappedException] { $module.FailJson("Failed to find a local or domain user with the name '$username'", $_) } $ntAccount = $accountSid.Translate([System.Security.Principal.NTAccount]) $domain, $username = $ntAccount.Value -split '\\' } # Make sure $null regardless of any input value if state: absent if ($state -eq 'absent') { $password = $null } Add-CSharpType -AnsibleModule $module -References @' using Microsoft.Win32.SafeHandles; using System; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Text; namespace Ansible.WinAutoLogon { internal class NativeHelpers { [StructLayout(LayoutKind.Sequential)] public class LSA_OBJECT_ATTRIBUTES { public UInt32 Length = 0; public IntPtr RootDirectory = IntPtr.Zero; public IntPtr ObjectName = IntPtr.Zero; public UInt32 Attributes = 0; public IntPtr SecurityDescriptor = IntPtr.Zero; public IntPtr SecurityQualityOfService = IntPtr.Zero; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct LSA_UNICODE_STRING { public UInt16 Length; public UInt16 MaximumLength; public IntPtr Buffer; public static explicit operator string(LSA_UNICODE_STRING s) { byte[] strBytes = new byte[s.Length]; Marshal.Copy(s.Buffer, strBytes, 0, s.Length); return Encoding.Unicode.GetString(strBytes); } public static SafeMemoryBuffer CreateSafeBuffer(string s) { if (s == null) return new SafeMemoryBuffer(IntPtr.Zero); byte[] stringBytes = Encoding.Unicode.GetBytes(s); int structSize = Marshal.SizeOf(typeof(LSA_UNICODE_STRING)); IntPtr buffer = Marshal.AllocHGlobal(structSize + stringBytes.Length); try { LSA_UNICODE_STRING lsaString = new LSA_UNICODE_STRING() { Length = (UInt16)(stringBytes.Length), MaximumLength = (UInt16)(stringBytes.Length), Buffer = IntPtr.Add(buffer, structSize), }; Marshal.StructureToPtr(lsaString, buffer, false); Marshal.Copy(stringBytes, 0, lsaString.Buffer, stringBytes.Length); return new SafeMemoryBuffer(buffer); } catch { // Make sure we free the pointer before raising the exception. Marshal.FreeHGlobal(buffer); throw; } } } } internal class NativeMethods { [DllImport("Advapi32.dll")] public static extern UInt32 LsaClose( IntPtr ObjectHandle); [DllImport("Advapi32.dll")] public static extern UInt32 LsaFreeMemory( IntPtr Buffer); [DllImport("Advapi32.dll")] internal static extern Int32 LsaNtStatusToWinError( UInt32 Status); [DllImport("Advapi32.dll")] public static extern UInt32 LsaOpenPolicy( IntPtr SystemName, NativeHelpers.LSA_OBJECT_ATTRIBUTES ObjectAttributes, LsaPolicyAccessMask AccessMask, out SafeLsaHandle PolicyHandle); [DllImport("Advapi32.dll")] public static extern UInt32 LsaRetrievePrivateData( SafeLsaHandle PolicyHandle, SafeMemoryBuffer KeyName, out SafeLsaMemory PrivateData); [DllImport("Advapi32.dll")] public static extern UInt32 LsaStorePrivateData( SafeLsaHandle PolicyHandle, SafeMemoryBuffer KeyName, SafeMemoryBuffer PrivateData); } internal class SafeLsaMemory : SafeBuffer { internal SafeLsaMemory() : base(true) { } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { return NativeMethods.LsaFreeMemory(handle) == 0; } } internal class SafeMemoryBuffer : SafeBuffer { internal SafeMemoryBuffer() : base(true) { } internal SafeMemoryBuffer(IntPtr ptr) : base(true) { base.SetHandle(ptr); } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { if (handle != IntPtr.Zero) Marshal.FreeHGlobal(handle); return true; } } public class SafeLsaHandle : SafeHandleZeroOrMinusOneIsInvalid { internal SafeLsaHandle() : base(true) { } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected override bool ReleaseHandle() { return NativeMethods.LsaClose(handle) == 0; } } public class Win32Exception : System.ComponentModel.Win32Exception { private string _exception_msg; public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { } public Win32Exception(int errorCode, string message) : base(errorCode) { _exception_msg = String.Format("{0} - {1} (Win32 Error Code {2}: 0x{3})", message, base.Message, errorCode, errorCode.ToString("X8")); } public override string Message { get { return _exception_msg; } } public static explicit operator Win32Exception(string message) { return new Win32Exception(message); } } [Flags] public enum LsaPolicyAccessMask : uint { ViewLocalInformation = 0x00000001, ViewAuditInformation = 0x00000002, GetPrivateInformation = 0x00000004, TrustAdmin = 0x00000008, CreateAccount = 0x00000010, CreateSecret = 0x00000020, CreatePrivilege = 0x00000040, SetDefaultQuotaLimits = 0x00000080, SetAuditRequirements = 0x00000100, AuditLogAdmin = 0x00000200, ServerAdmin = 0x00000400, LookupNames = 0x00000800, Read = 0x00020006, Write = 0x000207F8, Execute = 0x00020801, AllAccess = 0x000F0FFF, } public class LsaUtil { public static SafeLsaHandle OpenPolicy(LsaPolicyAccessMask access) { NativeHelpers.LSA_OBJECT_ATTRIBUTES oa = new NativeHelpers.LSA_OBJECT_ATTRIBUTES(); SafeLsaHandle lsaHandle; UInt32 res = NativeMethods.LsaOpenPolicy(IntPtr.Zero, oa, access, out lsaHandle); if (res != 0) throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res), String.Format("LsaOpenPolicy({0}) failed", access.ToString())); return lsaHandle; } public static string RetrievePrivateData(SafeLsaHandle handle, string key) { using (SafeMemoryBuffer keyBuffer = NativeHelpers.LSA_UNICODE_STRING.CreateSafeBuffer(key)) { SafeLsaMemory buffer; UInt32 res = NativeMethods.LsaRetrievePrivateData(handle, keyBuffer, out buffer); using (buffer) { if (res != 0) { // If the data object was not found we return null to indicate it isn't set. if (res == 0xC0000034) // STATUS_OBJECT_NAME_NOT_FOUND return null; throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res), String.Format("LsaRetrievePrivateData({0}) failed", key)); } NativeHelpers.LSA_UNICODE_STRING lsaString = (NativeHelpers.LSA_UNICODE_STRING) Marshal.PtrToStructure(buffer.DangerousGetHandle(), typeof(NativeHelpers.LSA_UNICODE_STRING)); return (string)lsaString; } } } public static void StorePrivateData(SafeLsaHandle handle, string key, string data) { using (SafeMemoryBuffer keyBuffer = NativeHelpers.LSA_UNICODE_STRING.CreateSafeBuffer(key)) using (SafeMemoryBuffer dataBuffer = NativeHelpers.LSA_UNICODE_STRING.CreateSafeBuffer(data)) { UInt32 res = NativeMethods.LsaStorePrivateData(handle, keyBuffer, dataBuffer); if (res != 0) { // When clearing the private data with null it may return this error which we can ignore. if (data == null && res == 0xC0000034) // STATUS_OBJECT_NAME_NOT_FOUND return; throw new Win32Exception(NativeMethods.LsaNtStatusToWinError(res), String.Format("LsaStorePrivateData({0}) failed", key)); } } } } } '@ $autoLogonRegPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' $logonDetails = Get-ItemProperty -LiteralPath $autoLogonRegPath $before = @{ state = 'absent' } if ('AutoAdminLogon' -in $logonDetails.PSObject.Properties.Name -and $logonDetails.AutoAdminLogon -eq 1) { $before.state = 'present' } $mapping = @{ DefaultUserName = 'username' DefaultDomainName = 'domain' AutoLogonCount = 'logon_count' } foreach ($map_detail in $mapping.GetEnumerator()) { if ($map_detail.Key -in $logonDetails.PSObject.Properties.Name) { $before."$($map_detail.Value)" = $logonDetails."$($map_detail.Key)" } } $module.Diff.before = $before $propParams = @{ LiteralPath = $autoLogonRegPath WhatIf = $module.CheckMode Force = $true } # First set the registry information # The DefaultPassword reg key should never be set, we use LSA to store the password in a more secure way. if ('DefaultPassword' -in (Get-Item -LiteralPath $autoLogonRegPath).Property) { # Bug on older Windows hosts where -WhatIf causes it fail to find the property if (-not $module.CheckMode) { Remove-ItemProperty -Name 'DefaultPassword' @propParams } $module.Result.changed = $true } $autoLogonKeyList = @{ DefaultUserName = @{ before = if ($before.ContainsKey('username')) { $before.username } else { $null } after = $username } DefaultDomainName = @{ before = if ($before.ContainsKey('domain')) { $before.domain } else { $null } after = $domain } AutoLogonCount = @{ before = if ($before.ContainsKey('logon_count')) { $before.logon_count } else { $null } after = $logonCount } } # Check AutoAdminLogon separately as it has different logic (key must exist) if ($state -ne $before.state) { $newValue = if ($state -eq 'present') { 1 } else { 0 } $null = New-ItemProperty -Name 'AutoAdminLogon' -Value $newValue -PropertyType DWord @propParams $module.Result.changed = $true } foreach ($key in $autoLogonKeyList.GetEnumerator()) { $beforeVal = $key.Value.before $after = $key.Value.after if ($state -eq 'present' -and $beforeVal -cne $after) { if ($null -ne $after) { $null = New-ItemProperty -Name $key.Key -Value $after @propParams } elseif (-not $module.CheckMode) { Remove-ItemProperty -Name $key.Key @propParams } $module.Result.changed = $true } elseif ($state -eq 'absent' -and $null -ne $beforeVal) { if (-not $module.CheckMode) { Remove-ItemProperty -Name $key.Key @propParams } $module.Result.changed = $true } } # Finally update the password in the LSA private store. $lsaHandle = [Ansible.WinAutoLogon.LsaUtil]::OpenPolicy('CreateSecret, GetPrivateInformation') try { $beforePass = [Ansible.WinAutoLogon.LsaUtil]::RetrievePrivateData($lsaHandle, 'DefaultPassword') if ($beforePass -cne $password) { # Due to .NET marshaling we need to pass in $null as NullString.Value so it's truly a null value. if ($null -eq $password) { $password = [NullString]::Value } if (-not $module.CheckMode) { [Ansible.WinAutoLogon.LsaUtil]::StorePrivateData($lsaHandle, 'DefaultPassword', $password) } $module.Result.changed = $true } } finally { $lsaHandle.Dispose() } # Need to manually craft the after diff in case we are running in check mode $module.Diff.after = @{ state = $state } if ($state -eq 'present') { $module.Diff.after.username = $username $module.Diff.after.domain = $domain if ($null -ne $logonCount) { $module.Diff.after.logon_count = $logonCount } } $module.ExitJson()