nickel@kokos.cs.tu-berlin.de (Juergen Nickelsen) (05/06/91)
From README: locktty 1.1 A long time I was looking for a utility to lock the screen of an ASCII terminal, something like lockscreen or xlock on Sunview resp. X Windows, 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. Changes to 1.0: - crypt() and getenv() predeclared (for ANSI compilers) - errno declared (isn't declared in every errno.h) - inserted fflush() after every (f)puts() - unlock prompt is really erased now - the number of failed unlock attempts is displayed after unlock - username and hostname are displayed in the unlock prompt These changes were inspired or suggested by the following people: David A. Berson, Tim Dawson, Greg Miller, Chris Phillips, Randy Hall. The program is without any changes successfully tested on - SunOS 4.1 on sun3, sun4, with cc, gcc, but on a sun3 with cc and -O it throws core sometimes, - Interactive ix/386 2.0.2, - Ultrix Worksystem V2.1 (Rev. 14), - HP-UX 7.00, - IRIX System V Release 3.2.1, - Nixdorf TOS 4.0.12, - IBM AIX 1.2 (PS/2), - ConvexOS Release V9.0. To compile it under Interactive UNIX, type "make isc", otherwise just type "make" to build locktty. Please send corrections, improvements, and flames to nickel@cs.tu-berlin.de (Juergen Nickelsen) #!/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 05/06/1991 12:23 UTC by a0528@gray3 # Source directory /usr/a0528/src/locktty # # existing files will NOT be overwritten unless -c is specified # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 243 -rw-r--r-- Makefile # 1495 -rw-r--r-- README # 1439 -rw-r--r-- locktty.1 # 7014 -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 isc : X make LIBS="$(LIBS) -linet" X clean : X rm -f *.o core *~ $(TARGET) SHAR_EOF chmod 0644 Makefile || echo 'restore of Makefile failed' Wc_c="`wc -c < 'Makefile'`" test 243 -eq "$Wc_c" || echo 'Makefile: original size 243, 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' && locktty 1.1 X A long time I was looking for a utility to lock the screen of an ASCII terminal, something like lockscreen or xlock on Sunview resp. X Windows, 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 Changes to 1.0: X - crypt() and getenv() predeclared (for ANSI compilers) X - errno declared (isn't declared in every errno.h) X - inserted fflush() after every (f)puts() X - unlock prompt is really erased now X - the number of failed unlock attempts is displayed after unlock X - username and hostname are displayed in the unlock prompt X These changes were inspired or suggested by the following people: David A. Berson, Tim Dawson, Greg Miller, Chris Phillips, Randy Hall. X The program is without any changes successfully tested on X - SunOS 4.1 on sun3, sun4, with cc, gcc, but on a sun3 with cc and -O it X throws core sometimes, X - Interactive ix/386 2.0.2, X - Ultrix Worksystem V2.1 (Rev. 14), X - HP-UX 7.00, X - IRIX System V Release 3.2.1, X - Nixdorf TOS 4.0.12, X - IBM AIX 1.2 (PS/2), X - ConvexOS Release V9.0. X To compile it under Interactive UNIX, type "make isc", otherwise just type "make" to build locktty. X Please send corrections, improvements, and flames to X X nickel@cs.tu-berlin.de (Juergen Nickelsen) SHAR_EOF chmod 0644 README || echo 'restore of README failed' Wc_c="`wc -c < 'README'`" test 1495 -eq "$Wc_c" || echo 'README: original size 1495, 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.1" "" .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 OPTIONS .TP .B -p ask for new password in ~/.lockpasswd .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. .br .I Locktty pretends to check the validity of ~/.lockpasswd, but checks only the length and the character set. .br Only the first 8 characters of the password are significant. .SH AUTHOR Juergen Nickelsen, Technische Universitaet Berlin, Germany .br nickel@cs.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 1439 -eq "$Wc_c" || echo 'locktty.1: original size 1439, 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 * version 1.1 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@cs.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> #include <pwd.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 SALTC \ X "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./" X /* characters that may appear in the salt */ X int X uid, /* userid */ X fail_count = -1; /* number of failed unlock attempts */ X struct passwd X *pw_entry; /* passwd file entry */ X 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 hostname[20], /* hostname */ X prompt[40] ; /* unlock prompt */ X extern int errno ; extern char *getenv(), *crypt() ; 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 /* get host and user names */ X X if (gethostname(hostname, 19) == -1) { X hostname[0] = '\0' ; X } X uid = getuid() ; X pw_entry = getpwuid(uid) ; X X /* note that pw_entry->pw_dir is the user's home dir */ X if (pw_entry != NULL) { X if (hostname[0] != '\0') { X sprintf(prompt, "Unlock %s@%s: ", pw_entry->pw_name, hostname) ; X } else { X sprintf(prompt, "Unlock user %s: ", pw_entry->pw_name) ; X } X } else if (hostname[0] != '\0') { X sprintf(prompt, "Unlock host %s ", hostname) ; X } else { X sprintf(prompt, "Unlock: " ) ; X } X X /* build name of password file */ X 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 fflush(stdout) ; 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 fflush(stdout) ; X reset() ; X exit(3) ; X } X X /* clear screen and read password */ X do { X fail_count++; X clear() ; X refresh() ; X fputs(prompt, stdout) ; X fflush(stdout) ; X X readpass(tmpl, false) ; X strcpy(newc, crypt(tmpl, oldc)) ; X } while (strcmp(newc, oldc) && X (puts("\r\nNo way.\r"), fflush(stdout), sleep(3), 1)) ; X /* this is not nice, I know */ X X /* ready */ X reset() ; X if (fail_count) { X printf("Failed attemps: %d\nPress return to exit ", fail_count) ; X fflush(stdout) ; X gets(oldc); X } 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 = ' ' ; /* to have a value which is neither */ X /* '\n' nor '\r' */ 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 int i ; X X /* reset modes */ X clear() ; X noraw() ; X echo() ; X /* end curses */ X endwin() ; X X /* delete prompt */ X for (i = 0; i < strlen(prompt); i++) { X putchar('\b'); X putchar(' '); X putchar('\b'); 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 fflush(stdout) ; X readpass(tmpl, true) ; X strcpy(oldc, crypt(tmpl, salt)) ; X fputs("\r\nRetype password: ", stdout) ; X fflush(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 fflush(stdout) ; 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 7014 -eq "$Wc_c" || echo 'locktty.c: original size 7014, current size' "$Wc_c" fi exit 0 -- Juergen Nickelsen nickel@cs.tu-berlin.de