ui_openssl.c 16.5 KB
Newer Older
1
/*
R
Rich Salz 已提交
2
 * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
3
 *
R
Rich Salz 已提交
4 5 6 7
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
8 9
 */

10
#include <openssl/e_os2.h>
11
#include <openssl/err.h>
12

13 14
/*
 * need for #define _POSIX_C_SOURCE arises whenever you pass -ansi to gcc
15
 * [maybe others?], because it masks interfaces not discussed in standard,
16 17
 * sigaction and fileno included. -pedantic would be more appropriate for the
 * intended purposes, but we can't prevent users from adding -ansi.
18
 */
19
#if defined(OPENSSL_SYS_VXWORKS)
20
# include <sys/types.h>
D
Dr. Stephen Henson 已提交
21 22
#endif

D
Dr. Stephen Henson 已提交
23
#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
24 25 26
# ifndef _POSIX_C_SOURCE
#  define _POSIX_C_SOURCE 2
# endif
D
Dr. Stephen Henson 已提交
27
#endif
28 29 30 31 32
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

33 34 35 36 37 38
#if !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VMS)
# ifdef OPENSSL_UNISTD
#  include OPENSSL_UNISTD
# else
#  include <unistd.h>
# endif
39 40 41 42
/*
 * If unistd.h defines _POSIX_VERSION, we conclude that we are on a POSIX
 * system and have sigaction and termios.
 */
43
# if defined(_POSIX_VERSION)
44

45 46 47 48
#  define SIGACTION
#  if !defined(TERMIOS) && !defined(TERMIO) && !defined(SGTTY)
#   define TERMIOS
#  endif
49

50
# endif
51 52 53 54
#endif

/* 06-Apr-92 Luke Brennan    Support for VMS */
#include "ui_locl.h"
55
#include "internal/cryptlib.h"
56

57
#ifdef OPENSSL_SYS_VMS          /* prototypes for sys$whatever */
58 59 60 61
# include <starlet.h>
# ifdef __DECC
#  pragma message disable DOLLARID
# endif
62 63 64
#endif

#ifdef WIN_CONSOLE_BUG
65
# include <windows.h>
66 67 68
# ifndef OPENSSL_SYS_WINCE
#  include <wincon.h>
# endif
R
Richard Levitte 已提交
69
#endif
70

71
/*
72 73
 * There are 6 types of terminal interface supported, TERMIO, TERMIOS, VMS,
 * MSDOS, WIN32 Console and SGTTY.
74 75 76 77 78 79 80
 *
 * If someone defines one of the macros TERMIO, TERMIOS or SGTTY, it will
 * remain respected.  Otherwise, we default to TERMIOS except for a few
 * systems that require something different.
 *
 * Note: we do not use SGTTY unless it's defined by the configuration.  We
 * may eventually opt to remove it's use entirely.
81 82
 */

83
#if !defined(TERMIOS) && !defined(TERMIO) && !defined(SGTTY)
84

85 86 87 88 89
# if defined(_LIBC)
#  undef  TERMIOS
#  define TERMIO
#  undef  SGTTY
/*
R
Rich Salz 已提交
90
 * We know that VMS, MSDOS, VXWORKS, use entirely other mechanisms.
91 92 93
 */
# elif !defined(OPENSSL_SYS_VMS) \
	&& !defined(OPENSSL_SYS_MSDOS) \
R
Rich Salz 已提交
94
	&& !defined(OPENSSL_SYS_VXWORKS)
95 96 97 98
#  define TERMIOS
#  undef  TERMIO
#  undef  SGTTY
# endif
99

R
Richard Levitte 已提交
100 101
#endif

102
#ifdef TERMIOS
103
# include <termios.h>
104 105 106 107
# define TTY_STRUCT             struct termios
# define TTY_FLAGS              c_lflag
# define TTY_get(tty,data)      tcgetattr(tty,data)
# define TTY_set(tty,data)      tcsetattr(tty,TCSANOW,data)
108 109 110
#endif

#ifdef TERMIO
111
# include <termio.h>
112 113 114 115
# define TTY_STRUCT             struct termio
# define TTY_FLAGS              c_lflag
# define TTY_get(tty,data)      ioctl(tty,TCGETA,data)
# define TTY_set(tty,data)      ioctl(tty,TCSETA,data)
116 117 118
#endif

#ifdef SGTTY
119
# include <sgtty.h>
120 121 122 123
# define TTY_STRUCT             struct sgttyb
# define TTY_FLAGS              sg_flags
# define TTY_get(tty,data)      ioctl(tty,TIOCGETP,data)
# define TTY_set(tty,data)      ioctl(tty,TIOCSETP,data)
124 125
#endif

