#!/usr/bin/env python # -*- coding: UTF-8 -*- ########################################################################## # TcosMonitor writen by MarioDebian # # TcosMonitor version __VERSION__ # # Copyright (c) 2006 Mario Izquierdo # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. ########################################################################### import sys, os import getopt import socket from time import time, ctime, localtime from subprocess import Popen, PIPE, STDOUT import pwd,grp import re import ipaddr import binascii import IPy import commands import utmp from UTMPCONST import * """ ACCOUNTING = 9 BOOT_TIME = 2 DEAD_PROCESS = 8 EMPTY = 0 INIT_PROCESS = 5 LOGIN_PROCESS = 6 NEW_TIME = 3 OLD_TIME = 4 RUN_LVL = 1 USER_PROCESS = 7 UT_HOSTSIZE = 256 UT_IDSIZE = 4 UT_LINESIZE = 32 UT_NAMESIZE = 32 UT_UNKNOWN = 0 """ debug=False def print_debug(txt): if debug: print >> sys.stderr, "tcos-last DEBUG: %s"%(txt) def is_bin(txt): if txt in ['3a', '2e', '61', '62', '63', '64', '65', '66']: # txt is ':' or '.' or a letter between a-f return False try: txt=int(txt) except ValueError: # can't convert txt to int, txt is hexadecimal aka binary return True if txt >= 30 and txt <= 39: # txt is between 0(0x30) and 9(0x39) return False # return binary by default return True def LastLogged(user): proc_user=commands.getoutput("pgrep -U $(id -u %s) -f -c '/usr/bin/tcos-dbus-client'" %user) print_debug("LastLogged() user=%s proc_user=%s" %(user,proc_user)) if (int(proc_user)) > 0: return True else: return False def parseIPAddress(ipstr, return_ipv4=True): """ pass an string or binary IP and return IPV4 """ newip=[] isBin=False #if ipstr.endswith(':0.0'): #ipstr=ipstr.replace(':0.0', '') #if ipstr.endswith(':0'): #ipstr=ipstr.replace(':0', '') ipstr=re.sub(':[0-9]*\.?(?<=.)[0-9]+$', '', ipstr) # hostname must start with letter and contain letters numbers and '-' or '.' if re.match(r'^[a-zA-Z][a-zA-Z0-9.-]+$', ipstr): # ipstr is a hostname return ipstr for it in ipstr: eol=is_bin(binascii.hexlify(it)) if eol: isBin=True #print_debug("%s => %s string=%s"%(it, binascii.hexlify(it), eol) ) newip.append(binascii.hexlify(it)) if isBin: ip=ipaddr.IPAddress(IPy.parseAddress("0x" + "".join(newip) )[0]) else: try: ip=ipaddr.IPAddress(ipstr) except Exception: #except Exception, err: #print_debug("parseIPAddress() Exception, error=%s"%err) return ipstr ipv4=ip if return_ipv4 and ip.version == 6 and ip.ipv4_mapped: ipv4=ip.ipv4_mapped.exploded return str(ipv4) try: opts, args = getopt.getopt(sys.argv[1:], ":hd", ["host=", "debug", "tcosdisplay", "user", "userid", "time", "pid", "display", "ingroup=", "semi"]) except getopt.error, msg: print msg print "for command line options use tcos-last --help" sys.exit(2) ACTION=None HOST="" INGROUP="" SEMI=False # process options for o, a in opts: if o == "--debug": debug=True if o == "--host": HOST=a if o == "--tcosdisplay": HOST=parseIPAddress(os.environ["DISPLAY"]) if o == "--user": ACTION="user" elif o == "--ingroup": ACTION="ingroup" INGROUP=a elif o == "--userid": ACTION="userid" elif o == "--time": ACTION="time" elif o == "--pid": ACTION="pid" elif o == "--display": ACTION="display" elif o == "--semi": SEMI=True def ipValid(ip): # ip is XXX.XXX.XXX.XXX # http://mail.python.org/pipermail/python-list/2006-March/333963.html try: xip=ip.split('.') if len(xip) != 4: return False for block in xip: if int(block) < 0 or int(block) >= 255: return False return True except: return False def GetIpAddress(hostname): print_debug("GetIpAddress() hostname=%s "%(hostname) ) try: return socket.getaddrinfo(hostname, None)[0][4][0] except: return None def GetHostname(ip): print_debug("GetHostname() ip=%s "%(ip) ) try: hostname = socket.gethostbyaddr(ip)[0] return hostname except: return None def GetLast(ip): last=[] data={} if ip != "" and not ipValid(ip): ip=GetIpAddress(ip) hostname=GetHostname(ip) print_debug("GetLast() ip=%s hostname=%s "%(ip,hostname)) #for i in range(10): last_file=WTMP_FILE display=":0" #if i != 0: # last_file=WTMP_FILE+".%d" %i if os.path.isfile(last_file): print_debug("GetLast() Searching in %s" %last_file) if (SEMI): a = utmp.UtmpRecord(WTMP_FILE) while 1: b = a.getutent() if not b: break if b.ut_type == USER_PROCESS: tmp_uthost=b.ut_host uthost=str(parseIPAddress(b.ut_host)) utline=str(parseIPAddress(b.ut_line)) half1="%s" %(uthost[:(len(uthost)/2)]) half2="%s" %(uthost[(len(uthost)/2):]) if half1 == half2 and str(parseIPAddress(half1)) == utline: b.ut_host = half1 else: b.ut_host = uthost print_debug(" ==> '%s' != '%s' ut_line=%s" %(str(parseIPAddress(b.ut_host)), ip, b.ut_line) ) if str(parseIPAddress(b.ut_host)) == ip or \ str(parseIPAddress(b.ut_host)) == hostname: if b.ut_line.startswith("pts/") or not \ os.path.isdir("/proc/%s"%b.ut_pid): continue print_debug(" Ip \"%s%s\" => found host=%s hostname=%s ut_line=%s user=%s pid=%s" % \ (ip, tmp_uthost, hostname, b.ut_host, b.ut_line, b.ut_user, b.ut_pid)) last=b display=tmp_uthost a.endutent() else: a = utmp.UtmpRecord() for b in a: #b = a.getutent() if not b: break if b.ut_type == USER_PROCESS: tmp_uthost=b.ut_host uthost=str(parseIPAddress(b.ut_host)) utline=str(parseIPAddress(b.ut_line)) half1="%s" %(uthost[:(len(uthost)/2)]) half2="%s" %(uthost[(len(uthost)/2):]) if half1 == half2 and str(parseIPAddress(half1)) == utline: b.ut_host = half1 else: b.ut_host = uthost print_debug(" => Searching for host \"%s:0\", hostname=%s found host=%s ut_line=%s user=%s"%(ip, hostname, b.ut_host,b.ut_line, b.ut_user)) # print_debug(" ==> '%s' != '%s' ut_line=%s" %(parseIPAddress(b.ut_host), ip, b.ut_line) ) #parseIPAddress(b.ut_line) == "%s:0"%(ip) or \ if parseIPAddress(b.ut_host) == "%s"%(ip) or \ parseIPAddress(b.ut_host) == "%s"%hostname : # found line ??? print_debug(" => found line ?? user=%s"%b.ut_user) if b.ut_line.startswith("pts/") or not \ os.path.isdir("/proc/%s"%b.ut_pid): continue if (b.ut_line.startswith("tty") and int(b.ut_line.replace('tty','')) >= 7): print_debug(" Ip \"%s%s\" => found host=%s hostname=%s ut_line=%s user=%s pid=%s"%(ip, tmp_uthost, hostname, b.ut_host,b.ut_line, b.ut_user, b.ut_pid)) last=b display=tmp_uthost a.endutent() #if last and os.path.isdir("/proc/%s"%last.ut_pid): break if last and os.path.isdir("/proc/%s"%last.ut_pid): if (SEMI): if (LastLogged(last.ut_user) == False): return data print_debug ("diff times now %s - old %s"%(ctime(time()), ctime(last.ut_tv[0]))) # take diff between now and login time diff=time()-last.ut_tv[0] # get days and set diff to rest days=int(diff/(3600*24)) diff=diff-days*3600*24 # get hours and set diff to rest hours=int(diff/3600) diff=diff-hours*3600 # get minutes and set seconds to rest minutes=int(diff/60) seconds=int(diff-minutes*60) print_debug ("days=%s hours=%s minutes=%s seconds=%s"%(days, hours, minutes, diff)) # only print days if > 0 if days == 0: timelogged="%02dh:%02dm"%(hours,minutes) else: timelogged="%dd %02dh:%02dm"%(days,hours,minutes) uid=pwd.getpwnam(last.ut_user)[2] print_debug("username %s uid=%s"%(last.ut_user, uid)) data={"pid":last.ut_pid, "fulltime":"%dd %02d:%02d:%02d"%(days,hours,minutes,seconds), "userid":uid, "user":last.ut_user, "host":last.ut_host.split(":")[0], "time":last.ut_tv[0], "timelogged":timelogged, "display":display} print_debug(data) return data data=GetLast(HOST) # print data if not data: print_debug("Error: no data") sys.exit(1) elif not ACTION: print_debug("Error need something to retrieve: --user, --uid, --time or --pid") sys.exit(1) elif ACTION == "user": print data['user'] elif ACTION == "userid": print data['userid'] elif ACTION == "time": print data['timelogged'] elif ACTION == "pid": print data['pid'] elif ACTION == "display": print data['display'] elif ACTION == "ingroup": usersingroup=[] try: # grp not work well with ldap users. cmd="groups %s 2>/dev/null" %data['user'] output=[] p = Popen(cmd, shell=True, bufsize=0, stdout=PIPE, stderr=STDOUT, close_fds=True).stdout for line in p.readlines(): if line != '\n': line=line.replace('\n', '') output.append(line) print_debug("cmd %s: %s" %(cmd,output)) usersingroup=output[0].split() #usersingroup=grp.getgrnam(INGROUP)[3] except Exception, err: usersingroup=[] if len(usersingroup) == 0: try: usersingroup=grp.getgrnam(INGROUP)[3] except: pass exclude="noexclude" for group in usersingroup: if INGROUP == group: exclude="exclude" print exclude