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: }