231 lines
6.8 KiB
Python
Executable file
231 lines
6.8 KiB
Python
Executable file
#! /usr/bin/env python
|
|
import os,string, getopt,time,sys,struct
|
|
""" usage : wwho [date] [-b secs (backwards)] [-p precision (sec/m/h/d)] [-l (last)]
|
|
[-a (all last msgs)] [-f wtmp_file] [-d (debug)]
|
|
DATE (2000 May 22 06:12:08)
|
|
|
|
wfile : idem, except : [-a (access)] FILE
|
|
|
|
ça marche. mais la recherche ds le wtmp pour construire _sessions_ est
|
|
pas du tout optimale -> lent pour un gros wtmp.
|
|
Améliorations à prévoir..
|
|
"""
|
|
optlist, args = getopt.getopt(sys.argv[1:], "adlb:p:f:")
|
|
|
|
date=""
|
|
emul_last=0
|
|
all_last=0
|
|
debug=0
|
|
datesec=0
|
|
precision=2
|
|
utmpF="/var/log/wtmp"
|
|
if len(args)>0 :
|
|
date=args[0]
|
|
print "cmd_line_date : %s" %date
|
|
for i in optlist :
|
|
if i[0] =='-l' : emul_last=1
|
|
if i[0] =='-a' : all_last=1
|
|
if i[0] =='-d' : debug=1
|
|
if i[0] =='-b' : datesec=time.time()-float(i[1])
|
|
if i[0] =='-p' : precision=float(i[1])
|
|
if i[0] =='-f' : utmpF=i[1]
|
|
if debug : print "Option found : "+repr(i)
|
|
|
|
if debug : print " argv[0] : %s" % sys.argv[0]
|
|
|
|
if not datesec :
|
|
if date :
|
|
if string.lower(os.path.basename(sys.argv[0]))=="wfile.py" :
|
|
datesec=os.path.getmtime(date) #modif time
|
|
if all_last : #access time
|
|
datesec=os.stat(date)[7]
|
|
# datesec=os.path.getatime(date) #BUG ! donne mtime !
|
|
all_last=0
|
|
print " Chosen file Time : %s" \
|
|
%time.ctime(datesec)
|
|
else :
|
|
t=time.strptime(date,"%Y %b %d %H:%M:%S")
|
|
#we still have to guess the DaylightSsavingTime flag -> -1
|
|
t2=[ t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],-1]
|
|
datesec = time.mktime(t2)
|
|
else : datesec =time.time()
|
|
|
|
def unpackstr(s, i=0):
|
|
for c in s:
|
|
if c == '\000': break
|
|
i = i + 1
|
|
return s[:i]
|
|
|
|
def msectime(secs,usecs) :
|
|
t=time.localtime(secs)
|
|
s=time.strftime("%d %b %Y %T",t)
|
|
s=s+ ( ".%06d"%usecs )[0:4]
|
|
#s=s+ time.strftime(" %z %Z",time.localtime(secs))
|
|
return s
|
|
|
|
|
|
if debug : print " Date : %s // datesec : "% date + repr(datesec)
|
|
print "Finding who were here at %s, with precision %fs."\
|
|
% (msectime(datesec,0),precision)
|
|
|
|
# the C struct declaration (on AIX 4.2.1)
|
|
# char ut_user[8];
|
|
# char ut_id[14];
|
|
# char ut_line[12];
|
|
# short ut_type;
|
|
# pid_t ut_pid; (int)
|
|
# short ut_exit.e_termination;
|
|
# short ut_exit.e_exit;
|
|
# time_t ut_time; (long)
|
|
# char ut_host[16];
|
|
# the format string to represent that structure
|
|
|
|
""" cf utmp.h , ou man utmp :
|
|
#define UT_LINESIZE 32
|
|
#define UT_NAMESIZE 32
|
|
#define UT_HOSTSIZE 256
|
|
|
|
/* The structure describing the status of a terminated process. This
|
|
type is used in `struct utmp' below. */
|
|
struct exit_status
|
|
{
|
|
short int e_termination; /* Process termination status. */
|
|
short int e_exit; /* Process exit status. */
|
|
};
|
|
|
|
/* The structure describing an entry in the user accounting database. */
|
|
struct utmp
|
|
{
|
|
short int ut_type; /* Type of login. */
|
|
pid_t ut_pid; /* Process ID of login process. */
|
|
char ut_line[UT_LINESIZE=32]; /* Devicename. */
|
|
char ut_id[4]; /* Inittab ID. */
|
|
char ut_user[UT_NAMESIZE=32]; /* Username. */
|
|
char ut_host[UT_HOSTSIZE=256]; /* Hostname for remote login. */
|
|
struct exit_status ut_exit; /* Exit status of a process marked
|
|
as DEAD_PROCESS. */
|
|
long int ut_session; /* Session ID, used for windowing. */
|
|
struct timeval ut_tv; /* Time entry was made. */
|
|
int32_t ut_addr_v6[4]; /* Internet address of remote host. */
|
|
char __unused[20]; /* Reserved for future use. */
|
|
};
|
|
"""
|
|
fmt="hi32s4s32s256shhlii4i20s"
|
|
#fmt="2s4s32s4s32s256s4s8s8s16s20s"
|
|
|
|
""" constants (for ut_type):
|
|
"""
|
|
UT_EMPTY = 0
|
|
UT_RUN_LVL = 1
|
|
UT_BOOT_TIME = 2
|
|
UT_NEW_TIME = 3
|
|
UT_OLD_TIME = 4
|
|
UT_INIT_PROCESS = 5
|
|
UT_LOGIN_PROCESS = 6
|
|
UT_USER_PROCESS = 7
|
|
UT_DEAD_PROCESS = 8
|
|
UT_ACCOUNTING = 9
|
|
record_size = struct.calcsize(fmt)
|
|
# read who is logged on to a UNIX system
|
|
file = open(utmpF, 'rb')
|
|
|
|
sessions={}
|
|
suspects=[]
|
|
|
|
def evdisp(event,zt,rev) :
|
|
( ut_t,ut_ut,zt_t,zt_ut,u,l,h,p,id,typ) =event
|
|
if not zt :
|
|
if zt_t: zt=msectime(zt_t,zt_ut)
|
|
else : zt=" -stillNow-"
|
|
if rev :
|
|
t=zt;
|
|
zt=msectime(ut_t,ut_ut)
|
|
else :
|
|
t=msectime(ut_t,ut_ut)
|
|
return '%-8s %-8s %d/%-2d/%-6d %-4s [%-24s]=>[%-24s] (%s)' % \
|
|
(u, l, typ,1,p, id, t, zt, h)
|
|
|
|
def rewind(sessions,n,criter,event) :
|
|
i=n
|
|
( ut_time,ut_utime,zt_time,zt_utime,user,line,host,pid,sessid,type) =event
|
|
i0=1
|
|
while i>i0 :
|
|
i=i-1
|
|
closethis=0
|
|
if criter=='all' :
|
|
closethis=1
|
|
if criter =='line':
|
|
closethis=(sessions[i][5] == line)
|
|
if closethis : i0=i
|
|
|
|
if closethis :
|
|
( ut_t,ut_ut,zt_t,zt_ut,u,l,h,p,id,typ)=ev=sessions[i]
|
|
if zt_t !=0 :
|
|
if criter=='all' : continue
|
|
if all_last :
|
|
s="-ERR: "
|
|
s=s+evdisp(ev,"",1)
|
|
else :
|
|
ev=sessions[i]=( ut_t,ut_ut,ut_time,ut_utime,u,l,h,p,id,typ)
|
|
if all_last :
|
|
s="-CLOS "
|
|
s=s+evdisp(ev,"",1)
|
|
if all_last :
|
|
print s
|
|
|
|
block = file.read(record_size)
|
|
n=1
|
|
while block:
|
|
( type,pid,line,id,user,host,exit_1,exit_2,ut_session,ut_time,ut_utime,\
|
|
ip1,ip2,ip3,ip4,unused) = \
|
|
struct.unpack(fmt, block)
|
|
user = unpackstr(user) # remove the null characters
|
|
line = unpackstr(line)
|
|
host = unpackstr(host)
|
|
id = unpackstr(id)
|
|
|
|
event = ( ut_time,ut_utime,0,0,user,line,host,pid,id,type)
|
|
|
|
if type and all_last :
|
|
s='USER: '
|
|
s=s+evdisp(event," -n/a-",0)
|
|
print s
|
|
if user in ['LOGIN','reboot','shutdown'] :
|
|
"Crash & such : everybody logs off.."
|
|
rewind(sessions,n,'all',event)
|
|
|
|
if type == 7 and user :
|
|
sessions[n]=event
|
|
n=n+1
|
|
|
|
if type == 8 :
|
|
rewind(sessions,n,'line',event)
|
|
|
|
block=file.read(record_size)
|
|
file.close()
|
|
|
|
print "Number of entries : %d" %n
|
|
|
|
evs=sessions.values()
|
|
evs.sort(lambda x, y: cmp(y[0]+y[1]*1e-7,x[0]+x[1]*1e-7) )
|
|
i=0
|
|
for ev in evs:
|
|
i=i+1
|
|
(ut_t,ut_ut,zt_t,zt_ut,u,l,h,p,id,typ)=ev
|
|
if emul_last : print evdisp(ev,"",0)
|
|
if datesec <360000 :
|
|
# secret feature : giving a near-epoch date does that :
|
|
if precision >0 and zt_t-ut_t < precision : continue
|
|
if precision <0 and zt_t-ut_t > -precision : continue
|
|
else :
|
|
if datesec + precision < ut_t : continue
|
|
if zt_t !=0 and zt_t + precision <datesec : continue
|
|
if emul_last : print "----SUSPECT"
|
|
suspects.append(ev)
|
|
|
|
print "\nAnd Now the \"suspects\" :"
|
|
|
|
suspects.sort(lambda x, y: cmp(x[2]-x[0], y[2]-y[0]))
|
|
for ev in suspects :
|
|
(ut_t,ut_ut,zt_t,zt_ut,u,l,h,p,id,typ)=ev
|
|
print evdisp(ev,"",0)
|