[comp.sources.misc] Gone-- Reserve a terminal

lavallee@HAWK.ULOWELL.EDU ("Warren J. Lavallee") (12/26/87)

[Rich Salz' comment upon receiving this submission: "Here's a first, A
uuencoded binary for Unix?  Ick -- toss it out." I agreed; the Sequent binary
has been deleted.  Kind of makes me question the sanity of some people.  ++bsa]

	Gone is a program that is meant to replace lock(1).   Gone draws
IN USE in hige letters on the top half of the screen, puts the number
of users and the loadave near the bottom and waits until someone types
in a password.  When it gets the password, it crypts it against the user
who is running the gone, if it matches, it exits.

	Gone does not use termcap.  The escape sequences need are not
supported by termcap.  This means that the program will only work on
VT[12]?? terminals and thier clones.  Exact terminals names that are
supported are vt100, vt200, vt220, vt240, and hds220.  You can edit
the source and add more names to gone.c if you have terminals not mentioned
above that are clones.

Included is the source, a man page, a README, and a uuencoded executable for
sequents with a super-fast crypt in it.
[No, it's not.  Not only are Unix binaries ridiculous, but the whole point of
crypt is to be slow and thereby slower to break via brute force.  If you want
fast, use caesar(1).  ++bsa]

	Any bugs, complaints, or impovements to....

	Warren Lavallee      University of Lowell, CS Dept.
	lavallee@hawk.cs.ulowell.edu   lavallee@ulowell.UUCP


#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# -rw-r--r--   1 allbery  System      1854 Dec 25 21:49 README
# -rw-r--r--   1 allbery  System       907 Dec 25 21:49 gone.1l
# -rw-r--r--   1 allbery  System     12765 Dec 25 21:50 gone.c
#
echo 'x - README'
if test -f README; then echo 'shar: not overwriting README'; else
sed 's/^X//' << '________This_Is_The_END________' > README
X
X	Gone is a program that is meant to replace lock(1).   Gone draws
XIN USE in hige letters on the top half of the screen, puts the number
Xof users and the loadave near the bottom and waits until someone types
Xin a password.  When it gets the password, it crypts it against the user
Xwho is running the gone, if it matches, it exits.  If it does not match
Xand WIZGROUP is defined, it checks it against all the members in WIZGROUP
Xin /etc/group.  Gone does not search thought the password file for people
Xwho are members of WIZGROUP via thier gid in the /etc/passwd file.  
X
X	Gone does not use termcap.  The escape sequences need are not
Xsupported by termcap.  This means that the program will only work on
XVT[12]?? terminals and thier clones.  Exact terminals names that are
Xsupported are vt100, vt200, vt220, vt240, and hds220.  You can edit
Xthe source and add more names to gone.c if you have terminals not mentioned
Xabove that are clones.
X
X	If you are not on a supported terminals, all the full screen
Xstuff id forgotten and 4 or 5 lines are printed out saying that the
Xterminal is inuse and the password is asked for.
X
X	Gone never times out.  There are two flags the gone will accept.
X
XThe -p flag will touch the terminal every five minutes (only in full
Xscreen mode) so that untamo and the like will leave the terminal alone.
X
XThe -d flag tells gone that you want to skip the full screen stuff and 
Xjust have the 4 or 5 lines.
X
X	For those of you lucky people who happen to be on a sequent, I
Xhave enclosed with the a uuencoded executable.  This executable has some
Xsuper-fast crypt routine compiled in, and it is MUCH faster than
Xthe library crypt.  It seems to be totally compatible on Dynix 2.1.
X
X	Any bugs, complaints, or impovements to....
X
X	Warren Lavallee      University of Lowell, CS Dept.
X	lavallee@hawk.cs.ulowell.edu   lavallee@ulowell.UUCP
________This_Is_The_END________
if test `wc -l < README` -ne 38; then
	echo 'shar: README was damaged during transit (should have been 38 bytes)'
fi
fi		; : end of overwriting check
echo 'x - gone.1l'
if test -f gone.1l; then echo 'shar: not overwriting gone.1l'; else
sed 's/^X//' << '________This_Is_The_END________' > gone.1l
X.TH GONE LOCAL "\*(V)" "AJR/WJL"
X.SH NAME
Xgone \- reserve a terminal
X.SH SYNOPSIS
X.B gone 
X.SH DESCRIPTION
X.IR Gone
Xclears the screen and prints a cute picture on the display.  It
Xthen asks you for a Magic Word.  The Magic Word is the password
Xyou use to log on to the system.  You must type this in to exit
Xgone.  Gone will display the load average and the number of users
Xthat are on the system near the bottom of the screen.  This info
Xwill be updated every minute.
X.SH INSPIRATION
X.IR Gone
Xwas written because using lock was too time consuming.  With
X.IR gone
Xall you have to do is type in gone and you are done. 
XThe escape sequences were snagged from 
X.IR VMS 
X(Ick, Gag) and converted it to 
X.IR UNIX!
X(Hurray!)
X.SH AUTHORS
XWarren Lavallee (converted it to C), 
XAndy Rosen  (provided DG/UX code so it would work on DG/UX systems)
X.SH ADDRESS
X	lavallee@hawk.cs.ulowell.edu
X	arosen@hawk.cs.ulowell.edu
________This_Is_The_END________
if test `wc -l < gone.1l` -ne 29; then
	echo 'shar: gone.1l was damaged during transit (should have been 29 bytes)'
