Link to home
Start Free TrialLog in
Avatar of arif_t2
arif_t2Flag for United States of America

asked on

Audit through Last command

I would like to audit users login on Solaris 10 sytems using either "last" command or wtmpx file ( as last command doesnot show year value ) .. I would like to run it daily for only 24 hours data and keep the output in one file without any duplicate values in it ( as some login stays more than 24 hours ). Output data should looks ilke as "last -a" output.
    Appreciate your help.

Thanks
Avatar of gheist
gheist
Flag of Belgium image

What problem are you trying to solve?
I have read your question 3 times and I can propose you to use last -a output, as you request and propose yourself.
Avatar of arif_t2

ASKER

"Last -a" output shows  all entries even previous years...I want to get only upto 24 hours old entries...

This is what i want to do,  
I need to run script every night lets say 11PM and get last 24 hours login/logout values ( same as last -a output ), append output in one file.  and then again next day run same script and append the output in same file, making sure no duplicate value in the file after comparing previous entries in that file...

 if user logged in more than 24 hours than that can cause duplicate value and other reasons which i dont know..

Mind you i am not a scripting guy, so may be solution is easy but i would appreciate if you can help me out..

Thanks
Avatar of arif_t2

ASKER

Anyone out there who can help me to audit users on Solaris Servers? appreciate it...
Avatar of arif_t2

ASKER

Underneath is the script i found on this site,

#!/usr/bin/perl
use strict;
my $template = "A32 A4 A32 l s s2 x2 l2 l x20 s A257 x";
my $recordsize = length(pack($template,()));
open WTMPX,"/var/adm/wtmpx" or die "Unable to open wtmpx:$!\n";
my $record;
while (read(WTMPX,$record,$recordsize)) {
  my ($ut_user,$ut_id,$ut_line,$ut_pid,$ut_type,$ut_e_termination,$ut_e_exit,$tv_sec,$tv_usec,$ut_session,$ut_syslen,$ut_host)= unpack($template,$record);

printf("%-8s %9s %30s %25s %8s\n",$ut_user, $ut_line, scalar localtime($tv_sec), $ut_host) if ($ut_user =~ /^[a-z]/) ;
}

close WTMPX;


output is,
oracle        sshd       Sun Jul  1 22:01:41 2007     lishadb01p.snapon.com
oracle        sshd       Sun Jul  1 22:01:41 2007                          
oracle        sshd       Sun Jul  1 22:01:42 2007     lishadb01p.snapon.com
oracle        sshd       Sun Jul  1 22:01:43 2007                          
root          sshd       Mon Jul  2 02:20:35 2007          ken25.snapon.com
root          sshd       Mon Jul  2 02:20:36 2007                          


Can someone help me to change the output same like "last -a" command, which is underneath,

oracle    sshd         Tue Feb 19 18:54 - 19:00  (00:05)   kenaerp01t.snapon.com
oracle    sshd         Tue Feb 19 18:53 - 18:54  (00:00)   kenaerp01t.snapon.com
oracle    sshd         Tue Feb 19 18:52 - 18:53  (00:00)   kenaerp01t.snapon.com
oracle    sshd         Tue Feb 19 18:50 - 18:52  (00:01)   kenaerp01t.snapon.com
oracle    sshd         Tue Feb 19 18:49 - 18:50  (00:00)   kenaerp01t.snapon.com
oracle    sshd         Tue Feb 19 18:47 - 18:49  (00:02)   kenaerp01t.snapon.com
oracle    sshd         Tue Feb 19 18:46 - 18:47  (00:01)   kenaerp01t.snapon.com
Avatar of wilcoxon
This should do it.  It should be pretty easy to combine this answer with the script from the other question I answered if you want to.