R
Rich Salz 已提交
126
#if !defined(_LIBC) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VMS)
127
# include <sys/ioctl.h>
128 129
#endif

130 131
#ifdef OPENSSL_SYS_MSDOS
# include <conio.h>
132 133
#endif

134 135 136 137 138
#ifdef OPENSSL_SYS_VMS
# include <ssdef.h>
# include <iodef.h>
# include <ttdef.h>
# include <descrip.h>
139
struct IOSB {
140 141 142 143
    short iosb$w_value;
    short iosb$w_count;
    long iosb$l_info;
};
144 145 146
#endif

#ifndef NX509_SIG
147
# define NX509_SIG 32
148 149 150 151 152 153
#endif

/* Define globals.  They are protected by a lock */
#ifdef SIGACTION
static struct sigaction savsig[NX509_SIG];
#else
154
static void (*savsig[NX509_SIG]) (int);
155 156
#endif

157
#ifdef OPENSSL_SYS_VMS
158
static struct IOSB iosb;
159 160 161 162
static $DESCRIPTOR(terminal, "TT");
static long tty_orig[3], tty_new[3]; /* XXX Is there any guarantee that this
                                      * will always suffice for the actual
                                      * structures? */
163 164
static long status;
static unsigned short channel = 0;
165 166
#elif defined(_WIN32) && !defined(_WIN32_WCE)
static DWORD tty_orig, tty_new;
167
#else
168 169 170
# if !defined(OPENSSL_SYS_MSDOS) || defined(__DJGPP__)
static TTY_STRUCT tty_orig, tty_new;
# endif
171
#endif
172
static FILE *tty_in, *tty_out;
173 174 175
static int is_a_tty;

/* Declare static functions */
R
Rich Salz 已提交
176
#if !defined(OPENSSL_SYS_WINCE)
177
static int read_till_nl(FILE *);
178 179 180
static void recsig(int);
static void pushsig(void);
static void popsig(void);
R
Richard Levitte 已提交
181
#endif
182
#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32)
183 184
static int noecho_fgets(char *buf, int size, FILE *tty);
#endif
185
static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl);
186 187

static int read_string(UI *ui, UI_STRING *uis);
188
static int write_string(UI *ui, UI_STRING *uis);
189 190 191 192 193 194

static int open_console(UI *ui);
static int echo_console(UI *ui);
static int noecho_console(UI *ui);
static int close_console(UI *ui);

195 196 197 198 199 200 201 202 203
static UI_METHOD ui_openssl = {
    "OpenSSL default user interface",
    open_console,
    write_string,
    NULL,                       /* No flusher is needed for command lines */
    read_string,
    close_console,
    NULL
};
204 205 206

/* The method with all the built-in thingies */
UI_METHOD *UI_OpenSSL(void)
207 208 209
{
    return &ui_openssl;
}
210

211 212 213 214
/*
 * The following function makes sure that info and error strings are printed
 * before any prompt.
 */
215
static int write_string(UI *ui, UI_STRING *uis)
216 217 218 219 220 221 222
{
    switch (UI_get_string_type(uis)) {
    case UIT_ERROR:
    case UIT_INFO:
        fputs(UI_get0_output_string(uis), tty_out);
        fflush(tty_out);
        break;
R
Rich Salz 已提交
223 224 225 226
    case UIT_NONE:
    case UIT_PROMPT:
    case UIT_VERIFY:
    case UIT_BOOLEAN:
227 228 229 230
        break;
    }
    return 1;
}
231 232

static int read_string(UI *ui, UI_STRING *uis)
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
{
    int ok = 0;

    switch (UI_get_string_type(uis)) {
    case UIT_BOOLEAN:
        fputs(UI_get0_output_string(uis), tty_out);
        fputs(UI_get0_action_string(uis), tty_out);
        fflush(tty_out);
        return read_string_inner(ui, uis,
                                 UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO,
                                 0);
    case UIT_PROMPT:
        fputs(UI_get0_output_string(uis), tty_out);
        fflush(tty_out);
        return read_string_inner(ui, uis,
                                 UI_get_input_flags(uis) & UI_INPUT_FLAG_ECHO,
                                 1);
    case UIT_VERIFY:
        fprintf(tty_out, "Verifying - %s", UI_get0_output_string(uis));
        fflush(tty_out);
        if ((ok = read_string_inner(ui, uis,
                                    UI_get_input_flags(uis) &
                                    UI_INPUT_FLAG_ECHO, 1)) <= 0)
            return ok;
        if (strcmp(UI_get0_result_string(uis), UI_get0_test_string(uis)) != 0) {
            fprintf(tty_out, "Verify failure\n");
            fflush(tty_out);
            return 0;
        }
        break;
R
Rich Salz 已提交
263 264 265
    case UIT_NONE:
    case UIT_INFO:
    case UIT_ERROR:
266 267 268 269
        break;
    }
    return 1;
}
270

