]>
Commit | Line | Data |
---|---|---|
94ec8c6b | 1 | #include "includes.h" |
b35eb612 | 2 | RCSID("$OpenBSD: cli.c,v 1.7 2001/02/04 15:32:23 stevesk Exp $"); |
94ec8c6b | 3 | |
4 | #include "xmalloc.h" | |
42f11eb2 | 5 | #include "log.h" |
94ec8c6b | 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 | |
8694a1ce | 132 | cli_write(const char* buf, int size) |
94ec8c6b | 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++) { | |
2b87da3b | 139 | if (buf[i] == '\n') |
140 | *p++ = buf[i]; | |
141 | else | |
142 | p = vis(p, buf[i], 0, 0); | |
143 | } | |
94ec8c6b | 144 | len = p - output; |
145 | ||
146 | for (pos = 0; pos < len; pos += ret) { | |
147 | ret = write(cli_output, output + pos, len - pos); | |
bbcf899f | 148 | if (ret == -1) { |
149 | xfree(output); | |
94ec8c6b | 150 | return -1; |
bbcf899f | 151 | } |
94ec8c6b | 152 | } |
bbcf899f | 153 | xfree(output); |
94ec8c6b | 154 | return 0; |
155 | } | |
156 | ||
157 | /* | |
158 | * Presents a prompt and returns the response allocated with xmalloc(). | |
159 | * Uses /dev/tty or stdin/out depending on arg. Optionally disables echo | |
160 | * of response depending on arg. Tries to ensure that no other userland | |
161 | * buffer is storing the response. | |
162 | */ | |
163 | char* | |
8694a1ce | 164 | cli_read_passphrase(const char* prompt, int from_stdin, int echo_enable) |
94ec8c6b | 165 | { |
166 | char buf[BUFSIZ]; | |
167 | char* p; | |
168 | ||
169 | if (!cli_open(from_stdin)) | |
170 | fatal("Cannot read passphrase."); | |
171 | ||
172 | fflush(stdout); | |
173 | ||
174 | cli_write(prompt, strlen(prompt)); | |
175 | cli_read(buf, sizeof buf, echo_enable); | |
176 | ||
177 | cli_close(); | |
178 | ||
179 | p = xstrdup(buf); | |
180 | memset(buf, 0, sizeof(buf)); | |
181 | return (p); | |
182 | } | |
183 | ||
184 | char* | |
185 | cli_prompt(char* prompt, int echo_enable) | |
186 | { | |
187 | return cli_read_passphrase(prompt, 0, echo_enable); | |
188 | } | |
189 | ||
190 | void | |
191 | cli_mesg(char* mesg) | |
192 | { | |
193 | cli_open(0); | |
194 | cli_write(mesg, strlen(mesg)); | |
195 | cli_write("\n", strlen("\n")); | |
196 | cli_close(); | |
197 | return; | |
198 | } |