From 7dfc99c69c647d576c36cf26a44595f3a56b07a7 Mon Sep 17 00:00:00 2001 From: krempp Date: Mon, 22 May 2000 23:40:25 +0200 Subject: [PATCH] initial import. darcs-hash:20000522214025-92525-03a24257a5b15606c91a9135e08692e671d5a0fd.gz --- wwho.py | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100755 wwho.py diff --git a/wwho.py b/wwho.py new file mode 100755 index 00000000..9422a43c --- /dev/null +++ b/wwho.py @@ -0,0 +1,215 @@ +#! /usr/bin/env python +# when-who, Sam K (2000) + +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) +""" +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 not datesec : + if date : + 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