R
Rich Salz 已提交
271
#if !defined(OPENSSL_SYS_WINCE)
272
/* Internal functions to read a string without echoing */
273
static int read_till_nl(FILE *in)
274 275 276
{
# define SIZE 4
    char buf[SIZE + 1];
277

278 279 280 281 282 283
    do {
        if (!fgets(buf, SIZE, in))
            return 0;
    } while (strchr(buf, '\n') == NULL);
    return 1;
}
284

285
static volatile sig_atomic_t intr_signal;
R
Richard Levitte 已提交
286
#endif
B
Ben Laurie 已提交
287

288
static int read_string_inner(UI *ui, UI_STRING *uis, int echo, int strip_nl)
289 290 291 292 293
{
    static int ps;
    int ok;
    char result[BUFSIZ];
    int maxsize = BUFSIZ - 1;
R
Rich Salz 已提交
294
#if !defined(OPENSSL_SYS_WINCE)
295 296
    char *p = NULL;
    int echo_eol = !echo;
297 298 299 300 301 302 303 304 305 306 307 308 309

    intr_signal = 0;
    ok = 0;
    ps = 0;

    pushsig();
    ps = 1;

    if (!echo && !noecho_console(ui))
        goto error;
    ps = 2;

    result[0] = '\0';
310 311 312 313
# if defined(_WIN32)
    if (is_a_tty) {
        DWORD numread;
#  if defined(CP_UTF8)
314 315
        if (GetEnvironmentVariableW(L"OPENSSL_WIN32_UTF8", NULL, 0) != 0) {
            WCHAR wresult[BUFSIZ];
316

317
            if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE),
318
                         wresult, maxsize, &numread, NULL)) {
319 320 321 322 323 324 325 326 327 328 329 330
                if (numread >= 2 &&
                    wresult[numread-2] == L'\r' &&
                    wresult[numread-1] == L'\n') {
                    wresult[numread-2] = L'\n';
                    numread--;
                }
                wresult[numread] = '\0';
                if (WideCharToMultiByte(CP_UTF8, 0, wresult, -1,
                                        result, sizeof(result), NULL, 0) > 0)
                    p = result;

                OPENSSL_cleanse(wresult, sizeof(wresult));
331
            }
332 333
        } else
#  endif
334 335 336 337 338 339 340 341 342 343 344 345
        if (ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
                         result, maxsize, &numread, NULL)) {
            if (numread >= 2 &&
                result[numread-2] == '\r' && result[numread-1] == '\n') {
                result[numread-2] = '\n';
                numread--;
            }
            result[numread] = '\0';
            p = result;
        }
    } else
# elif defined(OPENSSL_SYS_MSDOS)
346 347 348 349 350
    if (!echo) {
        noecho_fgets(result, maxsize, tty_in);
        p = result;             /* FIXME: noecho_fgets doesn't return errors */
    } else
# endif
351
    p = fgets(result, maxsize, tty_in);
R
Richard Levitte 已提交
352
    if (p == NULL)
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
        goto error;
    if (feof(tty_in))
        goto error;
    if (ferror(tty_in))
        goto error;
    if ((p = (char *)strchr(result, '\n')) != NULL) {
        if (strip_nl)
            *p = '\0';
    } else if (!read_till_nl(tty_in))
        goto error;
    if (UI_set_result(ui, uis, result) >= 0)
        ok = 1;

 error:
    if (intr_signal == SIGINT)
        ok = -1;
369
    if (echo_eol)
370 371 372 373 374 375
        fprintf(tty_out, "\n");
    if (ps >= 2 && !echo && !echo_console(ui))
        ok = 0;

    if (ps >= 1)
        popsig();
376
#else
377
    ok = 1;
378 379
#endif

380 381 382
    OPENSSL_cleanse(result, BUFSIZ);
    return ok;
}
383 384 385

