[alt.sources] locktty - lock terminal, Part 01/01

uff67@granat.cs.tu-berlin.de (Auer u. Nickelsen) (04/15/91)

from README:

A long time I was looking for a utility to lock the screen of an ASCII
terminal, something like lockscreen or xlock, but didn't find
anything.

OK, here is "locktty". To keep it portable even for systems with a
shadow password file, I keep the crypted password in a file in the
user's home directory. If the file does not exist, the user is
prompted for a password.

The password file can be changed by using the -p option.

The program is without any changes successfully tested on
  - SunOS 4.1,
  - Interactive ix/386 2.0.2, 
  - Ultrix Worksystem V2.1 (Rev. 14), 
  - HP-UX 7.00.

Just type "make".

Please send corrections, improvements, and flames to
	nickel@w104zrz.zrz.tu-berlin.de

#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 04/15/1991 16:15 UTC by a0528@gray3
# Source directory /usr/a0528/gaga
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    209 -rw-r--r-- Makefile
#    690 -rw-r--r-- README
#   1371 -rw-r--r-- locktty.1
#   5663 -rw-r--r-- locktty.c
#
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
CC = cc
LIBS = -lcurses -ltermcap
SHELL = /bin/sh
CFLAGS = -O
SOURCE = locktty.c
TARGET = locktty
X
$(TARGET) : $(SOURCE)
X	$(CC) $(CFLAGS) -o $(TARGET) $(SOURCE) $(LIBS)
X
clean : 
X	rm -f *.o core *~ $(TARGET)
X
SHAR_EOF
chmod 0644 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 209 -eq "$Wc_c" ||
	echo 'Makefile: original size 209, current size' "$Wc_c"
fi
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
	echo 'x - skipping README (File already exists)'
else
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
A long time I was looking for a utility to lock the screen of an ASCII
terminal, something like lockscreen or xlock, but didn't find
anything.
X
OK, here is "locktty". To keep it portable even for systems with a
shadow password file, I keep the crypted password in a file in the
user's home directory. If the file does not exist, the user is
prompted for a password.
X
The password file can be changed by using the -p option.
X
The program is without any changes successfully tested on
X  - SunOS 4.1,
X  - Interactive ix/386 2.0.2, 
X  - Ultrix Worksystem V2.1 (Rev. 14), 
X  - HP-UX 7.00.
X
Just type "make".
X
Please send corrections, improvements, and flames to
X	nickel@w104zrz.zrz.tu-berlin.de
SHAR_EOF
chmod 0644 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 690 -eq "$Wc_c" ||
	echo 'README: original size 690, current size' "$Wc_c"
fi
# ============= locktty.1 ==============
if test -f 'locktty.1' -a X"$1" != X"-c"; then
	echo 'x - skipping locktty.1 (File already exists)'
else
echo 'x - extracting locktty.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'locktty.1' &&
.TH LOCKTTY 1L "LOCKTTY 1.0" ""
.SH NAME
locktty - lock terminal
.SH SYNOPSIS
.B locktty
[
.B -p
]
.PP
.SH DESCRIPTION
.I Locktty\^
puts the terminal into raw mode, clears the screen, and
prompts the user for a password. Entered passwords are crypted and
checked against a crypted password in a file in the users' home
directory (~/.lockpasswd). If the correct password is given, the
terminal is set into normal state again. If not, a message is given,
and after some time a new password is read.
.PP
If the file ~/.lockpasswd does not exist, the user is prompted for
a password twice before the screen is locked. This password is
crypted and stored in ~/.lockpasswd.
.PP
The encrypted password in ~/.lockpasswd can be changed by invoking
.I locktty 
with the 
.B -p 
option.
.SH DIAGNOSTICS
.TP
~/.lockpasswd in wrong format
~/.lockpasswd does not appear to be a valid password crypt.
.SH FILES
$HOME/.lockpasswd             encrypted password
.SH BUGS
I haven't found a portable way to flush input before reading a new
password.
.br
The executable is huge compared to the source, but I couldn't resist
using the curses library.
.br
.I Locktty
pretends to check the validity of ~/.lockpasswd, but checks only the
length and the character set.
.SH AUTHOR
Juergen Nickelsen, Technische Universitaet Berlin, Germany
.br
nickel@w104zrz.zrz.tu-berlin.de
.SH COPYRIGHTS
None.
SHAR_EOF
chmod 0644 locktty.1 ||
echo 'restore of locktty.1 failed'
Wc_c="`wc -c < 'locktty.1'`"
test 1371 -eq "$Wc_c" ||
	echo 'locktty.1: original size 1371, current size' "$Wc_c"
