[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.10

1.10    ! deraadt     1: /*     $OpenBSD: misc.c,v 1.4 2001/02/28 17:52:54 deraadt Exp $        */
        !             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.10    ! deraadt    28: RCSID("$OpenBSD: cli.c,v 1.9 2001/02/10 12:44:02 markus 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;
                    139:
                    140:        if (!echo)
                    141:                cli_echo_disable();
                    142:
                    143:        while (ch != '\n') {
                    144:                if (read(cli_input, &ch, 1) != 1)
                    145:                        break;
                    146:                if (ch == '\n' || intr != 0)
                    147:                        break;
                    148:                if (i < size)
                    149:                        buf[i++] = ch;
                    150:        }
                    151:        buf[i] = '\0';
                    152:
                    153:        if (!echo)
                    154:                cli_echo_restore();
                    155:        if (!intr && !echo)
                    156:                (void) write(cli_output, "\n", 1);
                    157:        return i;
                    158: }
                    159:
                    160: static int
                    161: cli_write(char* buf, int size)
                    162: {
                    163:        int i, len, pos, ret = 0;
                    164:        char *output, *p;
                    165:
                    166:        output = xmalloc(4*size);
                    167:        for (p = output, i = 0; i < size; i++) {
1.9       markus    168:                if (buf[i] == '\n' || buf[i] == '\r')
1.7       stevesk   169:                        *p++ = buf[i];
                    170:                else
                    171:                        p = vis(p, buf[i], 0, 0);
                    172:        }
1.1       markus    173:        len = p - output;
                    174:
                    175:        for (pos = 0; pos < len; pos += ret) {
                    176:                ret = write(cli_output, output + pos, len - pos);
1.3       markus    177:                if (ret == -1) {
1.4       markus    178:                        xfree(output);
1.1       markus    179:                        return -1;
1.3       markus    180:                }
1.1       markus    181:        }
1.5       markus    182:        xfree(output);
1.1       markus    183:        return 0;
                    184: }
                    185:
                    186: /*
                    187:  * Presents a prompt and returns the response allocated with xmalloc().
                    188:  * Uses /dev/tty or stdin/out depending on arg.  Optionally disables echo
                    189:  * of response depending on arg.  Tries to ensure that no other userland
                    190:  * buffer is storing the response.
                    191:  */
                    192: char*
                    193: cli_read_passphrase(char* prompt, int from_stdin, int echo_enable)
                    194: {
                    195:        char    buf[BUFSIZ];
                    196:        char*   p;
                    197:
                    198:        if (!cli_open(from_stdin))
                    199:                fatal("Cannot read passphrase.");
                    200:
                    201:        fflush(stdout);
                    202:
                    203:        cli_write(prompt, strlen(prompt));
                    204:        cli_read(buf, sizeof buf, echo_enable);
                    205:
                    206:        cli_close();
                    207:
                    208:        p = xstrdup(buf);
                    209:        memset(buf, 0, sizeof(buf));
                    210:        return (p);
                    211: }
                    212:
                    213: char*
                    214: cli_prompt(char* prompt, int echo_enable)
                    215: {
                    216:        return cli_read_passphrase(prompt, 0, echo_enable);
                    217: }
                    218:
                    219: void
                    220: cli_mesg(char* mesg)
                    221: {
                    222:        cli_open(0);
                    223:        cli_write(mesg, strlen(mesg));
                    224:        cli_write("\n", strlen("\n"));
                    225:        cli_close();
                    226:        return;
                    227: }