1 /* 2 * Copyright 2001-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include "internal/e_os.h" 11 #include <openssl/e_os2.h> 12 #include <openssl/err.h> 13 #include <openssl/ui.h> 14 15 #ifndef OPENSSL_NO_UI_CONSOLE 16 /* 17 * need for #define _POSIX_C_SOURCE arises whenever you pass -ansi to gcc 18 * [maybe others?], because it masks interfaces not discussed in standard, 19 * sigaction and fileno included. -pedantic would be more appropriate for the 20 * intended purposes, but we can't prevent users from adding -ansi. 21 */ 22 #if defined(OPENSSL_SYS_VXWORKS) 23 #include <sys/types.h> 24 #endif 25 26 #if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS) 27 #ifndef _POSIX_C_SOURCE 28 #define _POSIX_C_SOURCE 2 29 #endif 30 #endif 31 #include <signal.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <errno.h> 35 36 #if !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VMS) 37 #include <unistd.h> 38 /* 39 * If unistd.h defines _POSIX_VERSION, we conclude that we are on a POSIX 40 * system and have sigaction and termios. 41 */ 42 #if defined(_POSIX_VERSION) && _POSIX_VERSION >= 199309L 43 44 #define SIGACTION 45 #if !defined(TERMIOS) && !defined(TERMIO) && !defined(SGTTY) 46 #define TERMIOS 47 #endif 48 49 #endif 50 #endif 51 52 #include "ui_local.h" 53 #include "internal/cryptlib.h" 54 55 #ifdef OPENSSL_SYS_VMS /* prototypes for sys$whatever */ 56 #include <starlet.h> 57 #ifdef __DECC 58 #pragma message disable DOLLARID 59 #endif 60 #endif 61 62 #ifdef WIN_CONSOLE_BUG 63 #include <windows.h> 64 #ifndef OPENSSL_SYS_WINCE 65 #include <wincon.h> 66 #endif 67 #endif 68 69 /* 70 * There are 6 types of terminal interface supported, TERMIO, TERMIOS, VMS, 71 * MSDOS, WIN32 Console and SGTTY. 72 * 73 * If someone defines one of the macros TERMIO, TERMIOS or SGTTY, it will 74 * remain respected. Otherwise, we default to TERMIOS except for a few 75 * systems that require something different. 76 * 77 * Note: we do not use SGTTY unless it's defined by the configuration. We 78 * may eventually opt to remove its use entirely. 79 */ 80 81 #if !defined(TERMIOS) && !defined(TERMIO) && !defined(SGTTY) 82 83 #if defined(_LIBC) 84 #undef TERMIOS 85 #define TERMIO 86 #undef SGTTY 87 /* 88 * We know that VMS, MSDOS, VXWORKS, use entirely other mechanisms. 89 */ 90 #elif !defined(OPENSSL_SYS_VMS) \ 91 && !defined(OPENSSL_SYS_MSDOS) \ 92 && !defined(OPENSSL_SYS_VXWORKS) 93 #define TERMIOS 94 #undef TERMIO 95 #undef SGTTY 96 #endif 97 98 #endif 99 100 #if defined(OPENSSL_SYS_VXWORKS) 101 #undef TERMIOS 102 #undef TERMIO 103 #undef SGTTY 104 #endif 105 106 #ifdef TERMIOS 107 #include <termios.h> 108 #define TTY_STRUCT struct termios 109 #define TTY_FLAGS c_lflag 110 #define TTY_get(tty, data) tcgetattr(tty, data) 111 #define TTY_set(tty, data) tcsetattr(tty, TCSANOW, data) 112 #endif 113 114 #ifdef TERMIO 115 #include <termio.h> 116 #define TTY_STRUCT struct termio 117 #define TTY_FLAGS c_lflag 118 #define TTY_get(tty, data) ioctl(tty, TCGETA, data) 119 #define TTY_set(tty, data) ioctl(tty, TCSETA, data) 120 #endif 121 122 #ifdef SGTTY 123 #include <sgtty.h> 124 #define TTY_STRUCT struct sgttyb 125 #define TTY_FLAGS sg_flags 126 #define TTY_get(tty, data) ioctl(tty, TIOCGETP, data) 127 #define TTY_set(tty, data) ioctl(tty, TIOCSETP, data) 128 #endif 129 130 #if !defined(_LIBC) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VMS) && !(defined(OPENSSL_SYS_TANDEM) && defined(_SPT_MODEL_)) 131 #include <sys/ioctl.h> 132 #endif 133 134 #ifdef OPENSSL_SYS_MSDOS 135 #include <conio.h> 136 #endif 137 138 #ifdef OPENSSL_SYS_VMS 139 #include <ssdef.h> 140 #include <iodef.h> 141 #include <ttdef.h> 142 #include <descrip.h> 143 struct IOSB { 144 short iosb$w_value; 145 short iosb$w_count; 146 long iosb$l_info; 147 }; 148 #endif 149 150 #ifndef NX509_SIG 151 #define NX509_SIG 32 152 #endif 153 154 /* Define globals. They are protected by a lock */ 155 #ifdef SIGACTION 156 static struct sigaction savsig[NX509_SIG]; 157 #else 158 static void (*savsig[NX509_SIG])(int); 159 #endif 160 161 #ifdef OPENSSL_SYS_VMS 162 static struct IOSB iosb; 163 static $DESCRIPTOR(terminal, "TT"); 164 static long tty_orig[3], tty_new[3]; /* XXX Is there any guarantee that this 165 * will always suffice for the actual 166 * structures? */ 167 static long status; 168 static unsigned short channel = 0; 169 #elif defined(_WIN32) && !defined(_WIN32_WCE) 170 static DWORD tty_orig, tty_new; 171 #else 172 #if !defined(OPENSSL_SYS_MSDOS) || defined(__DJGPP__) 173 static TTY_STRUCT tty_orig, tty_new; 174 #endif 175 #endif 176 static FILE *tty_in, *tty_out; 177 static int is_a_tty; 178 179 /* Declare static functions */ 180 #if !defined(OPENSSL_SYS_WINCE) 181 static int read_till_nl(FILE *); 182 static void recsig(int); 183 static void pushsig(void); 184 static void popsig(void); 185 #endif 186 #if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32) 187 static int noecho_fgets(char *buf, int size, FILE *tty); 188 #endif 189 static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl); 190 191 static int read_string(UI *ui, UI_STRING *uis); 192 static int write_string(UI *ui, UI_STRING *uis); 193 194 static int open_console(UI *ui); 195 static int echo_console(UI *ui); 196 static int noecho_console(UI *ui); 197 static int close_console(UI *ui); 198 199 /* 200 * The following function makes sure that info and error strings are printed 201 * before any prompt. 202 */ 203 static int write_string(UI *ui, UI_STRING *uis) 204 { 205 switch (UI_get_string_type(uis)) { 206 case UIT_ERROR: 207 case UIT_INFO: 208 fputs(UI_get0_output_string(uis), tty_out); 209 fflush(tty_out); 210 break; 211 case UIT_NONE: 212 case UIT_PROMPT: 213 case UIT_VERIFY: 214 case UIT_BOOLEAN: 215 break; 216 } 217 return 1; 218 } 219 220 static int read_string(UI *ui, UI_STRING *uis) 221 { 222 int ok = 0; 223 224 switch (UI_get_string_type(uis)) { 225 case UIT_BOOLEAN: 226 fputs(UI_get0_output_string(uis), tty_out); 227 fputs(UI_get0_action_string(uis), tty_out); 228 fflush(tty_out); 229 return read_string_inner(ui, uis, 230 UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO, 231 0); 232 case UIT_PROMPT: 233 fputs(UI_get0_output_string(uis), tty_out); 234 fflush(tty_out); 235 return read_string_inner(ui, uis, 236 UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO, 237 1); 238 case UIT_VERIFY: 239 fprintf(tty_out, "Verifying - %s", UI_get0_output_string(uis)); 240 fflush(tty_out); 241 if ((ok = read_string_inner(ui, uis, 242 UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO, 1)) 243 <= 0) 244 return ok; 245 if (strcmp(UI_get0_result_string(uis), UI_get0_test_string(uis)) != 0) { 246 fprintf(tty_out, "Verify failure\n"); 247 fflush(tty_out); 248 return 0; 249 } 250 break; 251 case UIT_NONE: 252 case UIT_INFO: 253 case UIT_ERROR: 254 break; 255 } 256 return 1; 257 } 258 259 #if !defined(OPENSSL_SYS_WINCE) 260 /* Internal functions to read a string without echoing */ 261 static int read_till_nl(FILE *in) 262 { 263 #define SIZE 4 264 char buf[SIZE + 1]; 265 266 do { 267 if (!fgets(buf, SIZE, in)) 268 return 0; 269 } while (strchr(buf, '\n') == NULL); 270 return 1; 271 } 272 273 static volatile sig_atomic_t intr_signal; 274 #endif 275 276 static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl) 277 { 278 static int ps; 279 int ok; 280 char result[BUFSIZ]; 281 int maxsize = BUFSIZ - 1; 282 #if !defined(OPENSSL_SYS_WINCE) 283 char *p = NULL; 284 int echo_eol = !echo; 285 286 intr_signal = 0; 287 ok = 0; 288 ps = 0; 289 290 pushsig(); 291 ps = 1; 292 293 if (!echo && !noecho_console(ui)) 294 goto error; 295 ps = 2; 296 297 result[0] = '\0'; 298 #if defined(_WIN32) 299 if (is_a_tty) { 300 DWORD numread; 301 #if defined(CP_UTF8) 302 if (GetEnvironmentVariableW(L"OPENSSL_WIN32_UTF8", NULL, 0) != 0) { 303 WCHAR wresult[BUFSIZ]; 304 305 if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), 306 wresult, maxsize, &numread, NULL)) { 307 if (numread >= 2 && wresult[numread - 2] == L'\r' && wresult[numread - 1] == L'\n') { 308 wresult[numread - 2] = L'\n'; 309 numread--; 310 } 311 wresult[numread] = '\0'; 312 if (WideCharToMultiByte(CP_UTF8, 0, wresult, -1, 313 result, sizeof(result), NULL, 0) 314 > 0) 315 p = result; 316 317 OPENSSL_cleanse(wresult, sizeof(wresult)); 318 } 319 } else 320 #endif 321 if (ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), 322 result, maxsize, &numread, NULL)) { 323 if (numread >= 2 && result[numread - 2] == '\r' && result[numread - 1] == '\n') { 324 result[numread - 2] = '\n'; 325 numread--; 326 } 327 result[numread] = '\0'; 328 p = result; 329 } 330 } else 331 #elif defined(OPENSSL_SYS_MSDOS) 332 if (!echo) { 333 noecho_fgets(result, maxsize, tty_in); 334 p = result; /* FIXME: noecho_fgets doesn't return errors */ 335 } else 336 #endif 337 p = fgets(result, maxsize, tty_in); 338 if (p == NULL) 339 goto error; 340 if (feof(tty_in)) 341 goto error; 342 if (ferror(tty_in)) 343 goto error; 344 if ((p = (char *)strchr(result, '\n')) != NULL) { 345 if (strip_nl) 346 *p = '\0'; 347 } else if (!read_till_nl(tty_in)) 348 goto error; 349 if (UI_set_result(ui, uis, result) >= 0) 350 ok = 1; 351 352 error: 353 if (intr_signal == SIGINT) 354 ok = -1; 355 if (echo_eol) 356 fprintf(tty_out, "\n"); 357 if (ps >= 2 && !echo && !echo_console(ui)) 358 ok = 0; 359 360 if (ps >= 1) 361 popsig(); 362 #else 363 ok = 1; 364 #endif 365 366 OPENSSL_cleanse(result, BUFSIZ); 367 return ok; 368 } 369 370 /* Internal functions to open, handle and close a channel to the console. */ 371 static int open_console(UI *ui) 372 { 373 if (!CRYPTO_THREAD_write_lock(ui->lock)) 374 return 0; 375 is_a_tty = 1; 376 377 #if defined(OPENSSL_SYS_VXWORKS) 378 tty_in = stdin; 379 tty_out = stderr; 380 #elif defined(_WIN32) && !defined(_WIN32_WCE) 381 if ((tty_out = fopen("conout$", "w")) == NULL) 382 tty_out = stderr; 383 384 if (GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &tty_orig)) { 385 tty_in = stdin; 386 } else { 387 is_a_tty = 0; 388 if ((tty_in = fopen("conin$", "r")) == NULL) 389 tty_in = stdin; 390 } 391 #else 392 #ifdef OPENSSL_SYS_MSDOS 393 #define DEV_TTY "con" 394 #else 395 #define DEV_TTY "/dev/tty" 396 #endif 397 if ((tty_in = fopen(DEV_TTY, "r")) == NULL) 398 tty_in = stdin; 399 if ((tty_out = fopen(DEV_TTY, "w")) == NULL) 400 tty_out = stderr; 401 #endif 402 403 #if defined(TTY_get) && !defined(OPENSSL_SYS_VMS) 404 if (TTY_get(fileno(tty_in), &tty_orig) == -1) { 405 #ifdef ENOTTY 406 if (errno == ENOTTY) 407 is_a_tty = 0; 408 else 409 #endif 410 #ifdef EINVAL 411 /* 412 * Ariel Glenn reports that solaris can return EINVAL instead. 413 * This should be ok 414 */ 415 if (errno == EINVAL) 416 is_a_tty = 0; 417 else 418 #endif 419 #ifdef ENXIO 420 /* 421 * Solaris can return ENXIO. 422 * This should be ok 423 */ 424 if (errno == ENXIO) 425 is_a_tty = 0; 426 else 427 #endif 428 #ifdef EIO 429 /* 430 * Linux can return EIO. 431 * This should be ok 432 */ 433 if (errno == EIO) 434 is_a_tty = 0; 435 else 436 #endif 437 #ifdef EPERM 438 /* 439 * Linux can return EPERM (Operation not permitted), 440 * e.g. if a daemon executes openssl via fork()+execve() 441 * This should be ok 442 */ 443 if (errno == EPERM) 444 is_a_tty = 0; 445 else 446 #endif 447 #ifdef ENODEV 448 /* 449 * MacOS X returns ENODEV (Operation not supported by device), 450 * which seems appropriate. 451 */ 452 if (errno == ENODEV) 453 is_a_tty = 0; 454 else 455 #endif 456 { 457 ERR_raise_data(ERR_LIB_UI, UI_R_UNKNOWN_TTYGET_ERRNO_VALUE, 458 "errno=%d", errno); 459 return 0; 460 } 461 } 462 #endif 463 #ifdef OPENSSL_SYS_VMS 464 status = sys$assign(&terminal, &channel, 0, 0); 465 466 /* if there isn't a TT device, something is very wrong */ 467 if (status != SS$_NORMAL) { 468 ERR_raise_data(ERR_LIB_UI, UI_R_SYSASSIGN_ERROR, 469 "status=%%X%08X", status); 470 return 0; 471 } 472 473 status = sys$qiow(0, channel, IO$_SENSEMODE, &iosb, 0, 0, tty_orig, 12, 474 0, 0, 0, 0); 475 476 /* If IO$_SENSEMODE doesn't work, this is not a terminal device */ 477 if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL)) 478 is_a_tty = 0; 479 #endif 480 return 1; 481 } 482 483 static int noecho_console(UI *ui) 484 { 485 #ifdef TTY_FLAGS 486 memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig)); 487 tty_new.TTY_FLAGS &= ~ECHO; 488 #endif 489 490 #if defined(TTY_set) && !defined(OPENSSL_SYS_VMS) 491 if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1)) 492 return 0; 493 #endif 494 #ifdef OPENSSL_SYS_VMS 495 if (is_a_tty) { 496 tty_new[0] = tty_orig[0]; 497 tty_new[1] = tty_orig[1] | TT$M_NOECHO; 498 tty_new[2] = tty_orig[2]; 499 status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, tty_new, 12, 500 0, 0, 0, 0); 501 if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL)) { 502 ERR_raise_data(ERR_LIB_UI, UI_R_SYSQIOW_ERROR, 503 "status=%%X%08X, iosb.iosb$w_value=%%X%08X", 504 status, iosb.iosb$w_value); 505 return 0; 506 } 507 } 508 #endif 509 #if defined(_WIN32) && !defined(_WIN32_WCE) 510 if (is_a_tty) { 511 tty_new = tty_orig; 512 tty_new &= ~ENABLE_ECHO_INPUT; 513 SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new); 514 } 515 #endif 516 return 1; 517 } 518 519 static int echo_console(UI *ui) 520 { 521 #if defined(TTY_set) && !defined(OPENSSL_SYS_VMS) 522 memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig)); 523 if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1)) 524 return 0; 525 #endif 526 #ifdef OPENSSL_SYS_VMS 527 if (is_a_tty) { 528 tty_new[0] = tty_orig[0]; 529 tty_new[1] = tty_orig[1]; 530 tty_new[2] = tty_orig[2]; 531 status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, tty_new, 12, 532 0, 0, 0, 0); 533 if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL)) { 534 ERR_raise_data(ERR_LIB_UI, UI_R_SYSQIOW_ERROR, 535 "status=%%X%08X, iosb.iosb$w_value=%%X%08X", 536 status, iosb.iosb$w_value); 537 return 0; 538 } 539 } 540 #endif 541 #if defined(_WIN32) && !defined(_WIN32_WCE) 542 if (is_a_tty) { 543 tty_new = tty_orig; 544 SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new); 545 } 546 #endif 547 return 1; 548 } 549 550 static int close_console(UI *ui) 551 { 552 int ret = 1; 553 554 if (tty_in != stdin) 555 fclose(tty_in); 556 if (tty_out != stderr) 557 fclose(tty_out); 558 #ifdef OPENSSL_SYS_VMS 559 status = sys$dassgn(channel); 560 if (status != SS$_NORMAL) { 561 ERR_raise_data(ERR_LIB_UI, UI_R_SYSDASSGN_ERROR, 562 "status=%%X%08X", status); 563 ret = 0; 564 } 565 #endif 566 CRYPTO_THREAD_unlock(ui->lock); 567 568 return ret; 569 } 570 571 #if !defined(OPENSSL_SYS_WINCE) 572 /* Internal functions to handle signals and act on them */ 573 static void pushsig(void) 574 { 575 #ifndef OPENSSL_SYS_WIN32 576 int i; 577 #endif 578 #ifdef SIGACTION 579 struct sigaction sa; 580 581 memset(&sa, 0, sizeof(sa)); 582 sa.sa_handler = recsig; 583 #endif 584 585 #ifdef OPENSSL_SYS_WIN32 586 savsig[SIGABRT] = signal(SIGABRT, recsig); 587 savsig[SIGFPE] = signal(SIGFPE, recsig); 588 savsig[SIGILL] = signal(SIGILL, recsig); 589 savsig[SIGINT] = signal(SIGINT, recsig); 590 savsig[SIGSEGV] = signal(SIGSEGV, recsig); 591 savsig[SIGTERM] = signal(SIGTERM, recsig); 592 #else 593 for (i = 1; i < NX509_SIG; i++) { 594 #ifdef SIGUSR1 595 if (i == SIGUSR1) 596 continue; 597 #endif 598 #ifdef SIGUSR2 599 if (i == SIGUSR2) 600 continue; 601 #endif 602 #ifdef SIGKILL 603 if (i == SIGKILL) /* We can't make any action on that. */ 604 continue; 605 #endif 606 #ifdef SIGACTION 607 sigaction(i, &sa, &savsig[i]); 608 #else 609 savsig[i] = signal(i, recsig); 610 #endif 611 } 612 #endif 613 614 #ifdef SIGWINCH 615 signal(SIGWINCH, SIG_DFL); 616 #endif 617 } 618 619 static void popsig(void) 620 { 621 #ifdef OPENSSL_SYS_WIN32 622 signal(SIGABRT, savsig[SIGABRT]); 623 signal(SIGFPE, savsig[SIGFPE]); 624 signal(SIGILL, savsig[SIGILL]); 625 signal(SIGINT, savsig[SIGINT]); 626 signal(SIGSEGV, savsig[SIGSEGV]); 627 signal(SIGTERM, savsig[SIGTERM]); 628 #else 629 int i; 630 for (i = 1; i < NX509_SIG; i++) { 631 #ifdef SIGUSR1 632 if (i == SIGUSR1) 633 continue; 634 #endif 635 #ifdef SIGUSR2 636 if (i == SIGUSR2) 637 continue; 638 #endif 639 #ifdef SIGACTION 640 sigaction(i, &savsig[i], NULL); 641 #else 642 signal(i, savsig[i]); 643 #endif 644 } 645 #endif 646 } 647 648 static void recsig(int i) 649 { 650 intr_signal = i; 651 } 652 #endif 653 654 /* Internal functions specific for Windows */ 655 #if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32) 656 static int noecho_fgets(char *buf, int size, FILE *tty) 657 { 658 int i; 659 char *p; 660 661 p = buf; 662 for (;;) { 663 if (size == 0) { 664 *p = '\0'; 665 break; 666 } 667 size--; 668 #if defined(_WIN32) 669 i = _getch(); 670 #else 671 i = getch(); 672 #endif 673 if (i == '\r') 674 i = '\n'; 675 *(p++) = i; 676 if (i == '\n') { 677 *p = '\0'; 678 break; 679 } 680 } 681 #ifdef WIN_CONSOLE_BUG 682 /* 683 * Win95 has several evil console bugs: one of these is that the last 684 * character read using getch() is passed to the next read: this is 685 * usually a CR so this can be trouble. No STDIO fix seems to work but 686 * flushing the console appears to do the trick. 687 */ 688 { 689 HANDLE inh; 690 inh = GetStdHandle(STD_INPUT_HANDLE); 691 FlushConsoleInputBuffer(inh); 692 } 693 #endif 694 return strlen(buf); 695 } 696 #endif 697 698 static UI_METHOD ui_openssl = { 699 "OpenSSL default user interface", 700 open_console, 701 write_string, 702 NULL, /* No flusher is needed for command lines */ 703 read_string, 704 close_console, 705 NULL 706 }; 707 708 /* The method with all the built-in console thingies */ 709 UI_METHOD *UI_OpenSSL(void) 710 { 711 return &ui_openssl; 712 } 713 714 static const UI_METHOD *default_UI_meth = &ui_openssl; 715 716 #else 717 718 static const UI_METHOD *default_UI_meth = NULL; 719 720 #endif 721 722 void UI_set_default_method(const UI_METHOD *meth) 723 { 724 default_UI_meth = meth; 725 } 726 727 const UI_METHOD *UI_get_default_method(void) 728 { 729 return default_UI_meth; 730 } 731