[BACK]Return to cli.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/cli.c, Revision 1.11

1.11    ! deraadt     1: /*     $OpenBSD: cli.c,v 1.10 2001/03/01 03:38:33 deraadt Exp $        */
1.10      deraadt     2:
                      3: /*
                      4:  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  *
                     15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     16:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     17:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     18:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     19:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     20:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     21:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     22:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     23:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     24:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     25:  */
                     26:
1.1       markus     27: #include "includes.h"
1.11    ! deraadt    28: RCSID("$OpenBSD: cli.c,v 1.10 2001/03/01 03:38:33 deraadt Exp $");
1.1       markus     29:
                     30: #include "xmalloc.h"
1.6       markus     31: #include "log.h"
1.8       itojun     32: #include "cli.h"
1.6       markus     33:
1.1       markus     34: #include <vis.h>
                     35:
                     36: static int cli_input = -1;
                     37: static int cli_output = -1;
                     38: static int cli_from_stdin = 0;
                     39:
                     40: sigset_t oset;
                     41: sigset_t nset;
                     42: struct sigaction nsa;
                     43: struct sigaction osa;
                     44: struct termios ntio;
                     45: struct termios otio;
                     46: int echo_modified;
                     47:
                     48: volatile int intr;
                     49:
                     50: static int
                     51: cli_open(int from_stdin)
                     52: {
                     53:        if (cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin)
                     54:                return 1;
                     55:
                     56:        if (from_stdin) {
                     57:                if (!cli_from_stdin && cli_input >= 0) {
                     58:                        (void)close(cli_input);
                     59:                }
                     60:                cli_input = STDIN_FILENO;
                     61:                cli_output = STDERR_FILENO;
                     62:        } else {
1.8       itojun     63:                cli_input = cli_output = open(_PATH_TTY, O_RDWR);
1.1       markus     64:                if (cli_input < 0)
                     65:                        fatal("You have no controlling tty.  Cannot read passphrase.");
                     66:        }
                     67:
                     68:        cli_from_stdin = from_stdin;
                     69:
                     70:        return cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin;
                     71: }
                     72:
                     73: static void
1.8       itojun     74: cli_close(void)
1.1       markus     75: {
                     76:        if (!cli_from_stdin && cli_input >= 0)
                     77:                close(cli_input);
                     78:        cli_input = -1;
                     79:        cli_output = -1;
                     80:        cli_from_stdin = 0;
                     81:        return;
                     82: }
                     83:
                     84: void
1.8       itojun     85: intrcatch(int sig)
1.1       markus     86: {
                     87:        intr = 1;
                     88: }
                     89:
                     90: static void
1.8       itojun     91: cli_echo_disable(void)
1.1       markus     92: {
                     93:        sigemptyset(&nset);
                     94:        sigaddset(&nset, SIGTSTP);
                     95:        (void) sigprocmask(SIG_BLOCK, &nset, &oset);
                     96:
                     97:        intr = 0;
                     98:
                     99:        memset(&nsa, 0, sizeof(nsa));
                    100:        nsa.sa_handler = intrcatch;
                    101:        (void) sigaction(SIGINT, &nsa, &osa);
                    102:
                    103:        echo_modified = 0;
                    104:        if (tcgetattr(cli_input, &otio) == 0 && (otio.c_lflag & ECHO)) {
                    105:                echo_modified = 1;
                    106:                ntio = otio;
                    107:                ntio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
                    108:                (void) tcsetattr(cli_input, TCSANOW, &ntio);
                    109:        }
                    110:        return;
                    111: }
                    112:
                    113: static void
