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