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 >