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