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 "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) & 243 UI_INPUT_FLAG_ECHO, 1)) <= 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 && 308 wresult[numread-2] == L'\r' && 309 wresult[numread-1] == L'\n') { 310 wresult[numread-2] = L'\n'; 311 numread--; 312 } 313 wresult[numread] = '\0'; 314 if (WideCharToMultiByte(CP_UTF8, 0, wresult, -1, 315 result, sizeof(result), NULL, 0) > 0) 316 p = result; 317 318 OPENSSL_cleanse(wresult, sizeof(wresult)); 319 } 320 } else 321 # endif 322 if (ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), 323 result, maxsize, &numread, NULL)) { 324 if (numread >= 2 && 325 result[numread-2] == '\r' && result[numread-1] == '\n') { 326 result[numread-2] = '\n'; 327 numread--; 328 } 329 result[numread] = '\0'; 330 p = result; 331 } 332 } else 333 # elif defined(OPENSSL_SYS_MSDOS) 334 if (!echo) { 335 noecho_fgets(result, maxsize, tty_in); 336 p = result; /* FIXME: noecho_fgets doesn't return errors */ 337 } else 338 # endif 339 p = fgets(result, maxsize, tty_in); 340 if (p == NULL) 341 goto error; 342 if (feof(tty_in)) 343 goto error; 344 if (ferror(tty_in)) 345 goto error; 346 if ((p = (char *)strchr(result, '\n')) != NULL) { 347 if (strip_nl) 348 *p = '\0'; 349 } else if (!read_till_nl(tty_in)) 350 goto error; 351 if (UI_set_result(ui, uis, result) >= 0) 352 ok = 1; 353 354 error: 355 if (intr_signal == SIGINT) 356 ok = -1; 357 if (echo_eol) 358 fprintf(tty_out, "\n"); 359 if (ps >= 2 && !echo && !echo_console(ui)) 360 ok = 0; 361 362 if (ps >= 1) 363 popsig(); 364 # else 365 ok = 1; 366 # endif 367 368 OPENSSL_cleanse(result, BUFSIZ); 369 return ok; 370 } 371 372 /* Internal functions to open, handle and close a channel to the console. */ 373 static int open_console(UI *ui) 374 { 375 if (!CRYPTO_THREAD_write_lock(ui->lock)) 376 return 0; 377 is_a_tty = 1; 378 379 # if defined(OPENSSL_SYS_VXWORKS) 380 tty_in = stdin; 381 tty_out = stderr; 382 # elif defined(_WIN32) && !defined(_WIN32_WCE) 383 if ((tty_out = fopen("conout$", "w")) == NULL) 384 tty_out = stderr; 385 386 if (GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &tty_orig)) { 387 tty_in = stdin; 388 } else { 389 is_a_tty = 0; 390 if ((tty_in = fopen("conin$", "r")) == NULL) 391 tty_in = stdin; 392 } 393 # else 394 # ifdef OPENSSL_SYS_MSDOS 395 # define DEV_TTY "con" 396 # else 397 # define DEV_TTY "/dev/tty" 398 # endif 399 if ((tty_in = fopen(DEV_TTY, "r")) == NULL) 400 tty_in = stdin; 401 if ((tty_out = fopen(DEV_TTY, "w")) == NULL) 402 tty_out = stderr; 403 # endif 404 405 # if defined(TTY_get) && !defined(OPENSSL_SYS_VMS) 406 if (TTY_get(fileno(tty_in), &tty_orig) == -1) { 407 # ifdef ENOTTY 408 if (errno == ENOTTY) 409 is_a_tty = 0; 410 else 411 # endif 412 # ifdef EINVAL 413 /* 414 * Ariel Glenn reports that solaris can return EINVAL instead. 415 * This should be ok 416 */ 417 if (errno == EINVAL) 418 is_a_tty = 0; 419 else 420 # endif 421 # ifdef ENXIO 422 /* 423 * Solaris can return ENXIO. 424 * This should be ok 425 */ 426 if (errno == ENXIO) 427 is_a_tty = 0; 428 else 429 # endif 430 # ifdef EIO 431 /* 432 * Linux can return EIO. 433 * This should be ok 434 */ 435 if (errno == EIO) 436 is_a_tty = 0; 437 else 438 # endif 439 # ifdef EPERM 440 /* 441 * Linux can return EPERM (Operation not permitted), 442 * e.g. if a daemon executes openssl via fork()+execve() 443 * This should be ok 444 */ 445 if (errno == EPERM) 446 is_a_tty = 0; 447 else 448 # endif 449 # ifdef ENODEV 450 /* 451 * MacOS X returns ENODEV (Operation not supported by device), 452 * which seems appropriate. 453 */ 454 if (errno == ENODEV) 455 is_a_tty = 0; 456 else 457 # endif 458 { 459 ERR_raise_data(ERR_LIB_UI, UI_R_UNKNOWN_TTYGET_ERRNO_VALUE, 460 "errno=%d", errno); 461 return 0; 462 } 463 } 464 # endif 465 # ifdef OPENSSL_SYS_VMS 466 status = sys$assign(&terminal, &channel, 0, 0); 467 468 /* if there isn't a TT device, something is very wrong */ 469 if (status != SS$_NORMAL) { 470 ERR_raise_data(ERR_LIB_UI, UI_R_SYSASSIGN_ERROR, 471 "status=%%X%08X", status); 472 return 0; 473 } 474 475 status = sys$qiow(0, channel, IO$_SENSEMODE, &iosb, 0, 0, tty_orig, 12, 476 0, 0, 0, 0); 477 478 /* If IO$_SENSEMODE doesn't work, this is not a terminal device */ 479 if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL)) 480 is_a_tty = 0; 481 # endif 482 return 1; 483 } 484 485 static int noecho_console(UI *ui) 486 { 487 # ifdef TTY_FLAGS 488 memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig)); 489 tty_new.TTY_FLAGS &= ~ECHO; 490 # endif 491 492 # if defined(TTY_set) && !defined(OPENSSL_SYS_VMS) 493 if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1)) 494 return 0; 495 # endif 496 # ifdef OPENSSL_SYS_VMS 497 if (is_a_tty) { 498 tty_new[0] = tty_orig[0]; 499 tty_new[1] = tty_orig[1] | TT$M_NOECHO; 500 tty_new[2] = tty_orig[2]; 501 status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, tty_new, 12, 502 0, 0, 0, 0); 503 if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL)) { 504 ERR_raise_data(ERR_LIB_UI, UI_R_SYSQIOW_ERROR, 505 "status=%%X%08X, iosb.iosb$w_value=%%X%08X", 506 status, iosb.iosb$w_value); 507 return 0; 508 } 509 } 510 # endif 511 # if defined(_WIN32) && !defined(_WIN32_WCE) 512 if (is_a_tty) { 513 tty_new = tty_orig; 514 tty_new &= ~ENABLE_ECHO_INPUT; 515 SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new); 516 } 517 # endif 518 return 1; 519 } 520 521 static int echo_console(UI *ui) 522 { 523 # if defined(TTY_set) && !defined(OPENSSL_SYS_VMS) 524 memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig)); 525 if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1)) 526 return 0; 527 # endif 528 # ifdef OPENSSL_SYS_VMS 529 if (is_a_tty) { 530 tty_new[0] = tty_orig[0]; 531 tty_new[1] = tty_orig[1]; 532 tty_new[2] = tty_orig[2]; 533 status = sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, tty_new, 12, 534 0, 0, 0, 0); 535 if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL)) { 536 ERR_raise_data(ERR_LIB_UI, UI_R_SYSQIOW_ERROR, 537 "status=%%X%08X, iosb.iosb$w_value=%%X%08X", 538 status, iosb.iosb$w_value); 539 return 0; 540 } 541 } 542 # endif 543 # if defined(_WIN32) && !defined(_WIN32_WCE) 544 if (is_a_tty) { 545 tty_new = tty_orig; 546 SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new); 547 } 548 # endif 549 return 1; 550 } 551 552 static int close_console(UI *ui) 553 { 554 int ret = 1; 555 556 if (tty_in != stdin) 557 fclose(tty_in); 558 if (tty_out != stderr) 559 fclose(tty_out); 560 # ifdef OPENSSL_SYS_VMS 561 status = sys$dassgn(channel); 562 if (status != SS$_NORMAL) { 563 ERR_raise_data(ERR_LIB_UI, UI_R_SYSDASSGN_ERROR, 564 "status=%%X%08X", status); 565 ret = 0; 566 } 567 # endif 568 CRYPTO_THREAD_unlock(ui->lock); 569 570 return ret; 571 } 572 573 # if !defined(OPENSSL_SYS_WINCE) 574 /* Internal functions to handle signals and act on them */ 575 static void pushsig(void) 576 { 577 # ifndef OPENSSL_SYS_WIN32 578 int i; 579 # endif 580 # ifdef SIGACTION 581 struct sigaction sa; 582 583 memset(&sa, 0, sizeof(sa)); 584 sa.sa_handler = recsig; 585 # endif 586 587 # ifdef OPENSSL_SYS_WIN32 588 savsig[SIGABRT] = signal(SIGABRT, recsig); 589 savsig[SIGFPE] = signal(SIGFPE, recsig); 590 savsig[SIGILL] = signal(SIGILL, recsig); 591 savsig[SIGINT] = signal(SIGINT, recsig); 592 savsig[SIGSEGV] = signal(SIGSEGV, recsig); 593 savsig[SIGTERM] = signal(SIGTERM, recsig); 594 # else 595 for (i = 1; i < NX509_SIG; i++) { 596 # ifdef SIGUSR1 597 if (i == SIGUSR1) 598 continue; 599 # endif 600 # ifdef SIGUSR2 601 if (i == SIGUSR2) 602 continue; 603 # endif 604 # ifdef SIGKILL 605 if (i == SIGKILL) /* We can't make any action on that. */ 606 continue; 607 # endif 608 # ifdef SIGACTION 609 sigaction(i, &sa, &savsig[i]); 610 # else 611 savsig[i] = signal(i, recsig); 612 # endif 613 } 614 # endif 615 616 # ifdef SIGWINCH 617 signal(SIGWINCH, SIG_DFL); 618 # endif 619 } 620 621 static void popsig(void) 622 { 623 # ifdef OPENSSL_SYS_WIN32 624 signal(SIGABRT, savsig[SIGABRT]); 625 signal(SIGFPE, savsig[SIGFPE]); 626 signal(SIGILL, savsig[SIGILL]); 627 signal(SIGINT, savsig[SIGINT]); 628 signal(SIGSEGV, savsig[SIGSEGV]); 629 signal(SIGTERM, savsig[SIGTERM]); 630 # else 631 int i; 632 for (i = 1; i < NX509_SIG; i++) { 633 # ifdef SIGUSR1 634 if (i == SIGUSR1) 635 continue; 636 # endif 637 # ifdef SIGUSR2 638 if (i == SIGUSR2) 639 continue; 640 # endif 641 # ifdef SIGACTION 642 sigaction(i, &savsig[i], NULL); 643 # else 644 signal(i, savsig[i]); 645 # endif 646 } 647 # endif 648 } 649 650 static void recsig(int i) 651 { 652 intr_signal = i; 653 } 654 # endif 655 656 /* Internal functions specific for Windows */ 657 # if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32) 658 static int noecho_fgets(char *buf, int size, FILE *tty) 659 { 660 int i; 661 char *p; 662 663 p = buf; 664 for (;;) { 665 if (size == 0) { 666 *p = '\0'; 667 break; 668 } 669 size--; 670 # if defined(_WIN32) 671 i = _getch(); 672 # else 673 i = getch(); 674 # endif 675 if (i == '\r') 676 i = '\n'; 677 *(p++) = i; 678 if (i == '\n') { 679 *p = '\0'; 680 break; 681 } 682 } 683 # ifdef WIN_CONSOLE_BUG 684 /* 685 * Win95 has several evil console bugs: one of these is that the last 686 * character read using getch() is passed to the next read: this is 687 * usually a CR so this can be trouble. No STDIO fix seems to work but 688 * flushing the console appears to do the trick. 689 */ 690 { 691 HANDLE inh; 692 inh = GetStdHandle(STD_INPUT_HANDLE); 693 FlushConsoleInputBuffer(inh); 694 } 695 # endif 696 return strlen(buf); 697 } 698 # endif 699 700 static UI_METHOD ui_openssl = { 701 "OpenSSL default user interface", 702 open_console, 703 write_string, 704 NULL, /* No flusher is needed for command lines */ 705 read_string, 706 close_console, 707 NULL 708 }; 709 710 /* The method with all the built-in console thingies */ 711 UI_METHOD *UI_OpenSSL(void) 712 { 713 return &ui_openssl; 714 } 715 716 static const UI_METHOD *default_UI_meth = &ui_openssl; 717 718 #else 719 720 static const UI_METHOD *default_UI_meth = NULL; 721 722 #endif 723 724 void UI_set_default_method(const UI_METHOD *meth) 725 { 726 default_UI_meth = meth; 727 } 728 729 const UI_METHOD *UI_get_default_method(void) 730 { 731 return default_UI_meth; 732 } 733