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