Return to BSD News archive
Path: euryale.cc.adfa.oz.au!newshost.carno.net.au!harbinger.cc.monash.edu.au!news.rmit.EDU.AU!news.unimelb.EDU.AU!munnari.OZ.AU!spool.mu.edu!uwm.edu!newsfeeds.sol.net!newspump.sol.net!mindspring!uunet!in3.uu.net!193.10.88.100!news00.sunet.se!sunic!mn6.swip.net!seunet!news2.swip.net!nike.volvo.se!cyklop.volvo.se!peter
From: peter hakanson <peter@cyklop.volvo.se>
Newsgroups: comp.unix.bsd.bsdi.misc
Subject: Re: Kicking Off people
Date: Mon, 30 Dec 1996 09:38:51 +0100
Organization: Volvo Corp.
Lines: 465
Message-ID: <Pine.BSD/.3.91.961230093735.10565A-100000@cyklop.volvo.se>
References: <199612300225.UAA13547@news1.anet-dfw.com>
NNTP-Posting-Host: cyklop.volvo.se
Mime-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
In-Reply-To: <199612300225.UAA13547@news1.anet-dfw.com>
Xref: euryale.cc.adfa.oz.au comp.unix.bsd.bsdi.misc:5497
My pleasure.
Snip%snip%snip%snip%snip%snip%snip%snip%snip%snip%snip%snip%
/* @(#) idler.c
*
* Authors: Fred Buck and Steve Manes
*
* This program is hereby released into the public domain.
* Any claims or rights of copyright are relinquished, however
* the authors disclaim any liability for the use of this program.
peter h volvodata modiferat enl:
sighup ignoererat !
fork() drar loss oss fraan terminalen
BUMPROOT = 0
* redone for bsd/sysV
*
* Usage: idler
* idler <filename>
* idler <tty-basename> <tty-basename> <tty-basename> ...
*
* Inactivity timer daemon for Xenix
*
* This program, when started at bootup by the line "/etc/idler"
* (or a line like "/etc/idler <filename>")
* in /etc/rc.user, watches each terminal for inactivity lasting longer
* than IDLEMAX minutes, sends a warning message to each inactive
* terminal, and sends hangup or termination signals (see below) to
* the processes associated with that terminal if it remains inactive
* for 60 seconds after the warning.
*
* If command-line arguments are given, they are interpreted as
* follows: if the first argument is the name of a readable ordinary
* file, that file is assumed to contain a list of terminals to watch,
* one terminal name per line within the file and all subsequent
* command-line arguments are disregarded. Otherwise, the command-line
* arguments are assumed to be names of terminals to watch for inactivity.
* Examples:
*
* /etc/idler
* watches every active terminal;
*
* /etc/idler filename
* watches the terminals specified, one per line, in file
* "filename";
*
* /etc/idler tty01 tty02 tty03
* watches the terminals "/dev/tty01", "/dev/tty02", and
* "/dev/tty03".
*
* If the first command argument is the name of a readable ordinary
* file, and the file is changed while this program is running, then
* the program will re-read the file at the beginning of each watching
* cycle. If the first line of such a file is a number, then that
* number will be taken as the new value for the number of minutes a
* user must be inactive to be classified as idle; example:
*
* 20
* tty01
* tty02
*
* if appearing in 'filename', and if this program was invoked with
* 'filename' as its only argument, then the idle-time is reset to 20
* minutes and only /dev/tty01 and /dev/tty02 are watched for inactivity.
*
* NOTE that terminal names specified on the command line must consist
* of the terminal basenames only; the program prefixes each such name
* with "/dev/"; the same observation applies to specifications within
* <filename>.
*
* In the event that a terminal's processes must be terminated,
* the process with the lowest number (presumably the login shell)
* is sent SIGHUP and all other processes are sent SIGTERM so as to
* kill 'nohup' processes possibly created previously on that terminal.
* Possibly, a malicious user may have created processes immune to
* SIGHUP and SIGTERM. If you fear this, you can change the spec for
* SIGTERM to SIGKILL: the only warning I offer is that SIGKILL leaves
* no room for a user process to clean up after itself before it dies.
*
* This program assumes that the 'ps' command takes a '-t' option and
* that the first line of "ps -t" output contains the string "PID".
*
* The user 'root' is, by default, immune from interference from this
* program. To change this, #define BUMPROOT as 1 below.
*/
/* #define DOLOG*/
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <utmp.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#ifdef __bsdi__
#include <termios.h>
#else
#include <termio.h>
#endif
#include <signal.h>
#ifdef DOLOG
#include <syslog.h>
#endif
#define IDLEMAX 8*60 /* minutes of idle time allowed */
#define MAXUSERS 50 /* maximum number of users at a time */
#define BUMPROOT 0 /* if 0, 'root' immune to this pgm */
#define LOGUSER 1 /* keeping a log? */
#define MAILUSER 1 /* notify by mail */
#define LOGFILE "/var/log/idler.log" /* sleepy user logname */
#define BSD /* or sysV */
/* System V Xenix puts more stuff into /etc/utmp than System
* III Xenix, such as that running on the Tandy 6000, does.
* If you have a Tandy 6000, delete the following #define.
*/
#ifndef __bsdi__
#define NOTABODY(x) (x.ut_type != USER_PROCESS) /* delete for Tandy 6000 */
#endif
static char ttynames[MAXUSERS][20]; /* ttynames to monitor */
int idlemins = IDLEMAX; /* this can be changed in <filename> */
void warn(), bump(), urec_cop(), read_tfile();
void hup(); /* ignore sighup */
main(argc,argv)
int argc;
char **argv;
{
register int i, idlers;
static FILE *tfile;
FILE *fopen();
struct stat argv1;
static time_t tfiletime;
int utmpfd,fd;
struct utmp user, users[MAXUSERS];
#ifdef __bsdi__
struct termios dummy;
#else
struct termio dummy;
#endif
char device[20];
if (argc > 1) {
if ((tfile = (FILE *)fopen(argv[1], "r")) != NULL &&
#ifdef __bsdi__
ioctl(fileno(tfile), TIOCGETA, &dummy) < 0)
#else
ioctl(fileno(tfile), TCGETA, &dummy) < 0)
#endif
{
/* argv[1] not a tty */
fstat(fileno(tfile), &argv1);
tfiletime = argv1.st_mtime;
read_tfile(tfile);
}
else { /* argv is list of ttys */
for (i=1; i < argc && i < MAXUSERS; ++i)
strncpy(ttynames[i-1], argv[i], 19);
}
}
/* porting changes peter h*/
#ifdef DOLOG
openlog("idler", LOG_PID | LOG_CONS, LOG_DAEMON);
syslog(LOG_CRIT,"Starting");
#endif
chdir("/");
umask(0);
if(fork() != 0)
exit(0); /* become non-process grp leader */
#ifdef sysV
setpgrp(); /* lose controlling term & become grp leader */
#endif
#ifdef BSD
setpgrp(0,getpid());
if( (fd = open("/dev/tty", O_RDWR)) >= 0){
ioctl(fd,TIOCNOTTY,(char *) 0);
close(fd);
}
#endif
#ifdef SIGTTOU
signal(SIGTTOU,SIG_IGN);
#endif
if(fork() != 0)
exit(0); /* first child process */
#ifdef __bsdi__
if ((utmpfd = open("/var/run/utmp", 0)) < 0)
#else
if ((utmpfd = open("/etc/utmp", 0)) < 0)
#endif
return(1);
idlers = 0;
signal(SIGHUP,hup); /* ignore SIGHUP */
while (1) {
/* sleep(idlemins * 60);*/ /* sleep most of the time */
sleep( 60); /* sleep most of the time */
#ifdef DOLOG
syslog(LOG_CRIT,"After sleep");
#endif
if (tfiletime) { /* should we re-read tfile? */
fstat(fileno(tfile), &argv1);
if (argv1.st_mtime > tfiletime) {
tfiletime = argv1.st_mtime;
read_tfile(tfile);
}
}
idlers = 0;
lseek(utmpfd,0L,0);
while ( read(utmpfd, &user, sizeof(user)) ) {
if (user.ut_line[0] == '\0')
continue;
if (user.ut_name[0] == '\0')
continue;
#ifdef NOTABODY
/* for Sys V, skip over non-user entries */
if (NOTABODY(user))
continue;
#endif
if (argc > 1) {
for (i=0; i < MAXUSERS;++i)
if (!strcmp(user.ut_line, ttynames[i]))
break;
if (i == MAXUSERS)
continue;
}
if (is_idle(&user))
urec_cop(&user, &users[idlers++]);
}
#ifdef DOLOG
syslog(LOG_CRIT,"if (idlers) ");
#endif
if (idlers) {
for (i=0; i < idlers; ++i)
warn(&users[i], 0);
sleep(60);
#ifdef DOLOG
syslog(LOG_CRIT,"sleep (60) ");
#endif
for (i=0; i < idlers; ++i)
bump(&users[i]);
}
}
}
int is_idle( user ) /* returns 1 if idle, 0 otherwise */
struct utmp *user;
{
long int idlemax;
struct stat tty;
char device[20];
time_t todnow;
#ifdef __bsdi__
if (!strcmp("console",user->ut_line))
return(0);
#else
if (user->ut_type == LOGIN_PROCESS || user->ut_type == INIT_PROCESS)
return(0);
#endif
if (!BUMPROOT && !strcmp(user->ut_name, "root"))
return(0);
sprintf(device, "/dev/%s", user->ut_line);
#ifdef DOLOG
syslog(LOG_CRIT,device);
#endif
#ifndef __bsdi__
if (user->ut_type == LOGIN_PROCESS || user->ut_type == INIT_PROCESS)
return(0);
#endif
#ifdef DOLOG
syslog(LOG_CRIT,"stat(%s,&tty)",device);
#endif
stat(device, &tty);
time(&todnow);
idlemax = idlemins * 60;
return( (todnow-tty.st_mtime) > idlemax &&
(todnow-tty.st_atime) > idlemax &&
(todnow-tty.st_ctime) > idlemax );
}
void bump( user ) /* kills user if idle > 60 secs */
struct utmp *user;
{
register int i;
int ttyfd;
FILE *processes, *popen();
int ps_num;
time_t todnow;
struct stat tty;
char device[20], cmdstr[50];
if (user->ut_line[0] == '\0' || user->ut_line == NULL)
return;
time(&todnow);
sprintf(device, "/dev/%s", user->ut_line);
stat(device, &tty);
if ((todnow-tty.st_atime) < 60)
return; /* guess user heeded warning */
warn(user, 1);
/* to get the user's process ID numbers, we read
* from the pipeline "ps -t <ttyname> | awk '!/PID/ {print $1}'"
*/
#ifdef __bsdi__
strcpy(cmdstr,"ps -t /dev/");
#else
strcpy(cmdstr,"ps -t ");
#endif
if (*user->ut_line)
strcat(cmdstr, user->ut_line);
strcat(cmdstr, " | awk '!/PID/ {print $1}' | sort");
processes = popen(cmdstr,"r");
i = 0;
while ( fscanf(processes,"%d",&ps_num) != EOF)
if (ps_num > 1) /* never swapper or init */
kill(ps_num, (((i++) == 0) ? SIGHUP : SIGTERM));
/* We use SIGTERM for processes other than the login
* shell to catch any 'nohup' commands.
*/
pclose(processes);
}
void urec_cop( ufrom, uto ) /* copies utmp structs */
struct utmp *ufrom, *uto;
{
register int i;
char *to, *from;
to = (char *) uto;
from = (char *) ufrom;
for (i=0; i < sizeof(struct utmp); ++i)
*(to++) = *(from++);
}
void read_tfile( fp ) /* loads 'ttynames' array from file */
FILE *fp;
{
register int i;
int newtimeout;
char *strchr();
fseek(fp, 0L, 0);
i = 0;
while (i < MAXUSERS && fgets(ttynames[i], 20, fp) != NULL) {
/* if first line is a number, then that's the new timeout */
if (i == 0 && (newtimeout = atoi(ttynames[0]))) {
idlemins = newtimeout;
#ifdef DOLOG
syslog(LOG_CRIT,"new timeout");
#endif
continue;
}
*(ttynames[i] + strlen(ttynames[i]) -1) = '\0';
++i;
}
}
/*----------------------------------------------------------------------
* warn(user, kickoff)
* warn sleepy user.
*
* mode = 0: send warning message
* 1: send him goodbye message, mail and log 'em
*----------------------------------------------------------------------*/
void warn( user, mode )
struct utmp *user;
int mode;
{
int utty;
char device[20];
FILE *fid;
time_t now;
char buff[20];
char *warn0 =
"\n\007One more minute without input and you will be disconnected!\n";
char *warn1 = "\n\nTime's up. Goodbye!\n\n";
sprintf(device, "/dev/%s", user->ut_line);
utty = open(device, (O_RDWR | O_NDELAY));
if (mode == 0) write(utty, warn0, strlen(warn0));
else write(utty, warn1, strlen(warn1));
close(device);
if (mode == 0)
return;
/* user's been kicked off */
time(&now);
if (LOGUSER && (fid = fopen(LOGFILE, "a+")) > 0) {
#ifdef __bsdi__
fprintf(fid, "%s on /dev/%s killed: %s", user->ut_name,user->ut_line, ctime(&now));
#else
fprintf(fid, "%s killed: %s", user->ut_user, ctime(&now));
#endif
fclose(fid);
}
/* mail user */
#ifdef MAILUSER
#ifdef __bsdi__
sprintf(buff, "mail -s \"Idler Disconnect\" %s", user->ut_name);
#else
sprintf(buff, "mail %s", user->ut_user);
#endif
if ( !(fid = popen(buff, "w")) )
return;
time(&now); /* added */
fprintf(fid, "\n\tFrom Idler at %s", ctime(&now));
fprintf(fid, "\n\tYou were automatically logged off ");
fprintf(fid, "\n\tfor terminal inactivity more then %d minutes.\n",idlemins);
pclose(fid);
#endif
}
void hup() /* SIGHUP handler */
{
signal (SIGHUP,hup); /* re-arm */
#ifdef DOLOG
syslog(LOG_CRIT,"SIGHUP");
#endif
}
Snip%snip%snip%snip%snip%snip%snip%snip%snip%snip%snip%snip%
--
Peter Hakanson VolvoData Dep 2580 phone +46 31 66 74 27
On Sun, 29 Dec 1996 david@news1.anet-dfw.com wrote:
> I would like a copy please.
>
>
> DB
>
> In article <5a6is6$n66@nike.volvo.se> you wrote:
> : Once upon a time i picked up a program called 'idler'
> : that killed idle users (settable)
>
> : It was originally written for xenix, but i have used it
> : on RT/PC, hpux and bsdi.
>
> : Want a copy ?
> : Bryan Logan (blogan@host1.dia.net) wrote:
> : : OK, we sometimes have these people that just dial-in and they leave. We
> : : have some that are PPP'd in for 24 hrs. sometimes. So henceforth the
> : : obvious question:
>
> : : How can I kick off people who are PPP'd in without telnetting to the
> : : router or flipping the modem? (I'm not at the office).
>
> : : Thanks.
> : : --
> : : -----
> : : Bryan Logan
> : : blogan@host1.dia.net
> : : http://www.dia.net/~blogan <---Now loaded with ActiveX!
>
> : --
> : --
> : NO JUNK EMAIL <peter@cyklop.volvo.se>
> : Peter Hakanson VolvoData Dep 2580 phone +46 31 66 74 27
>