1.8       itojun    114: cli_echo_restore(void)
1.1       markus    115: {
                    116:        if (echo_modified != 0) {
                    117:                tcsetattr(cli_input, TCSANOW, &otio);
                    118:                echo_modified = 0;
                    119:        }
                    120:
                    121:        (void) sigprocmask(SIG_SETMASK, &oset, NULL);
                    122:        (void) sigaction(SIGINT, &osa, NULL);
                    123:
                    124:        if (intr != 0) {
                    125:                kill(getpid(), SIGINT);
                    126:                sigemptyset(&nset);
                    127:                /* XXX tty has not neccessarily drained by now? */
                    128:                sigsuspend(&nset);
                    129:                intr = 0;
                    130:        }
                    131:        return;
                    132: }
                    133:
                    134: static int
                    135: cli_read(char* buf, int size, int echo)
                    136: {
                    137:        char ch = 0;
                    138:        int i = 0;
1.11    ! deraadt   139:        int n;
1.1       markus    140:
                    141:        if (!echo)
                    142:                cli_echo_disable();
                    143:
                    144:        while (ch != '\n') {
1.11    ! deraadt   145:                n = read(cli_input, &ch, 1);
        !           146:                if (n == -1 && (errno == EAGAIN || errno == EINTR))
        !           147:                        continue;
        !           148:                if (n != 1)
1.1       markus    149:                        break;
                    150:                if (ch == '\n' || intr != 0)
                    151:                        break;
                    152:                if (i < size)
                    153:                        buf[i++] = ch;
                    154:        }
                    155:        buf[i] = '\0';
                    156:
                    157:        if (!echo)
                    158:                cli_echo_restore();
                    159:        if (!intr && !echo)
                    160:                (void) write(cli_output, "\n", 1);
                    161:        return i;
                    162: }
                    163:
                    164: static int
                    165: cli_write(char* buf, int size)
                    166: {
                    167:        int i, len, pos, ret = 0;
                    168:        char *output, *p;
                    169:
                    170:        output = xmalloc(4*size);
                    171:        for (p = output, i = 0; i < size; i++) {
1.9       markus    172:                if (buf[i] == '\n' || buf[i] == '\r')
1.7       stevesk   173:                        *p++ = buf[i];
                    174:                else
                    175:                        p = vis(p, buf[i], 0, 0);
                    176:        }
1.1       markus    177:        len = p - output;
                    178:
                    179:        for (pos = 0; pos < len; pos += ret) {
                    180:                ret = write(cli_output, output + pos, len - pos);
1.3       markus    181:                if (ret == -1) {
1.4       markus    182:                        xfree(output);
1.1       markus    183:                        return -1;
1.3       markus    184:                }
1.1       markus    185:        }
1.5       markus    186:        xfree(output);
1.1       markus    187:        return 0;
                    188: }
                    189:
                    190: /*
                    191:  * Presents a prompt and returns the response allocated with xmalloc().
                    192:  * Uses /dev/tty or stdin/out depending on arg.  Optionally disables echo
                    193:  * of response depending on arg.  Tries to ensure that no other userland
                    194:  * buffer is storing the response.
                    195:  */
                    196: char*
                    197: cli_read_passphrase(char* prompt, int from_stdin, int echo_enable)
                    198: {
                    199:        char    buf[BUFSIZ];
                    200:        char*   p;
                    201:
                    202:        if (!cli_open(from_stdin))
                    203:                fatal("Cannot read passphrase.");
                    204:
                    205:        fflush(stdout);
                    206:
                    207:        cli_write(prompt, strlen(prompt));
                    208:        cli_read(buf, sizeof buf, echo_enable);
                    209:
                    210:        cli_close();
                    211:
                    212:        p = xstrdup(buf);
                    213:        memset(buf, 0, sizeof(buf));
                    214:        return (p);
                    215: }
                    216:
                    217: char*
                    218: cli_prompt(char* prompt, int echo_enable)
                    219: {
                    220:        return cli_read_passphrase(prompt, 0, echo_enable);
                    221: }
                    222:
                    223: void
                    224: cli_mesg(char* mesg)
                    225: {
                    226:        cli_open(0);
                    227:        cli_write(mesg, strlen(mesg));
                    228:        cli_write("\n", strlen("\n"));
                    229:        cli_close();
                    230:        return;
                    231: }