背景知识:
参考书籍:
求助:
源码如下:
#!/usr/bin/perl -w
########################################################################################
# 文件:wtmpx2.pl
# 功能:从wtmpx日志里找出最近登录信息写到系统日志里;
# 作者:半点闲
# 时间:2012-11-11 11:55 光棍节快乐
# 系统:SCO_SV scosysv 3.2 5.0.6 i386 Perl5.6.0 built for i486-pc-sco3.2v5.0
# 说明:所使用的系统日志功能很弱无法提供登录到系统用户的信息,结合cron定时执行本程序,将提取到
# 的登录信息写到系统日志里.同时,机房采用"集中日志服务器"统一接收系统发送到远端日志进行集中分
# 析处理.
#
# 进一步说明:
# 系统比较陈旧,因是生产用机即不能升级现在又无法更换在,使用Sys::Syslog模块处理系统日志时,
# 在Ubuntu+Perl5.14正常的代码,在本机上无法编辑通过提示:
# your vendor has not defined the Sys::Syslog macro _PATH_LOG...
# <>书中找到一段话:在Perl5.6之前,为了运行这个模块需要syslog.ph头文件,
# 但这个文件不和Perl发布版一起提供,需要使用h2ph工具手工产生.在使用Sys::Syslog之前应当
# 升级5.6或更高版本。
# 我的Perl版本按书上所说是满足要求的,难道好事都让我遇到了,不解!想起Perl名言"TMOTWTDI"
# 日志部分暂时交给shell的logger命令处理.
# --------------------------------------------------------------------------------------
# 修改:2012-11-12
# BUG1:时间精度缺失造成重复记录的问题;
# BUG语句:
# my ($sec,$min,$hour,$mday,$mon,$year_off) = (localtime)[0..5];
# ($sec,$min,$hour,$mday,$mon,$year_off) = (localtime $tv_sec)[0..5];
# 影响语句:next if($first_time >= $tv_time);
# 描述:如当前时间为11:00:00用做数字写入文件时为1100,此时,wtmpx文件中若有登录时间为10:01:01
# 将造成(1100>=100101)返回假值.
# 更正:全部以字符方式运算
# $sec = sprintf "%02d",$sec; #不足2位补0
# $min = sprintf "%02d",$min;
# $hour = sprintf "%02d",$hour;
# 同时修改下述语句:
# next if($current_date ne $tv_date);
# next if($first_time ge $tv_time);
########################################################################################
use strict;
$SIG {__WARN__} = \&log_warn;
sub log_warn(){
#warn信息也写到日志里;
system "echo '@_' | logger -it wtmpx -p auth.info";
}
my $wtmpx_file = '/var/adm/wtmpx';
my $first_file = "/var/adm/first"; #记录前一次查询的时间
my $template = 'A32 A4 A32 s s s s l l l x20 s Z257 x';#ScoUnix5模版
my $recordsize = length( pack( $template, () ) );
my ($sec,$min,$hour,$mday,$mon,$year_off) = (localtime)[0..5];
my $current_date = $year_off + 1900 . $mon + 1 . $mday;
$sec = sprintf "%02d",$sec; #不足2位补0
$min = sprintf "%02d",$min;
$hour = sprintf "%02d",$hour;
my $session = open FIRST_FILE, '+<', $first_file or warn "Unable to open $first_file:$!\n";
my $first_time; #前次查询的时间
if ($session){
$first_time = ; #获取先前的时间
seek FIRST_FILE, 0, 0; #移到文件头
print FIRST_FILE "$hour$min$sec";
close FIRST_FILE or warn "Unable to close $first_file:$!\n";
} else {
$first_time = "$hour$min$sec"; #使用当前时间
$session = open FIRST_FILE, '>', $first_file or warn "err2:Unable to open $first_file:$!\n";
if ($session){
print FIRST_FILE $first_time;
close FIRST_FILE or warn "err2:Unable to close $first_file:$!\n";
}
}
open WTMP, '<', $wtmpx_file or die "Unable to open wtmpx:$!\n";
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) = ();
my $record;
while( read( WTMP, $record, $recordsize ) ) {
($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 );
next if $ut_type == 8; #忽略退出的用户
($sec,$min,$hour,$mday,$mon,$year_off) = (localtime $tv_sec)[0..5];
my $tv_date = $year_off + 1900 . $mon + 1 . $mday;
$sec = sprintf "%02d",$sec;
$min = sprintf "%02d",$min;
$hour = sprintf "%02d",$hour;
my $tv_time = "$hour$min$sec";
next if($current_date ne $tv_date); #跳过非当前系统日期的记录(当字符串进行比较)
next if($first_time ge $tv_time); #跳过前次查询过的记录(此句只能放在日期比较后面)
if ($ut_id eq 'ftp'){
$ut_user = "FTP LOGIN $ut_user";
} else {
$ut_user = "LOGIN $ut_user";
}
my $format_record = "$ut_user:$ut_id:$ut_line:PID:$ut_pid:TYPE:$ut_type:HOST:$ut_host:$tv_date $hour:$min:$sec";
system "echo '$format_record' | logger -it wtmpx -p auth.info";
}
close WTMP;
写入Syslog日志效果图:
日志服务器接收效果图: