[net.sources] Lock your terminal

shanks@teneron.UUCP (Dave Shanks) (09/11/85)

The article to which this is a followup contained a shell script for
locking the author's terminal while he was away.  Unfortunately, as
another person pointed out, there are security holes in it.

Here is the source for gone.c which I copied off the net about a year
and a half ago.  I believe it to be secure.  Could some kind wizard
mail me if it is not?   By the way, the origional poster said that it
came from the Rand Corporation Distribution Tape.  Sorry, but I don't
have a manual page.

Dave Shanks	..!tektronix!reed!teneron!shanks
Teneron Corp.
6700 SW 105th   Suite 200
Beaverton, OR  97005
(503) 646-1599

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# gone.c

echo x - gone.c
cat > "gone.c" << '//E*O*F gone.c//'

/*
/*      this program ignores its arguments, and won't do ANYTHING
/*      until you type your password.  All signals are ignored.
/*
/*      If someone else wants to use your terminal while you are away,
/*      he'll have to hang it up and start over.  This would be hard
/*      to fix and would require gone to be setuid root, because you
/*      would have to spawn a login, then put back your userid into
/*      /etc/wtmp.  Also, while he is logged in, your `gone' disappears
/*      from the output of `w'.  FURTHERmore, you have to remember
/*      that when he logs off, you are back in the loop waiting for
/*      your password so you can continue...
/*
/*      Dave Yost, Rand, Aug 27, 1981
/**/

#include <whoami.h>
#include <stdio.h>
#include <pwd.h>
#include <sgtty.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>

#define Block
typedef int void;    /* if old C compiler */

#define MAXALARM ((unsigned int) 65535)

extern char *crypt ();
extern char *strcpy ();
extern char *malloc ();
char   *xgetpass ();
int     setpwent ();
char   *r1bindex ();
struct  passwd *whoisthis ();
extern char *strsav ();

main(argc, argv)
int argc;
char **argv;
{
	char *fullname;
	struct  passwd *pwd;

	if (argc <= 1) {
		fprintf (stderr,
			 "Say something about how long you will be gone and where.\n");
		exit (1);
	}

	if (NULL == (pwd = whoisthis ())) {
		fprintf (stderr, "Who are you?\n");
		exit (1);
	}

	if (*pwd->pw_passwd == '\0') {
		fprintf (stderr, "Your password is null\n");
		exit (1);
	}

	fullname = r1bindex (pwd->pw_gecos, ';');
	printf ("This terminal is in use by %s (%s) on %s\n",
		pwd->pw_name, fullname, sysname);
	printf ("If you really must use it, you will have to turn it off and on again.\n");
	(void) alarm (MAXALARM);
	settty ();
	for (;;) {
		register char *namep;
		namep = crypt (xgetpass ("Password: "), pwd->pw_passwd);
		if (!strcmp (namep, pwd->pw_passwd)) {
			prttime ((long ) (MAXALARM - alarm (0)) / 60);
			break;
		}
		fprintf (stderr, "Password incorrect\n");
	}
	unsettty ();
	exit (0);
}

int ttyset;
struct sgttyb outstty;

settty ()
{
    register int tmp;

    for (tmp = 1; tmp < NSIG; ++tmp) {
	switch (tmp) {
	case SIGHUP:
	case SIGTERM:
	    break;
	default:
	    (void) signal (tmp, SIG_IGN);
	    break;
	}
    }

    if (gtty (0, &outstty) >= 0) {
	ttyset = 1;
	tmp = outstty.sg_flags;
	outstty.sg_flags &= ~ECHO;
	if (0 > stty (0, &outstty)) {
	    fprintf (stderr, "Can't set tty modes.\n");
	    exit (1);
	}
	outstty.sg_flags = tmp;
    }
}

unsettty ()
{
    if (ttyset)
	(void) stty (0, &outstty);
}

char *
xgetpass (prompt)
char *prompt;
{
	register char *p;
	register int c;
	static char pbuf[9];

	fprintf (stderr, prompt);
	for (p = pbuf; (c = getchar ()) != '\n' && c != EOF; ) {
		if (p < &pbuf[8])
			*p++ = c;
	}
	*p = '\0';
	fprintf (stderr, "\n");
	return pbuf;
}

/*
 * prttime prints a time in hours and minutes.
 */
prttime (tim)
long tim;
{
	printf ("You were gone for ");
	if (tim >= 60)
		printf ("%ld:%02ld\n", tim / 60, tim % 60);
	else if ((tim %= 60) > 0)
		printf ("%ld minute%s\n", tim, tim == 1 ? "" : "s");
	else
		printf ("less than a minute\n");
	return;
}

/*
 * r1bindex (str, chr) stands for Right plus 1 or Beginning index of
 *      chr in str.  I.e. return ptr 1 past LAST occurance of chr in
 *      str, OR beginning of the string if str doesn't contain chr.
 */

char *
r1bindex (str, chr)
register char *str;
register int chr;
{
	register char *cp;

	for (cp = str; *cp; cp++) ;
	--cp;
	while (cp >= str && *cp != chr)
		--cp;
	return ++cp;
}

#define ROOTUID 0

struct passwd *
whoisthis ()
{
	struct stat statbuf;
	register int uid;
	register struct passwd *pwd;
	extern struct passwd *really();
	extern struct passwd *getpwuid();

	if (   (   fstat (0, &statbuf) >= 0
		&& (uid = statbuf.st_uid) != ROOTUID
	       )
	    || (uid = getuid()) != ROOTUID
	   ) {
		setpwent();
		pwd = getpwuid (uid);
		endpwent();
		if (NULL != pwd)
			return pwd;
	}
	return really ();
}

struct passwd *
really ()
{
	register char *rootpass;
	register struct passwd *pwd;
	extern struct passwd *getpwuid();
	extern struct passwd *getpwnam();

	setpwent();
	pwd = getpwuid (ROOTUID);
	endpwent();
	rootpass = strsav (pwd->pw_passwd);
	for (;;) Block {
		register int nwho;
		char who[20];
		fprintf (stderr, "Who is this, really?\n");
		(void) fflush(stdout);
		who[0] = '\0';
		(void) fgets (who, sizeof who - 2, stdin);
		nwho = strlen(who);
		if (who[nwho - 1] == '\n')
			who[--nwho] = '\0';
		if (nwho != 0) {
		    setpwent();
		    pwd = getpwnam (who);
		    endpwent();
		    if (NULL != pwd) {
			    pwd->pw_passwd = rootpass;
			    return pwd;
		    }
		}
	}
}

char *
strsav (str)
register char *str;
{
    register char *sav;

    if (!(sav = malloc ((unsigned int) strlen (str) + 1))) {
	fprintf (stderr, "Ran out of memory\n");
	exit (1);
    }
    (void) strcpy (sav, str);
    return sav;
}


//E*O*F gone.c//

exit 0