#!/usr/bin/perl
use strict;
my $template = "A32 A4 A32 l s s2 x2 l2 l x20 s A257 x";
my $recordsize = length(pack($template,()));
open WTMPX,"/var/adm/wtmpx" or die "Unable to open wtmpx:$!\n";
my $record;
while (read(WTMPX,$record,$recordsize)) {
  my ($ut_user,$ut_id,$ut_line,$ut_pid,$ut_type,$ut_e_termination,$ut_e_exit,$tv_sec,$tv_usec,$ut_session,$ut_syslen,$ut_host)= unpack($template,$record);

# time returns # of seconds since epoch of current time
# 86400 is # of seconds in a day
printf("%-8s %9s %30s %25s %8s\n",$ut_user, $ut_line, scalar localtime($tv_sec), $ut_host) if ($ut_user =~ /^[a-z]/ and $tv_sec >= time-86400) ;
}

close WTMPX;

Open in new window

Avatar of arif_t2

ASKER

When i run script i get underneath values... But "last -a" output shows couple of more values as show underneath as well...Do we know why script is skipping those and how can we resolve it?

Script output:
bsp           sshd 1 May 10 15:04 - 15:05 (00:00) 10.0.6.95
bsp           sshd 1 May 10 15:11 - 15:12 (00:00) 10.0.6.95
bsp           sshd 2 May 11 07:39 - 07:39 (00:00) 10.0.6.95


last -a | grep bsp
bsp       sshd         Tue May 11 07:39 - 07:39  (00:00)   10.0.6.95
bsp       sshd         Tue May 11 07:38 - 07:39  (00:00)   10.0.6.95
bsp       sshd         Mon May 10 15:11 - 15:12  (00:00)   10.0.6.95
bsp       sshd         Mon May 10 15:04 - 15:05  (00:00)   10.0.6.95
bsp       sshd         Mon May 10 15:04 - 15:04  (00:00)   10.0.6.95


Avatar of arif_t2

ASKER

and output mentioned in above comments are through script underneath,, Let me know what changes are required... thanks

#!/usr/bin/perl
use strict;
my $template = "A32 A4 A32 l s s2 x2 l2 l x20 s A257 x";
my $recordsize = length(pack($template,()));
open WTMPX,"/var/adm/wtmpx" or die "Unable to open wtmpx:$!\n";
my ($record, %prev);
MAIN:
while (read(WTMPX,$record,$recordsize)) {
    # 0 $ut_user
    # 1 $ut_id
    # 2 $ut_line
    # 3 $ut_pid
    # 4 $ut_type
    # 5 $ut_e_termination
    # 6 $ut_e_exit
    # 7 $tv_sec
    # 8 $tv_usec
    # 9 $ut_session
    # 10 $ut_syslen
    # 11 $ut_host
    my @vals = unpack($template,$record);
    next MAIN unless ($vals[0] and $vals[0] =~ /bsp/);
    if ($vals[11]) { # login
        # error-checking
        #if (exists $prev{$vals[0]}{$vals[2]}) {
        #    warn "there's already a login entry for $vals[0] on $vals[2] - over-writing";
        #}
        $prev{$vals[0]}{$vals[2]} = [@vals];
    } else { # assuming logout/dead proc
        # error-checking
        if (not exists $prev{$vals[0]}{$vals[2]}) {
#    warn "could not find a login entry for $vals[0] on $vals[2] - skipping";
            next MAIN;
        }
        my @stm = (localtime $prev{$vals[0]}{$vals[2]}[7])[6,4,3,2,1];
        $stm[1] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$stm[1]]
;
        my @etm = (localtime $vals[7])[2,1];
        my $dmin = int(($vals[7] - $prev{$vals[0]}{$vals[2]}[7])/60); # get min
        my $dhr = int($dmin/60); # get hours
        $dmin -= $dhr*60;
        printf("%-8s %9s %s %s %02d %02d:%02d - %02d:%02d (%02d:%02d) %-s\n", $vals[0], $vals[2], @stm, @etm, $dhr, $dmin, $prev{$vals[0]}{$vals[2]}[11]) if ($vals[0] =~ /bsp/
 and $vals[7] >= time-86400);
        delete $prev{$vals[0]}{$vals[2]};
    }
}
close WTMPX;

# users still logged in will be in %prev still

