Annotation of src/usr.bin/ssh/cli.c, Revision 1.12
1.12 ! mouring 1: /* $OpenBSD: cli.c,v 1.11 2001/03/06 00:33:04 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.12 ! mouring 28: RCSID("$OpenBSD: cli.c,v 1.11 2001/03/06 00:33:04 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
1.12 ! mouring 165: cli_write(const char* buf, int size)
1.1 markus 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*
1.12 ! mouring 197: cli_read_passphrase(const char* prompt, int from_stdin, int echo_enable)
1.1 markus 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: }