home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume7 / idle.users / idel.c next >
Encoding:
C/C++ Source or Header  |  1986-12-09  |  5.3 KB  |  176 lines

  1. /* idles deamon - kills off users who have not used their terminals for
  2.  * a specified time.
  3.  * Tested and run for 6 month on 4.2 BSD at site Erix.
  4.  * Change LMESSAGE, WMESSAGE, DAYOUY, NIGHTO, EVENING, MORNING and SLEEP
  5.  * to what you want locally (see comments in code) compile and run (as root).
  6.  * preferably started in /etc/rc.local by lines something like this:
  7.  *    if [ -f /usr/local/lib/id ]; then
  8.  *        /usr/local/lib/id & echo -n ' idle'    >/dev/console
  9.  *    fi
  10.  * when starting local daemons.
  11.  * The daemon wakes up every SLEEP minutes, reads UTMP and stats the terminals
  12.  * to see if when they were last used. A warning (WMESSAGE) is sent if the 
  13.  * time elapsed excedes time WARN minutes. The user is logged out and a message
  14.  * (LMESSAGE) is sent if the user has been idle for more than DAYOUT minutes
  15.  * between the hours MORNING to EVENING or else NIGHTO minutes. Error messages
  16.  * are sent to syslog LOG_CRIT. A log of users logged out is sent to syslog
  17.  * LOG_INFO. Useful for defending system managers from irate users who do 
  18.  * something stupid and log themselves out and then blame the daemon!
  19.  */
  20. #include <utmp.h>
  21. #include <sys/types.h>
  22. #include <sys/time.h>
  23. #include <sys/stat.h>
  24. #include <sys/file.h>
  25. #include <sgtty.h>
  26. #include <syslog.h>
  27. #include <setjmp.h>
  28. #include <signal.h>
  29. #include <strings.h>
  30. #define UTMP "/etc/utmp"
  31. #define LMESSAGE "\007\007\rAuto logout - too long idle time\r\n"
  32. #define WMESSAGE "\007\007\rThe idle deamon has spotted you\r\n"
  33. #define DAYOUT 480 /* logout after this number of idle minutes - daytime*/
  34. #define NIGHTO 120 /* logout after this number of idle minutes - nightime */
  35. #define MORNING 7 /* start of daytime */
  36. #define EVENING 18 /* start of evening time */
  37. #define WARN 90 /* start sending warnings after this time */
  38. #define SLEEP 10 /* time (minutes) between each check */
  39.  
  40. jmp_buf env;
  41. struct utmp ut;
  42. struct stat sbuf;
  43. struct timeval tv;
  44. struct timezone tz;
  45. struct tm *ltime;
  46. struct stat sbuf;
  47. main()
  48. {
  49.     int fd, minutes, logout;
  50.     char fname[12];
  51. #ifndef DEBUG
  52.     if (fork() != 0) exit(0); /* kill off parent */
  53.     /* close all files */
  54.     fd = getdtablesize();
  55.     for ( fd--; fd>=0; fd--){
  56.         (void) close(fd);
  57.     }
  58.     /* create files for std{in,out,err} if they are used by syslog or some 
  59.        such stupidity */
  60.     if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
  61.     if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
  62.     if ((fd = open("/dev/null", O_RDWR)) < 0 ) exit(1);
  63.     /* now remove the controling tty (if there is one) */
  64.     if ( (fd = open("/dev/tty", O_RDWR)) >= 0 ) {
  65.         (void) ioctl(fd, TIOCNOTTY, 0);
  66.         (void) close(fd);
  67.     }
  68. #endif
  69.     
  70.     while (1) {
  71.         /* open the utmp file */
  72.         if ((fd = open(UTMP, O_RDONLY, 0)) < 0) {
  73.             syslog(LOG_CRIT, "Idles can't open utmp");
  74.             exit(1);
  75.         }
  76.         /* get the time */
  77.         if (gettimeofday(&tv, &tz) != 0) {
  78.             syslog(LOG_CRIT, "Idles can't get timeofday");
  79.             exit(1);
  80.         }
  81.         ltime = localtime(&tv.tv_sec);
  82.         /* work out the logout time limit */
  83.         if ((ltime->tm_hour > MORNING) && (ltime->tm_hour < EVENING)) {
  84.             logout = DAYOUT;
  85.         }
  86.         else logout = NIGHTO;
  87.         
  88.         /* read the utmp file, record by record until finished */
  89.         while (read(fd, &ut, sizeof(struct utmp)) == sizeof(struct utmp)) {
  90.             if (ut.ut_line[0] != '\0' && ut.ut_name[0] != '\0') {
  91.                 /* get the last time of use of the terminal by
  92.                    stat-ing the terminal */
  93.                 strcpy(fname, "/dev/");
  94.                 strcat(fname, ut.ut_line);
  95.                 if (stat(fname, &sbuf) != 0) {
  96.                     perror("idles: stat: ");
  97.                     continue;
  98.                 }
  99.                 /* calculate the number of minutes since the terminal was last
  100.                    acessed */
  101.                 minutes = (tv.tv_sec - sbuf.st_atime ) / 60;
  102.                 /* kill him off or warn him if he hasn't used his terminal */
  103.                 if (minutes >= logout) {
  104.                     zap(fname, LMESSAGE, 0);
  105.                     syslog(LOG_INFO, "Auto logout %s %s ",
  106.                       ut.ut_name, ut.ut_line);
  107.                 }
  108.                 else if (minutes >= WARN) {
  109.                     zap(fname, WMESSAGE, 1);
  110.                 }
  111.             }
  112.         }
  113.         (void) close(fd);
  114.         /* sleep until its time to start again */
  115.         sleep(SLEEP * 60);
  116.     }
  117. }
  118. /* kill or warn a user */
  119. zap(fname, message, warn)
  120. char *fname, *message;
  121. {
  122.     int allarmed();
  123.     struct sgttyb ttyb;
  124.     int tfd;
  125.     if (fork() == 0) {
  126.         /* child kills the offender */
  127.         /* close all files */
  128.         tfd = getdtablesize();
  129.         for ( tfd--; tfd>=0; tfd--){
  130.             (void) close(tfd);
  131.         }
  132.         /* now remove the controling tty (if there is one) */
  133.         if ( (tfd = open("/dev/tty", O_RDWR)) >= 0 ) {
  134.             (void) ioctl(tfd, TIOCNOTTY, 0);
  135.             (void) close(tfd);
  136.         }
  137.         /* this open will also set a new controling terminal */
  138.         tfd = open(fname, O_RDWR, 0600) ;
  139.         if (tfd < 0) exit(1);
  140.         /* setup a timeout if against all odds we get hung */
  141.         signal(SIGALRM,allarmed);
  142.         alarm(2);
  143.         if (setjmp(env) == 0) {
  144.             /* do this to prevent ^S from hanging the process */
  145.             (void) ioctl(tfd, TIOCSTART, (char *)0);
  146.             /* toggle cbreak to disrupt any terminal paging */
  147.             (void) ioctl(tfd, TIOCGETP, &ttyb);
  148.             ttyb.sg_flags ^= CBREAK;
  149.             (void) ioctl(tfd, TIOCSETP, &ttyb);
  150.             ttyb.sg_flags ^= CBREAK;
  151.             (void) ioctl(tfd, TIOCSETP, &ttyb);
  152.             
  153.             /* write out the logout message */
  154.             write(tfd, message, strlen(message));
  155.         
  156.             /* flush it out for safety's sake */
  157.             (void) ioctl(tfd, TIOCFLUSH, (char *)0);
  158.         }
  159.         alarm(0);
  160.         (void) close(tfd);
  161.         /* kill off the offender's login and exit */
  162.         if (!warn) vhangup();
  163.         exit(0);
  164.     }
  165.     /*parent: wait for the forked process*/
  166.     while (wait(0) == 0);
  167. }
  168.  
  169. /* just longjmp out if timed out (SIGALRM received) */
  170. allarmed(sig)
  171. int sig;
  172. {
  173. longjmp(env,1);
  174. }
  175.  
  176.