It looks like day-of-week is numeric rather than text.  As to the older entries being excluded, I limited it to only the last day in one of the earlier version (now commented out).  This should work.

#!/usr/bin/perl
use strict;
my $template = "A32 A4 A32 l s s2 x2 l2 l x20 s A257 x";
my $recordsize = length(pack($template,()));
open WTMPX,"/var/adm/wtmpx" or die "Unable to open wtmpx:$!\n";
my ($record, %prev);
MAIN:
while (read(WTMPX,$record,$recordsize)) {
    # 0 $ut_user
    # 1 $ut_id
    # 2 $ut_line
    # 3 $ut_pid
    # 4 $ut_type
    # 5 $ut_e_termination
    # 6 $ut_e_exit
    # 7 $tv_sec
    # 8 $tv_usec
    # 9 $ut_session
    # 10 $ut_syslen
    # 11 $ut_host
    my @vals = unpack($template,$record);
    next MAIN unless ($vals[0] and $vals[0] =~ /bsp/);
    if ($vals[11]) { # login
        # error-checking
        #if (exists $prev{$vals[0]}{$vals[2]}) {
        #    warn "there's already a login entry for $vals[0] on $vals[2] - over-writing";
        #}
        $prev{$vals[0]}{$vals[2]} = [@vals];
    } else { # assuming logout/dead proc
        # error-checking
        if (not exists $prev{$vals[0]}{$vals[2]}) {
#    warn "could not find a login entry for $vals[0] on $vals[2] - skipping";
            next MAIN;
        }
        my @stm = (localtime $prev{$vals[0]}{$vals[2]}[7])[6,4,3,2,1];
	$stm[0] = (qw(Sun Mon Tue Wed The Fri Sat))[$stm[0]];
        $stm[1] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$stm[1]]
;
        my @etm = (localtime $vals[7])[2,1];
        my $dmin = int(($vals[7] - $prev{$vals[0]}{$vals[2]}[7])/60); # get min
        my $dhr = int($dmin/60); # get hours
        $dmin -= $dhr*60;
        printf("%-8s %-9s %s %s %02d %02d:%02d - %02d:%02d (%02d:%02d) %-s\n", $vals[0], $vals[2], @stm, @etm, $dhr, $dmin, $prev{$vals[0]}{$vals[2]}[11]) if ($vals[0] =~ /bsp/);
	# remove this to allow further back in time
	# and $vals[7] >= time-86400);
        delete $prev{$vals[0]}{$vals[2]};
    }
}
close WTMPX;

# users still logged in will be in %prev still

Open in new window

Avatar of arif_t2

ASKER

I needed for only one day so i added "and $vals[7] >= time-86400"  and ran again..output is underneath... but if you compare with output of "last -a", its still missing something.

script output:
bsp      pts/36    Tue May 11 14:54 - 16:17 (01:23) 10.0.45.115
bsp      sshd      Tue May 11 14:54 - 16:17 (01:23) 10.0.45.115
bsp      sshd      Wed May 12 07:41 - 07:41 (00:00) 10.0.6.95



last -a | grep bsp | head -n 6
bsp       sshd         Wed May 12 07:41 - 07:41  (00:00)   10.0.6.95
bsp       sshd         Wed May 12 07:40 - 07:41  (00:00)   10.0.6.95
bsp       pts/29       Wed May 12 01:03   still logged in  10.6.1.32
bsp       sshd         Wed May 12 01:03 - 02:43  (01:39)   10.6.1.32
bsp       pts/36       Tue May 11 14:54 - 16:17  (01:23)   10.0.45.115
bsp       sshd         Tue May 11 14:54 - 15:03  (00:08)   10.0.45.115


Two issues:

1. End time of underneath record is different from last -a output

 bsp      sshd      Tue May 11 14:54 - 16:17 (01:23) 10.0.45.115

2. Missing two records,

I guess this one missing due to other has same start time.
bsp       sshd         Wed May 12 01:03 - 02:43  (01:39)   10.6.1.32

I guess this is missing due to other value has same end time.
bsp       sshd         Wed May 12 07:40 - 07:41  (00:00)   10.0.6.95
Avatar of arif_t2

