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> 143struct 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 156static struct sigaction savsig[NX509_SIG]; 157# else 158static void (*savsig[NX509_SIG]) (int); 159# endif 160 161# ifdef OPENSSL_SYS_VMS 162static struct IOSB iosb; 163static $DESCRIPTOR(terminal, "TT"); 164static long tty_orig[3], tty_new[3]; /* XXX Is there any guarantee that this 165 * will always suffice for the actual 166 * structures? */ 167static long status; 168static unsigned short channel = 0; 169# elif defined(_WIN32) && !defined(_WIN32_WCE) 170static DWORD tty_orig, tty_new; 171# else 172# if !defined(OPENSSL_SYS_MSDOS) || defined(__DJGPP__) 173static TTY_STRUCT tty_orig, tty_new; 174# endif 175# endif 176static FILE *tty_in, *tty_out; 177static int is_a_tty; 178 179/* Declare static functions */ 180# if !defined(OPENSSL_SYS_WINCE) 181static int read_till_nl(FILE *); 182static void recsig(int); 183static void pushsig(void); 184static void popsig(void); 185# endif 186# if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32) 187static int noecho_fgets(char *buf, int size, FILE *tty); 188# endif 189static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl); 190 191static int read_string(UI *ui, UI_STRING *uis); 192static int write_string(UI *ui, UI_STRING *uis); 193 194static int open_console(UI *ui); 195static int echo_console(UI *ui); 196static int noecho_console(UI *ui); 197static 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 */ 203static 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 220static 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 */ 261static 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 273static volatile sig_atomic_t intr_signal; 274# endif 275 276static 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. */ 373static 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 485static 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 521static 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 552static 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 */ 575static 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 621static 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 650static 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) 658static 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 700static 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 */ 711UI_METHOD *UI_OpenSSL(void) 712{ 713 return &ui_openssl; 714} 715 716static const UI_METHOD *default_UI_meth = &ui_openssl; 717 718#else 719 720static const UI_METHOD *default_UI_meth = NULL; 721 722#endif 723 724void UI_set_default_method(const UI_METHOD *meth) 725{ 726 default_UI_meth = meth; 727} 728 729const UI_METHOD *UI_get_default_method(void) 730{ 731 return default_UI_meth; 732} 733