win_whoami: new module to emulate whoami executable (#33295)
This commit is contained in:
parent
cd36164239
commit
38de7c4bb1
4 changed files with 1301 additions and 0 deletions
836
lib/ansible/modules/windows/win_whoami.ps1
Normal file
836
lib/ansible/modules/windows/win_whoami.ps1
Normal file
|
@ -0,0 +1,836 @@
|
||||||
|
#!powershell
|
||||||
|
# This file is part of Ansible
|
||||||
|
|
||||||
|
# Copyright (c) 2017 Ansible Project
|
||||||
|
# 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.CamelConversion
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$session_util = @'
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ansible
|
||||||
|
{
|
||||||
|
public class SessionInfo
|
||||||
|
{
|
||||||
|
// SECURITY_LOGON_SESSION_DATA
|
||||||
|
public UInt64 LogonId { get; internal set; }
|
||||||
|
public Sid Account { get; internal set; }
|
||||||
|
public string LoginDomain { get; internal set; }
|
||||||
|
public string AuthenticationPackage { get; internal set; }
|
||||||
|
public SECURITY_LOGON_TYPE LogonType { get; internal set; }
|
||||||
|
public string LoginTime { get; internal set; }
|
||||||
|
public string LogonServer { get; internal set; }
|
||||||
|
public string DnsDomainName { get; internal set; }
|
||||||
|
public string Upn { get; internal set; }
|
||||||
|
public ArrayList UserFlags { get; internal set; }
|
||||||
|
|
||||||
|
// TOKEN_STATISTICS
|
||||||
|
public SECURITY_IMPERSONATION_LEVEL ImpersonationLevel { get; internal set; }
|
||||||
|
public TOKEN_TYPE TokenType { get; internal set; }
|
||||||
|
|
||||||
|
// TOKEN_GROUPS
|
||||||
|
public ArrayList Groups { get; internal set; }
|
||||||
|
public Sid LogonSid { get; internal set; }
|
||||||
|
public ArrayList Rights { get; internal set; }
|
||||||
|
|
||||||
|
// TOKEN_MANDATORY_LABEL
|
||||||
|
public Sid Label { get; internal set; }
|
||||||
|
|
||||||
|
// TOKEN_PRIVILEGES
|
||||||
|
public Hashtable Privileges { get; internal set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Win32Exception : System.ComponentModel.Win32Exception
|
||||||
|
{
|
||||||
|
private string _msg;
|
||||||
|
public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
|
||||||
|
public Win32Exception(int errorCode, string message) : base(errorCode)
|
||||||
|
{
|
||||||
|
_msg = String.Format("{0} ({1}, Win32ErrorCode {2})", message, base.Message, errorCode);
|
||||||
|
}
|
||||||
|
public override string Message { get { return _msg; } }
|
||||||
|
public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
public struct LSA_UNICODE_STRING
|
||||||
|
{
|
||||||
|
public UInt16 Length;
|
||||||
|
public UInt16 MaximumLength;
|
||||||
|
public IntPtr buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct LUID
|
||||||
|
{
|
||||||
|
public UInt32 LowPart;
|
||||||
|
public Int32 HighPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct SECURITY_LOGON_SESSION_DATA
|
||||||
|
{
|
||||||
|
public UInt32 Size;
|
||||||
|
public LUID LogonId;
|
||||||
|
public LSA_UNICODE_STRING Username;
|
||||||
|
public LSA_UNICODE_STRING LoginDomain;
|
||||||
|
public LSA_UNICODE_STRING AuthenticationPackage;
|
||||||
|
public SECURITY_LOGON_TYPE LogonType;
|
||||||
|
public UInt32 Session;
|
||||||
|
public IntPtr Sid;
|
||||||
|
public UInt64 LoginTime;
|
||||||
|
public LSA_UNICODE_STRING LogonServer;
|
||||||
|
public LSA_UNICODE_STRING DnsDomainName;
|
||||||
|
public LSA_UNICODE_STRING Upn;
|
||||||
|
public UInt32 UserFlags;
|
||||||
|
public LSA_LAST_INTER_LOGON_INFO LastLogonInfo;
|
||||||
|
public LSA_UNICODE_STRING LogonScript;
|
||||||
|
public LSA_UNICODE_STRING ProfilePath;
|
||||||
|
public LSA_UNICODE_STRING HomeDirectory;
|
||||||
|
public LSA_UNICODE_STRING HomeDirectoryDrive;
|
||||||
|
public UInt64 LogoffTime;
|
||||||
|
public UInt64 KickOffTime;
|
||||||
|
public UInt64 PasswordLastSet;
|
||||||
|
public UInt64 PasswordCanChange;
|
||||||
|
public UInt64 PasswordMustChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct LSA_LAST_INTER_LOGON_INFO
|
||||||
|
{
|
||||||
|
public UInt64 LastSuccessfulLogon;
|
||||||
|
public UInt64 LastFailedLogon;
|
||||||
|
public UInt32 FailedAttemptCountSinceLastSuccessfulLogon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TOKEN_TYPE
|
||||||
|
{
|
||||||
|
TokenPrimary = 1,
|
||||||
|
TokenImpersonation
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SECURITY_IMPERSONATION_LEVEL
|
||||||
|
{
|
||||||
|
SecurityAnonymous,
|
||||||
|
SecurityIdentification,
|
||||||
|
SecurityImpersonation,
|
||||||
|
SecurityDelegation
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SECURITY_LOGON_TYPE
|
||||||
|
{
|
||||||
|
System = 0, // Used only by the Sytem account
|
||||||
|
Interactive = 2,
|
||||||
|
Network,
|
||||||
|
Batch,
|
||||||
|
Service,
|
||||||
|
Proxy,
|
||||||
|
Unlock,
|
||||||
|
NetworkCleartext,
|
||||||
|
NewCredentials,
|
||||||
|
RemoteInteractive,
|
||||||
|
CachedInteractive,
|
||||||
|
CachedRemoteInteractive,
|
||||||
|
CachedUnlock
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum TokenGroupAttributes : uint
|
||||||
|
{
|
||||||
|
SE_GROUP_ENABLED = 0x00000004,
|
||||||
|
SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002,
|
||||||
|
SE_GROUP_INTEGRITY = 0x00000020,
|
||||||
|
SE_GROUP_INTEGRITY_ENABLED = 0x00000040,
|
||||||
|
SE_GROUP_LOGON_ID = 0xC0000000,
|
||||||
|
SE_GROUP_MANDATORY = 0x00000001,
|
||||||
|
SE_GROUP_OWNER = 0x00000008,
|
||||||
|
SE_GROUP_RESOURCE = 0x20000000,
|
||||||
|
SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum UserFlags : uint
|
||||||
|
{
|
||||||
|
LOGON_OPTIMIZED = 0x4000,
|
||||||
|
LOGON_WINLOGON = 0x8000,
|
||||||
|
LOGON_PKINIT = 0x10000,
|
||||||
|
LOGON_NOT_OPTMIZED = 0x20000,
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct SID_AND_ATTRIBUTES
|
||||||
|
{
|
||||||
|
public IntPtr Sid;
|
||||||
|
public UInt32 Attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct LUID_AND_ATTRIBUTES
|
||||||
|
{
|
||||||
|
public LUID Luid;
|
||||||
|
public UInt32 Attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct TOKEN_GROUPS
|
||||||
|
{
|
||||||
|
public UInt32 GroupCount;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
|
||||||
|
public SID_AND_ATTRIBUTES[] Groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct TOKEN_MANDATORY_LABEL
|
||||||
|
{
|
||||||
|
public SID_AND_ATTRIBUTES Label;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct TOKEN_STATISTICS
|
||||||
|
{
|
||||||
|
public LUID TokenId;
|
||||||
|
public LUID AuthenticationId;
|
||||||
|
public UInt64 ExpirationTime;
|
||||||
|
public TOKEN_TYPE TokenType;
|
||||||
|
public SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
|
||||||
|
public UInt32 DynamicCharged;
|
||||||
|
public UInt32 DynamicAvailable;
|
||||||
|
public UInt32 GroupCount;
|
||||||
|
public UInt32 PrivilegeCount;
|
||||||
|
public LUID ModifiedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct TOKEN_PRIVILEGES
|
||||||
|
{
|
||||||
|
public UInt32 PrivilegeCount;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
|
||||||
|
public LUID_AND_ATTRIBUTES[] Privileges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AccessToken : IDisposable
|
||||||
|
{
|
||||||
|
public enum TOKEN_INFORMATION_CLASS
|
||||||
|
{
|
||||||
|
TokenUser = 1,
|
||||||
|
TokenGroups,
|
||||||
|
TokenPrivileges,
|
||||||
|
TokenOwner,
|
||||||
|
TokenPrimaryGroup,
|
||||||
|
TokenDefaultDacl,
|
||||||
|
TokenSource,
|
||||||
|
TokenType,
|
||||||
|
TokenImpersonationLevel,
|
||||||
|
TokenStatistics,
|
||||||
|
TokenRestrictedSids,
|
||||||
|
TokenSessionId,
|
||||||
|
TokenGroupsAndPrivileges,
|
||||||
|
TokenSessionReference,
|
||||||
|
TokenSandBoxInert,
|
||||||
|
TokenAuditPolicy,
|
||||||
|
TokenOrigin,
|
||||||
|
TokenElevationType,
|
||||||
|
TokenLinkedToken,
|
||||||
|
TokenElevation,
|
||||||
|
TokenHasRestrictions,
|
||||||
|
TokenAccessInformation,
|
||||||
|
TokenVirtualizationAllowed,
|
||||||
|
TokenVirtualizationEnabled,
|
||||||
|
TokenIntegrityLevel,
|
||||||
|
TokenUIAccess,
|
||||||
|
TokenMandatoryPolicy,
|
||||||
|
TokenLogonSid,
|
||||||
|
TokenIsAppContainer,
|
||||||
|
TokenCapabilities,
|
||||||
|
TokenAppContainerSid,
|
||||||
|
TokenAppContainerNumber,
|
||||||
|
TokenUserClaimAttributes,
|
||||||
|
TokenDeviceClaimAttributes,
|
||||||
|
TokenRestrictedUserClaimAttributes,
|
||||||
|
TokenRestrictedDeviceClaimAttributes,
|
||||||
|
TokenDeviceGroups,
|
||||||
|
TokenRestrictedDeviceGroups,
|
||||||
|
TokenSecurityAttributes,
|
||||||
|
TokenIsRestricted,
|
||||||
|
MaxTokenInfoClass
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr hToken = IntPtr.Zero;
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern IntPtr GetCurrentProcess();
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true)]
|
||||||
|
private static extern bool OpenProcessToken(
|
||||||
|
IntPtr ProcessHandle,
|
||||||
|
TokenAccessLevels DesiredAccess,
|
||||||
|
out IntPtr TokenHandle);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true)]
|
||||||
|
private static extern bool GetTokenInformation(
|
||||||
|
IntPtr TokenHandle,
|
||||||
|
TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||||
|
IntPtr TokenInformation,
|
||||||
|
UInt32 TokenInformationLength,
|
||||||
|
out UInt32 ReturnLength);
|
||||||
|
|
||||||
|
public AccessToken(TokenAccessLevels tokenAccessLevels)
|
||||||
|
{
|
||||||
|
IntPtr currentProcess = GetCurrentProcess();
|
||||||
|
if (!OpenProcessToken(currentProcess, tokenAccessLevels, out hToken))
|
||||||
|
throw new Win32Exception("OpenProcessToken() for current process failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr GetTokenInformation<T>(out T tokenInformation, TOKEN_INFORMATION_CLASS tokenClass)
|
||||||
|
{
|
||||||
|
UInt32 tokenLength = 0;
|
||||||
|
GetTokenInformation(hToken, tokenClass, IntPtr.Zero, 0, out tokenLength);
|
||||||
|
|
||||||
|
IntPtr infoPtr = Marshal.AllocHGlobal((int)tokenLength);
|
||||||
|
|
||||||
|
if (!GetTokenInformation(hToken, tokenClass, infoPtr, tokenLength, out tokenLength))
|
||||||
|
throw new Win32Exception(String.Format("GetTokenInformation() data for {0} failed", tokenClass.ToString()));
|
||||||
|
|
||||||
|
tokenInformation = (T)Marshal.PtrToStructure(infoPtr, typeof(T));
|
||||||
|
return infoPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~AccessToken() { Dispose(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LsaHandle : IDisposable
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum DesiredAccess : uint
|
||||||
|
{
|
||||||
|
POLICY_VIEW_LOCAL_INFORMATION = 0x00000001,
|
||||||
|
POLICY_VIEW_AUDIT_INFORMATION = 0x00000002,
|
||||||
|
POLICY_GET_PRIVATE_INFORMATION = 0x00000004,
|
||||||
|
POLICY_TRUST_ADMIN = 0x00000008,
|
||||||
|
POLICY_CREATE_ACCOUNT = 0x00000010,
|
||||||
|
POLICY_CREATE_SECRET = 0x00000020,
|
||||||
|
POLICY_CREATE_PRIVILEGE = 0x00000040,
|
||||||
|
POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080,
|
||||||
|
POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100,
|
||||||
|
POLICY_AUDIT_LOG_ADMIN = 0x00000200,
|
||||||
|
POLICY_SERVER_ADMIN = 0x00000400,
|
||||||
|
POLICY_LOOKUP_NAMES = 0x00000800,
|
||||||
|
POLICY_NOTIFICATION = 0x00001000
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr handle = IntPtr.Zero;
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true)]
|
||||||
|
private static extern uint LsaOpenPolicy(
|
||||||
|
LSA_UNICODE_STRING[] SystemName,
|
||||||
|
ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
|
DesiredAccess AccessMask,
|
||||||
|
out IntPtr PolicyHandle);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true)]
|
||||||
|
private static extern uint LsaClose(
|
||||||
|
IntPtr ObjectHandle);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = false)]
|
||||||
|
private static extern int LsaNtStatusToWinError(
|
||||||
|
uint Status);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct LSA_OBJECT_ATTRIBUTES
|
||||||
|
{
|
||||||
|
public int Length;
|
||||||
|
public IntPtr RootDirectory;
|
||||||
|
public IntPtr ObjectName;
|
||||||
|
public int Attributes;
|
||||||
|
public IntPtr SecurityDescriptor;
|
||||||
|
public IntPtr SecurityQualityOfService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LsaHandle(DesiredAccess desiredAccess)
|
||||||
|
{
|
||||||
|
LSA_OBJECT_ATTRIBUTES lsaAttr;
|
||||||
|
lsaAttr.RootDirectory = IntPtr.Zero;
|
||||||
|
lsaAttr.ObjectName = IntPtr.Zero;
|
||||||
|
lsaAttr.Attributes = 0;
|
||||||
|
lsaAttr.SecurityDescriptor = IntPtr.Zero;
|
||||||
|
lsaAttr.SecurityQualityOfService = IntPtr.Zero;
|
||||||
|
lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
|
||||||
|
LSA_UNICODE_STRING[] system = new LSA_UNICODE_STRING[1];
|
||||||
|
system[0].buffer = IntPtr.Zero;
|
||||||
|
|
||||||
|
uint res = LsaOpenPolicy(system, ref lsaAttr, desiredAccess, out handle);
|
||||||
|
if (res != 0)
|
||||||
|
throw new Win32Exception(LsaNtStatusToWinError(res), "LsaOpenPolicy() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (handle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
LsaClose(handle);
|
||||||
|
handle = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~LsaHandle() { Dispose(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Sid
|
||||||
|
{
|
||||||
|
public string SidString { get; internal set; }
|
||||||
|
public string DomainName { get; internal set; }
|
||||||
|
public string AccountName { get; internal set; }
|
||||||
|
public SID_NAME_USE SidType { get; internal set; }
|
||||||
|
|
||||||
|
public enum SID_NAME_USE
|
||||||
|
{
|
||||||
|
SidTypeUser = 1,
|
||||||
|
SidTypeGroup,
|
||||||
|
SidTypeDomain,
|
||||||
|
SidTypeAlias,
|
||||||
|
SidTypeWellKnownGroup,
|
||||||
|
SidTypeDeletedAccount,
|
||||||
|
SidTypeInvalid,
|
||||||
|
SidTypeUnknown,
|
||||||
|
SidTypeComputer,
|
||||||
|
SidTypeLabel,
|
||||||
|
SidTypeLogon,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern bool LookupAccountSid(
|
||||||
|
string lpSystemName,
|
||||||
|
[MarshalAs(UnmanagedType.LPArray)]
|
||||||
|
byte[] Sid,
|
||||||
|
StringBuilder lpName,
|
||||||
|
ref UInt32 cchName,
|
||||||
|
StringBuilder ReferencedDomainName,
|
||||||
|
ref UInt32 cchReferencedDomainName,
|
||||||
|
out SID_NAME_USE peUse);
|
||||||
|
|
||||||
|
public Sid(IntPtr sidPtr)
|
||||||
|
{
|
||||||
|
SecurityIdentifier sid;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sid = new SecurityIdentifier(sidPtr);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(String.Format("Failed to cast IntPtr to SecurityIdentifier: {0}", e));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSidInfo(sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sid(SecurityIdentifier sid)
|
||||||
|
{
|
||||||
|
SetSidInfo(sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return SidString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSidInfo(SecurityIdentifier sid)
|
||||||
|
{
|
||||||
|
byte[] sidBytes = new byte[sid.BinaryLength];
|
||||||
|
sid.GetBinaryForm(sidBytes, 0);
|
||||||
|
|
||||||
|
StringBuilder lpName = new StringBuilder();
|
||||||
|
UInt32 cchName = 0;
|
||||||
|
StringBuilder referencedDomainName = new StringBuilder();
|
||||||
|
UInt32 cchReferencedDomainName = 0;
|
||||||
|
SID_NAME_USE peUse;
|
||||||
|
LookupAccountSid(null, sidBytes, lpName, ref cchName, referencedDomainName, ref cchReferencedDomainName, out peUse);
|
||||||
|
|
||||||
|
lpName.EnsureCapacity((int)cchName);
|
||||||
|
referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
|
||||||
|
|
||||||
|
SidString = sid.ToString();
|
||||||
|
if (!LookupAccountSid(null, sidBytes, lpName, ref cchName, referencedDomainName, ref cchReferencedDomainName, out peUse))
|
||||||
|
{
|
||||||
|
int lastError = Marshal.GetLastWin32Error();
|
||||||
|
|
||||||
|
if (lastError != 1332 && lastError != 1789) // Fails to lookup Logon Sid
|
||||||
|
{
|
||||||
|
throw new Win32Exception(lastError, String.Format("LookupAccountSid() failed for SID: {0} {1}", sid.ToString(), lastError));
|
||||||
|
}
|
||||||
|
else if (SidString.StartsWith("S-1-5-5-"))
|
||||||
|
{
|
||||||
|
AccountName = String.Format("LogonSessionId_{0}", SidString.Substring(8));
|
||||||
|
DomainName = "NT AUTHORITY";
|
||||||
|
SidType = SID_NAME_USE.SidTypeLogon;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AccountName = null;
|
||||||
|
DomainName = null;
|
||||||
|
SidType = SID_NAME_USE.SidTypeUnknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AccountName = lpName.ToString();
|
||||||
|
DomainName = referencedDomainName.ToString();
|
||||||
|
SidType = peUse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SessionUtil
|
||||||
|
{
|
||||||
|
[DllImport("secur32.dll", SetLastError = false)]
|
||||||
|
private static extern uint LsaFreeReturnBuffer(
|
||||||
|
IntPtr Buffer);
|
||||||
|
|
||||||
|
[DllImport("secur32.dll", SetLastError = false)]
|
||||||
|
private static extern uint LsaEnumerateLogonSessions(
|
||||||
|
out UInt64 LogonSessionCount,
|
||||||
|
out IntPtr LogonSessionList);
|
||||||
|
|
||||||
|
[DllImport("secur32.dll", SetLastError = false)]
|
||||||
|
private static extern uint LsaGetLogonSessionData(
|
||||||
|
IntPtr LogonId,
|
||||||
|
out IntPtr ppLogonSessionData);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = false)]
|
||||||
|
private static extern int LsaNtStatusToWinError(
|
||||||
|
uint Status);
|
||||||
|
|
||||||
|
[DllImport("advapi32", SetLastError = true)]
|
||||||
|
private static extern uint LsaEnumerateAccountRights(
|
||||||
|
IntPtr PolicyHandle,
|
||||||
|
IntPtr AccountSid,
|
||||||
|
out IntPtr UserRights,
|
||||||
|
out UInt64 CountOfRights);
|
||||||
|
|
||||||
|
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern bool LookupPrivilegeName(
|
||||||
|
string lpSystemName,
|
||||||
|
ref LUID lpLuid,
|
||||||
|
StringBuilder lpName,
|
||||||
|
ref UInt32 cchName);
|
||||||
|
|
||||||
|
private const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001;
|
||||||
|
private const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||||
|
private const UInt32 STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034;
|
||||||
|
private const UInt32 STATUS_ACCESS_DENIED = 0xC0000022;
|
||||||
|
|
||||||
|
public static SessionInfo GetSessionInfo()
|
||||||
|
{
|
||||||
|
AccessToken accessToken = new AccessToken(TokenAccessLevels.Query);
|
||||||
|
|
||||||
|
// Get Privileges
|
||||||
|
Hashtable privilegeInfo = new Hashtable();
|
||||||
|
TOKEN_PRIVILEGES privileges;
|
||||||
|
IntPtr privilegesPtr = accessToken.GetTokenInformation(out privileges, AccessToken.TOKEN_INFORMATION_CLASS.TokenPrivileges);
|
||||||
|
LUID_AND_ATTRIBUTES[] luidAndAttributes = new LUID_AND_ATTRIBUTES[privileges.PrivilegeCount];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PtrToStructureArray(luidAndAttributes, privilegesPtr.ToInt64() + Marshal.SizeOf(privileges.PrivilegeCount));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(privilegesPtr);
|
||||||
|
}
|
||||||
|
foreach (LUID_AND_ATTRIBUTES luidAndAttribute in luidAndAttributes)
|
||||||
|
{
|
||||||
|
LUID privLuid = luidAndAttribute.Luid;
|
||||||
|
UInt32 privNameLen = 0;
|
||||||
|
StringBuilder privName = new StringBuilder();
|
||||||
|
LookupPrivilegeName(null, ref privLuid, null, ref privNameLen);
|
||||||
|
privName.EnsureCapacity((int)(privNameLen + 1));
|
||||||
|
if (!LookupPrivilegeName(null, ref privLuid, privName, ref privNameLen))
|
||||||
|
throw new Win32Exception("LookupPrivilegeName() failed");
|
||||||
|
|
||||||
|
string state = "disabled";
|
||||||
|
if ((luidAndAttribute.Attributes & SE_PRIVILEGE_ENABLED) == SE_PRIVILEGE_ENABLED)
|
||||||
|
state = "enabled";
|
||||||
|
if ((luidAndAttribute.Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT) == SE_PRIVILEGE_ENABLED_BY_DEFAULT)
|
||||||
|
state = "enabled-by-default";
|
||||||
|
privilegeInfo.Add(privName.ToString(), state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Current Process LogonSID, User Rights and Groups
|
||||||
|
Sid logonSid = null;
|
||||||
|
ArrayList userRights = new ArrayList();
|
||||||
|
ArrayList userGroups = new ArrayList();
|
||||||
|
TOKEN_GROUPS groups;
|
||||||
|
IntPtr groupsPtr = accessToken.GetTokenInformation(out groups, AccessToken.TOKEN_INFORMATION_CLASS.TokenGroups);
|
||||||
|
SID_AND_ATTRIBUTES[] sidAndAttributes = new SID_AND_ATTRIBUTES[groups.GroupCount];
|
||||||
|
LsaHandle lsaHandle = null;
|
||||||
|
// We can only get rights if we are an admin
|
||||||
|
if (new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator))
|
||||||
|
lsaHandle = new LsaHandle(LsaHandle.DesiredAccess.POLICY_LOOKUP_NAMES);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PtrToStructureArray(sidAndAttributes, groupsPtr.ToInt64() + IntPtr.Size);
|
||||||
|
foreach (SID_AND_ATTRIBUTES sidAndAttribute in sidAndAttributes)
|
||||||
|
{
|
||||||
|
TokenGroupAttributes attributes = (TokenGroupAttributes)sidAndAttribute.Attributes;
|
||||||
|
if (attributes.HasFlag(TokenGroupAttributes.SE_GROUP_ENABLED) && lsaHandle != null)
|
||||||
|
{
|
||||||
|
ArrayList rights = GetAccountRights(lsaHandle.handle, sidAndAttribute.Sid);
|
||||||
|
foreach (string right in rights)
|
||||||
|
{
|
||||||
|
// Includes both Privileges and Account Rights, only add the ones with Logon in the name
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb545671(v=vs.85).aspx
|
||||||
|
if (!userRights.Contains(right) && right.Contains("Logon"))
|
||||||
|
userRights.Add(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Do not include the Logon SID in the groups category
|
||||||
|
if (attributes.HasFlag(TokenGroupAttributes.SE_GROUP_LOGON_ID))
|
||||||
|
logonSid = new Sid(sidAndAttribute.Sid);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Hashtable groupInfo = new Hashtable();
|
||||||
|
Sid group = new Sid(sidAndAttribute.Sid);
|
||||||
|
ArrayList groupAttributes = new ArrayList();
|
||||||
|
foreach (TokenGroupAttributes attribute in Enum.GetValues(typeof(TokenGroupAttributes)))
|
||||||
|
{
|
||||||
|
if (attributes.HasFlag(attribute))
|
||||||
|
{
|
||||||
|
string attributeName = attribute.ToString().Substring(9);
|
||||||
|
attributeName = attributeName.Replace('_', ' ');
|
||||||
|
attributeName = attributeName.First().ToString().ToUpper() + attributeName.Substring(1).ToLower();
|
||||||
|
groupAttributes.Add(attributeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Using snake_case here as I can't generically convert all dict keys in PS (see Privileges)
|
||||||
|
groupInfo.Add("sid", group.SidString);
|
||||||
|
groupInfo.Add("domain_name", group.DomainName);
|
||||||
|
groupInfo.Add("account_name", group.AccountName);
|
||||||
|
groupInfo.Add("type", group.SidType);
|
||||||
|
groupInfo.Add("attributes", groupAttributes);
|
||||||
|
userGroups.Add(groupInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(groupsPtr);
|
||||||
|
if (lsaHandle != null)
|
||||||
|
lsaHandle.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Integrity Level
|
||||||
|
Sid integritySid = null;
|
||||||
|
TOKEN_MANDATORY_LABEL mandatoryLabel;
|
||||||
|
IntPtr mandatoryLabelPtr = accessToken.GetTokenInformation(out mandatoryLabel, AccessToken.TOKEN_INFORMATION_CLASS.TokenIntegrityLevel);
|
||||||
|
Marshal.FreeHGlobal(mandatoryLabelPtr);
|
||||||
|
integritySid = new Sid(mandatoryLabel.Label.Sid);
|
||||||
|
|
||||||
|
// Get Token Statistics
|
||||||
|
TOKEN_STATISTICS tokenStats;
|
||||||
|
IntPtr tokenStatsPtr = accessToken.GetTokenInformation(out tokenStats, AccessToken.TOKEN_INFORMATION_CLASS.TokenStatistics);
|
||||||
|
Marshal.FreeHGlobal(tokenStatsPtr);
|
||||||
|
|
||||||
|
SessionInfo sessionInfo = GetSessionDataForLogonSession(tokenStats.AuthenticationId);
|
||||||
|
sessionInfo.LogonSid = logonSid;
|
||||||
|
sessionInfo.Groups = userGroups;
|
||||||
|
sessionInfo.Label = integritySid;
|
||||||
|
sessionInfo.ImpersonationLevel = tokenStats.ImpersonationLevel;
|
||||||
|
sessionInfo.TokenType = tokenStats.TokenType;
|
||||||
|
sessionInfo.Privileges = privilegeInfo;
|
||||||
|
sessionInfo.Rights = userRights;
|
||||||
|
return sessionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ArrayList GetAccountRights(IntPtr lsaHandle, IntPtr sid)
|
||||||
|
{
|
||||||
|
UInt32 res;
|
||||||
|
ArrayList rights = new ArrayList();
|
||||||
|
IntPtr userRightsPointer = IntPtr.Zero;
|
||||||
|
UInt64 countOfRights = 0;
|
||||||
|
|
||||||
|
res = LsaEnumerateAccountRights(lsaHandle, sid, out userRightsPointer, out countOfRights);
|
||||||
|
if (res != 0 && res != STATUS_OBJECT_NAME_NOT_FOUND)
|
||||||
|
throw new Win32Exception(LsaNtStatusToWinError(res), "LsaEnumerateAccountRights() failed");
|
||||||
|
else if (res != STATUS_OBJECT_NAME_NOT_FOUND)
|
||||||
|
{
|
||||||
|
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[countOfRights];
|
||||||
|
PtrToStructureArray(userRights, userRightsPointer.ToInt64());
|
||||||
|
rights = new ArrayList();
|
||||||
|
foreach (LSA_UNICODE_STRING right in userRights)
|
||||||
|
rights.Add(Marshal.PtrToStringUni(right.buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return rights;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SessionInfo GetSessionDataForLogonSession(LUID logonSession)
|
||||||
|
{
|
||||||
|
uint res;
|
||||||
|
UInt64 count = 0;
|
||||||
|
IntPtr luidPtr = IntPtr.Zero;
|
||||||
|
SessionInfo sessionInfo = null;
|
||||||
|
UInt64 processDataId = ConvertLuidToUint(logonSession);
|
||||||
|
|
||||||
|
res = LsaEnumerateLogonSessions(out count, out luidPtr);
|
||||||
|
if (res != 0)
|
||||||
|
throw new Win32Exception(LsaNtStatusToWinError(res), "LsaEnumerateLogonSessions() failed");
|
||||||
|
Int64 luidAddr = luidPtr.ToInt64();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (UInt64 i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
IntPtr dataPointer = IntPtr.Zero;
|
||||||
|
res = LsaGetLogonSessionData(luidPtr, out dataPointer);
|
||||||
|
if (res == STATUS_ACCESS_DENIED) // Non admins won't be able to get info for session's that are not their own
|
||||||
|
{
|
||||||
|
luidPtr = new IntPtr(luidPtr.ToInt64() + Marshal.SizeOf(typeof(LUID)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (res != 0)
|
||||||
|
throw new Win32Exception(LsaNtStatusToWinError(res), String.Format("LsaGetLogonSessionData() failed {0}", res));
|
||||||
|
|
||||||
|
SECURITY_LOGON_SESSION_DATA sessionData = (SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(dataPointer, typeof(SECURITY_LOGON_SESSION_DATA));
|
||||||
|
UInt64 sessionDataid = ConvertLuidToUint(sessionData.LogonId);
|
||||||
|
|
||||||
|
if (sessionDataid == processDataId)
|
||||||
|
{
|
||||||
|
ArrayList userFlags = new ArrayList();
|
||||||
|
UserFlags flags = (UserFlags)sessionData.UserFlags;
|
||||||
|
foreach (UserFlags flag in Enum.GetValues(typeof(UserFlags)))
|
||||||
|
{
|
||||||
|
if (flags.HasFlag(flag))
|
||||||
|
{
|
||||||
|
string flagName = flag.ToString().Substring(6);
|
||||||
|
flagName = flagName.Replace('_', ' ');
|
||||||
|
flagName = flagName.First().ToString().ToUpper() + flagName.Substring(1).ToLower();
|
||||||
|
userFlags.Add(flagName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionInfo = new SessionInfo()
|
||||||
|
{
|
||||||
|
AuthenticationPackage = Marshal.PtrToStringUni(sessionData.AuthenticationPackage.buffer),
|
||||||
|
DnsDomainName = Marshal.PtrToStringUni(sessionData.DnsDomainName.buffer),
|
||||||
|
LoginDomain = Marshal.PtrToStringUni(sessionData.LoginDomain.buffer),
|
||||||
|
LoginTime = ConvertIntegerToDateString(sessionData.LoginTime),
|
||||||
|
LogonId = ConvertLuidToUint(sessionData.LogonId),
|
||||||
|
LogonServer = Marshal.PtrToStringUni(sessionData.LogonServer.buffer),
|
||||||
|
LogonType = sessionData.LogonType,
|
||||||
|
Upn = Marshal.PtrToStringUni(sessionData.Upn.buffer),
|
||||||
|
UserFlags = userFlags,
|
||||||
|
Account = new Sid(sessionData.Sid)
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
luidPtr = new IntPtr(luidPtr.ToInt64() + Marshal.SizeOf(typeof(LUID)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LsaFreeReturnBuffer(new IntPtr(luidAddr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessionInfo == null)
|
||||||
|
throw new Exception(String.Format("Could not find the data for logon session {0}", processDataId));
|
||||||
|
return sessionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ConvertIntegerToDateString(UInt64 time)
|
||||||
|
{
|
||||||
|
if (time == 0)
|
||||||
|
return null;
|
||||||
|
if (time > (UInt64)DateTime.MaxValue.ToFileTime())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
DateTime dateTime = DateTime.FromFileTime((long)time);
|
||||||
|
return dateTime.ToString("o");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UInt64 ConvertLuidToUint(LUID luid)
|
||||||
|
{
|
||||||
|
UInt32 low = luid.LowPart;
|
||||||
|
UInt64 high = (UInt64)luid.HighPart;
|
||||||
|
high = high << 32;
|
||||||
|
UInt64 uintValue = (high | (UInt64)low);
|
||||||
|
return uintValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PtrToStructureArray<T>(T[] array, Int64 pointerAddress)
|
||||||
|
{
|
||||||
|
Int64 pointerOffset = pointerAddress;
|
||||||
|
for (int i = 0; i < array.Length; i++, pointerOffset += Marshal.SizeOf(typeof(T)))
|
||||||
|
array[i] = (T)Marshal.PtrToStructure(new IntPtr(pointerOffset), typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<T> GetValues<T>()
|
||||||
|
{
|
||||||
|
return Enum.GetValues(typeof(T)).Cast<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@
|
||||||
|
|
||||||
|
Add-Type -TypeDefinition $session_util
|
||||||
|
$session_info = [Ansible.SessionUtil]::GetSessionInfo()
|
||||||
|
|
||||||
|
Function Convert-Value($value) {
|
||||||
|
$new_value = $value
|
||||||
|
if ($value -is [System.Collections.ArrayList]) {
|
||||||
|
$new_value = [System.Collections.ArrayList]@()
|
||||||
|
foreach ($list_value in $value) {
|
||||||
|
$new_list_value = Convert-Value -value $list_value
|
||||||
|
[void]$new_value.Add($new_list_value)
|
||||||
|
}
|
||||||
|
} elseif ($value -is [Hashtable]) {
|
||||||
|
$new_value = @{}
|
||||||
|
foreach ($entry in $value.GetEnumerator()) {
|
||||||
|
$entry_value = Convert-Value -value $entry.Value
|
||||||
|
# manually convert Sid type entry to remove the SidType prefix
|
||||||
|
if ($entry.Name -eq "type") {
|
||||||
|
$entry_value = $entry_value.Replace("SidType", "")
|
||||||
|
}
|
||||||
|
$new_value[$entry.Name] = $entry_value
|
||||||
|
}
|
||||||
|
} elseif ($value -is [Ansible.Sid]) {
|
||||||
|
$new_value = @{
|
||||||
|
sid = $value.SidString
|
||||||
|
account_name = $value.AccountName
|
||||||
|
domain_name = $value.DomainName
|
||||||
|
type = $value.SidType.ToString().Replace("SidType", "")
|
||||||
|
}
|
||||||
|
} elseif ($value -is [Enum]) {
|
||||||
|
$new_value = $value.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ,$new_value
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = @{
|
||||||
|
changed = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$properties = [type][Ansible.SessionInfo]
|
||||||
|
foreach ($property in $properties.DeclaredProperties) {
|
||||||
|
$property_name = $property.Name
|
||||||
|
$property_value = $session_info.$property_name
|
||||||
|
$snake_name = Convert-StringToSnakeCase -string $property_name
|
||||||
|
|
||||||
|
$result.$snake_name = Convert-Value -value $property_value
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit-Json -obj $result
|
226
lib/ansible/modules/windows/win_whoami.py
Normal file
226
lib/ansible/modules/windows/win_whoami.py
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (c) 2017 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
# this is a windows documentation stub. actual code lives in the .ps1
|
||||||
|
# file of the same name
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: win_whoami
|
||||||
|
version_added: "2.5"
|
||||||
|
short_description: Returns information about the current user and process
|
||||||
|
description:
|
||||||
|
- Designed to return the same information as the C(whoami /all) command.
|
||||||
|
- Also includes information missing from C(whoami) such as logon metadata like
|
||||||
|
logon rights, id, type.
|
||||||
|
options:
|
||||||
|
notes:
|
||||||
|
- If running this module with a non admin user, the logon rights will be an
|
||||||
|
empty list as Administrator rights are required to query LSA for the
|
||||||
|
information.
|
||||||
|
author:
|
||||||
|
- Jordan Borean (@jborean93)
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r'''
|
||||||
|
- name: get whoami information
|
||||||
|
win_whoami:
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = r'''
|
||||||
|
authentication_package:
|
||||||
|
description: The name of the authentication package used to authenticate the
|
||||||
|
user in the session.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: Negotiate
|
||||||
|
user_flags:
|
||||||
|
description: The user flags for the logon session, see UserFlags in
|
||||||
|
U(https://msdn.microsoft.com/en-us/library/windows/desktop/aa380128).
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: Winlogon
|
||||||
|
upn:
|
||||||
|
description: The user principal name of the current user.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: Administrator@DOMAIN.COM
|
||||||
|
logon_type:
|
||||||
|
description: The logon type that identifies the logon method, see
|
||||||
|
U(https://msdn.microsoft.com/en-us/library/windows/desktop/aa380129.aspx).
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: Network
|
||||||
|
privileges:
|
||||||
|
description: A dictionary of privileges and their state on the logon token.
|
||||||
|
returned: success
|
||||||
|
type: dict
|
||||||
|
sample: {
|
||||||
|
"SeChangeNotifyPrivileges": "enabled-by-default",
|
||||||
|
"SeRemoteShutdownPrivilege": "disabled",
|
||||||
|
"SeDebugPrivilege": "enabled"
|
||||||
|
}
|
||||||
|
label:
|
||||||
|
description: The mandatory label set to the logon session.
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
domain_name:
|
||||||
|
description: The domain name of the label SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: Mandatory Label
|
||||||
|
sid:
|
||||||
|
description: The SID in string form.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: S-1-16-12288
|
||||||
|
account_name:
|
||||||
|
description: The account name of the label SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: High Mandatory Level
|
||||||
|
type:
|
||||||
|
description: The type of SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: Label
|
||||||
|
impersonation_level:
|
||||||
|
description: The impersonation level of the token, only valid if
|
||||||
|
C(token_type) is C(TokenImpersonation), see
|
||||||
|
U(https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572.aspx).
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: SecurityAnonymous
|
||||||
|
login_time:
|
||||||
|
description: The logon time in ISO 8601 format
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: '2017-11-27T06:24:14.3321665+10:00'
|
||||||
|
groups:
|
||||||
|
description: A list of groups and attributes that the user is a member of.
|
||||||
|
returned: success
|
||||||
|
type: list
|
||||||
|
sample: [
|
||||||
|
{
|
||||||
|
"account_name": "Domain Users",
|
||||||
|
"domain_name": "DOMAIN",
|
||||||
|
"attributes": [
|
||||||
|
"Mandatory",
|
||||||
|
"Enabled by default",
|
||||||
|
"Enabled"
|
||||||
|
],
|
||||||
|
"sid": "S-1-5-21-1654078763-769949647-2968445802-513",
|
||||||
|
"type": "Group"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account_name": "Administrators",
|
||||||
|
"domain_name": "BUILTIN",
|
||||||
|
"attributes": [
|
||||||
|
"Mandatory",
|
||||||
|
"Enabled by default",
|
||||||
|
"Enabled",
|
||||||
|
"Owner"
|
||||||
|
],
|
||||||
|
"sid": "S-1-5-32-544",
|
||||||
|
"type": "Alias"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
logon_sid:
|
||||||
|
description: The logon SID details.
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
domain_name:
|
||||||
|
description: The domain name of the logon SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: NT AUTHORITY
|
||||||
|
sid:
|
||||||
|
description: The SID in string form.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: S-1-5-5-0-4163312
|
||||||
|
account_name:
|
||||||
|
description: The account name of the logon SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: LogonSessionId_0_4163312
|
||||||
|
type:
|
||||||
|
description: The type of SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: Logon
|
||||||
|
account:
|
||||||
|
description: The running account SID details.
|
||||||
|
returned: success
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
domain_name:
|
||||||
|
description: The domain name of the account SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: DOMAIN
|
||||||
|
sid:
|
||||||
|
description: The SID in string form.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: S-1-5-21-1654078763-769949647-2968445802-500
|
||||||
|
account_name:
|
||||||
|
description: The account name of the account SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: Administrator
|
||||||
|
type:
|
||||||
|
description: The type of SID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: User
|
||||||
|
login_domain:
|
||||||
|
description: The name of the domain used to authenticate the owner of the
|
||||||
|
session.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: DOMAIN
|
||||||
|
rights:
|
||||||
|
description: A list of logon rights assigned to the logon.
|
||||||
|
returned: success and running user is a member of the local Administrators group
|
||||||
|
type: list
|
||||||
|
sample: [
|
||||||
|
"SeNetworkLogonRight",
|
||||||
|
"SeInteractiveLogonRight",
|
||||||
|
"SeBatchLogonRight",
|
||||||
|
"SeRemoteInteractiveLogonRight"
|
||||||
|
]
|
||||||
|
logon_server:
|
||||||
|
description: The name of the server used to authentcate the owner of the
|
||||||
|
logon session.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: DC01
|
||||||
|
logon_id:
|
||||||
|
description: The unique identifier of the logon session.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 20470143
|
||||||
|
dns_domain_name:
|
||||||
|
description: The DNS name of the logon session, this is an empty string if
|
||||||
|
this is not set.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: DOMAIN.COM
|
||||||
|
token_type:
|
||||||
|
description: The token type to indicate whether it is a primary or
|
||||||
|
impersonation token.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: TokenPrimary
|
||||||
|
'''
|
1
test/integration/targets/win_whoami/aliases
Normal file
1
test/integration/targets/win_whoami/aliases
Normal file
|
@ -0,0 +1 @@
|
||||||
|
windows/ci/group3
|
238
test/integration/targets/win_whoami/tasks/main.yml
Normal file
238
test/integration/targets/win_whoami/tasks/main.yml
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
---
|
||||||
|
- name: run win_whoami with normal execution
|
||||||
|
win_whoami:
|
||||||
|
register: win_whoami_result
|
||||||
|
|
||||||
|
- name: assert win_whoami with normal execution
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not win_whoami_result is changed
|
||||||
|
- win_whoami_result.account.account_name is defined
|
||||||
|
- win_whoami_result.account.domain_name is defined
|
||||||
|
- win_whoami_result.account.sid is defined
|
||||||
|
- win_whoami_result.account.type == 'User'
|
||||||
|
- win_whoami_result.authentication_package is defined
|
||||||
|
- win_whoami_result.dns_domain_name is defined
|
||||||
|
- win_whoami_result.groups|count >= 1
|
||||||
|
- win_whoami_result.groups[0].account_name is defined
|
||||||
|
- win_whoami_result.groups[0].attributes is defined
|
||||||
|
- win_whoami_result.groups[0].domain_name is defined
|
||||||
|
- win_whoami_result.groups[0].sid is defined
|
||||||
|
- win_whoami_result.groups[0].type is defined
|
||||||
|
- win_whoami_result.impersonation_level == 'SecurityAnonymous'
|
||||||
|
- win_whoami_result.label.account_name == 'High Mandatory Level'
|
||||||
|
- win_whoami_result.label.domain_name == 'Mandatory Label'
|
||||||
|
- win_whoami_result.label.sid == 'S-1-16-12288'
|
||||||
|
- win_whoami_result.label.type == 'Label'
|
||||||
|
- win_whoami_result.login_domain is defined
|
||||||
|
- win_whoami_result.login_time is defined
|
||||||
|
- win_whoami_result.logon_id is defined
|
||||||
|
- win_whoami_result.logon_server is defined
|
||||||
|
- win_whoami_result.logon_sid.account_name is defined
|
||||||
|
- win_whoami_result.logon_sid.domain_name is defined
|
||||||
|
- win_whoami_result.logon_sid.sid is defined
|
||||||
|
- win_whoami_result.logon_sid.type == 'Logon'
|
||||||
|
- win_whoami_result.logon_type.startswith('Network')
|
||||||
|
- win_whoami_result.privileges is defined
|
||||||
|
- win_whoami_result.rights|count >= 1
|
||||||
|
- win_whoami_result.token_type == 'TokenPrimary'
|
||||||
|
- win_whoami_result.upn is defined
|
||||||
|
- win_whoami_result.user_flags is defined
|
||||||
|
|
||||||
|
- name: run win_whoami with SYSTEM execution
|
||||||
|
win_whoami:
|
||||||
|
become: yes
|
||||||
|
become_method: runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: win_whoami_result
|
||||||
|
|
||||||
|
- name: assert win_whoami with SYSTEM execution
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not win_whoami_result is changed
|
||||||
|
- win_whoami_result.account.account_name == 'SYSTEM'
|
||||||
|
- win_whoami_result.account.domain_name == 'NT AUTHORITY'
|
||||||
|
- win_whoami_result.account.sid == 'S-1-5-18'
|
||||||
|
- win_whoami_result.account.type == 'User'
|
||||||
|
- win_whoami_result.authentication_package is defined
|
||||||
|
- win_whoami_result.dns_domain_name is defined
|
||||||
|
- win_whoami_result.groups|count >= 1
|
||||||
|
- win_whoami_result.groups[0].account_name is defined
|
||||||
|
- win_whoami_result.groups[0].attributes is defined
|
||||||
|
- win_whoami_result.groups[0].domain_name is defined
|
||||||
|
- win_whoami_result.groups[0].sid is defined
|
||||||
|
- win_whoami_result.groups[0].type is defined
|
||||||
|
- win_whoami_result.impersonation_level == 'SecurityAnonymous'
|
||||||
|
- win_whoami_result.label.account_name == 'System Mandatory Level'
|
||||||
|
- win_whoami_result.label.domain_name == 'Mandatory Label'
|
||||||
|
- win_whoami_result.label.sid == 'S-1-16-16384'
|
||||||
|
- win_whoami_result.label.type == 'Label'
|
||||||
|
- win_whoami_result.login_domain is defined
|
||||||
|
- win_whoami_result.login_time is defined
|
||||||
|
- win_whoami_result.logon_id is defined
|
||||||
|
- win_whoami_result.logon_server is defined
|
||||||
|
- win_whoami_result.logon_sid == None
|
||||||
|
- win_whoami_result.logon_type == 'System'
|
||||||
|
- win_whoami_result.privileges is defined
|
||||||
|
- win_whoami_result.rights|count >= 1
|
||||||
|
- win_whoami_result.token_type == 'TokenPrimary'
|
||||||
|
- win_whoami_result.upn is defined
|
||||||
|
- win_whoami_result.user_flags is defined
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
become_username: ansible_become
|
||||||
|
become_username_limited: ansible_limited
|
||||||
|
gen_pw: password123! + {{lookup('password', '/dev/null chars=ascii_letters,digits length=8')}}
|
||||||
|
|
||||||
|
- name: ensure current user is not the become user
|
||||||
|
win_shell: whoami
|
||||||
|
register: whoami_out
|
||||||
|
failed_when: whoami_out.stdout_lines[0].endswith(become_username) or whoami_out.stdout_lines[0].endswith(become_username_limited)
|
||||||
|
|
||||||
|
- name: create user
|
||||||
|
win_user:
|
||||||
|
name: '{{become_username}}'
|
||||||
|
password: '{{gen_pw}}'
|
||||||
|
update_password: always
|
||||||
|
groups: Administrators
|
||||||
|
register: become_user_info
|
||||||
|
|
||||||
|
- name: create user limited
|
||||||
|
win_user:
|
||||||
|
name: '{{become_username_limited}}'
|
||||||
|
password: '{{gen_pw}}'
|
||||||
|
update_password: always
|
||||||
|
groups: Users
|
||||||
|
register: become_user_info_limited
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: get become user profile dir so we can clean it up later
|
||||||
|
vars: &become_vars
|
||||||
|
ansible_become_user: '{{become_username}}'
|
||||||
|
ansible_become_password: '{{gen_pw}}'
|
||||||
|
ansible_become_method: runas
|
||||||
|
ansible_become: yes
|
||||||
|
win_shell: $env:USERPROFILE
|
||||||
|
register: profile_dir_out
|
||||||
|
|
||||||
|
- name: ensure profile dir contains test username (eg, if become fails silently, prevent deletion of real user profile)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- become_username in profile_dir_out.stdout_lines[0]
|
||||||
|
|
||||||
|
- name: get become user limited profile dir so we can clean it up later
|
||||||
|
vars: &become_vars_limited
|
||||||
|
ansible_become_user: '{{become_username_limited}}'
|
||||||
|
ansible_become_password: '{{gen_pw}}'
|
||||||
|
ansible_become_method: runas
|
||||||
|
ansible_become: yes
|
||||||
|
win_shell: $env:USERPROFILE
|
||||||
|
register: profile_dir_out_limited
|
||||||
|
|
||||||
|
- name: ensure limited profile dir contains test username (eg, if become fails silently, prevent deletion of real user profile)
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- become_username_limited in profile_dir_out_limited.stdout_lines[0]
|
||||||
|
|
||||||
|
- name: run win_whoami with become execution
|
||||||
|
win_whoami:
|
||||||
|
vars: *become_vars
|
||||||
|
register: win_whoami_result
|
||||||
|
|
||||||
|
- name: assert win_whoami with become execution
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not win_whoami_result is changed
|
||||||
|
- win_whoami_result.account.account_name == "ansible_become"
|
||||||
|
- win_whoami_result.account.domain_name is defined
|
||||||
|
- win_whoami_result.account.sid == become_user_info.sid
|
||||||
|
- win_whoami_result.account.type == 'User'
|
||||||
|
- win_whoami_result.authentication_package == "NTLM"
|
||||||
|
- win_whoami_result.dns_domain_name == ""
|
||||||
|
- win_whoami_result.groups|count >= 1
|
||||||
|
- win_whoami_result.groups[0].account_name is defined
|
||||||
|
- win_whoami_result.groups[0].attributes is defined
|
||||||
|
- win_whoami_result.groups[0].domain_name is defined
|
||||||
|
- win_whoami_result.groups[0].sid is defined
|
||||||
|
- win_whoami_result.groups[0].type is defined
|
||||||
|
- win_whoami_result.impersonation_level is defined
|
||||||
|
- win_whoami_result.label.account_name == 'High Mandatory Level'
|
||||||
|
- win_whoami_result.label.domain_name == 'Mandatory Label'
|
||||||
|
- win_whoami_result.label.sid == 'S-1-16-12288'
|
||||||
|
- win_whoami_result.label.type == 'Label'
|
||||||
|
- win_whoami_result.login_domain is defined
|
||||||
|
- win_whoami_result.login_time is defined
|
||||||
|
- win_whoami_result.logon_id is defined
|
||||||
|
- win_whoami_result.logon_server is defined
|
||||||
|
- win_whoami_result.logon_sid.account_name is defined
|
||||||
|
- win_whoami_result.logon_sid.domain_name is defined
|
||||||
|
- win_whoami_result.logon_sid.sid is defined
|
||||||
|
- win_whoami_result.logon_sid.type == 'Logon'
|
||||||
|
- win_whoami_result.logon_type == "Interactive"
|
||||||
|
- win_whoami_result.privileges is defined
|
||||||
|
- '"SeInteractiveLogonRight" in win_whoami_result.rights'
|
||||||
|
- win_whoami_result.token_type == 'TokenPrimary'
|
||||||
|
- win_whoami_result.upn == ''
|
||||||
|
- win_whoami_result.user_flags is defined
|
||||||
|
|
||||||
|
- name: run win_whoami with limited become execution
|
||||||
|
win_whoami:
|
||||||
|
vars: *become_vars_limited
|
||||||
|
register: win_whoami_result
|
||||||
|
|
||||||
|
- name: assert win_whoami with limited become execution
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not win_whoami_result is changed
|
||||||
|
- win_whoami_result.account.account_name == "ansible_limited"
|
||||||
|
- win_whoami_result.account.domain_name is defined
|
||||||
|
- win_whoami_result.account.sid == become_user_info_limited.sid
|
||||||
|
- win_whoami_result.account.type == 'User'
|
||||||
|
- win_whoami_result.authentication_package == "NTLM"
|
||||||
|
- win_whoami_result.dns_domain_name == ""
|
||||||
|
- win_whoami_result.groups|count >= 1
|
||||||
|
- win_whoami_result.groups[0].account_name is defined
|
||||||
|
- win_whoami_result.groups[0].attributes is defined
|
||||||
|
- win_whoami_result.groups[0].domain_name is defined
|
||||||
|
- win_whoami_result.groups[0].sid is defined
|
||||||
|
- win_whoami_result.groups[0].type is defined
|
||||||
|
- win_whoami_result.impersonation_level is defined
|
||||||
|
- win_whoami_result.label.account_name == 'Medium Mandatory Level'
|
||||||
|
- win_whoami_result.label.domain_name == 'Mandatory Label'
|
||||||
|
- win_whoami_result.label.sid == 'S-1-16-8192'
|
||||||
|
- win_whoami_result.label.type == 'Label'
|
||||||
|
- win_whoami_result.login_domain is defined
|
||||||
|
- win_whoami_result.login_time is defined
|
||||||
|
- win_whoami_result.logon_id is defined
|
||||||
|
- win_whoami_result.logon_server is defined
|
||||||
|
- win_whoami_result.logon_sid.account_name is defined
|
||||||
|
- win_whoami_result.logon_sid.domain_name is defined
|
||||||
|
- win_whoami_result.logon_sid.sid is defined
|
||||||
|
- win_whoami_result.logon_sid.type == 'Logon'
|
||||||
|
- win_whoami_result.logon_type == "Interactive"
|
||||||
|
- win_whoami_result.privileges is defined
|
||||||
|
- win_whoami_result.rights == []
|
||||||
|
- win_whoami_result.token_type == 'TokenPrimary'
|
||||||
|
- win_whoami_result.upn == ''
|
||||||
|
- win_whoami_result.user_flags is defined
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: ensure test user is deleted
|
||||||
|
win_user:
|
||||||
|
name: '{{item}}'
|
||||||
|
state: absent
|
||||||
|
with_items:
|
||||||
|
- '{{become_username}}'
|
||||||
|
- '{{become_username_limited}}'
|
||||||
|
|
||||||
|
- name: ensure test user profile is deleted
|
||||||
|
win_shell: rmdir /S /Q {{profile_dir_out.stdout_lines[0]}}
|
||||||
|
args:
|
||||||
|
executable: cmd.exe
|
||||||
|
when: become_username in profile_dir_out.stdout_lines[0]
|
||||||
|
|
||||||
|
- name: ensure limited test user profile is deleted
|
||||||
|
win_shell: rmdir /S /Q {{profile_dir_out_limited.stdout_lines[0]}}
|
||||||
|
args:
|
||||||
|
executable: cmd.exe
|
||||||
|
when: become_username_limited in profile_dir_out_limited.stdout_lines[0]
|
Loading…
Add table
Reference in a new issue