blob: 27d0d9e18cbc861b48ab746f24bad94527f7e334 [file] [log] [blame]
Damien Miller874d77b2000-10-14 16:23:11 +11001#include "includes.h"
Damien Miller389edc42000-11-06 12:39:34 +11002RCSID("$OpenBSD: cli.c,v 1.2 2000/10/16 09:38:44 djm Exp $");
Damien Miller874d77b2000-10-14 16:23:11 +11003
4#include "xmalloc.h"
5#include "ssh.h"
6
7static int cli_input = -1;
8static int cli_output = -1;
9static int cli_from_stdin = 0;
10
11sigset_t oset;
12sigset_t nset;
13struct sigaction nsa;
14struct sigaction osa;
15struct termios ntio;
16struct termios otio;
17int echo_modified;
18
19volatile int intr;
20
21static int
22cli_open(int from_stdin)
23{
24 if (cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin)
25 return 1;
26
27 if (from_stdin) {
28 if (!cli_from_stdin && cli_input >= 0) {
29 (void)close(cli_input);
30 }
31 cli_input = STDIN_FILENO;
32 cli_output = STDERR_FILENO;
33 } else {
34 cli_input = cli_output = open("/dev/tty", O_RDWR);
35 if (cli_input < 0)
36 fatal("You have no controlling tty. Cannot read passphrase.");
37 }
38
39 cli_from_stdin = from_stdin;
40
41 return cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin;
42}
43
44static void
45cli_close()
46{
47 if (!cli_from_stdin && cli_input >= 0)
48 close(cli_input);
49 cli_input = -1;
50 cli_output = -1;
51 cli_from_stdin = 0;
52 return;
53}
54
55void
56intrcatch()
57{
58 intr = 1;
59}
60
61static void
62cli_echo_disable()
63{
64 sigemptyset(&nset);
65 sigaddset(&nset, SIGTSTP);
66 (void) sigprocmask(SIG_BLOCK, &nset, &oset);
67
68 intr = 0;
69
70 memset(&nsa, 0, sizeof(nsa));
71 nsa.sa_handler = intrcatch;
72 (void) sigaction(SIGINT, &nsa, &osa);
73
74 echo_modified = 0;
75 if (tcgetattr(cli_input, &otio) == 0 && (otio.c_lflag & ECHO)) {
76 echo_modified = 1;
77 ntio = otio;
78 ntio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
79 (void) tcsetattr(cli_input, TCSANOW, &ntio);
80 }
81 return;
82}
83
84static void
85cli_echo_restore()
86{
87 if (echo_modified != 0) {
88 tcsetattr(cli_input, TCSANOW, &otio);
89 echo_modified = 0;
90 }
91
92 (void) sigprocmask(SIG_SETMASK, &oset, NULL);
93 (void) sigaction(SIGINT, &osa, NULL);
94
95 if (intr != 0) {
96 kill(getpid(), SIGINT);
97 sigemptyset(&nset);
98 /* XXX tty has not neccessarily drained by now? */
99 sigsuspend(&nset);
100 intr = 0;
101 }
102 return;
103}
104
105static int
106cli_read(char* buf, int size, int echo)
107{
108 char ch = 0;
109 int i = 0;
110
111 if (!echo)
112 cli_echo_disable();
113
114 while (ch != '\n') {
115 if (read(cli_input, &ch, 1) != 1)
116 break;
117 if (ch == '\n' || intr != 0)
118 break;
119 if (i < size)
120 buf[i++] = ch;
121 }
122 buf[i] = '\0';
123
124 if (!echo)
125 cli_echo_restore();
126 if (!intr && !echo)
127 (void) write(cli_output, "\n", 1);
128 return i;
129}
130
131static int
132cli_write(char* buf, int size)
133{
134 int i, len, pos, ret = 0;
135 char *output, *p;
136
137 output = xmalloc(4*size);
138 for (p = output, i = 0; i < size; i++) {
139 if (buf[i] == '\n')
140 *p++ = buf[i];
141 else
142 p = vis(p, buf[i], 0, 0);
143 }
144 len = p - output;
145
146 for (pos = 0; pos < len; pos += ret) {
147 ret = write(cli_output, output + pos, len - pos);
148 if (ret == -1)
149 return -1;
150 }
151 return 0;
152}
153
154/*
155 * Presents a prompt and returns the response allocated with xmalloc().
156 * Uses /dev/tty or stdin/out depending on arg. Optionally disables echo
157 * of response depending on arg. Tries to ensure that no other userland
158 * buffer is storing the response.
159 */
160char*
161cli_read_passphrase(char* prompt, int from_stdin, int echo_enable)
162{
163 char buf[BUFSIZ];
164 char* p;
165
166 if (!cli_open(from_stdin))
167 fatal("Cannot read passphrase.");
168
169 fflush(stdout);
170
171 cli_write(prompt, strlen(prompt));
172 cli_read(buf, sizeof buf, echo_enable);
173
174 cli_close();
175
176 p = xstrdup(buf);
177 memset(buf, 0, sizeof(buf));
178 return (p);
179}
180
181char*
182cli_prompt(char* prompt, int echo_enable)
183{
184 return cli_read_passphrase(prompt, 0, echo_enable);
185}
186
187void
188cli_mesg(char* mesg)
189{
190 cli_open(0);
191 cli_write(mesg, strlen(mesg));
192 cli_write("\n", strlen("\n"));
193 cli_close();
194 return;
195}