/* Internal functions to open, handle and close a channel to the console.  */
static int open_console(UI *ui)
386
{
387
    CRYPTO_THREAD_write_lock(ui->lock);
388
    is_a_tty = 1;
389

R
Rich Salz 已提交
390
#if defined(OPENSSL_SYS_VXWORKS)
391 392
    tty_in = stdin;
    tty_out = stderr;
393 394 395 396 397 398 399 400 401 402 403
#elif defined(_WIN32) && !defined(_WIN32_WCE)
    if ((tty_out = fopen("conout$", "w")) == NULL)
        tty_out = stderr;

    if (GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &tty_orig)) {
        tty_in = stdin;
    } else {
        is_a_tty = 0;
        if ((tty_in = fopen("conin$", "r")) == NULL)
            tty_in = stdin;
    }
404
#else
405 406 407 408 409 410 411 412 413
# ifdef OPENSSL_SYS_MSDOS
#  define DEV_TTY "con"
# else
#  define DEV_TTY "/dev/tty"
# endif
    if ((tty_in = fopen(DEV_TTY, "r")) == NULL)
        tty_in = stdin;
    if ((tty_out = fopen(DEV_TTY, "w")) == NULL)
        tty_out = stderr;
414 415
#endif

416
#if defined(TTY_get) && !defined(OPENSSL_SYS_VMS)
417 418 419 420 421 422 423 424 425 426 427 428 429 430
    if (TTY_get(fileno(tty_in), &tty_orig) == -1) {
# ifdef ENOTTY
        if (errno == ENOTTY)
            is_a_tty = 0;
        else
# endif
# ifdef EINVAL
            /*
             * Ariel Glenn ariel@columbia.edu reports that solaris can return
             * EINVAL instead.  This should be ok
             */
        if (errno == EINVAL)
            is_a_tty = 0;
        else
431 432 433 434 435 436 437 438 439
# endif
# ifdef ENODEV
            /*
             * MacOS X returns ENODEV (Operation not supported by device),
             * which seems appropriate.
             */
        if (errno == ENODEV)
            is_a_tty = 0;
        else
440
# endif
441 442 443 444 445 446 447 448
            {
                char tmp_num[10];
                BIO_snprintf(tmp_num, sizeof(tmp_num) - 1, "%d", errno);
                UIerr(UI_F_OPEN_CONSOLE, UI_R_UNKNOWN_TTYGET_ERRNO_VALUE);
                ERR_add_error_data(2, "errno=", tmp_num);

                return 0;
            }
449
    }
450
#endif
451
#ifdef OPENSSL_SYS_VMS
452 453 454 455 456 457 458 459 460 461 462
    status = sys$assign(&terminal, &channel, 0, 0);
    if (status != SS$_NORMAL)
        return 0;
    status =
        sys$qiow(0, channel, IO$_SENSEMODE, &iosb, 0, 0, tty_orig, 12, 0, 0,
                 0, 0);
    if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL))
        return 0;
#endif
    return 1;
}
463 464

static int noecho_console(UI *ui)
465
{
466
#ifdef TTY_FLAGS
467 468
    memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig));
    tty_new.TTY_FLAGS &= ~ECHO;
469 470
#endif

471
#if defined(TTY_set) && !defined(OPENSSL_SYS_VMS)
472 473
    if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1))
        return 0;
474
#endif
475
#ifdef OPENSSL_SYS_VMS
476 477 478 479 480 481 482 483
    tty_new[0] = tty_orig[0];
    tty_new[1] = tty_orig[1] | TT$M_NOECHO;
    tty_new[2] = tty_orig[2];
    status =
        sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, tty_new, 12, 0, 0, 0,
                 0);
    if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL))
        return 0;
484 485 486 487 488 489 490
#endif
#if defined(_WIN32) && !defined(_WIN32_WCE)
    if (is_a_tty) {
        tty_new = tty_orig;
        tty_new &= ~ENABLE_ECHO_INPUT;
        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new);
    }
491 492 493
#endif
    return 1;
}
494 495

static int echo_console(UI *ui)
496
{
497
#if defined(TTY_set) && !defined(OPENSSL_SYS_VMS)
498 499
    memcpy(&(tty_new), &(tty_orig), sizeof(tty_orig));
    tty_new.TTY_FLAGS |= ECHO;
500 501
#endif

502
#if defined(TTY_set) && !defined(OPENSSL_SYS_VMS)
503 504
    if (is_a_tty && (TTY_set(fileno(tty_in), &tty_new) == -1))
        return 0;
505
#endif
506
#ifdef OPENSSL_SYS_VMS
507 508 509 510 511 512 513 514
    tty_new[0] = tty_orig[0];
    tty_new[1] = tty_orig[1] & ~TT$M_NOECHO;
    tty_new[2] = tty_orig[2];
    status =
        sys$qiow(0, channel, IO$_SETMODE, &iosb, 0, 0, tty_new, 12, 0, 0, 0,
                 0);
    if ((status != SS$_NORMAL) || (iosb.iosb$w_value != SS$_NORMAL))
        return 0;
515 516 517 518 519 520 521
#endif
#if defined(_WIN32) && !defined(_WIN32_WCE)
    if (is_a_tty) {
        tty_new = tty_orig;
        tty_new |= ENABLE_ECHO_INPUT;
        SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), tty_new);
    }
