readpass.c revision 22347
1/* readpass.c: The opiereadpass() library function.
2
3%%% portions-copyright-cmetz
4Portions of this software are Copyright 1996 by Craig Metz, All Rights
5Reserved. The Inner Net License Version 2 applies to these portions of
6the software.
7You should have received a copy of the license with this software. If
8you didn't get a copy, you may request one from <license@inner.net>.
9
10Portions of this software are Copyright 1995 by Randall Atkinson and Dan
11McDonald, All Rights Reserved. All Rights under this copyright are assigned
12to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
13License Agreement applies to this software.
14
15        History:
16
17	Modified by cmetz for OPIE 2.3. Use TCSAFLUSH always.
18	Modified by cmetz for OPIE 2.22. Replaced echo w/ flags.
19               Really use FUNCTION.
20	Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al.
21               Flush extraneous characters up to eol. Handle gobs of possible
22               erase and kill keys if on a terminal. To do so, use RAW
23               terminal I/O and handle echo ourselves. (should also help
24               DOS et al portability). Fixed include order. Re-did MSDOS
25	       and OS/2 includes. Set up VMIN and VTIME. Added some non-UNIX
26	       portability cruft. Limit backspacing and killing. In terminal
27               mode, eat random other control characters. Added eof handling.
28        Created at NRL for OPIE 2.2 from opiesubr.c. Change opiestrip_crlf to
29               opiestripcrlf. Don't strip to seven bits.
30*/
31#include "opie_cfg.h"
32
33#include <stdio.h>
34#include <string.h>
35#include <stdlib.h>	/* ANSI C standard library */
36
37#ifdef unix
38#include <fcntl.h>      /* POSIX file control function headers */
39#include <termios.h>    /* POSIX Terminal I/O functions */
40#if HAVE_UNISTD_H
41#include <unistd.h>     /* POSIX standard definitions */
42#endif /* HAVE_UNISTD_H */
43#include <signal.h>
44#include <setjmp.h>
45#endif /* unix */
46
47#ifdef __MSDOS__
48#include <dos.h>
49#endif /* __MSDOS__ */
50
51#ifdef __OS2__
52#define INCL_KBD
53#include <os2.h>
54#include <io.h>
55#endif /* __OS2__ */
56
57#include "opie.h"
58
59#define CONTROL(x) (x - 64)
60
61char *bsseq = "\b \b";
62
63#ifdef unix
64static jmp_buf jmpbuf;
65
66static VOIDRET catch FUNCTION((i), int i)
67{
68  longjmp(jmpbuf, 1);
69}
70#endif /* unix */
71
72char *opiereadpass FUNCTION((buf, len, flags), char *buf AND int len AND int flags)
73{
74#ifdef unix
75  struct termios attr, orig_attr;
76#endif /* unix */
77  char erase[5];
78  char kill[4];
79  char eof[4];
80
81  memset(erase, 0, sizeof(erase));
82  memset(kill, 0, sizeof(kill));
83  memset(eof, 0, sizeof(eof));
84
85  /* This section was heavily rewritten by rja following the model of code
86     samples circa page 151 of the POSIX Programmer's Guide by Donald Lewine,
87     ISBN 0-937175-73-0. That book is Copyright 1991 by O'Reilly &
88     Associates, Inc. All Rights Reserved. I recommend the book to anyone
89     trying to write portable software. rja */
90
91#ifdef unix
92  if (setjmp(jmpbuf))
93    goto error;
94
95  signal(SIGINT, catch);
96#endif /* unix */
97
98  /* Flush any pending output */
99  fflush(stderr);
100  fflush(stdout);
101
102#ifdef unix
103  /* Get original terminal attributes */
104  if (isatty(0)) {
105    if (tcgetattr(0, &orig_attr))
106      return NULL;
107
108    /* copy terminal settings into attr */
109    memcpy(&attr, &orig_attr, sizeof(struct termios));
110
111    attr.c_lflag &= ~(ECHO | ICANON);
112    attr.c_lflag |= ISIG;
113
114    attr.c_cc[VMIN] = 1;
115    attr.c_cc[VTIME] = 0;
116
117    erase[0] = CONTROL('H');
118    erase[1] = 127;
119
120#ifdef CERASE
121    {
122    char *e = erase;
123
124    while(*e)
125      if (*(e++) == CERASE)
126        break;
127
128    if (!*e)
129      *e = CERASE;
130    }
131#endif /* CERASE */
132#ifdef VERASE
133    {
134    char *e = erase;
135
136    while(*e)
137      if (*(e++) == attr.c_cc[VERASE])
138        break;
139
140    if (!*e)
141      *e = attr.c_cc[VERASE];
142    }
143#endif /* VERASE */
144
145    kill[0] = CONTROL('U');
146#ifdef CKILL
147    {
148    char *e = kill;
149
150    while(*e)
151      if (*(e++) == CKILL)
152        break;
153
154    if (!*e)
155      *e = CKILL;
156    }
157#endif /* CKILL */
158#ifdef VKILL
159    {
160    char *e = kill;
161
162    while(*e)
163      if (*(e++) == attr.c_cc[VKILL])
164        break;
165
166    if (!*e)
167      *e = attr.c_cc[VKILL];
168    }
169#endif /* VKILL */
170
171    eof[0] = CONTROL('D');
172#ifdef CEOF
173    {
174    char *e = eof;
175
176    while(*e)
177      if (*(e++) == CEOF)
178        break;
179
180    if (!*e)
181      *e = CEOF;
182    }
183#endif /* CEOF */
184#ifdef VEOF
185    {
186    char *e = eof;
187
188    while(*e)
189      if (*(e++) == attr.c_cc[VEOF])
190        break;
191
192    if (!*e)
193      *e = VEOF;
194    }
195#endif /* VEOF */
196
197    if (tcsetattr(0, TCSAFLUSH, &attr))
198      goto error;
199  }
200#else /* unix */
201  erase[0] = CONTROL('H');
202  erase[1] = 127;
203  kill[0] = CONTROL('U');
204  eof[0] = CONTROL('D');
205  eof[1] = CONTROL('Z');
206#endif /* unix */
207
208  {
209  char *c = buf, *end = buf + len, *e;
210#ifdef __OS2__
211  KBDKEYINFO keyInfo;
212#endif /* __OS2__ */
213
214loop:
215#ifdef unix
216  if (read(0, c, 1) != 1)
217    goto error;
218#endif /* unix */
219#ifdef MSDOS
220  *c = bdos(7, 0, 0);
221#endif /* MSDOS */
222#ifdef __OS2__
223  KbdCharIn(&keyInfo, 0, 0);
224  *c = keyInfo.chChar;
225#endif /* __OS2__ */
226
227  if ((*c == '\r') || (*c == '\n')) {
228    *c = 0;
229    goto restore;
230  }
231
232  e = eof;
233  while(*e)
234    if (*(e++) == *c)
235      goto error;
236
237  e = erase;
238  while(*e)
239    if (*(e++) == *c) {
240      if (c <= buf)
241	goto beep;
242
243      if (flags & 1)
244        write(1, bsseq, sizeof(bsseq) - 1);
245      c--;
246      goto loop;
247    }
248
249  e = kill;
250  while(*e)
251    if (*(e++) == *c) {
252      if (c <= buf)
253	goto beep;
254
255      if (flags & 1)
256        while(c-- > buf)
257          write(1, bsseq, sizeof(bsseq) - 1);
258
259      c = buf;
260      goto loop;
261    }
262
263  if (c < end) {
264    if (*c < 32)
265      goto beep;
266    if (flags & 1)
267      write(1, c, 1);
268    c++;
269  } else {
270  beep:
271    *c = CONTROL('G');
272    write(1, c, 1);
273  }
274
275  goto loop;
276  }
277
278restore:
279#ifdef unix
280  /* Restore previous tty modes */
281  if (isatty(0))
282    if (tcsetattr(0, TCSAFLUSH, &orig_attr))
283      return NULL;
284
285  signal(SIGINT, SIG_DFL);
286#endif /* unix */
287
288  /* After the secret key is taken from the keyboard, the line feed is
289     written to standard error instead of standard output.  That means that
290     anyone using the program from a terminal won't notice, but capturing
291     standard output will get the key words without a newline in front of
292     them. */
293  if (!(flags & 4)) {
294    fprintf(stderr, "\n");
295    fflush(stderr);
296  }
297
298  return buf;
299
300error:
301  *buf = 0;
302  buf = NULL;
303  goto restore;
304}
305