ASKER

Some changes in script needs to be done so it does not skip records which matches only start or end time..
I had missed that both were within the last day so that's not the issue.
 
 Uncomment lines 24-27 and 32 and then run it again and post the output.  It's very hard to debug at this point as I don't have your wtmpx file and neither the script nor last output the full data rows from wtmpx.

Also add the below lines at the end of the script:

foreach my $user (keys %prev) {
    foreach my $term (keys %{$prev{$user}}) {
        print "$user\t$term\t@{$prev{$user}{$term}}\n";
    }
}

I'm guessing it is not finding some of the logout entries in wtmpx.
I'm not sure what you meant by your last comment.  Could you explain more?
Avatar of arif_t2

ASKER

When i remove comments from error message line, i get thousands of thosands of error messages..


there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on ftp27174 - over-writing at ./testing2_new line 26.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on ftp20760 - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on ftp19971 - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
there's already a login entry for bsp on sshd - over-writing at ./testing2_new line 26.
could not find a login entry for bsp on sshd - skipping at ./testing2_new line 32.
Avatar of arif_t2

ASKER

Also in my last comment when i said that
    "Some changes in script needs to be done so it does not skip records which matches only start or end time.."

I mean  by that is Script is skipping records which has same start time or end time as other records has.. for e.g from last output underneath,
bsp       sshd         Wed May 12 07:41 - 07:41  (00:00)   10.0.6.95
bsp       sshd         Wed May 12 07:40 - 07:41  (00:00)   10.0.6.95

it shows only underneath value as skipping due to same end time 07:41
 bsp      sshd      Wed May 12 07:41 - 07:41 (00:00) 10.0.6.95

And from last output underneath,
bsp       pts/29       Wed May 12 01:03   still logged in  10.6.1.32
bsp       sshd         Wed May 12 01:03 - 02:43  (01:39)   10.6.1.32

It shows nothing as skipping "still logged in" record and skipping other record due to same start time 01:03


Avatar of arif_t2

ASKER

I know its hard for you to find the reason when you dont have wtmpx file access.... May be you can help me in this,

My reason to go for wtmpx file was that  "last -a " output doesnot shows  YEAR value..and due to that it was showing records of previous year even when i need for 1 day only.... if you can help me overcome that then i can use output of "last -a" and get only last 24 hours records through script with skip of "still logged in" records...
The script should not be skipping anything based on start/end time.  The only time the script skips entries (or should anyway) is when the user and port are the same.

One of

bsp       sshd         Wed May 12 07:41 - 07:41  (00:00)   10.0.6.95
bsp        sshd         Wed May 12 07:40 - 07:41  (00:00)   10.0.6.95

would be skipped unless the logout of the second line happened before the login of the first line as they are on the same port/terminal for the same user.  I can't see any way in wtmpx (at least without having one available) to differentiate at a finer level than that.

Neither of the below would be skipped as they are on a different port/term.  The "still logged in" line is skipped as I added the comment (and possibly stated) that the still logged in data would be in %prev still at the end of the script.

bsp       pts/29       Wed May 12 01:03   still logged in  10.6.1.32
bsp        sshd         Wed May 12 01:03 - 02:43  (01:39)   10.6.1.32

If you recomment out the warn lines (and remove the above mentioned code to add) and add the lines below, it will list the ones that are still logged in (according to wtmpx):

foreach my $user (keys %prev) {
    foreach my $term (keys  %{$prev{$user}}) {
        my @stm = (localtime $prev{$vals[0]}{$vals[2]}[7])[6,4,3,2,1];
        $stm[0] = (qw(Sun Mon Tue Wed Thu Fri Sat))[$stm[0]];
         $stm[1] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov  Dec))[$stm[1]];
        printf("%-8s %-9s %s %s %02d %02d:%02d   still logged in        %-s\n", $vals[0], $vals[2], @stm, $prev{$vals[0]}{$vals[2]}[11]) if ($vals[0] =~ /bsp/);
   }
}

