v07i089: A simple BSD idle-users daemon

sources-request at mirror.UUCP sources-request at mirror.UUCP
Thu Dec 11 04:40:55 AEST 1986


Submitted by: seismo!erix!mike (Mike Williams)
Mod.sources: Volume 7, Issue 89
Archive-name: idle.users

Dear Moderator,

Please find within the source code for a daemon I have been running for
more than 6 months without problems on our 4.2BSD system. It simply
logs off idle users afer giving them fair warning. See comments at the
start of the code for more details.

I wrote this thing after I noticed the some users never logged off.  I
have seen similar things on the net before, but they all seemed rather
complicated, whereas this thing is very simple and easy to use and
configure.  Maybe the config data should be read from a file, I thought
of this but felt that the thing is so seldom reconfigured that this
seemed unecessary. Have not put in any comments about this being public
domain etc, but of course anyone can use this exactly as they want as
far as I am concerned.

Mike Williams (mike at erix.UUCP or ...mcvax!enea!erix!mike)

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "End of shell archive."
# Contents:  Makefile idel.c
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'Makefile'" '(46 characters)'
if test -f 'Makefile' ; then 
  echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' >Makefile <<'@//E*O*F Makefile//'
X
Xidel:	idel.c
X	$(CC) $(CFLAGS) -o idel idel.c
@//E*O*F Makefile//
if test 46 -ne "`wc -c <'Makefile'`"; then
    echo shar: error transmitting "'Makefile'" '(should have been 46 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'idel.c'" '(5448 characters)'
if test -f 'idel.c' ; then 
  echo shar: will not over-write existing file "'idel.c'"
