Adding user-tracker.pl version 1.0
[user-tracker.git] / user-tracker.pl
1 #!/usr/bin/perl
2 #
3 # Copyright (C) 2013, Jason Self
4 #
5 # This program gives you software freedom; you can copy, modify, convey,
6 # and/or redistribute it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 3 of the
8 # License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with this program in a file called 'GPLv3.txt'. If not, see 
17 # http://www.gnu.org/licenses/gpl-3.0-standalone.html or write to the:
18 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor
19 # Boston, MA 02110-1301, USA.
20 #
21 # Documentation (in pod format) at the bottom of this file
22
23 use strict;
24 no strict 'refs';
25 use warnings;
26 no warnings qw(once);
27
28 use Getopt::Long;
29 use Pod::Usage;
30 use YAML qw(LoadFile);
31 use File::ReadBackwards;
32 use Date::Manip;
33
34 #-----------------------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------------------
36
37 my $file_lastrun = "user-tracker.run";
38 my $file_log = "user-tracker.log";
39
40 my ($output, $help, $man, $now, $last_run, %last_login);
41 our ($date, $user);
42
43 #-----------------------------------------------------------------------------------------
44
45 #-- print usage if the script is not called properly
46 pod2usage(2) unless
47   GetOptions( 'output=s' => \$output, 'help|?' => \$help, man => \$man);
48 pod2usage(-exitstatus => 0, -verbose => 2) if $man;
49 pod2usage(1) if $help;
50
51 $now = scalar localtime;
52
53 #-- read output log and store values in %last_login
54 $output = $file_log if not defined $output;
55 if ( open LOG, "<$output" )
56 {
57   while ( <LOG> )
58   {
59     chomp;
60     ($date, $user) = split ' - ', $_;
61     $last_login{$user} = $date;
62   }
63 }
64 else
65 {
66   warn "Can't open $output: $! ... probably first run\n";
67 }
68 open LOG, ">$output" or die "Can't open $output: $!\n";
69
70 if ( open LASTRUN,"<$file_lastrun" )
71 {
72   my $date = <LASTRUN>;
73   $last_run = ParseDate($date);
74
75 else
76 {
77   warn "Can't open $file_lastrun: $! ... parsing all lines of the log files\n";
78   $last_run = ParseDate("Jan 01 00:00 1970");
79 }
80
81 #-- $config is a reference to a structure like this:
82 #   $config = {
83 #          '/var/log/mail.log' => [
84 #                                 {
85 #                                   'pattern' => '^(.{15}).*Login: user=<([^>]+).*',
86 #                                   'first' => 'date',
87 #                                   'second' => 'user'
88 #                                 },
89 #                                 { ...
90 #                                 ],
91 #          '/var/log/auth.log' => [ ... etc
92 my $config = LoadFile("user-tracker.cfg") or die "Can't open config file: $!\n";
93
94 foreach my $file ( sort keys %{$config} )
95 {
96   my $fh = File::ReadBackwards->new($file) or warn "Can't open $file: $!\n" and next;
97   while ( defined(my $line = $fh->readline()) )
98   {
99     foreach my $element ( @{$config->{$file}} )
100     {
101       ($date, $user) = (undef, undef);
102       
103       #-- store values in $date and $user
104       (${$element->{first}}, ${$element->{second}}) = ($line =~ $element->{pattern});
105       
106       #-- skip line if $date not defined
107       next if ( not defined $date );
108       
109       #-- stop  processing the file if the date is earlier than $last_run
110       last if (  Date_Cmp(ParseDate($date),$last_run) < 0 );
111
112       #-- line matches, update %last_login
113       if ( not exists $last_login{$user} or Date_Cmp(ParseDate($date),ParseDate($last_login{$user})) > 0 )
114       {
115         $last_login{$user} = $date;  
116       }
117     }
118   }
119 }
120
121 #-- save to output file
122 foreach ( sort { ParseDate($last_login{$a}) cmp ParseDate($last_login{$b}) } keys %last_login )
123 {
124   print LOG "$last_login{$_} - $_\n";
125 }
126
127 open LASTRUN, ">$file_lastrun" or die "Can't open $file_lastrun: $!\n";
128 print LASTRUN $now;
129 close LASTRUN
130
131 __END__
132
133 #-----------------------------------------------------------------------------------------
134
135 =pod
136
137 =head1 NAME
138
139 User Tracker
140
141 =head1 SYNOPSIS
142
143 usertracker.pl [-o output] [-h] [-man]
144
145 =head1 ARGUMENTS
146
147 =over
148
149 =item -o output
150
151 name of output file, if not provided, write to file specified in $file_log
152
153 =item -h, --help
154
155 display help information and exits
156
157 =item -man
158
159 display a more detailed help information, including author and changelog
160
161 =back
162
163 =head1 DESCRIPTION
164
165 Scans specified log files for information about logged-in users and adds the list of 
166 logged users to a file
167
168 =head1 AUTHOR
169
170 Jason Self (j@jxself.org)
171
172 =head1 CHANGELOG
173
174 =over 
175
176 =item Feb 03, 2013 : v1.0
177
178 - Initial release
179
180 =back
181
182 =cut