I doubt there is any way to change the behavior of last.
Avatar of arif_t2

ASKER

I understand about "still logged in" records b/c we dont need that anyways.. I was concern about other records specially the one next to still logon record, b/c i know its skipping and it did same on other servers also...Anyways, I will try again today and tomorrow to make sure .....
I now understand first part of your answer and ok that it will skip b/c both has same user and port/terminal......just for my knowledge, is it possible to compare on basis of user and duration rather than user and port
Not really.  The duration is calculated based on login and logout times.  There may be something else besides just user and port that could be used to differentiate further but it's not clear from looking at the (sparse) wtmpx documentation what that is.

It's possible that for some reason, the script is missing logout records so it might be useful to output the "still logged in" records for now and see if there are ones appearing in there that last -a doesn't report as still logged in.
Avatar of arif_t2

ASKER

Ok.. i will do that..

If you dont mind......one more question..... Script  does not show "ftp" connection whereas "last -a" output does.. Check the last 3 days output underneath..


Script output:
bsp      sshd      Sun May 09 08:41 - 13:26 (04:44) 10.6.1.81
bsp      pts/41    Sun May 09 08:41 - 14:47 (06:05) 10.6.1.81
bsp      pts/15    Mon May 10 09:19 - 09:20 (00:01) 10.6.1.105
bsp      sshd      Mon May 10 09:19 - 09:20 (00:01) 10.6.1.105
bsp      sshd      Mon May 10 11:57 - 11:58 (00:00) 10.0.18.63
bsp      sshd      Mon May 10 12:51 - 12:52 (00:00) 10.0.18.63
bsp      sshd      Mon May 10 15:03 - 15:04 (00:00) 10.0.6.95
bsp      sshd      Mon May 10 15:10 - 15:11 (00:00) 10.0.6.95
bsp      pts/29    Mon May 10 12:11 - 22:40 (10:28) 10.6.1.57
bsp      sshd      Mon May 10 15:57 - 22:40 (06:43)
bsp      sshd      Tue May 11 07:38 - 07:39 (00:00) 10.0.6.95
bsp      pts/36    Tue May 11 14:54 - 16:17 (01:23) 10.0.45.115
bsp      sshd      Tue May 11 14:54 - 16:17 (01:23) 10.0.45.115
bsp      sshd      Wed May 12 07:41 - 07:41 (00:00) 10.0.6.95






last command ouput:

