home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3292 / locktty.c < prev    next >
C/C++ Source or Header  |  1991-05-06  |  7KB  |  305 lines

  1. /* locktty - lock terminal 
  2.  * version 1.1
  3.  *
  4.  * compile with cc -o locktty locktty.c -lcurses -ltermcap
  5.  * Usage: locktty [ -p ]
  6.  *
  7.  * locktty puts the terminal into raw mode, clears the screen, and
  8.  * prompts the user for a password. Entered passwords are crypted and
  9.  * checked against a crypted password in a file in the users' home
  10.  * directory (~/.lockpasswd). If the correct password is given, the
  11.  * terminal is set into normal state again. If not, a messgae is
  12.  * given, and after some time a new password is read.
  13.  * If the file ~/.lockpasswd does not exist, the user is prompted for
  14.  * a password twice before the screen is locked. This password is
  15.  * crypted and stored in ~/.lockpasswd.
  16.  * The encrypted password in ~/.lockpasswd can be changed by invoking
  17.  * locktty with the -p option.
  18.  *
  19.  * Please send corrections, improvements, and flames to
  20.  *    nickel@cs.tu-berlin.de (Juergen Nickelsen)
  21.  */
  22.  
  23. #include <curses.h>
  24. #include <signal.h>
  25. #include <stdio.h>
  26. #include <errno.h>
  27. #include <fcntl.h>
  28. #include <string.h>
  29. #include <pwd.h>
  30.  
  31. #define true    1
  32. #define false    0
  33.  
  34. #define SIZE    1024        /* maximum size for password */
  35. #define PFILE    ".lockpasswd"    /* name of password file */
  36. #define MAXPATHLEN    4096    /* this should exceed the real value
  37.                  * on nearly all machines */
  38. #define CLEN    14        /* enough for the crypted pwd's */
  39. #define SALTC    \
  40.     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
  41.                 /* characters that may appear in the salt */
  42.  
  43. int 
  44.     uid,            /* userid */
  45.     fail_count = -1;        /* number of failed unlock attempts */
  46.  
  47. struct passwd 
  48.     *pw_entry;            /* passwd file entry */
  49.  
  50. char
  51.     *progname,            /* the name of the game */
  52.     newc[CLEN + 1],        /* entered pwd (crypted) */
  53.     oldc[CLEN + 1],        /* old pwd (crypted) */
  54.     pfilnam[MAXPATHLEN],    /* name of password file */
  55.     hostname[20],        /* hostname */
  56.     prompt[40] ;        /* unlock prompt */
  57.  
  58. extern int errno ;
  59. extern char *getenv(), *crypt() ;
  60.  
  61.  
  62. main(argc, argv)
  63. int argc ;
  64. char **argv ;
  65. {
  66.     char 
  67.     tmpl[SIZE+1],        /* space for reading from terminal */
  68.     *slp ;            /* pointer to slash in progname */
  69.     int pwdfile ;        /* read handle for password file */
  70.  
  71.     /* determine name of program */
  72.     progname = *argv ;
  73.     if (slp = strrchr(progname, '/')) {
  74.     progname = slp + 1 ;
  75.     }
  76.  
  77.     /* get host and user names */
  78.  
  79.     if (gethostname(hostname, 19) == -1) {
  80.     hostname[0] = '\0' ;
  81.     }
  82.     uid = getuid() ;
  83.     pw_entry = getpwuid(uid) ;
  84.  
  85.     /* note that pw_entry->pw_dir is the user's home dir */
  86.     if (pw_entry != NULL) {
  87.     if (hostname[0] != '\0') {
  88.         sprintf(prompt, "Unlock %s@%s: ", pw_entry->pw_name, hostname) ;
  89.     } else {
  90.         sprintf(prompt, "Unlock user %s: ", pw_entry->pw_name) ;
  91.     }
  92.     } else if (hostname[0] != '\0') {
  93.     sprintf(prompt, "Unlock host %s ", hostname) ;
  94.     } else {
  95.     sprintf(prompt, "Unlock: " ) ;
  96.     }
  97.  
  98.     /* build name of password file */
  99.     
  100.     strcpy(pfilnam, getenv("HOME")) ;
  101.     strcat(pfilnam, "/") ;
  102.     strcat(pfilnam, PFILE) ;
  103.  
  104.     prepterm() ;        /* prepare terminal */
  105.  
  106.     if (argc > 1) {        /* check arguments */
  107.     if (strcmp(argv[1], "-p") || argc != 2) {
  108.         reset() ;
  109.         usage() ;
  110.         exit(1) ;
  111.     } else {
  112.         newpwdfile() ;    /* -p: new password */
  113.     }
  114.     }
  115.  
  116.     /* Open password file. If it does not exist, create it first. */
  117.     do {
  118.     if ((pwdfile = open(pfilnam, O_RDONLY)) == -1) {
  119.         if (errno == ENOENT) {
  120.         puts("No password file.\r") ;
  121.         fflush(stdout) ;
  122.         newpwdfile() ;
  123.         } else {
  124.         perror(pfilnam) ;
  125.         reset() ;
  126.         exit(errno) ;
  127.         }
  128.     }
  129.     } while (pwdfile == -1) ;
  130.     
  131.     /* read and check old crypt */
  132.     if (read(pwdfile, oldc, CLEN) != CLEN || checkoldc()) {
  133.     fputs("~/", stdout) ;
  134.     fputs(PFILE, stdout) ;
  135.     puts(" in wrong format\r") ;
  136.     fflush(stdout) ;
  137.     reset() ;
  138.     exit(3) ;
  139.     }
  140.  
  141.     /* clear screen and read password */
  142.     do {
  143.         fail_count++;
  144.     clear() ;
  145.     refresh() ;
  146.     fputs(prompt, stdout) ;
  147.     fflush(stdout) ;
  148.  
  149.     readpass(tmpl, false) ;
  150.     strcpy(newc, crypt(tmpl, oldc)) ;
  151.     } while (strcmp(newc, oldc) && 
  152.          (puts("\r\nNo way.\r"), fflush(stdout), sleep(3), 1)) ;
  153.                 /* this is not nice, I know */
  154.  
  155.     /* ready */
  156.     reset() ;
  157.     if (fail_count) {  
  158.     printf("Failed attemps: %d\nPress return to exit ", fail_count) ;
  159.     fflush(stdout) ;
  160.     gets(oldc);
  161.     }
  162.     exit(0) ;
  163. }
  164.  
  165.  
  166. /* read a line in raw mode, terminated by newline or carriage return
  167.  * or exceeding SIZE. Can get interrupted by Ctrl-C if intr != 0. */
  168. readpass(p, intr)
  169. char *p ;
  170. int intr ;
  171. {
  172.     int n ;
  173.     char c = ' ' ;        /* to have a value which is neither */
  174.                 /* '\n' nor '\r' */
  175.  
  176.     for (n = 0; n < SIZE && c != '\r' && c != '\n'; n++) {
  177.     c = p[n] = getchar() ;
  178.     if (intr && c == '\003') {
  179.         reset() ;
  180.         exit(1) ;
  181.     }
  182.     }
  183.     p[n] = '\0' ;
  184. }
  185.  
  186.  
  187. /* prepare terminal: open stdin and stdout to /dev/tty, don't echo */
  188. /* characters and make sure we get no signal (raw mode + some help). */
  189. prepterm()
  190. {
  191.     int in ;
  192.  
  193.     /* we want to read the password ONLY from a terminal */
  194.     if ((in = open("/dev/tty", O_RDWR)) == -1) {
  195.     perror("/dev/tty") ;
  196.     exit(1) ;
  197.     }
  198.     close(0) ;
  199.     dup(in) ;
  200.     close(1) ;
  201.     dup(in) ;
  202.     close(2) ;
  203.     dup(in) ;
  204.  
  205.     /* make sure we won't get interrupted */
  206.     initscr() ;
  207.     raw() ;
  208.     /* the break key on ISC's at386 console generates a SIGINT even in
  209.      * raw mode */
  210.     signal(SIGINT, SIG_IGN) ;
  211.  
  212.     /* don't echo keystrokes */
  213.     noecho() ;
  214. }
  215.  
  216.  
  217. /* put terminal into a state the user is supposed to want after the */
  218. /* termination of the program. */
  219. reset()
  220. {
  221.     int i ;
  222.  
  223.     /* reset modes */
  224.     clear() ;
  225.     noraw() ;
  226.     echo() ;
  227.     /* end curses */
  228.     endwin() ;
  229.  
  230.     /* delete prompt */
  231.     for (i = 0; i < strlen(prompt); i++) {
  232.     putchar('\b');
  233.     putchar(' ');
  234.     putchar('\b');
  235.     }
  236. }
  237.  
  238.  
  239. /* create a new password file */
  240. newpwdfile()
  241. {
  242.     char tmpl[SIZE+1], salt[3] ;
  243.     int out ;
  244.  
  245.     /* make salt for crypt */
  246.     srand(time(NULL)) ;
  247.     salt[0] = SALTC[rand() % strlen(SALTC)] ;
  248.     salt[1] = SALTC[rand() % strlen(SALTC)] ;
  249.     salt[3] = '\0' ;
  250.  
  251.     /* read and verify password */
  252.     fputs("Enter password:  ", stdout) ;
  253.     fflush(stdout) ;
  254.     readpass(tmpl, true) ;
  255.     strcpy(oldc, crypt(tmpl, salt)) ;
  256.     fputs("\r\nRetype password: ", stdout) ;
  257.     fflush(stdout) ;
  258.     readpass(tmpl, true) ;
  259.     strcpy(newc, crypt(tmpl, salt)) ;
  260.     newc[CLEN] = '\0' ;
  261.  
  262.     if (strcmp(oldc, newc)) {
  263.     puts("\r\nNo match.\r") ;
  264.     fflush(stdout) ;
  265.     reset() ;
  266.     exit(2) ;
  267.     }
  268.  
  269.     /* create password file */
  270.     if ((out = open(pfilnam, O_WRONLY | O_CREAT, 0600)) == -1) {
  271.     reset() ;
  272.     perror(pfilnam) ;
  273.     exit(errno) ;
  274.     }
  275.  
  276.     /* write crypt */
  277.     write(out, newc, CLEN) ;
  278.     close(out) ;
  279. }
  280.  
  281.  
  282. usage()
  283. {
  284.     fputs("Usage: ", stdout) ;
  285.     fputs(progname, stdout) ;
  286.     puts(" [ -p ]\r") ;
  287. }
  288.  
  289.  
  290. /* returns true if oldc does not look like a valid crypt */
  291. checkoldc()
  292. {
  293.     int i ;
  294.  
  295.     /* check for illegal characters */
  296.     for (i = 0; i < CLEN - 1; i++) {
  297.     if (!strchr(SALTC, oldc[i])) {
  298.         return true ;
  299.     }
  300.     }
  301.  
  302.     /* check for terminating null character */
  303.     return oldc[i] ;
  304. }
  305.