summaryrefslogtreecommitdiff
path: root/readpass.c
diff options
context:
space:
mode:
Diffstat (limited to 'readpass.c')
-rw-r--r--readpass.c119
1 files changed, 107 insertions, 12 deletions
diff --git a/readpass.c b/readpass.c
index 7e52cae9c..974d67f0b 100644
--- a/readpass.c
+++ b/readpass.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: readpass.c,v 1.54 2019/06/28 13:35:04 deraadt Exp $ */ 1/* $OpenBSD: readpass.c,v 1.61 2020/01/23 07:10:22 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -48,7 +48,7 @@
48#include "uidswap.h" 48#include "uidswap.h"
49 49
50static char * 50static char *
51ssh_askpass(char *askpass, const char *msg) 51ssh_askpass(char *askpass, const char *msg, const char *env_hint)
52{ 52{
53 pid_t pid, ret; 53 pid_t pid, ret;
54 size_t len; 54 size_t len;
@@ -58,25 +58,27 @@ ssh_askpass(char *askpass, const char *msg)
58 void (*osigchld)(int); 58 void (*osigchld)(int);
59 59
60 if (fflush(stdout) != 0) 60 if (fflush(stdout) != 0)
61 error("ssh_askpass: fflush: %s", strerror(errno)); 61 error("%s: fflush: %s", __func__, strerror(errno));
62 if (askpass == NULL) 62 if (askpass == NULL)
63 fatal("internal error: askpass undefined"); 63 fatal("internal error: askpass undefined");
64 if (pipe(p) == -1) { 64 if (pipe(p) == -1) {
65 error("ssh_askpass: pipe: %s", strerror(errno)); 65 error("%s: pipe: %s", __func__, strerror(errno));
66 return NULL; 66 return NULL;
67 } 67 }
68 osigchld = signal(SIGCHLD, SIG_DFL); 68 osigchld = ssh_signal(SIGCHLD, SIG_DFL);
69 if ((pid = fork()) == -1) { 69 if ((pid = fork()) == -1) {
70 error("ssh_askpass: fork: %s", strerror(errno)); 70 error("%s: fork: %s", __func__, strerror(errno));
71 signal(SIGCHLD, osigchld); 71 ssh_signal(SIGCHLD, osigchld);
72 return NULL; 72 return NULL;
73 } 73 }
74 if (pid == 0) { 74 if (pid == 0) {
75 close(p[0]); 75 close(p[0]);
76 if (dup2(p[1], STDOUT_FILENO) == -1) 76 if (dup2(p[1], STDOUT_FILENO) == -1)
77 fatal("ssh_askpass: dup2: %s", strerror(errno)); 77 fatal("%s: dup2: %s", __func__, strerror(errno));
78 if (env_hint != NULL)
79 setenv("SSH_ASKPASS_PROMPT", env_hint, 1);
78 execlp(askpass, askpass, msg, (char *)NULL); 80 execlp(askpass, askpass, msg, (char *)NULL);
79 fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); 81 fatal("%s: exec(%s): %s", __func__, askpass, strerror(errno));
80 } 82 }
81 close(p[1]); 83 close(p[1]);
82 84
@@ -96,7 +98,7 @@ ssh_askpass(char *askpass, const char *msg)
96 while ((ret = waitpid(pid, &status, 0)) == -1) 98 while ((ret = waitpid(pid, &status, 0)) == -1)
97 if (errno != EINTR) 99 if (errno != EINTR)
98 break; 100 break;
99 signal(SIGCHLD, osigchld); 101 ssh_signal(SIGCHLD, osigchld);
100 if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) { 102 if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
101 explicit_bzero(buf, sizeof(buf)); 103 explicit_bzero(buf, sizeof(buf));
102 return NULL; 104 return NULL;
@@ -108,6 +110,9 @@ ssh_askpass(char *askpass, const char *msg)
108 return pass; 110 return pass;
109} 111}
110 112
113/* private/internal read_passphrase flags */
114#define RP_ASK_PERMISSION 0x8000 /* pass hint to askpass for confirm UI */
115
111/* 116/*
112 * Reads a passphrase from /dev/tty with echo turned off/on. Returns the 117 * Reads a passphrase from /dev/tty with echo turned off/on. Returns the
113 * passphrase (allocated with xmalloc). Exits if EOF is encountered. If 118 * passphrase (allocated with xmalloc). Exits if EOF is encountered. If
@@ -119,6 +124,7 @@ read_passphrase(const char *prompt, int flags)
119{ 124{
120 char cr = '\r', *askpass = NULL, *ret, buf[1024]; 125 char cr = '\r', *askpass = NULL, *ret, buf[1024];
121 int rppflags, use_askpass = 0, ttyfd; 126 int rppflags, use_askpass = 0, ttyfd;
127 const char *askpass_hint = NULL;
122 128
123 rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF; 129 rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF;
124 if (flags & RP_USE_ASKPASS) 130 if (flags & RP_USE_ASKPASS)
@@ -155,7 +161,9 @@ read_passphrase(const char *prompt, int flags)
155 askpass = getenv(SSH_ASKPASS_ENV); 161 askpass = getenv(SSH_ASKPASS_ENV);
156 else 162 else
157 askpass = _PATH_SSH_ASKPASS_DEFAULT; 163 askpass = _PATH_SSH_ASKPASS_DEFAULT;
158 if ((ret = ssh_askpass(askpass, prompt)) == NULL) 164 if ((flags & RP_ASK_PERMISSION) != 0)
165 askpass_hint = "confirm";
166 if ((ret = ssh_askpass(askpass, prompt, askpass_hint)) == NULL)
159 if (!(flags & RP_ALLOW_EOF)) 167 if (!(flags & RP_ALLOW_EOF))
160 return xstrdup(""); 168 return xstrdup("");
161 return ret; 169 return ret;
@@ -183,7 +191,8 @@ ask_permission(const char *fmt, ...)
183 vsnprintf(prompt, sizeof(prompt), fmt, args); 191 vsnprintf(prompt, sizeof(prompt), fmt, args);
184 va_end(args); 192 va_end(args);
185 193
186 p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF); 194 p = read_passphrase(prompt,
195 RP_USE_ASKPASS|RP_ALLOW_EOF|RP_ASK_PERMISSION);
187 if (p != NULL) { 196 if (p != NULL) {
188 /* 197 /*
189 * Accept empty responses and responses consisting 198 * Accept empty responses and responses consisting
@@ -197,3 +206,89 @@ ask_permission(const char *fmt, ...)
197 206
198 return (allowed); 207 return (allowed);
199} 208}
209
210struct notifier_ctx {
211 pid_t pid;
212 void (*osigchld)(int);
213};
214
215struct notifier_ctx *
216notify_start(int force_askpass, const char *fmt, ...)
217{
218 va_list args;
219 char *prompt = NULL;
220 int devnull;
221 pid_t pid;
222 void (*osigchld)(int);
223 const char *askpass;
224 struct notifier_ctx *ret;
225
226 va_start(args, fmt);
227 xvasprintf(&prompt, fmt, args);
228 va_end(args);
229
230 if (fflush(NULL) != 0)
231 error("%s: fflush: %s", __func__, strerror(errno));
232 if (!force_askpass && isatty(STDERR_FILENO)) {
233 (void)write(STDERR_FILENO, "\r", 1);
234 (void)write(STDERR_FILENO, prompt, strlen(prompt));
235 (void)write(STDERR_FILENO, "\r\n", 2);
236 free(prompt);
237 return NULL;
238 }
239 if ((askpass = getenv("SSH_ASKPASS")) == NULL)
240 askpass = _PATH_SSH_ASKPASS_DEFAULT;
241 if (getenv("DISPLAY") == NULL || *askpass == '\0') {
242 debug3("%s: cannot notify", __func__);
243 free(prompt);
244 return NULL;
245 }
246 osigchld = ssh_signal(SIGCHLD, SIG_DFL);
247 if ((pid = fork()) == -1) {
248 error("%s: fork: %s", __func__, strerror(errno));
249 ssh_signal(SIGCHLD, osigchld);
250 free(prompt);
251 return NULL;
252 }
253 if (pid == 0) {
254 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1)
255 fatal("%s: open %s", __func__, strerror(errno));
256 if (dup2(devnull, STDIN_FILENO) == -1 ||
257 dup2(devnull, STDOUT_FILENO) == -1)
258 fatal("%s: dup2: %s", __func__, strerror(errno));
259 closefrom(STDERR_FILENO + 1);
260 setenv("SSH_ASKPASS_PROMPT", "none", 1); /* hint to UI */
261 execlp(askpass, askpass, prompt, (char *)NULL);
262 error("%s: exec(%s): %s", __func__, askpass, strerror(errno));
263 _exit(1);
264 /* NOTREACHED */
265 }
266 if ((ret = calloc(1, sizeof(*ret))) == NULL) {
267 kill(pid, SIGTERM);
268 fatal("%s: calloc failed", __func__);
269 }
270 ret->pid = pid;
271 ret->osigchld = osigchld;
272 free(prompt);
273 return ret;
274}
275
276void
277notify_complete(struct notifier_ctx *ctx)
278{
279 int ret;
280
281 if (ctx == NULL || ctx->pid <= 0) {
282 free(ctx);
283 return;
284 }
285 kill(ctx->pid, SIGTERM);
286 while ((ret = waitpid(ctx->pid, NULL, 0)) == -1) {
287 if (errno != EINTR)
288 break;
289 }
290 if (ret == -1)
291 fatal("%s: waitpid: %s", __func__, strerror(errno));
292 ssh_signal(SIGCHLD, ctx->osigchld);
293 free(ctx);
294}