bsp       ftp          Wed May 12 15:39 - 15:40  (00:00)   10.0.8.91
bsp       ftp          Wed May 12 15:33 - 15:35  (00:01)   10.0.8.91
bsp       sshd         Wed May 12 07:41 - 07:41  (00:00)   10.0.6.95
bsp       sshd         Wed May 12 07:40 - 07:41  (00:00)   10.0.6.95
bsp       pts/29       Wed May 12 01:03   still logged in  10.6.1.32
bsp       sshd         Wed May 12 01:03 - 02:43  (01:39)   10.6.1.32
bsp       pts/36       Tue May 11 14:54 - 16:17  (01:23)   10.0.45.115
bsp       sshd         Tue May 11 14:54 - 15:03  (00:08)   10.0.45.115
bsp       sshd         Tue May 11 07:38 - 07:39  (00:00)   10.0.6.95
bsp       sshd         Tue May 11 07:38 - 07:38  (00:00)   10.0.6.95
bsp       ftp          Mon May 10 17:35 - 17:46  (00:10)   10.0.6.83
bsp       ftp          Mon May 10 17:20 - 17:35  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 17:05 - 17:20  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 16:50 - 17:05  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 16:35 - 16:50  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 16:19 - 16:34  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 16:04 - 16:19  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 15:49 - 16:04  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 15:34 - 15:49  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 15:12 - 15:34  (00:22)   10.0.6.83
bsp       sshd         Mon May 10 15:10 - 15:11  (00:00)   10.0.6.95
bsp       sshd         Mon May 10 15:03 - 15:04  (00:00)   10.0.6.95
bsp       sshd         Mon May 10 15:03 - 15:03  (00:00)   10.0.6.95
bsp       ftp          Mon May 10 14:59 - 15:12  (00:12)   10.0.6.83
bsp       ftp          Mon May 10 14:44 - 14:59  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 14:29 - 14:44  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 14:14 - 14:29  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 13:48 - 14:13  (00:25)   10.0.6.83
bsp       ftp          Mon May 10 13:33 - 13:48  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 13:08 - 13:33  (00:24)   10.0.6.83
bsp       ftp          Mon May 10 12:53 - 13:08  (00:15)   10.0.6.83
bsp       sshd         Mon May 10 12:51 - 12:52  (00:00)   10.0.18.63
bsp       ftp          Mon May 10 12:38 - 12:53  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 12:23 - 12:38  (00:15)   10.0.6.83
bsp       pts/29       Mon May 10 12:11 - 22:40  (10:28)   10.6.1.57
bsp       sshd         Mon May 10 12:11 - 12:51  (00:39)   10.6.1.57
bsp       ftp          Mon May 10 12:07 - 12:22  (00:15)   10.0.6.83
bsp       sshd         Mon May 10 11:57 - 11:58  (00:00)   10.0.18.63
bsp       sshd         Mon May 10 11:57 - 11:57  (00:00)   10.0.18.63
bsp       ftp          Mon May 10 11:52 - 12:07  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 11:37 - 11:52  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 11:22 - 11:37  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 11:07 - 11:22  (00:15)   10.0.6.83
bsp       ftp          Mon May 10 10:51 - 11:06  (00:15)   10.0.6.83
bsp       pts/15       Mon May 10 09:19 - 09:20  (00:01)   10.6.1.105
bsp       sshd         Mon May 10 09:19 - 09:20  (00:01)   10.6.1.105
bsp       pts/41       Sun May  9 08:41 - 14:47  (06:05)   10.6.1.81
bsp       sshd         Sun May  9 08:41 - 13:26  (04:44)   10.6.1.81


Any reason??
Odd.  I'm not sure what would be causing that.  My best guess is that last knows something we don't - possibly ftp records are listed with no port in wtmpx but last knows that means it's ftp.
Avatar of arif_t2

ASKER

I guess wtmpx has ftp records as well..b/c when i run your's other script, it gives me these values, mentioned underneath...

Script:
#!/usr/bin/perl
use strict;
my $template = "A32 A4 A32 l s s2 x2 l2 l x20 s A257 x";
my $recordsize = length(pack($template,()));
open WTMPX,"/var/adm/wtmpx" or die "Unable to open wtmpx:$!\n";
my $record;
while (read(WTMPX,$record,$recordsize)) {
  my ($ut_user,$ut_id,$ut_line,$ut_pid,$ut_type,$ut_e_termination,$ut_e_exit,$tv_sec,$tv_usec,$ut_session,$ut_syslen,$ut_host)= unpack($template,$record);

# time returns # of seconds since epoch of current time
# 86400 is # of seconds in a day
printf("%-8s %9s %30s %25s %8s\n",$ut_user, $ut_line, scalar localtime($tv_sec), $ut_host) if ($ut_user =~ /bsp/ and $tv_sec >= time-86400) ;
}

close WTMPX;


Output:
bsp           sshd       Wed May 12 01:03:44 2010                 10.6.1.32        
bsp         pts/29       Wed May 12 01:03:45 2010                 10.6.1.32        
bsp           sshd       Wed May 12 07:40:52 2010                 10.0.6.95        
bsp           sshd       Wed May 12 07:41:06 2010                 10.0.6.95        
bsp           sshd       Wed May 12 07:41:40 2010                                  
bsp           sshd       Wed May 12 09:49:10 2010                                  
bsp       ftp20682       Wed May 12 15:33:29 2010                 10.0.8.91        
bsp       ftp20682       Wed May 12 15:35:00 2010                 10.0.8.91        
bsp       ftp28479       Wed May 12 15:39:23 2010                 10.0.8.91        
bsp       ftp28479       Wed May 12 15:40:02 2010                 10.0.8.91
Ah - ftp records are different.  I'm pretty sure all of the ftp records are there - they are just mis-put in the "still logged in".  In order to handle those, the script will need to be modified.  The difference is that ftp records have the host present on both login and logout (whereas normal logins only seem to have it present on login).

