home *** CD-ROM | disk | FTP | other *** search
- /* locktty - lock terminal
- * version 1.1 patchlevel 1
- *
- * compile with cc -o locktty locktty.c -lcurses -ltermcap
- * Usage: locktty [ -p ]
- *
- * 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 messgae is
- * given, and after some time a new password is read.
- * 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.
- * The encrypted password in ~/.lockpasswd can be changed by invoking
- * locktty with the -p option.
- *
- * Please send corrections, improvements, and flames to
- * nickel@cs.tu-berlin.de (Juergen Nickelsen)
- */
-
- #include <curses.h>
- #include <signal.h>
- #include <stdio.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <string.h>
- #include <pwd.h>
-
- #define true 1
- #define false 0
-
- #define SIZE 1024 /* maximum size for password */
- #define PFILE ".lockpasswd" /* name of password file */
- #define MAXPATHLEN 4096 /* this should exceed the real value
- * on nearly all machines */
- #define CLEN 14 /* enough for the crypted pwd's */
- #define SALTC \
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
- /* characters that may appear in the salt */
-
- int
- uid, /* userid */
- fail_count = -1; /* number of failed unlock attempts */
-
- struct passwd
- *pw_entry; /* passwd file entry */
-
- char
- *progname, /* the name of the game */
- newc[CLEN + 1], /* entered pwd (crypted) */
- oldc[CLEN + 1], /* old pwd (crypted) */
- pfilnam[MAXPATHLEN], /* name of password file */
- hostname[20], /* hostname */
- prompt[40] ; /* unlock prompt */
-
- extern int errno ;
- extern char *getenv(), *crypt() ;
-
-
- main(argc, argv)
- int argc ;
- char **argv ;
- {
- char
- tmpl[SIZE+1], /* space for reading from terminal */
- *slp ; /* pointer to slash in progname */
- int pwdfile ; /* read handle for password file */
-
- /* determine name of program */
- progname = *argv ;
- if (slp = strrchr(progname, '/')) {
- progname = slp + 1 ;
- }
-
- /* get host and user names */
-
- if (gethostname(hostname, 19) == -1) {
- hostname[0] = '\0' ;
- }
- uid = getuid() ;
- pw_entry = getpwuid(uid) ;
-
- /* note that pw_entry->pw_dir is the user's home dir */
- if (pw_entry != NULL) {
- if (hostname[0] != '\0') {
- sprintf(prompt, "Unlock %s@%s: ", pw_entry->pw_name, hostname) ;
- } else {
- sprintf(prompt, "Unlock user %s: ", pw_entry->pw_name) ;
- }
- } else if (hostname[0] != '\0') {
- sprintf(prompt, "Unlock host %s ", hostname) ;
- } else {
- sprintf(prompt, "Unlock: " ) ;
- }
-
- /* build name of password file */
-
- strcpy(pfilnam, getenv("HOME")) ;
- strcat(pfilnam, "/") ;
- strcat(pfilnam, PFILE) ;
-
- prepterm() ; /* prepare terminal */
-
- if (argc > 1) { /* check arguments */
- if (strcmp(argv[1], "-p") || argc != 2) {
- reset() ;
- usage() ;
- exit(1) ;
- } else {
- newpwdfile() ; /* -p: new password */
- }
- }
-
- /* Open password file. If it does not exist, create it first. */
- do {
- if ((pwdfile = open(pfilnam, O_RDONLY)) == -1) {
- if (errno == ENOENT) {
- puts("No password file.\r") ;
- fflush(stdout) ;
- newpwdfile() ;
- } else {
- perror(pfilnam) ;
- reset() ;
- exit(errno) ;
- }
- }
- } while (pwdfile == -1) ;
-
- /* read and check old crypt */
- if (read(pwdfile, oldc, CLEN) != CLEN || checkoldc()) {
- fputs("~/", stdout) ;
- fputs(PFILE, stdout) ;
- puts(" in wrong format\r") ;
- fflush(stdout) ;
- reset() ;
- exit(3) ;
- }
-
- /* clear screen and read password */
- do {
- fail_count++;
- clear() ;
- refresh() ;
- fputs(prompt, stdout) ;
- fflush(stdout) ;
-
- readpass(tmpl, false) ;
- strcpy(newc, crypt(tmpl, oldc)) ;
- } while (strcmp(newc, oldc) &&
- (puts("\r\nNo way.\r"), fflush(stdout), sleep(3), 1)) ;
- /* this is not nice, I know */
-
- /* ready */
- reset() ;
- if (fail_count) {
- printf("Failed attemps: %d\nPress return to exit ", fail_count) ;
- fflush(stdout) ;
- gets(oldc);
- }
- exit(0) ;
- }
-
-
- /* read a line in raw mode, terminated by newline or carriage return
- * or exceeding SIZE. Can get interrupted by Ctrl-C if intr != 0. */
- readpass(p, intr)
- char *p ;
- int intr ;
- {
- int n ;
- char c = ' ' ; /* to have a value which is neither */
- /* '\n' nor '\r' */
-
- for (n = 0; n < SIZE && c != '\r' && c != '\n'; n++) {
- c = p[n] = getchar() ;
- if (intr && c == '\003') {
- reset() ;
- exit(1) ;
- }
- }
- p[n] = '\0' ;
- }
-
-
- /* 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()
- {
- int in ;
-
- /* we want to read the password ONLY from a terminal */
- if ((in = open("/dev/tty", O_RDWR)) == -1) {
- perror("/dev/tty") ;
- exit(1) ;
- }
- close(0) ;
- dup(in) ;
- close(1) ;
- dup(in) ;
- close(2) ;
- dup(in) ;
-
- /* make sure we won't get interrupted */
- initscr() ;
- raw() ;
- /* the break key on ISC's at386 console generates a SIGINT even in
- * raw mode */
- signal(SIGINT, SIG_IGN) ;
-
- /* don't echo keystrokes */
- noecho() ;
- }
-
-
- /* put terminal into a state the user is supposed to want after the */
- /* termination of the program. */
- reset()
- {
- int i ;
-
- /* reset modes */
- clear() ;
- noraw() ;
- echo() ;
- /* end curses */
- endwin() ;
-
- /* delete prompt */
- for (i = 0; i < strlen(prompt); i++) {
- putchar('\b');
- putchar(' ');
- putchar('\b');
- }
- }
-
-
- /* create a new password file */
- newpwdfile()
- {
- char tmpl[SIZE+1], salt[3] ;
- int out ;
-
- /* make salt for crypt */
- srand(time(NULL)) ;
- salt[0] = SALTC[rand() % strlen(SALTC)] ;
- salt[1] = SALTC[rand() % strlen(SALTC)] ;
- salt[2] = '\0' ;
-
- /* read and verify password */
- fputs("Enter password: ", stdout) ;
- fflush(stdout) ;
- readpass(tmpl, true) ;
- strcpy(oldc, crypt(tmpl, salt)) ;
- fputs("\r\nRetype password: ", stdout) ;
- fflush(stdout) ;
- readpass(tmpl, true) ;
- strcpy(newc, crypt(tmpl, salt)) ;
- newc[CLEN] = '\0' ;
-
- if (strcmp(oldc, newc)) {
- puts("\r\nNo match.\r") ;
- fflush(stdout) ;
- reset() ;
- exit(2) ;
- }
-
- /* create password file */
- if ((out = open(pfilnam, O_WRONLY | O_CREAT, 0600)) == -1) {
- reset() ;
- perror(pfilnam) ;
- exit(errno) ;
- }
-
- /* write crypt */
- write(out, newc, CLEN) ;
- close(out) ;
- }
-
-
- usage()
- {
- fputs("Usage: ", stdout) ;
- fputs(progname, stdout) ;
- puts(" [ -p ]\r") ;
- }
-
-
- /* returns true if oldc does not look like a valid crypt */
- checkoldc()
- {
- int i ;
-
- /* check for illegal characters */
- for (i = 0; i < CLEN - 1; i++) {
- if (!strchr(SALTC, oldc[i])) {
- return true ;
- }
- }
-
- /* check for terminating null character */
- return oldc[i] ;
- }
-