| 1 | /*--------------------------------------------------------------------------- |
| 2 | |
| 3 | ttyio.c |
| 4 | |
| 5 | This file contains routines for doing console input/output, including code |
| 6 | for non-echoing input. It is used by the encryption/decryption code but |
| 7 | does not contain any restricted code itself. This file is shared between |
| 8 | Info-ZIP's Zip and UnZip. |
| 9 | |
| 10 | Contains: echo() (VMS only) |
| 11 | Echon() (Unix only) |
| 12 | Echoff() (Unix only) |
| 13 | screenlines() (Unix only) |
| 14 | zgetch() (Unix and non-Unix versions) |
| 15 | getp() ("PC," Unix/Atari/Be, VMS/VMCMS/MVS) |
| 16 | |
| 17 | ---------------------------------------------------------------------------*/ |
| 18 | |
| 19 | #define __TTYIO_C /* identifies this source module */ |
| 20 | |
| 21 | #include "zip.h" |
| 22 | #include "crypt.h" |
| 23 | |
| 24 | #if (CRYPT || (defined(UNZIP) && !defined(FUNZIP))) |
| 25 | /* Non-echo console/keyboard input is needed for (en/de)cryption's password |
| 26 | * entry, and for UnZip(SFX)'s MORE and Pause features. |
| 27 | * (The corresponding #endif is found at the end of this module.) |
| 28 | */ |
| 29 | |
| 30 | #include "ttyio.h" |
| 31 | |
| 32 | #ifndef PUTC |
| 33 | # define PUTC putc |
| 34 | #endif |
| 35 | |
| 36 | #ifdef ZIP |
| 37 | # ifdef GLOBAL /* used in Amiga system headers, maybe others too */ |
| 38 | # undef GLOBAL |
| 39 | # endif |
| 40 | # define GLOBAL(g) g |
| 41 | #else |
| 42 | # define GLOBAL(g) G.g |
| 43 | #endif |
| 44 | |
| 45 | #ifdef __BEOS__ /* why yes, we do */ |
| 46 | # define HAVE_TERMIOS_H |
| 47 | #endif |
| 48 | |
| 49 | #ifdef _POSIX_VERSION |
| 50 | # ifndef USE_POSIX_TERMIOS |
| 51 | # define USE_POSIX_TERMIOS /* use POSIX style termio (termios) */ |
| 52 | # endif |
| 53 | # ifndef HAVE_TERMIOS_H |
| 54 | # define HAVE_TERMIOS_H /* POSIX termios.h */ |
| 55 | # endif |
| 56 | #endif /* _POSIX_VERSION */ |
| 57 | |
| 58 | #ifdef UNZIP /* Zip handles this with the unix/configure script */ |
| 59 | # ifndef _POSIX_VERSION |
| 60 | # if (defined(SYSV) || defined(CRAY)) && !defined(__MINT__) |
| 61 | # ifndef USE_SYSV_TERMIO |
| 62 | # define USE_SYSV_TERMIO |
| 63 | # endif |
| 64 | # ifdef COHERENT |
| 65 | # ifndef HAVE_TERMIO_H |
| 66 | # define HAVE_TERMIO_H |
| 67 | # endif |
| 68 | # ifdef HAVE_SYS_TERMIO_H |
| 69 | # undef HAVE_SYS_TERMIO_H |
| 70 | # endif |
| 71 | # else /* !COHERENT */ |
| 72 | # ifdef HAVE_TERMIO_H |
| 73 | # undef HAVE_TERMIO_H |
| 74 | # endif |
| 75 | # ifndef HAVE_SYS_TERMIO_H |
| 76 | # define HAVE_SYS_TERMIO_H |
| 77 | # endif |
| 78 | # endif /* ?COHERENT */ |
| 79 | # endif /* (SYSV || CRAY) && !__MINT__ */ |
| 80 | # endif /* !_POSIX_VERSION */ |
| 81 | # if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__)) |
| 82 | # ifndef NO_FCNTL_H |
| 83 | # define NO_FCNTL_H |
| 84 | # endif |
| 85 | # endif /* !(BSD4_4 || SYSV || __convexc__) */ |
| 86 | #endif /* UNZIP */ |
| 87 | |
| 88 | #ifdef HAVE_TERMIOS_H |
| 89 | # ifndef USE_POSIX_TERMIOS |
| 90 | # define USE_POSIX_TERMIOS |
| 91 | # endif |
| 92 | #endif |
| 93 | |
| 94 | #if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H)) |
| 95 | # ifndef USE_SYSV_TERMIO |
| 96 | # define USE_SYSV_TERMIO |
| 97 | # endif |
| 98 | #endif |
| 99 | |
| 100 | #if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE)) |
| 101 | # include <sys/ioctl.h> |
| 102 | # define GOT_IOCTL_H |
| 103 | /* int ioctl OF((int, int, zvoid *)); GRR: may need for some systems */ |
| 104 | #endif |
| 105 | |
| 106 | #ifndef HAVE_WORKING_GETCH |
| 107 | /* include system support for switching of console echo */ |
| 108 | # ifdef VMS |
| 109 | # include <descrip.h> |
| 110 | # include <iodef.h> |
| 111 | # include <ttdef.h> |
| 112 | # include <starlet.h> |
| 113 | # include <ssdef.h> |
| 114 | # else /* !VMS */ |
| 115 | # ifdef HAVE_TERMIOS_H |
| 116 | # include <termios.h> |
| 117 | # define sgttyb termios |
| 118 | # define sg_flags c_lflag |
| 119 | # define GTTY(f, s) tcgetattr(f, (zvoid *) s) |
| 120 | # define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s) |
| 121 | # else /* !HAVE_TERMIOS_H */ |
| 122 | # ifdef USE_SYSV_TERMIO /* Amdahl, Cray, all SysV? */ |
| 123 | # ifdef HAVE_TERMIO_H |
| 124 | # include <termio.h> |
| 125 | # endif |
| 126 | # ifdef HAVE_SYS_TERMIO_H |
| 127 | # include <sys/termio.h> |
| 128 | # endif |
| 129 | # ifdef NEED_PTEM |
| 130 | # include <sys/stream.h> |
| 131 | # include <sys/ptem.h> |
| 132 | # endif |
| 133 | # define sgttyb termio |
| 134 | # define sg_flags c_lflag |
| 135 | # define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s) |
| 136 | # define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s) |
| 137 | # else /* !USE_SYSV_TERMIO */ |
| 138 | # ifndef CMS_MVS |
| 139 | # if (!defined(MINIX) && !defined(GOT_IOCTL_H)) |
| 140 | # include <sys/ioctl.h> |
| 141 | # endif |
| 142 | # include <sgtty.h> |
| 143 | # define GTTY gtty |
| 144 | # define STTY stty |
| 145 | # ifdef UNZIP |
| 146 | /* |
| 147 | * XXX : Are these declarations needed at all ???? |
| 148 | */ |
| 149 | /* |
| 150 | * GRR: let's find out... Hmmm, appears not... |
| 151 | int gtty OF((int, struct sgttyb *)); |
| 152 | int stty OF((int, struct sgttyb *)); |
| 153 | */ |
| 154 | # endif |
| 155 | # endif /* !CMS_MVS */ |
| 156 | # endif /* ?USE_SYSV_TERMIO */ |
| 157 | # endif /* ?HAVE_TERMIOS_H */ |
| 158 | # ifndef NO_FCNTL_H |
| 159 | # ifndef UNZIP |
| 160 | # include <fcntl.h> |
| 161 | # endif |
| 162 | # else |
| 163 | char *ttyname OF((int)); |
| 164 | # endif |
| 165 | # endif /* ?VMS */ |
| 166 | #endif /* !HAVE_WORKING_GETCH */ |
| 167 | |
| 168 | |
| 169 | |
| 170 | #ifndef HAVE_WORKING_GETCH |
| 171 | #ifdef VMS |
| 172 | |
| 173 | /* |
| 174 | * Turn keyboard echoing on or off (VMS). Loosely based on VMSmunch.c |
| 175 | * and hence on Joe Meadows' file.c code. |
| 176 | */ |
| 177 | int echo(opt) |
| 178 | int opt; |
| 179 | { |
| 180 | /* |
| 181 | * For VMS v5.x: |
| 182 | * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming, |
| 183 | * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6 |
| 184 | * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services, |
| 185 | * System Services Reference Manual, pp. sys-23, sys-379 |
| 186 | * fixed-length descriptor info: Programming, Vol. 3, System Services, |
| 187 | * Intro to System Routines, sec. 2.9.2 |
| 188 | * Greg Roelofs, 15 Aug 91 |
| 189 | */ |
| 190 | |
| 191 | /* SKM: make global? */ |
| 192 | static struct dsc$descriptor_s DevDesc = |
| 193 | {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"}; |
| 194 | /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */ |
| 195 | static short DevChan, iosb[4]; |
| 196 | static long status; |
| 197 | static unsigned long oldmode[2], newmode[2]; /* each = 8 bytes */ |
| 198 | |
| 199 | |
| 200 | /* assign a channel to standard input */ |
| 201 | status = sys$assign(&DevDesc, &DevChan, 0, 0); |
| 202 | if (!(status & 1)) |
| 203 | return status; |
| 204 | |
| 205 | /* use sys$qio and the IO$_SENSEMODE function to determine the current |
| 206 | * tty status (for password reading, could use IO$_READVBLK function |
| 207 | * instead, but echo on/off will be more general) |
| 208 | */ |
| 209 | status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0, |
| 210 | oldmode, 8, 0, 0, 0, 0); |
| 211 | if (!(status & 1)) |
| 212 | return status; |
| 213 | status = iosb[0]; |
| 214 | if (!(status & 1)) |
| 215 | return status; |
| 216 | |
| 217 | /* copy old mode into new-mode buffer, then modify to be either NOECHO or |
| 218 | * ECHO (depending on function argument opt) |
| 219 | */ |
| 220 | newmode[0] = oldmode[0]; |
| 221 | newmode[1] = oldmode[1]; |
| 222 | if (opt == 0) /* off */ |
| 223 | newmode[1] |= TT$M_NOECHO; /* set NOECHO bit */ |
| 224 | else |
| 225 | newmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */ |
| 226 | |
| 227 | /* use the IO$_SETMODE function to change the tty status */ |
| 228 | status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0, |
| 229 | newmode, 8, 0, 0, 0, 0); |
| 230 | if (!(status & 1)) |
| 231 | return status; |
| 232 | status = iosb[0]; |
| 233 | if (!(status & 1)) |
| 234 | return status; |
| 235 | |
| 236 | /* deassign the sys$input channel by way of clean-up */ |
| 237 | status = sys$dassgn(DevChan); |
| 238 | if (!(status & 1)) |
| 239 | return status; |
| 240 | |
| 241 | return SS$_NORMAL; /* we be happy */ |
| 242 | |
| 243 | } /* end function echo() */ |
| 244 | |
| 245 | |
| 246 | #else /* !VMS: basically Unix */ |
| 247 | |
| 248 | |
| 249 | /* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */ |
| 250 | #ifndef CMS_MVS |
| 251 | |
| 252 | #ifdef ZIP /* moved to globals.h for UnZip */ |
| 253 | static int echofd=(-1); /* file descriptor whose echo is off */ |
| 254 | #endif |
| 255 | |
| 256 | /* |
| 257 | * Turn echo off for file descriptor f. Assumes that f is a tty device. |
| 258 | */ |
| 259 | void Echoff(__G__ f) |
| 260 | __GDEF |
| 261 | int f; /* file descriptor for which to turn echo off */ |
| 262 | { |
| 263 | struct sgttyb sg; /* tty device structure */ |
| 264 | |
| 265 | GLOBAL(echofd) = f; |
| 266 | GTTY(f, &sg); /* get settings */ |
| 267 | sg.sg_flags &= ~ECHO; /* turn echo off */ |
| 268 | STTY(f, &sg); |
| 269 | } |
| 270 | |
| 271 | /* |
| 272 | * Turn echo back on for file descriptor echofd. |
| 273 | */ |
| 274 | void Echon(__G) |
| 275 | __GDEF |
| 276 | { |
| 277 | struct sgttyb sg; /* tty device structure */ |
| 278 | |
| 279 | if (GLOBAL(echofd) != -1) { |
| 280 | GTTY(GLOBAL(echofd), &sg); /* get settings */ |
| 281 | sg.sg_flags |= ECHO; /* turn echo on */ |
| 282 | STTY(GLOBAL(echofd), &sg); |
| 283 | GLOBAL(echofd) = -1; |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | #endif /* !CMS_MVS */ |
| 288 | #endif /* ?VMS */ |
| 289 | |
| 290 | |
| 291 | #if (defined(UNZIP) && !defined(FUNZIP)) |
| 292 | |
| 293 | #if (defined(UNIX) || defined(__BEOS__)) |
| 294 | #ifdef MORE |
| 295 | |
| 296 | /* |
| 297 | * Get the number of lines on the output terminal. SCO Unix apparently |
| 298 | * defines TIOCGWINSZ but doesn't support it (!M_UNIX). |
| 299 | * |
| 300 | * GRR: will need to know width of terminal someday, too, to account for |
| 301 | * line-wrapping. |
| 302 | */ |
| 303 | |
| 304 | #if (defined(TIOCGWINSZ) && !defined(M_UNIX)) |
| 305 | |
| 306 | int screenlines() |
| 307 | { |
| 308 | struct winsize wsz; |
| 309 | #ifdef DEBUG_WINSZ |
| 310 | static int firsttime = TRUE; |
| 311 | #endif |
| 312 | |
| 313 | /* see termio(4) under, e.g., SunOS */ |
| 314 | if (ioctl(1, TIOCGWINSZ, &wsz) == 0) { |
| 315 | #ifdef DEBUG_WINSZ |
| 316 | if (firsttime) { |
| 317 | firsttime = FALSE; |
| 318 | fprintf(stderr, "ttyio.c screenlines(): ws_row = %d\n", |
| 319 | wsz.ws_row); |
| 320 | } |
| 321 | #endif |
| 322 | /* number of columns = ws_col */ |
| 323 | return (wsz.ws_row > 0)? wsz.ws_row : 24; /* number of rows */ |
| 324 | |
| 325 | } else { /* this happens when piping to more(1), for example */ |
| 326 | #ifdef DEBUG_WINSZ |
| 327 | if (firsttime) { |
| 328 | firsttime = FALSE; |
| 329 | fprintf(stderr, |
| 330 | "ttyio.c screenlines(): ioctl(TIOCGWINSZ) failed\n")); |
| 331 | } |
| 332 | #endif |
| 333 | return 24; /* VT-100 assumed to be minimal hardware */ |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | #else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */ |
| 338 | |
| 339 | int screenlines() |
| 340 | { |
| 341 | char *envptr, *getenv(); |
| 342 | int n; |
| 343 | |
| 344 | /* GRR: this is overly simplistic, but don't have access to stty/gtty |
| 345 | * system anymore |
| 346 | */ |
| 347 | envptr = getenv("LINES"); |
| 348 | if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) |
| 349 | return 24; /* VT-100 assumed to be minimal hardware */ |
| 350 | else |
| 351 | return n; |
| 352 | } |
| 353 | |
| 354 | #endif /* ?(TIOCGWINSZ && !M_UNIX) */ |
| 355 | #endif /* MORE */ |
| 356 | |
| 357 | |
| 358 | /* |
| 359 | * Get a character from the given file descriptor without echo or newline. |
| 360 | */ |
| 361 | int zgetch(__G__ f) |
| 362 | __GDEF |
| 363 | int f; /* file descriptor from which to read */ |
| 364 | { |
| 365 | #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) |
| 366 | char oldmin, oldtim; |
| 367 | #endif |
| 368 | char c; |
| 369 | struct sgttyb sg; /* tty device structure */ |
| 370 | |
| 371 | GTTY(f, &sg); /* get settings */ |
| 372 | #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) |
| 373 | oldmin = sg.c_cc[VMIN]; /* save old values */ |
| 374 | oldtim = sg.c_cc[VTIME]; |
| 375 | sg.c_cc[VMIN] = 1; /* need only one char to return read() */ |
| 376 | sg.c_cc[VTIME] = 0; /* no timeout */ |
| 377 | sg.sg_flags &= ~ICANON; /* canonical mode off */ |
| 378 | #else |
| 379 | sg.sg_flags |= CBREAK; /* cbreak mode on */ |
| 380 | #endif |
| 381 | sg.sg_flags &= ~ECHO; /* turn echo off, too */ |
| 382 | STTY(f, &sg); /* set cbreak mode */ |
| 383 | GLOBAL(echofd) = f; /* in case ^C hit (not perfect: still CBREAK) */ |
| 384 | |
| 385 | read(f, &c, 1); /* read our character */ |
| 386 | |
| 387 | #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) |
| 388 | sg.c_cc[VMIN] = oldmin; /* restore old values */ |
| 389 | sg.c_cc[VTIME] = oldtim; |
| 390 | sg.sg_flags |= ICANON; /* canonical mode on */ |
| 391 | #else |
| 392 | sg.sg_flags &= ~CBREAK; /* cbreak mode off */ |
| 393 | #endif |
| 394 | sg.sg_flags |= ECHO; /* turn echo on */ |
| 395 | STTY(f, &sg); /* restore canonical mode */ |
| 396 | GLOBAL(echofd) = -1; |
| 397 | |
| 398 | return (int)c; |
| 399 | } |
| 400 | |
| 401 | |
| 402 | #else /* !UNIX && !__BEOS__ */ |
| 403 | |
| 404 | |
| 405 | int zgetch(__G__ f) |
| 406 | __GDEF |
| 407 | int f; /* file descriptor from which to read (must be open already) */ |
| 408 | { |
| 409 | char c, c2; |
| 410 | |
| 411 | /*--------------------------------------------------------------------------- |
| 412 | Get a character from the given file descriptor without echo; can't fake |
| 413 | CBREAK mode (i.e., newline required), but can get rid of all chars up to |
| 414 | and including newline. |
| 415 | ---------------------------------------------------------------------------*/ |
| 416 | |
| 417 | echoff(f); |
| 418 | read(f, &c, 1); |
| 419 | if (c != '\n') |
| 420 | do { |
| 421 | read(f, &c2, 1); /* throw away all other chars up thru newline */ |
| 422 | } while (c2 != '\n'); |
| 423 | echon(); |
| 424 | return (int)c; |
| 425 | } |
| 426 | |
| 427 | #endif /* ?(UNIX || __BEOS__) */ |
| 428 | |
| 429 | #endif /* UNZIP && !FUNZIP */ |
| 430 | #endif /* !HAVE_WORKING_GETCH */ |
| 431 | |
| 432 | |
| 433 | #if CRYPT /* getp() is only used with full encryption */ |
| 434 | |
| 435 | /* |
| 436 | * Simple compile-time check for source compatibility between |
| 437 | * zcrypt and ttyio: |
| 438 | */ |
| 439 | #if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7)) |
| 440 | error: This Info-ZIP tool requires zcrypt 2.7 or later. |
| 441 | #endif |
| 442 | |
| 443 | /* |
| 444 | * Get a password of length n-1 or less into *p using the prompt *m. |
| 445 | * The entered password is not echoed. |
| 446 | */ |
| 447 | |
| 448 | #ifdef HAVE_WORKING_GETCH |
| 449 | /* |
| 450 | * For the AMIGA, getch() is defined as Agetch(), which is in |
| 451 | * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch() |
| 452 | * uses the infrastructure that is already in place in filedate.c, it is |
| 453 | * smaller. With this function, echoff() and echon() are not needed. |
| 454 | * |
| 455 | * For the MAC, a non-echo macgetch() function is defined in the MacOS |
| 456 | * specific sources which uses the event handling mechanism of the |
| 457 | * desktop window manager to get a character from the keyboard. |
| 458 | * |
| 459 | * For the other systems in this section, a non-echo getch() function |
| 460 | * is either contained the C runtime library (conio package), or getch() |
| 461 | * is defined as an alias for a similar system specific RTL function. |
| 462 | */ |
| 463 | |
| 464 | #ifndef WINDLL /* WINDLL does not support a console interface */ |
| 465 | #ifndef QDOS /* QDOS supplies a variant of this function */ |
| 466 | |
| 467 | /* This is the getp() function for all systems (with TTY type user interface) |
| 468 | * that supply a working `non-echo' getch() function for "raw" console input. |
| 469 | */ |
| 470 | char *getp(__G__ m, p, n) |
| 471 | __GDEF |
| 472 | ZCONST char *m; /* prompt for password */ |
| 473 | char *p; /* return value: line input */ |
| 474 | int n; /* bytes available in p[] */ |
| 475 | { |
| 476 | char c; /* one-byte buffer for read() to use */ |
| 477 | int i; /* number of characters input */ |
| 478 | char *w; /* warning on retry */ |
| 479 | |
| 480 | /* get password */ |
| 481 | w = ""; |
| 482 | do { |
| 483 | fputs(w, stderr); /* warning if back again */ |
| 484 | fputs(m, stderr); /* display prompt and flush */ |
| 485 | fflush(stderr); |
| 486 | i = 0; |
| 487 | do { /* read line, keeping first n characters */ |
| 488 | if ((c = (char)getch()) == '\r') |
| 489 | c = '\n'; /* until user hits CR */ |
| 490 | if (c == 8 || c == 127) { |
| 491 | if (i > 0) i--; /* the `backspace' and `del' keys works */ |
| 492 | } |
| 493 | else if (i < n) |
| 494 | p[i++] = c; /* truncate past n */ |
| 495 | } while (c != '\n'); |
| 496 | PUTC('\n', stderr); fflush(stderr); |
| 497 | w = "(line too long--try again)\n"; |
| 498 | } while (p[i-1] != '\n'); |
| 499 | p[i-1] = 0; /* terminate at newline */ |
| 500 | |
| 501 | return p; /* return pointer to password */ |
| 502 | |
| 503 | } /* end function getp() */ |
| 504 | |
| 505 | #endif /* !QDOS */ |
| 506 | #endif /* !WINDLL */ |
| 507 | |
| 508 | |
| 509 | #else /* !HAVE_WORKING_GETCH */ |
| 510 | |
| 511 | |
| 512 | #if (defined(UNIX) || defined(__MINT__) || defined(__BEOS__)) |
| 513 | |
| 514 | #ifndef _PATH_TTY |
| 515 | # ifdef __MINT__ |
| 516 | # define _PATH_TTY ttyname(2) |
| 517 | # else |
| 518 | # define _PATH_TTY "/dev/tty" |
| 519 | # endif |
| 520 | #endif |
| 521 | |
| 522 | char *getp(__G__ m, p, n) |
| 523 | __GDEF |
| 524 | ZCONST char *m; /* prompt for password */ |
| 525 | char *p; /* return value: line input */ |
| 526 | int n; /* bytes available in p[] */ |
| 527 | { |
| 528 | char c; /* one-byte buffer for read() to use */ |
| 529 | int i; /* number of characters input */ |
| 530 | char *w; /* warning on retry */ |
| 531 | int f; /* file descriptor for tty device */ |
| 532 | |
| 533 | #ifdef PASSWD_FROM_STDIN |
| 534 | /* Read from stdin. This is unsafe if the password is stored on disk. */ |
| 535 | f = 0; |
| 536 | #else |
| 537 | /* turn off echo on tty */ |
| 538 | |
| 539 | if ((f = open(_PATH_TTY, 0)) == -1) |
| 540 | return NULL; |
| 541 | #endif |
| 542 | /* get password */ |
| 543 | w = ""; |
| 544 | do { |
| 545 | fputs(w, stderr); /* warning if back again */ |
| 546 | fputs(m, stderr); /* prompt */ |
| 547 | fflush(stderr); |
| 548 | i = 0; |
| 549 | echoff(f); |
| 550 | do { /* read line, keeping n */ |
| 551 | read(f, &c, 1); |
| 552 | if (i < n) |
| 553 | p[i++] = c; |
| 554 | } while (c != '\n'); |
| 555 | echon(); |
| 556 | PUTC('\n', stderr); fflush(stderr); |
| 557 | w = "(line too long--try again)\n"; |
| 558 | } while (p[i-1] != '\n'); |
| 559 | p[i-1] = 0; /* terminate at newline */ |
| 560 | |
| 561 | #ifndef PASSWD_FROM_STDIN |
| 562 | close(f); |
| 563 | #endif |
| 564 | |
| 565 | return p; /* return pointer to password */ |
| 566 | |
| 567 | } /* end function getp() */ |
| 568 | |
| 569 | #endif /* UNIX || __MINT__ || __BEOS__ */ |
| 570 | |
| 571 | |
| 572 | |
| 573 | #if (defined(VMS) || defined(CMS_MVS)) |
| 574 | |
| 575 | char *getp(__G__ m, p, n) |
| 576 | __GDEF |
| 577 | ZCONST char *m; /* prompt for password */ |
| 578 | char *p; /* return value: line input */ |
| 579 | int n; /* bytes available in p[] */ |
| 580 | { |
| 581 | char c; /* one-byte buffer for read() to use */ |
| 582 | int i; /* number of characters input */ |
| 583 | char *w; /* warning on retry */ |
| 584 | FILE *f; /* file structure for SYS$COMMAND device */ |
| 585 | |
| 586 | #ifdef PASSWD_FROM_STDIN |
| 587 | f = stdin; |
| 588 | #else |
| 589 | if ((f = fopen(ctermid(NULL), "r")) == NULL) |
| 590 | return NULL; |
| 591 | #endif |
| 592 | |
| 593 | /* get password */ |
| 594 | fflush(stdout); |
| 595 | w = ""; |
| 596 | do { |
| 597 | if (*w) /* bug: VMS apparently adds \n to NULL fputs */ |
| 598 | fputs(w, stderr); /* warning if back again */ |
| 599 | fputs(m, stderr); /* prompt */ |
| 600 | fflush(stderr); |
| 601 | i = 0; |
| 602 | echoff(f); |
| 603 | do { /* read line, keeping n */ |
| 604 | if ((c = (char)getc(f)) == '\r') |
| 605 | c = '\n'; |
| 606 | if (i < n) |
| 607 | p[i++] = c; |
| 608 | } while (c != '\n'); |
| 609 | echon(); |
| 610 | PUTC('\n', stderr); fflush(stderr); |
| 611 | w = "(line too long--try again)\n"; |
| 612 | } while (p[i-1] != '\n'); |
| 613 | p[i-1] = 0; /* terminate at newline */ |
| 614 | #ifndef PASSWD_FROM_STDIN |
| 615 | fclose(f); |
| 616 | #endif |
| 617 | |
| 618 | return p; /* return pointer to password */ |
| 619 | |
| 620 | } /* end function getp() */ |
| 621 | |
| 622 | #endif /* VMS || CMS_MVS */ |
| 623 | #endif /* ?HAVE_WORKING_GETCH */ |
| 624 | #endif /* CRYPT */ |
| 625 | #endif /* CRYPT || (UNZIP && !FUNZIP) */ |