I think the below will fix ftp (replaces lines 23-29).

Also, I'd suggest changing line 22 and removing the other conditionals.

I think the below is the "final" version of the script.  Let me know if you see any more issues that I can help with.

#!/usr/bin/perl
use strict;
my $template = "A32 A4 A32 l s s2 x2 l2 l x20 s A257 x";
my $recordsize = length(pack($template,()));
open WTMPX,"/var/adm/wtmpx" or die "Unable to open wtmpx:$!\n";
my ($record, %prev);
MAIN:
while (read(WTMPX,$record,$recordsize)) {
    # 0 $ut_user
    # 1 $ut_id
    # 2 $ut_line
    # 3 $ut_pid
    # 4 $ut_type
    # 5 $ut_e_termination
    # 6 $ut_e_exit
    # 7 $tv_sec
    # 8 $tv_usec
    # 9 $ut_session
    # 10 $ut_syslen
    # 11 $ut_host
    my @vals = unpack($template,$record);
    # put all the conditionals on this line to make changing them easier
    next MAIN unless ($vals[0] and $vals[7] >= time-86400 and $vals[0] =~ /bsp/);
    if ($vals[11]) { # login
        if ($vals[2] =~ m{^ftp} and exists $prev{$vals[0]}{$vals[2]}) {
            # it's ftp and already exists so it's really a logout
            my @stm = (localtime $prev{$vals[0]}{$vals[2]}[7])[6,4,3,2,1];
            $stm[0] = (qw(Sun Mon Tue Wed The Fri Sat))[$stm[0]];
            $stm[1] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$stm[1]];
            my @etm = (localtime $vals[7])[2,1];
            my $dmin = int(($vals[7] - $prev{$vals[0]}{$vals[2]}[7])/60); # get min
            my $dhr = int($dmin/60); # get hours
            $dmin -= $dhr*60;
            printf("%-8s %-9s %s %s %02d %02d:%02d - %02d:%02d (%02d:%02d) %-s\n", $vals[0], $vals[2], @stm, @etm, $dhr, $dmin, $prev{$vals[0]}{$vals[2]}[11]);
            delete $prev{$vals[0]}{$vals[2]};
        } else {
            # error-checking
            #if (exists $prev{$vals[0]}{$vals[2]}) {
            #    warn "there's already a login entry for $vals[0] on $vals[2] - over-writing";
            #}
            $prev{$vals[0]}{$vals[2]} = [@vals];
        }
    } else { # assuming logout/dead proc
        # error-checking
        if (not exists $prev{$vals[0]}{$vals[2]}) {
#    warn "could not find a login entry for $vals[0] on $vals[2] - skipping";
            next MAIN;
        }
        my @stm = (localtime $prev{$vals[0]}{$vals[2]}[7])[6,4,3,2,1];
        $stm[0] = (qw(Sun Mon Tue Wed The Fri Sat))[$stm[0]];
        $stm[1] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$stm[1]]
;
        my @etm = (localtime $vals[7])[2,1];
        my $dmin = int(($vals[7] - $prev{$vals[0]}{$vals[2]}[7])/60); # get min
        my $dhr = int($dmin/60); # get hours
        $dmin -= $dhr*60;
        printf("%-8s %-9s %s %s %02d %02d:%02d - %02d:%02d (%02d:%02d) %-s\n", $vals[0], $vals[2], @stm, @etm, $dhr, $dmin, $prev{$vals[0]}{$vals[2]}[11]);
        delete $prev{$vals[0]}{$vals[2]};
    }
}
close WTMPX;

