sub get_logon_events()

in managementnode/lib/VCL/Module/OS/Windows/Version_6.pm [2408:2565]


sub get_logon_events {
	my $self = shift;
	if (ref($self) !~ /VCL::Module/i) {
		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
		return;
	}
	
	my ($past_minutes) = @_;
	my $offset_minutes = $self->get_timezone_offset_minutes() || 0;
	
	my $logon_type_names = {
		0 => 'System',
		2 => 'Interactive',
		3 => 'Network',
		4 => 'Batch',
		5 => 'Service',
		6 => 'Proxy',
		7 => 'Unlock',
		8 => 'NetworkCleartext',
		9 => 'NewCredentials',
		10 => 'RemoteInteractive',
		11 => 'CachedInteractive',
		12 => 'CachedRemoteInteractive',
		13 => 'CachedUnlock',
	};
	
	my $security_event_log = 'Security';
	my $lsm_event_log = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational';
	
	my $event_ids = {
		'Microsoft-Windows-Security-Auditing' => {
			4624 => 'An account was successfully logged on',
		},
		'Microsoft-Windows-TerminalServices-LocalSessionManager' => {
			21 => 'Remote Desktop Services: Session logon succeeded',
			25 => 'Remote Desktop Services: Session reconnection succeeded',
			1101 => 'Remote Desktop Services: Session logon succeeded',
			1105 => 'Remote Desktop Services: Session reconnection succeeded',
		},
	};
	
	my $security_event_id_string = "EventID=" . join(' or EventID=', keys(%{$event_ids->{'Microsoft-Windows-Security-Auditing'}}));
	my $lsm_event_id_string = "EventID=" . join(' or EventID=', keys(%{$event_ids->{'Microsoft-Windows-TerminalServices-LocalSessionManager'}}));
	
	my $time_created_string = '';
	if ($past_minutes) {
		my $milliseconds = ($past_minutes * 60 * 1000);
		$time_created_string = "and TimeCreated[timediff(\@SystemTime) <= $milliseconds]";
	}
	
	my $security_query = <<EOF;
*[
	System[
		Provider[\@Name="Microsoft-Windows-Security-Auditing"]
		and Task=12544
		and ($security_event_id_string)
		$time_created_string
	]
	and
	EventData[
		Data[\@Name="TargetUserName"]!="ANONYMOUS LOGON"
		and Data[\@Name="TargetUserName"]!="SYSTEM"
		and Data[\@Name="IpAddress"]!="127.0.0.1"
		and Data[\@Name="LogonType"]!="5"
	]
]
EOF
	
	my $lsm_query = <<EOF;
*[
	System[
		Provider[\@Name="Microsoft-Windows-TerminalServices-LocalSessionManager"]
		and ($lsm_event_id_string)
		$time_created_string
	]
]
EOF
	
	my (@security_events, @lsm_events);
	@security_events = $self->query_event_log($security_event_log, $security_query);
	@lsm_events = $self->query_event_log($lsm_event_log, $lsm_query);
	
	my $logon_event_hash = {};
	for my $event (@security_events, @lsm_events) {
		my $system = $event->{System} || next;
		
		my $provider_name   = $system->{Provider}{Name};
		my $system_time     = $system->{TimeCreated}{SystemTime};
		my $event_record_id = $system->{EventRecordID};
		my $event_id        = $system->{EventID};
		my $process_pid     = $system->{Execution}{ProcessID};
		
		my $logon_event = {
			event_record_id => $event_record_id,
			event_id        => $event_id,
			provider        => $provider_name,
			pid             => $event_id,
		};
		$logon_event->{description} = $event_ids->{$provider_name}{$event_id} if $event_ids->{$provider_name}{$event_id};
		
		# Convert system time format to datetime: 2014-03-18T19:18:41.421250000Z
		my ($date, $time) = $system_time =~ /^([\d-]+)T([\d:]+)\./;
		next if (!$date || !$time);
		my $datetime = "$date $time";
		
		# The time returned is UTC and not adjusted for the computer's time zone
		my $epoch_seconds = convert_to_epoch_seconds($datetime);
		$epoch_seconds += ($offset_minutes * 60);
		$datetime = convert_to_datetime($epoch_seconds);
		$logon_event->{datetime} = $datetime;
		$logon_event->{epoch} = $epoch_seconds;
		
		if ($provider_name eq 'Microsoft-Windows-Security-Auditing') {
			my $event_data = $event->{EventData}{Data} || next;
			
			$logon_event->{user}          = $event_data->{TargetUserName};
			$logon_event->{remote_ip}     = $event_data->{IpAddress} if $event_data->{IpAddress};
			$logon_event->{remote_port}   = $event_data->{IpPort} if $event_data->{IpPort};
			$logon_event->{logon_type_id} = $event_data->{LogonType} if $event_data->{LogonType};
			
			my $logon_type_id = $event_data->{LogonType};
			if (defined($logon_type_id)) {
				$logon_event->{logon_type_id} = $logon_type_id;
				$logon_event->{logon_type} = $logon_type_names->{$logon_type_id} if $logon_type_names->{$logon_type_id};
			}
		}
		elsif ($provider_name eq 'Microsoft-Windows-TerminalServices-LocalSessionManager') {
			my $user_data = $event->{UserData}{EventXML} || next;;
			
			$logon_event->{user}       = $user_data->{User};
			$logon_event->{remote_ip}  = $user_data->{Address} if $user_data->{Address};
			$logon_event->{session_id} = $user_data->{SessionID} if $user_data->{SessionID};
		}
		
		if (!$logon_event->{user} || ref($logon_event->{user})) {
			next;
		}
		$logon_event->{user} =~ s/.*\\+//g;
		
		if ($logon_event->{remote_ip} && ($logon_event->{remote_ip} eq '0.0.0.0' || $logon_event->{remote_ip} =~ /-/)) {
			delete $logon_event->{remote_ip};
		}
		
		if ($logon_event->{remote_port} && $logon_event->{remote_port} =~ /-/) {
			delete $logon_event->{remote_port};
		}
		
		# Add to the hash - use key containing the provider name and record ID in case events have the same epoch time
		$logon_event_hash->{"$epoch_seconds-$provider_name-$event_record_id"} = $logon_event;
	}
	
	# Convert the hash to an array sorted by the epoch time keys
	my @logon_events = map { $logon_event_hash->{$_} } sort keys %$logon_event_hash;
	
	my $logon_event_count = scalar(@logon_events);
	notify($ERRORS{'DEBUG'}, 0, "retrieved $logon_event_count logon event" . ($logon_event_count == 1 ? '' : 's') . ":\n" . format_data(\@logon_events));
	return @logon_events;
}