fi
# ============= locktty.c ==============
if test -f 'locktty.c' -a X"$1" != X"-c"; then
	echo 'x - skipping locktty.c (File already exists)'
else
echo 'x - extracting locktty.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'locktty.c' &&
/* locktty - lock terminal 
X *
X * compile with cc -o locktty locktty.c -lcurses -ltermcap
X * Usage: locktty [ -p ]
X *
X * locktty puts the terminal into raw mode, clears the screen, and
X * prompts the user for a password. Entered passwords are crypted and
X * checked against a crypted password in a file in the users' home
X * directory (~/.lockpasswd). If the correct password is given, the
X * terminal is set into normal state again. If not, a messgae is
X * given, and after some time a new password is read.
X * If the file ~/.lockpasswd does not exist, the user is prompted for
X * a password twice before the screen is locked. This password is
X * crypted and stored in ~/.lockpasswd.
X * The encrypted password in ~/.lockpasswd can be changed by invoking
X * locktty with the -p option.
X *
X * Please send corrections, improvements, and flames to
X *	nickel@w104zrz.zrz.tu-berlin.de (Juergen Nickelsen)
X */
X
#include <curses.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
X
#define true	1
#define false	0
X
#define SIZE	1024		/* maximum size for password */
#define PFILE	".lockpasswd"	/* name of password file */
#define MAXPATHLEN	4096	/* this should exceed the real value
X				 * on nearly all machines */
#define CLEN	14		/* enough for the crypted pwd's */
#define LOCKP	"Unlock: "	/* prompt in "lock" mode */
#define SALTC	\
X	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
X				/* characters that may appear in the salt */
char
X    *progname,			/* the name of the game */
X    newc[CLEN + 1],		/* entered pwd (crypted) */
X    oldc[CLEN + 1],		/* old pwd (crypted) */
X    pfilnam[MAXPATHLEN] ;	/* name of password file */
X
X
main(argc, argv)
int argc ;
char **argv ;
{
X    char 
X	tmpl[SIZE+1],		/* space for reading from terminal */
X	*slp ;			/* pointer to slash in progname */
X    int pwdfile ;		/* read handle for password file */
X
X    /* determine name of program */
X    progname = *argv ;
X    if (slp = strrchr(progname, '/')) {
X	progname = slp + 1 ;
X    }
X
X    /* build name of password file */
X    strcpy(pfilnam, getenv("HOME")) ;
X    strcat(pfilnam, "/") ;
X    strcat(pfilnam, PFILE) ;
X
X    prepterm() ;		/* prepare terminal */
X
X    if (argc > 1) {		/* check arguments */
X	if (strcmp(argv[1], "-p") || argc != 2) {
X	    reset() ;
X	    usage() ;
X	    exit(1) ;
X	} else {
X	    newpwdfile() ;	/* -p: new password */
X	}
X    }
X
X    /* Open password file. If it does not exist, create it first. */
X    do {
X	if ((pwdfile = open(pfilnam, O_RDONLY)) == -1) {
X	    if (errno == ENOENT) {
X		puts("No password file.\r") ;
X		newpwdfile() ;
X	    } else {
X		perror(pfilnam) ;
X		reset() ;
X		exit(errno) ;
X	    }
X	}
X    } while (pwdfile == -1) ;
X    
X    /* read and check old crypt */
X    if (read(pwdfile, oldc, CLEN) != CLEN || checkoldc()) {
X	fputs("~/", stdout) ;
X	fputs(PFILE, stdout) ;
X	puts(" in wrong format\r") ;
X	reset() ;
X	exit(3) ;
X    }
X
X    /* clear screen and read password */
X    do {
X	clear() ;
X	refresh() ;
X	fputs(LOCKP, stdout) ;
X
X	readpass(tmpl, false) ;
X	strcpy(newc, crypt(tmpl, oldc)) ;
X    } while (strcmp(newc, oldc) && (puts("\r\nNo way.\r"), sleep(3), 1)) ;
X
X    /* ready */
X    reset() ;
X    exit(0) ;
}
X
X
/* read a line in raw mode, terminated by newline or carriage return
X * or exceeding SIZE. Can get interrupted by Ctrl-C if intr != 0. */
readpass(p, intr)
char *p ;
int intr ;
{
X    int n ;
X    char c = ' ' ;
X
X    for (n = 0; n < SIZE && c != '\r' && c != '\n'; n++) {
X	c = p[n] = getchar() ;
X	if (intr && c == '\003') {
X	    reset() ;
X	    exit(1) ;
X	}
X    }
X    p[n] = '\0' ;
}
X
X
/* prepare terminal: open stdin and stdout to /dev/tty, don't echo */
/* characters and make sure we get no signal (raw mode + some help). */
prepterm()
{
X    int in ;
X
X    /* we want to read the password ONLY from a terminal */
X    if ((in = open("/dev/tty", O_RDWR)) == -1) {
X	perror("/dev/tty") ;
X	exit(1) ;
X    }
X    close(0) ;
X    dup(in) ;
X    close(1) ;
X    dup(in) ;
X    close(2) ;
X    dup(in) ;
X
X    /* make sure we won't get interrupted */
X    initscr() ;
X    raw() ;
X    /* the break key on ISC's at386 console generates a SIGINT even in
X     * raw mode */
X    signal(SIGINT, SIG_IGN) ;
X
X    /* don't echo keystrokes */
X    noecho() ;
}
X
X
/* put terminal into a state the user is supposed to want after the */
/* termination of the program. */
reset()
{
X    clear() ;
X    noraw() ;
X    echo() ;
X    endwin() ;
X    putchar('\r') ;
X
}
X
X
/* create a new password file */
newpwdfile()
{
X    char tmpl[SIZE+1], salt[3] ;
X    int out ;
X
X    /* make salt for crypt */
X    srand(time(NULL)) ;
X    salt[0] = SALTC[rand() % strlen(SALTC)] ;
X    salt[1] = SALTC[rand() % strlen(SALTC)] ;
X    salt[3] = '\0' ;
X
X    /* read and verify password */
X    fputs("Enter password:  ", stdout) ;
X    readpass(tmpl, true) ;
X    strcpy(oldc, crypt(tmpl, salt)) ;
X    fputs("\r\nRetype password: ", stdout) ;
X    readpass(tmpl, true) ;
X    strcpy(newc, crypt(tmpl, salt)) ;
X    newc[CLEN] = '\0' ;
X
X    if (strcmp(oldc, newc)) {
X	puts("\r\nNo match.\r") ;
X	reset() ;
X	exit(2) ;
X    }
X
X    /* create password file */
X    if ((out = open(pfilnam, O_WRONLY | O_CREAT, 0600)) == -1) {
X	reset() ;
X	perror(pfilnam) ;
X	exit(errno) ;
X    }
X
X    /* write crypt */
X    write(out, newc, CLEN) ;
X    close(out) ;
}
X
X
usage()
{
X    fputs("Usage: ", stdout) ;
X    fputs(progname, stdout) ;
X    puts(" [ -p ]\r") ;
}
X
X
/* returns true if oldc does not look like a valid crypt */
checkoldc()
{
X    int i ;
X
X    /* check for illegal characters */
X    for (i = 0; i < CLEN - 1; i++) {
X	if (!strchr(SALTC, oldc[i])) {
X	    return true ;
X	}
X    }
X
X    /* check for terminating null character */
X    return oldc[i] ;
}
SHAR_EOF
chmod 0644 locktty.c ||
echo 'restore of locktty.c failed'
Wc_c="`wc -c < 'locktty.c'`"
test 5663 -eq "$Wc_c" ||
	echo 'locktty.c: original size 5663, current size' "$Wc_c"
fi
exit 0