122347Spst/* readpass.c: The opiereadpass() library function. 222347Spst 329964Sache%%% portions-copyright-cmetz-96 492906SmarkmPortions of this software are Copyright 1996-1999 by Craig Metz, All Rights 522347SpstReserved. The Inner Net License Version 2 applies to these portions of 622347Spstthe software. 722347SpstYou should have received a copy of the license with this software. If 822347Spstyou didn't get a copy, you may request one from <license@inner.net>. 922347Spst 1022347SpstPortions of this software are Copyright 1995 by Randall Atkinson and Dan 1122347SpstMcDonald, All Rights Reserved. All Rights under this copyright are assigned 1222347Spstto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 1322347SpstLicense Agreement applies to this software. 1422347Spst 1522347Spst History: 1622347Spst 1729964Sache Modified by cmetz for OPIE 2.31. Use usleep() to delay after setting 1829964Sache the terminal attributes; this might help certain buggy 1929964Sache systems. 2022347Spst Modified by cmetz for OPIE 2.3. Use TCSAFLUSH always. 2122347Spst Modified by cmetz for OPIE 2.22. Replaced echo w/ flags. 2222347Spst Really use FUNCTION. 2322347Spst Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al. 2422347Spst Flush extraneous characters up to eol. Handle gobs of possible 2522347Spst erase and kill keys if on a terminal. To do so, use RAW 2622347Spst terminal I/O and handle echo ourselves. (should also help 2722347Spst DOS et al portability). Fixed include order. Re-did MSDOS 2822347Spst and OS/2 includes. Set up VMIN and VTIME. Added some non-UNIX 2922347Spst portability cruft. Limit backspacing and killing. In terminal 3022347Spst mode, eat random other control characters. Added eof handling. 3122347Spst Created at NRL for OPIE 2.2 from opiesubr.c. Change opiestrip_crlf to 3222347Spst opiestripcrlf. Don't strip to seven bits. 3322347Spst*/ 3422347Spst#include "opie_cfg.h" 3522347Spst 3622347Spst#include <stdio.h> 3722347Spst#include <string.h> 3822347Spst#include <stdlib.h> /* ANSI C standard library */ 3922347Spst 4022347Spst#ifdef unix 4122347Spst#include <fcntl.h> /* POSIX file control function headers */ 4222347Spst#include <termios.h> /* POSIX Terminal I/O functions */ 4322347Spst#if HAVE_UNISTD_H 4422347Spst#include <unistd.h> /* POSIX standard definitions */ 4522347Spst#endif /* HAVE_UNISTD_H */ 4622347Spst#include <signal.h> 4722347Spst#include <setjmp.h> 4822347Spst#endif /* unix */ 4922347Spst 5022347Spst#ifdef __MSDOS__ 5122347Spst#include <dos.h> 5222347Spst#endif /* __MSDOS__ */ 5322347Spst 5422347Spst#ifdef __OS2__ 5522347Spst#define INCL_KBD 5622347Spst#include <os2.h> 5722347Spst#include <io.h> 5822347Spst#endif /* __OS2__ */ 5922347Spst 6022347Spst#include "opie.h" 6122347Spst 6222347Spst#define CONTROL(x) (x - 64) 6322347Spst 6422347Spstchar *bsseq = "\b \b"; 6522347Spst 6622347Spst#ifdef unix 6722347Spststatic jmp_buf jmpbuf; 6822347Spst 6922347Spststatic VOIDRET catch FUNCTION((i), int i) 7022347Spst{ 7122347Spst longjmp(jmpbuf, 1); 7222347Spst} 7322347Spst#endif /* unix */ 7422347Spst 7522347Spstchar *opiereadpass FUNCTION((buf, len, flags), char *buf AND int len AND int flags) 7622347Spst{ 7722347Spst#ifdef unix 7822347Spst struct termios attr, orig_attr; 7922347Spst#endif /* unix */ 8022347Spst char erase[5]; 8122347Spst char kill[4]; 8222347Spst char eof[4]; 8322347Spst 8422347Spst memset(erase, 0, sizeof(erase)); 8522347Spst memset(kill, 0, sizeof(kill)); 8622347Spst memset(eof, 0, sizeof(eof)); 8722347Spst 8822347Spst /* This section was heavily rewritten by rja following the model of code 8922347Spst samples circa page 151 of the POSIX Programmer's Guide by Donald Lewine, 9022347Spst ISBN 0-937175-73-0. That book is Copyright 1991 by O'Reilly & 9122347Spst Associates, Inc. All Rights Reserved. I recommend the book to anyone 9222347Spst trying to write portable software. rja */ 9322347Spst 9422347Spst#ifdef unix 9522347Spst if (setjmp(jmpbuf)) 9622347Spst goto error; 9722347Spst 9822347Spst signal(SIGINT, catch); 9922347Spst#endif /* unix */ 10022347Spst 10122347Spst /* Flush any pending output */ 10222347Spst fflush(stderr); 10322347Spst fflush(stdout); 10422347Spst 10522347Spst#ifdef unix 10622347Spst /* Get original terminal attributes */ 10722347Spst if (isatty(0)) { 10822347Spst if (tcgetattr(0, &orig_attr)) 10922347Spst return NULL; 11022347Spst 11122347Spst /* copy terminal settings into attr */ 11222347Spst memcpy(&attr, &orig_attr, sizeof(struct termios)); 11322347Spst 11422347Spst attr.c_lflag &= ~(ECHO | ICANON); 11522347Spst attr.c_lflag |= ISIG; 11622347Spst 11722347Spst attr.c_cc[VMIN] = 1; 11822347Spst attr.c_cc[VTIME] = 0; 11922347Spst 12022347Spst erase[0] = CONTROL('H'); 12122347Spst erase[1] = 127; 12222347Spst 12322347Spst#ifdef CERASE 12422347Spst { 12522347Spst char *e = erase; 12622347Spst 12722347Spst while(*e) 12822347Spst if (*(e++) == CERASE) 12922347Spst break; 13022347Spst 13122347Spst if (!*e) 13222347Spst *e = CERASE; 13322347Spst } 13422347Spst#endif /* CERASE */ 13522347Spst#ifdef VERASE 13622347Spst { 13722347Spst char *e = erase; 13822347Spst 13922347Spst while(*e) 14022347Spst if (*(e++) == attr.c_cc[VERASE]) 14122347Spst break; 14222347Spst 14322347Spst if (!*e) 14422347Spst *e = attr.c_cc[VERASE]; 14522347Spst } 14622347Spst#endif /* VERASE */ 14722347Spst 14822347Spst kill[0] = CONTROL('U'); 14922347Spst#ifdef CKILL 15022347Spst { 15122347Spst char *e = kill; 15222347Spst 15322347Spst while(*e) 15422347Spst if (*(e++) == CKILL) 15522347Spst break; 15622347Spst 15722347Spst if (!*e) 15822347Spst *e = CKILL; 15922347Spst } 16022347Spst#endif /* CKILL */ 16122347Spst#ifdef VKILL 16222347Spst { 16322347Spst char *e = kill; 16422347Spst 16522347Spst while(*e) 16622347Spst if (*(e++) == attr.c_cc[VKILL]) 16722347Spst break; 16822347Spst 16922347Spst if (!*e) 17022347Spst *e = attr.c_cc[VKILL]; 17122347Spst } 17222347Spst#endif /* VKILL */ 17322347Spst 17422347Spst eof[0] = CONTROL('D'); 17522347Spst#ifdef CEOF 17622347Spst { 17722347Spst char *e = eof; 17822347Spst 17922347Spst while(*e) 18022347Spst if (*(e++) == CEOF) 18122347Spst break; 18222347Spst 18322347Spst if (!*e) 18422347Spst *e = CEOF; 18522347Spst } 18622347Spst#endif /* CEOF */ 18722347Spst#ifdef VEOF 18822347Spst { 18922347Spst char *e = eof; 19022347Spst 19122347Spst while(*e) 19222347Spst if (*(e++) == attr.c_cc[VEOF]) 19322347Spst break; 19422347Spst 19522347Spst if (!*e) 19622347Spst *e = VEOF; 19722347Spst } 19822347Spst#endif /* VEOF */ 19922347Spst 20029964Sache#if HAVE_USLEEP 20129964Sache usleep(1); 20229964Sache#endif /* HAVE_USLEEP */ 20329964Sache 20422347Spst if (tcsetattr(0, TCSAFLUSH, &attr)) 20522347Spst goto error; 20629964Sache 20729964Sache#if HAVE_USLEEP 20829964Sache usleep(1); 20929964Sache#endif /* HAVE_USLEEP */ 21022347Spst } 21122347Spst#else /* unix */ 21222347Spst erase[0] = CONTROL('H'); 21322347Spst erase[1] = 127; 21422347Spst kill[0] = CONTROL('U'); 21522347Spst eof[0] = CONTROL('D'); 21622347Spst eof[1] = CONTROL('Z'); 21722347Spst#endif /* unix */ 21822347Spst 21922347Spst { 22022347Spst char *c = buf, *end = buf + len, *e; 22122347Spst#ifdef __OS2__ 22222347Spst KBDKEYINFO keyInfo; 22322347Spst#endif /* __OS2__ */ 22422347Spst 22522347Spstloop: 22622347Spst#ifdef unix 22722347Spst if (read(0, c, 1) != 1) 22822347Spst goto error; 22922347Spst#endif /* unix */ 23022347Spst#ifdef MSDOS 23122347Spst *c = bdos(7, 0, 0); 23222347Spst#endif /* MSDOS */ 23322347Spst#ifdef __OS2__ 23422347Spst KbdCharIn(&keyInfo, 0, 0); 23522347Spst *c = keyInfo.chChar; 23622347Spst#endif /* __OS2__ */ 23722347Spst 23822347Spst if ((*c == '\r') || (*c == '\n')) { 23922347Spst *c = 0; 24022347Spst goto restore; 24122347Spst } 24222347Spst 24322347Spst e = eof; 24422347Spst while(*e) 24522347Spst if (*(e++) == *c) 24622347Spst goto error; 24722347Spst 24822347Spst e = erase; 24922347Spst while(*e) 25022347Spst if (*(e++) == *c) { 25122347Spst if (c <= buf) 25222347Spst goto beep; 25322347Spst 25422347Spst if (flags & 1) 25522347Spst write(1, bsseq, sizeof(bsseq) - 1); 25622347Spst c--; 25722347Spst goto loop; 25822347Spst } 25922347Spst 26022347Spst e = kill; 26122347Spst while(*e) 26222347Spst if (*(e++) == *c) { 26322347Spst if (c <= buf) 26422347Spst goto beep; 26522347Spst 26622347Spst if (flags & 1) 26722347Spst while(c-- > buf) 26822347Spst write(1, bsseq, sizeof(bsseq) - 1); 26922347Spst 27022347Spst c = buf; 27122347Spst goto loop; 27222347Spst } 27322347Spst 27422347Spst if (c < end) { 27522347Spst if (*c < 32) 27622347Spst goto beep; 27722347Spst if (flags & 1) 27822347Spst write(1, c, 1); 27922347Spst c++; 28022347Spst } else { 28122347Spst beep: 28222347Spst *c = CONTROL('G'); 28322347Spst write(1, c, 1); 28422347Spst } 28522347Spst 28622347Spst goto loop; 28722347Spst } 28822347Spst 28922347Spstrestore: 29022347Spst#ifdef unix 29122347Spst /* Restore previous tty modes */ 29222347Spst if (isatty(0)) 29322347Spst if (tcsetattr(0, TCSAFLUSH, &orig_attr)) 29422347Spst return NULL; 29522347Spst 29622347Spst signal(SIGINT, SIG_DFL); 29722347Spst#endif /* unix */ 29822347Spst 29922347Spst /* After the secret key is taken from the keyboard, the line feed is 30022347Spst written to standard error instead of standard output. That means that 30122347Spst anyone using the program from a terminal won't notice, but capturing 30222347Spst standard output will get the key words without a newline in front of 30322347Spst them. */ 30422347Spst if (!(flags & 4)) { 30522347Spst fprintf(stderr, "\n"); 30622347Spst fflush(stderr); 30722347Spst } 30822347Spst 30922347Spst return buf; 31022347Spst 31122347Spsterror: 31222347Spst *buf = 0; 31322347Spst buf = NULL; 31422347Spst goto restore; 31522347Spst} 316