else
sed 's/^X//' >idel.c <<'@//E*O*F idel.c//'
X/* idles deamon - kills off users who have not used their terminals for
X * a specified time.
X * Tested and run for 6 month on 4.2 BSD at site Erix.
X * Change LMESSAGE, WMESSAGE, DAYOUY, NIGHTO, EVENING, MORNING and SLEEP
X * to what you want locally (see comments in code) compile and run (as root).
X * preferably started in /etc/rc.local by lines something like this:
X *	if [ -f /usr/local/lib/id ]; then
X *		/usr/local/lib/id & echo -n ' idle'	>/dev/console
X *	fi
X * when starting local daemons.
X * The daemon wakes up every SLEEP minutes, reads UTMP and stats the terminals
X * to see if when they were last used. A warning (WMESSAGE) is sent if the 
X * time elapsed excedes time WARN minutes. The user is logged out and a message
X * (LMESSAGE) is sent if the user has been idle for more than DAYOUT minutes
X * between the hours MORNING to EVENING or else NIGHTO minutes. Error messages
X * are sent to syslog LOG_CRIT. A log of users logged out is sent to syslog
X * LOG_INFO. Useful for defending system managers from irate users who do 
X * something stupid and log themselves out and then blame the daemon!
X */
X#include <utmp.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X#include <sgtty.h>
X#include <syslog.h>
X#include <setjmp.h>
X#include <signal.h>
X#include <strings.h>
X#define UTMP "/etc/utmp"
X#define LMESSAGE "\007\007\rAuto logout - too long idle time\r\n"
X#define WMESSAGE "\007\007\rThe idle deamon has spotted you\r\n"
X#define DAYOUT 480 /* logout after this number of idle minutes - daytime*/
X#define NIGHTO 120 /* logout after this number of idle minutes - nightime */
X#define MORNING 7 /* start of daytime */
X#define EVENING 18 /* start of evening time */
X#define WARN 90 /* start sending warnings after this time */
X#define SLEEP 10 /* time (minutes) between each check */
X
Xjmp_buf env;
Xstruct utmp ut;
Xstruct stat sbuf;
Xstruct timeval tv;
Xstruct timezone tz;
Xstruct tm *ltime;
Xstruct stat sbuf;
Xmain()
X{
X	int fd, minutes, logout;
X	char fname[12];
X#ifndef DEBUG
X	if (fork() != 0) exit(0); /* kill off parent */
X	/* close all files */
X	fd = getdtablesize();
X	for ( fd--; fd>=0; fd--){
X		(void) close(fd);
X	}
X	/* create files for std{in,out,err} if they are used by syslog or some 
X	   such stupidity */
X	if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
X	if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
X	if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
X	/* now remove the controling tty (if there is one) */
X	if ( (fd = open("/dev/tty", O_RDWR)) >= 0 ) {
X		(void) ioctl(fd, TIOCNOTTY, 0);
X		(void) close(fd);
X	}
X#endif
X	
X	while (1) {
X		/* open the utmp file */
X		if ((fd = open(UTMP, O_RDONLY, 0)) < 0) {
X			syslog(LOG_CRIT, "Idles can't open utmp");
X			exit(1);
X		}
X		/* get the time */
X		if (gettimeofday(&tv, &tz) != 0) {
X			syslog(LOG_CRIT, "Idles can't get timeofday");
X			exit(1);
X		}
X		ltime = localtime(&tv.tv_sec);
X		/* work out the logout time limit */
X		if ((ltime->tm_hour > MORNING) && (ltime->tm_hour < EVENING)) {
X			logout = DAYOUT;
X		}
X		else logout = NIGHTO;
X		
X		/* read the utmp file, record by record until finished */
X		while (read(fd, &ut, sizeof(struct utmp)) == sizeof(struct utmp)) {
X			if (ut.ut_line[0] != '\0' && ut.ut_name[0] != '\0') {
X				/* get the last time of use of the terminal by
X				   stat-ing the terminal */
X				strcpy(fname, "/dev/");
X				strcat(fname, ut.ut_line);
X				if (stat(fname, &sbuf) != 0) {
X					perror("idles: stat: ");
X					continue;
X				}
X				/* calculate the number of minutes since the terminal was last
X				   acessed */
X				minutes = (tv.tv_sec - sbuf.st_atime ) / 60;
X				/* kill him off or warn him if he hasn't used his terminal */
X				if (minutes >= logout) {
X					zap(fname, LMESSAGE, 0);
X					syslog(LOG_INFO, "Auto logout %s %s ",
X					  ut.ut_name, ut.ut_line);
X				}
X				else if (minutes >= WARN) {
X					zap(fname, WMESSAGE, 1);
X				}
X			}
X		}
X		(void) close(fd);
X		/* sleep until its time to start again */
X		sleep(SLEEP * 60);
X	}
X}
X/* kill or warn a user */
Xzap(fname, message, warn)
Xchar *fname, *message;
X{
X	int allarmed();
X	struct sgttyb ttyb;
X	int tfd;
X	if (fork() == 0) {
X		/* child kills the offender */
X		/* close all files */
X		tfd = getdtablesize();
X		for ( tfd--; tfd>=0; tfd--){
X			(void) close(tfd);
X		}
X		/* now remove the controling tty (if there is one) */
X		if ( (tfd = open("/dev/tty", O_RDWR)) >= 0 ) {
X			(void) ioctl(tfd, TIOCNOTTY, 0);
X			(void) close(tfd);
X		}
X		/* this open will also set a new controling terminal */
X		tfd = open(fname, O_RDWR, 0600) ;
X		if (tfd < 0) exit(1);
X		/* setup a timeout if against all odds we get hung */
X		signal(SIGALRM,allarmed);
X		alarm(2);
X		if (setjmp(env) == 0) {
X			/* do this to prevent ^S from hanging the process */
X			(void) ioctl(tfd, TIOCSTART, (char *)0);
X			/* toggle cbreak to disrupt any terminal paging */
X			(void) ioctl(tfd, TIOCGETP, &ttyb);
X			ttyb.sg_flags ^= CBREAK;
X			(void) ioctl(tfd, TIOCSETP, &ttyb);
X			ttyb.sg_flags ^= CBREAK;
X			(void) ioctl(tfd, TIOCSETP, &ttyb);
X			
X			/* write out the logout message */
X			write(tfd, message, strlen(message));
X		
X			/* flush it out for safety's sake */
X			(void) ioctl(tfd, TIOCFLUSH, (char *)0);
X		}
X		alarm(0);
X		(void) close(tfd);
X		/* kill off the offender's login and exit */
X		if (!warn) vhangup();
X		exit(0);
X	}
X	/*parent: wait for the forked process*/
X	while (wait(0) == 0);
X}
X
X/* just longjmp out if timed out (SIGALRM received) */
Xallarmed(sig)
Xint sig;
X{
Xlongjmp(env,1);
X}
X
@//E*O*F idel.c//
if test 5448 -ne "`wc -c <'idel.c'`"; then
    echo shar: error transmitting "'idel.c'" '(should have been 5448 characters)'
fi
fi # end of overwriting check
echo shar: "End of shell archive."
exit 0



More information about the Mod.sources mailing list