# users still logged in will be in %prev still
foreach my $user (keys %prev) {
    foreach my $term (keys  %{$prev{$user}}) {
        my @stm = (localtime $prev{$vals[0]}{$vals[2]}[7])[6,4,3,2,1];
        $stm[0] = (qw(Sun Mon Tue Wed Thu Fri Sat))[$stm[0]];
        $stm[1] = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov  Dec))[$stm[1]];
        printf("%-8s %-9s %s %s %02d %02d:%02d   still logged in  %-s\n", $vals[0], $vals[2], @stm, $prev{$vals[0]}{$vals[2]}[11]) if ($vals[0] =~ /bsp/);
    }
}

Open in new window

Avatar of arif_t2

ASKER

Thanks, its working ... I am going to run it for couple of days to see if its not duplicating or anything.. If there any issue then will bother you again...  Sorry
   Just for my knowledge can you write a brief explanation of each line/command we used in this script ...It will help me explaining others in my team, who are not a Perl guys like me..... Appreciate it...

Thanks
Avatar of arif_t2

ASKER

I am trying to add hostname, date etc in printf but its printring each value on seperate lines, how can i write in one line..  Also how can i save output in one FILE..

Code:
$OS= (`uname`);
$DATE=(`date +%Y-%m-%d`);
$HOST=(`hostname`);

printf("%7s,  %8s,  %5s, %-4s,%-5s,  %s,  %s,    %02d, %02d:%02d,-,%02d:%02d, (%02d:%02d), %-s\n", $HOST, $DATE, $OS, $vals[0], 'ftp' , @stm, @etm, $dhr, $dmin, $prev{$vals[0]}{$vals[2]}[11]);


Output:
kenaerp01t
,  2010-05-13
,  SunOS
, bsp ,ftp  ,  3,  4,    12, 15:33,-,15:35, (00:01), 10.0.8.91
kenaerp01t
,  2010-05-13
,  SunOS
, bsp ,ftp  ,  3,  4,    12, 15:39,-,15:40, (00:00), 10.0.8.91
kenaerp01t
,  2010-05-13
,  SunOS
, bsp ,ftp  ,  4,  4,    13, 09:58,-,10:01, (00:02), 10.0.8.87
Backticks commands usually add a newline.  You need to add the lines below between the assignments and the printf.

chomp $OS;
chomp $DATE;
chomp $HOST;

Also, you should be able to get date within perl using localtime and hostname via $ENV{HOST} or $ENV{HOSTNAME}.

In order to write the output to a file, you need to add this near the top of the file:

open OUT, '>', $output_file or die "could not write $output_file: $!";
# replace $output_file in line above with whatever you want

and then change the printf lines to be:

printf(OUT "$fmt"...
Avatar of arif_t2

ASKER

Ok..Its working and one more question... If i need to email that file, then from perl how can i do that...
For email, you need to either shell out and directly call sendmail (or similar) or use one of the mail modules (I don't use them often so never remember which I liked - see search.cpan.org).
Avatar of arif_t2

ASKER

I just realized that i can not able to run this script on my old HP servers as those doesnot have Perl on it.... So i wanted to ask you, how difficult it is to convert this Perl script  to Ksh?  if its possible then can you help me out on it... I really appreciate it...

Thanks
It might be possible but I'm not a ksh expert.  The decoding of the binary data is the likely problem spot.

The simple solution (with regard to your program) is to install perl on the old HP servers.

If that is not possible, I would suggest awarding points for this question and then open a new question in the ksh and any other possible topic areas and post the final version of the perl script.
Avatar of arif_t2

ASKER

Ok..I will do that.. final question before awarding points,  

1. As HP has different path for perl(#!/usr/contrib/Q4/bin/perl) than solaris (#!/usr/bin/perl)and i am running one script for both...how can i mentioned both paths in script.

2. File name and path of output file is also different in HP, how can i mention both files that if one not exsists then it go to other in underneath line.
open OUT, '>>',"$OUTDATE.txt" or die "could not write to file: $!";
ASKER CERTIFIED SOLUTION
Avatar of wilcoxon
wilcoxon
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of arif_t2

ASKER

Thanks for your help... Its working ... If i face any other issues than will open new thread... Thanks again.