522 523 524
#endif
    return 1;
}
525 526

static int close_console(UI *ui)
527 528 529 530 531
{
    if (tty_in != stdin)
        fclose(tty_in);
    if (tty_out != stderr)
        fclose(tty_out);
532
#ifdef OPENSSL_SYS_VMS
533
    status = sys$dassgn(channel);
534
#endif
535
    CRYPTO_THREAD_unlock(ui->lock);
536

537 538
    return 1;
}
539

R
Rich Salz 已提交
540
#if !defined(OPENSSL_SYS_WINCE)
541 542
/* Internal functions to handle signals and act on them */
static void pushsig(void)
543 544 545 546 547 548
{
# ifndef OPENSSL_SYS_WIN32
    int i;
# endif
# ifdef SIGACTION
    struct sigaction sa;
549

550
    memset(&sa, 0, sizeof(sa));
551 552
    sa.sa_handler = recsig;
# endif
553

554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
# ifdef OPENSSL_SYS_WIN32
    savsig[SIGABRT] = signal(SIGABRT, recsig);
    savsig[SIGFPE] = signal(SIGFPE, recsig);
    savsig[SIGILL] = signal(SIGILL, recsig);
    savsig[SIGINT] = signal(SIGINT, recsig);
    savsig[SIGSEGV] = signal(SIGSEGV, recsig);
    savsig[SIGTERM] = signal(SIGTERM, recsig);
# else
    for (i = 1; i < NX509_SIG; i++) {
#  ifdef SIGUSR1
        if (i == SIGUSR1)
            continue;
#  endif
#  ifdef SIGUSR2
        if (i == SIGUSR2)
            continue;
#  endif
#  ifdef SIGKILL
        if (i == SIGKILL)       /* We can't make any action on that. */
            continue;
#  endif
#  ifdef SIGACTION
        sigaction(i, &sa, &savsig[i]);
#  else
        savsig[i] = signal(i, recsig);
#  endif
    }
# endif
582

583 584 585 586
# ifdef SIGWINCH
    signal(SIGWINCH, SIG_DFL);
# endif
}
587 588

static void popsig(void)
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
{
# ifdef OPENSSL_SYS_WIN32
    signal(SIGABRT, savsig[SIGABRT]);
    signal(SIGFPE, savsig[SIGFPE]);
    signal(SIGILL, savsig[SIGILL]);
    signal(SIGINT, savsig[SIGINT]);
    signal(SIGSEGV, savsig[SIGSEGV]);
    signal(SIGTERM, savsig[SIGTERM]);
# else
    int i;
    for (i = 1; i < NX509_SIG; i++) {
#  ifdef SIGUSR1
        if (i == SIGUSR1)
            continue;
#  endif
#  ifdef SIGUSR2
        if (i == SIGUSR2)
            continue;
#  endif
#  ifdef SIGACTION
        sigaction(i, &savsig[i], NULL);
#  else
        signal(i, savsig[i]);
#  endif
    }
# endif
}
616 617

static void recsig(int i)
618 619 620
{
    intr_signal = i;
}
R
Richard Levitte 已提交
621
#endif
622 623

/* Internal functions specific for Windows */
624
#if defined(OPENSSL_SYS_MSDOS) && !defined(_WIN32)
625
static int noecho_fgets(char *buf, int size, FILE *tty)
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
{
    int i;
    char *p;

    p = buf;
    for (;;) {
        if (size == 0) {
            *p = '\0';
            break;
        }
        size--;
# if defined(_WIN32)
        i = _getch();
# else
        i = getch();
# endif
        if (i == '\r')
            i = '\n';
        *(p++) = i;
        if (i == '\n') {
            *p = '\0';
            break;
        }
    }
# ifdef WIN_CONSOLE_BUG
    /*
     * Win95 has several evil console bugs: one of these is that the last
     * character read using getch() is passed to the next read: this is
     * usually a CR so this can be trouble. No STDIO fix seems to work but
     * flushing the console appears to do the trick.
     */
    {
        HANDLE inh;
        inh = GetStdHandle(STD_INPUT_HANDLE);
        FlushConsoleInputBuffer(inh);
    }
# endif
    return (strlen(buf));
}
665
#endif