fi
fi		; : end of overwriting check
echo 'x - gone.c'
if test -f gone.c; then echo 'shar: not overwriting gone.c'; else
sed 's/^X//' << '________This_Is_The_END________' > gone.c
Xstatic char *credits="@(#) GONE Version 1.0--(c)1987  University of Lowell.\n";
X#define VERSION "1.0"
X
Xstatic char *authors = "@(#)Warren Lavallee, Andy Rosen";
X
X/*
X * All rights reserved with the following exceptions
X * 
X * This software is supplied free of charge.  This software, or any part
X * of it, may  not  be  redistributed or otherwise made available to, or
X * used  by, any  other  person  without the inclusion of this copyright
X * notice.  This software may not be used to make a profit in any way.
X * 
X * This  software  is provided with absolutely no warranty, to the extent
X * permitted  by  applicable  state law.  In no event, unless required by
X * applicable law, will the author(s) of this this software be liable for
X * any damages caused by this software.
X * 
X * This will compile under Ultrix 2.0, BSD 4.3, DGUX 3.00, 
X *   Dynix 2.1, and other BSD clones.
X */
X
X/**
X *  C program by Warren Lavallee
X *  DGUX code by Andy Rosen
X **/
X
X/**         You may undefine this if you don't want it                 **/
X
X#define WIZGROUP "wheel"    /** Magic group:
X                              * If you type in the password of someone
X			      * in this group, you will get out.
X			      *
X			      * I think this is better than having a
X			      * global password like "hasta la vista"
X			      * like some locks have.
X			     **/
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <signal.h>
X#include <pwd.h>
X#include <sys/file.h>
X#include <utmp.h>
X#include <sys/ttydev.h>
X#include <nlist.h>
X#include <time.h>
X#include <sgtty.h>
X#include <grp.h>
X#include <assert.h>
X
X#ifdef FCRYPT
X/** Fcrypt works on Sequents, and is much faster so we use that instead **/
X#define CRYPT fcrypt
Xchar *fcrypt ();
X#else
Xchar *crypt ();
X#define CRYPT crypt
X#endif
X
X#ifdef UENT
X#include <uent.h>
X#endif
X
X#ifdef dgux
X#include <fcntl.h>
X#endif
X
Xtypedef enum {false, true} bool;
X
Xchar *getenv(), *getpass(), *ttyname(), *strcpy();
X
Xlong startup_time;		/** Time we started up                   **/
X
Xint die();			/** Exits	                         **/
Xint pflag = 0, 			/** Touch the terminal evey 5 minutes    **/
X    dflag = 0, 			/** Want to use dumb format anyways?     **/
X    pid, 			/** Used with fork		         **/
X    dumb;			/** Am I dumb?			         **/
X
Xbool virgin = true; 		/** Am I a virgin?		         **/
X
Xstruct passwd *pwd;		/** Used to find next variable (myname)  **/
Xchar myname[9];			/** Who am i?			         **/
Xchar hostname[28];		/** Where am i?			         **/
Xchar *validate();		/** Is this password valid?	         **/
X
Xstruct unode {                  /** In here goes the encrypted passwords **/
X  char name[81];                /**  of all the people in WIZGROUP.      **/
X  char passwd[20];              /** Faster this way, instead of scanning **/
X  struct unode *next;           /**  the whole password file each time   **/
X} *wizusers = NULL;             /**  a password is typed in.             **/
X
X#ifdef UENT
Xstruct uent muent;
X#endif
Xchar *mcrypt();                 /** My crypt.  Decides whether to use
X                                 **  the fast crypt, or the library
X				 **  crypt
X				 **/
Xmain(argc, argv)
X     int argc;
X     char *argv[];
X{
X  register i = 1;
X  char *obuf = (char *) malloc (80L*25L);
X  char *term = getenv("TERM");		/** Terminal type                **/
X  char *tty = ttyname(0);		/** My ttyname			 **/
X  char *liberator = NULL;		/** Who liberated this terminal? **/
X  
X  setbuf (stdout, obuf);
X
X#ifdef dgux
X  assert(1);				/** Just checking                **/
X#endif
X
X#ifdef UENT
X  muent = getuent(getuid());
X#endif
X
X  while ((i <= argc-1) && (argv[i++][0] == '-')) {
X    switch (argv[i-1][1]) {
X    case 'p': 
X      ++pflag;
X      break;
X    case 'd': 
X      ++dflag;
X      break;
X    default: fprintf(stderr, "%s:  Can\'t grok a %c\n", argv[0], argv[i-1][1]);
X      sleep (1);
X      break;
X    }
X  }
X  if (pflag && dflag) 
X	fprintf(stderr, "%s: p option can not be specified with d.\n",
X		argv[0]);
X#ifndef dgux
X  startup_time = time(0);
X#else
X  startup_time = time((long *)0);  /* wierd */
X#endif
X  
X  dumb = 0;
X  gethostname(hostname, 28);
X  
X  /** These are the terminals that this is compatible with.  If
X   *  the invoker isn't on one of these, we define dumb, and
X   *  skip all the frills.
X   **/
X  
X  if (!dflag) {
X    if (strcmp(term, "vt100") && strcmp(term, "vt200")
X	&& strcmp(term, "vt220")  && strcmp(term, "vt240")
X	&& strcmp(term, "hds220")) dumb++;
X  } else dumb = 1;
X  
X  (void) signal(SIGINT, SIG_IGN);
X  (void) signal(SIGQUIT, SIG_IGN);
X  (void) signal(SIGTSTP, SIG_IGN);
X  (void) signal(SIGTERM, die);
X  
X  if ((pwd = getpwuid(getuid())) == NULL) 
X    {     /** Not in passwd file.  Hmmm.  Funky.        **/
X      assert(pwd == NULL);
X      printf("Who the hell are you, and how did you manage that?\n");
X      exit(-1);
X    }
X  else 
X    strcpy(myname, pwd->pw_name);
X  
X  do_screen() ;
X  
X  if (!dumb)
X    do {
X      assert(!dumb);
X      pid = fork ();
X      switch (pid) {
X      case -1: 
X	assert(pid == -1);
X	fprintf(stderr, "\033[20;25HCan't fork... retrying...");
X	pid = fork ();
X	if (pid = 0)
X	  dodate (); /** Success **/
X	break;
X      case 0:  
X	dodate ();      /** success **/
X	/** NOT REACHED **/
X	break;
X      default:
X	break;
X      }
X    } while (pid == -1);
X  
X#ifdef FCRYPT
X  init_des ();
X#endif
X  init_pwd ();
X
X  /** Loop until we get either the users password, or roots password **/
X  for (;;) {   /**   Main body of program.  Loop until valid password **/
X    char *passwd;
X    if (!dumb)
X      passwd = getpass ("\033[20;19H      Magic Word:\033[K ");
X    else
X      passwd = getpass ("Enter the magic word: ");
X    if (!strcmp(passwd, "real"))
X      fprintf(stderr, "\033[0;36H %s %d %d ", argv[0], getegid(), geteuid());
X    else if ((!strcmp(passwd, "help")) || (*passwd == '?'))
X      fprintf(stderr, "\033[0;19HMagic Word is the password you log in with.");
X    else if ((liberator = validate(passwd)) != NULL)
X      break;
X
X    putchar(07);
X    fflush(stdout);
X  }
X  if (!dumb) 
X     printf("\033[20;12HWelcome, %s, to this account.\033[J\n\n", liberator);
X  else 
X     printf("\nWelcome, %s, to this account.\n", liberator);
X  
X  if (!dumb)
X    kill (pid,SIGTERM);
X  fflush (stdout);
X}
X
Xdouble load();
X
Xdodate () 
X{
X  long foo[2];
X#ifdef dgux
X  char *obuf = (char *) malloc(80*5);
X#endif
X  char *tty = ttyname(0);
X  int count = 0;
X  
X#ifdef dgux
X  setbuf(stdout, obuf);
X#endif
X
X  nice(10);
X  signal (SIGTERM, die);
X  for (;;) {
X    if (pflag) { /* Touch the terminal every soo often */
X      foo[0] = foo[1] = time(0);
X      utime(tty, foo);
X    }
X    if (++count > 5) {
X      count = 0;
X      do_screen();
X    }
X    
X    printf ("\033[22;27Hload: %.2f, and %d users.\033[K\033[23;18HStarted up at %26s\033[20;37H", load(), users(), ctime(&startup_time));
X    fflush (stdout);      /** Moves cursor to Password: prompt **/
X    sleep (60);
X  }
X}
Xdie () {
X  exit (1);
X}
X
Xint Fkmem;
Xint Futmp;
Xstatic double avenrun[3];
X
Xstatic struct utmp buf;
X
Xstatic struct nlist nl[] = {
X#define N_AVENRUN	0
X#ifndef dgux
X  { "_avenrun" },
X#else
X  { "avenrun" },
X#endif
X  { "" },
X};
X
X/*
X * load - Return the 5 minute load average
X */
Xdouble load()
X{
X  register i;
X#ifdef dgux
X  double lavg[3];
X#endif
X  
X#if ns32000
X  nlist("/dynix", nl);
X#endif
X#if dgux
X  nlist("/dgux", nl);
X#endif
X#if vax
X  nlist("/vmunix", nl);
X#endif
X  
X  if (nl[0].n_type == 0) return (-1);
X  
X  if ((Fkmem = open("/dev/kmem", 0)) < 0) return (-1);
X  
X  lseek(Fkmem, (long)nl[N_AVENRUN].n_value, 0);
X#if ns32000
X  {   long l_avenrun[3]; 
X      read(Fkmem, l_avenrun, sizeof(l_avenrun));
X      for (i=0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
X	avenrun[i] = ((double)l_avenrun[i])/1000.0;
X      }
X    }
X#endif
X#ifdef dgux
X  lseek(Fkmem, (long)nl->n_value, 0);
X  read(Fkmem, (char *)lavg, sizeof(lavg));
X  avenrun[0] = lavg[0];
X#endif
X#ifdef vax
X  read(Fkmem, avenrun, sizeof(avenrun));
X#endif
X  close(Fkmem);
X  return (avenrun[0]);
X}
X
X/*
X * users - Count the number of users logged in.
X */
Xusers()
X{
X#ifdef dgux
X  struct utmp *ut;
X#endif
X  int count = 0;
X  
X  
X  /* Get number of users */
X#ifdef dgux
X  setutent();
X  while (ut = getutent()) if (ut->ut_type == USER_PROCESS) count++;
X  endutent();
X#else
X  if ((Futmp = open("/etc/utmp", 0)) < 0) return (-1);
X  
X  (void) lseek(Futmp, (long)0, 0);
X  while (read(Futmp, &buf, sizeof(buf)) > 0) {
X    if (buf.ut_name[0] != '\0') {
X      count++;
X    }
X  }
X  close(Futmp);
X#endif
X  return (count);
X}
Xdo_screen () {
X  
X  if (!dumb) {
X    printf ("\033[H\033[2J\033(0\0331");    /** Clear screen, Graphics mode **/
X    
X    
X    printf ("\
X   lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk\n\
X   x                                                                       x\n\
X   x   ////////    //      //        ///     ///    ////////    /////////  x\n\
X   x  aaaaaaaa/   aa/     aa/       aaa/    aaa/   aaaaaaaa/   aaaaaaaaa/  x\n\
X   x     aa/      aaa/    aa/       aaa/    aaa/   aa/         aa/         x\n");
X    printf("\
X   x     aa/      aa/a/   aa/  ///  aaa/    aaa/   aa///////   aa//////    x\n\
X   x     aa/      aa/ a/  aa/ aaa/  aaa/    aaa/   aaaaaaaa/   aaaaaaa/    x\n\
X   x     aa/      aa/  a/ aa/       aaa/    aaa/         aa/   aa/         x\n\
X   x   //aa////   aa/   a/aa/       aaa/////aaa/    /////aa/   aa////////  x\n");
X    printf("\
X   x  aaaaaaaa/   aa/    aaa/        aaaaaaaaa/    aaaaaaaa/   aaaaaaaaa/  x\n\
X   x                                                                       x\n\
X   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj\n");
X    
X    printf ("\033(B\0332");
X    printf ("\n\033[0m\033#3  This terminal is IN USE by %s\n", myname);
X    printf ("\033[0m\033#4  This terminal is IN USE by %s\n", myname);
X    printf ("\033#5");
X    printf ("\n\n    Version %s for %s (%s)... Derived from a DCL command file\n", VERSION, 
X#ifdef unix
X	    "UNIX",
X#else
X	    "VMS",		/** ICK!!!!! **/
X#endif
X	    hostname);
X    /**  	 Skip the @(#) junk in the banner 			**/
X    printf ("\033[16;0H         %s", (char *) (credits+4));
X#ifdef UENT
X    printf ("\033[24;0H                This terminal is in use by %s", muent.fullname);
X#endif
X    if (virgin == true) {
X       assert(virgin == true);
X       printf("\033[20;25HInitializing....");
X       virgin = false;
X    } else
X       printf("\033[20;25HMagic Word:\033[K");     
X  fflush(stdout);
X  }
X  else {        /** Less verbose... For terminals that can't do 
X		 * neat graphics.
X		 */
X#ifdef UENT
X    printf("This terminal has been locked by %s\n", muent.fullname);
X#endif
X    printf("Terminal is LOCKED, RESERVED\!\n");
X    printf("NO TRESSPASSING.  BEWARE OF DOG.  NOBODY HOME.\n");
X    printf("OUT TO LUNCH.  TRESSPASSERS WILL BE PROSECUTED.\n");
X  }
X  fflush(stdout);
X}
X/** Do the crypt.
X **/
Xchar *mcrypt(arg1, arg2)
Xchar *arg1, *arg2;
X{
Xchar *output;
X
X	output = CRYPT(arg1, arg2);
X	return(output);
X}
X/** Is the a valid password?  Should I exit?  returns NULL if invalid attempt,
X ** else returns a pointer to the name of the person who liberated the 
X ** terminal.
X **/
Xchar *validate(passwd) 
Xchar *passwd; 
X{
Xstruct unode *foo;
X
X      foo = wizusers;
X
X      while (foo != NULL) {
X	   if (!strcmp(foo->passwd, mcrypt(passwd, foo->passwd))) 
X		return (foo->name);
X	   foo = foo->next;
X	}
X    return (NULL);
X}
X/** Load crypted passwords into memory. 
X **/
Xinit_pwd () {
X   register i = 0;
X   struct passwd *hisent = NULL;
X#ifdef WIZGROUP
X   register g = 0;
X   struct group *grp = NULL;
X   struct unode *newone;
X#endif
X#ifdef UENT
X   struct uent fooent;
X#endif
X
X   if ((hisent = getpwuid(getuid())) == NULL) 
X     {
X       printf("Who the hell are you?\n");
X       exit(-1);
X     }
X   else {
X     if ((wizusers = (struct unode *) malloc (sizeof(struct unode))) == NULL) {
X	assert(wizusers = NULL);
X	perror("malloc failed");
X	kill(pid, SIGTERM);
X	exit (-1);
X     }
X#ifdef UENT
X     fooent = getuent(hisent->pw_uid);
X     strcpy(wizusers->name, fooent.fullname);
X#else
X     strcpy(wizusers->name, hisent->pw_name);
X#endif
X     wizusers->next = NULL;
X     strcpy(wizusers->passwd, hisent->pw_passwd);
X   }
X
X#ifdef WIZGROUP
X   if ((grp = getgrnam(WIZGROUP)) != NULL) 
X     while (grp->gr_mem[g] != NULL) {
X       setpwent ();
X       if ((hisent = getpwnam(grp->gr_mem[g++])) != NULL) 
X	 {
X	   if ((newone=(struct unode *)malloc(sizeof(struct unode)))==NULL) {
X	     assert(newone == NULL);
X	     perror("malloc failed");
X	     kill(pid, SIGTERM);
X	     exit (-1);
X	   }
X#ifdef UENT
X	   fooent = getuent(hisent->pw_uid);
X	   strcpy(newone->name, fooent.fullname);
X#else
X	   strcpy(newone->name, hisent->pw_name);
X#endif
X  	   strcpy(newone->passwd, hisent->pw_passwd);
X	   newone->next = wizusers;
X	   wizusers = newone;
X	   assert(wizusers != NULL);
X	 }
X       endpwent();
X     }	
X#endif
X}
________This_Is_The_END________
if test `wc -l < gone.c` -ne 500; then
	echo 'shar: gone.c was damaged during transit (should have been 500 bytes)'
fi
fi		; : end of overwriting check
exit 0
----
lavallee@ulowell.cs.ulowell.edu 		lavallee@hawk.cs.ulowell.edu