]>
Commit | Line | Data |
---|---|---|
94ec8c6b | 1 | #include "includes.h" |
6c09e23c | 2 | RCSID("$OpenBSD: cli.c,v 1.2 2000/10/16 09:38:44 djm Exp $"); |
94ec8c6b | 3 | |
4 | #include "xmalloc.h" | |
5 | #include "ssh.h" | |
6 | ||
7 | static int cli_input = -1; | |
8 | static int cli_output = -1; | |
9 | static int cli_from_stdin = 0; | |
10 | ||
11 | sigset_t oset; | |
12 | sigset_t nset; | |
13 | struct sigaction nsa; | |
14 | struct sigaction osa; | |
15 | struct termios ntio; | |
16 | struct termios otio; | |
17 | int echo_modified; | |
18 | ||
19 | volatile int intr; | |
20 | ||
21 | static int | |
22 | cli_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 | ||
44 | static void | |
45 | cli_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 | ||
55 | void | |
56 | intrcatch() | |
57 | { | |
58 | intr = 1; | |
59 | } | |
60 | ||
61 | static void | |
62 | cli_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 | ||
84 | static void | |
85 | cli_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 | ||
105 | static int | |
106 | cli_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 | ||
131 | static int | |
132 | cli_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 | */ | |
160 | char* | |
161 | cli_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 | ||
181 | char* | |
182 | cli_prompt(char* prompt, int echo_enable) | |
183 | { | |
184 | return cli_read_passphrase(prompt, 0, echo_enable); | |
185 | } | |
186 | ||
187 | void | |
188 | cli_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 | } |