diff options
author | djm@openbsd.org <djm@openbsd.org> | 2019-11-12 22:34:20 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2019-11-13 10:15:46 +1100 |
commit | 5d1c1590d736694f41b03e686045f08fcae20d62 (patch) | |
tree | a8260a4f40fc44afc14c24a29d26092749910ceb /readpass.c | |
parent | 166927fd410823eec8a7b2472463db51e0e6fef5 (diff) |
upstream: dd API for performing one-shot notifications via tty or
SSH_ASKPASS
OpenBSD-Commit-ID: 9484aea33aff5b62ce3642bf259546c7639f23f3
Diffstat (limited to 'readpass.c')
-rw-r--r-- | readpass.c | 86 |
1 files changed, 85 insertions, 1 deletions
diff --git a/readpass.c b/readpass.c index 7e52cae9c..33fc03bb7 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.55 2019/11/12 22:34:20 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -197,3 +197,87 @@ ask_permission(const char *fmt, ...) | |||
197 | 197 | ||
198 | return (allowed); | 198 | return (allowed); |
199 | } | 199 | } |
200 | |||
201 | struct notifier_ctx { | ||
202 | pid_t pid; | ||
203 | void (*osigchld)(int); | ||
204 | }; | ||
205 | |||
206 | struct notifier_ctx * | ||
207 | notify_start(int force_askpass, const char *fmt, ...) | ||
208 | { | ||
209 | va_list args; | ||
210 | char *prompt = NULL; | ||
211 | int devnull; | ||
212 | pid_t pid; | ||
213 | void (*osigchld)(int); | ||
214 | const char *askpass; | ||
215 | struct notifier_ctx *ret; | ||
216 | |||
217 | va_start(args, fmt); | ||
218 | xvasprintf(&prompt, fmt, args); | ||
219 | va_end(args); | ||
220 | |||
221 | if (fflush(NULL) != 0) | ||
222 | error("%s: fflush: %s", __func__, strerror(errno)); | ||
223 | if (!force_askpass && isatty(STDERR_FILENO)) { | ||
224 | (void)write(STDERR_FILENO, "\r", 1); | ||
225 | (void)write(STDERR_FILENO, prompt, strlen(prompt)); | ||
226 | (void)write(STDERR_FILENO, "\r\n", 2); | ||
227 | free(prompt); | ||
228 | return NULL; | ||
229 | } | ||
230 | if (getenv("DISPLAY") == NULL || | ||
231 | (askpass = getenv("SSH_ASKPASS")) == NULL || *askpass == '\0') { | ||
232 | debug3("%s: cannot notify", __func__); | ||
233 | free(prompt); | ||
234 | return NULL; | ||
235 | } | ||
236 | osigchld = signal(SIGCHLD, SIG_DFL); | ||
237 | if ((pid = fork()) == -1) { | ||
238 | error("%s: fork: %s", __func__, strerror(errno)); | ||
239 | signal(SIGCHLD, osigchld); | ||
240 | free(prompt); | ||
241 | return NULL; | ||
242 | } | ||
243 | if (pid == 0) { | ||
244 | if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) | ||
245 | fatal("%s: open %s", __func__, strerror(errno)); | ||
246 | if (dup2(devnull, STDIN_FILENO) == -1 || | ||
247 | dup2(devnull, STDOUT_FILENO) == -1) | ||
248 | fatal("%s: dup2: %s", __func__, strerror(errno)); | ||
249 | closefrom(STDERR_FILENO + 1); | ||
250 | setenv("SSH_ASKPASS_PROMPT", "none", 1); /* hint to UI */ | ||
251 | execlp(askpass, askpass, prompt, (char *)NULL); | ||
252 | fatal("%s: exec(%s): %s", __func__, askpass, strerror(errno)); | ||
253 | /* NOTREACHED */ | ||
254 | } | ||
255 | if ((ret = calloc(1, sizeof(*ret))) == NULL) { | ||
256 | kill(pid, SIGTERM); | ||
257 | fatal("%s: calloc failed", __func__); | ||
258 | } | ||
259 | ret->pid = pid; | ||
260 | ret->osigchld = osigchld; | ||
261 | free(prompt); | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | void | ||
266 | notify_complete(struct notifier_ctx *ctx) | ||
267 | { | ||
268 | int ret; | ||
269 | |||
270 | if (ctx == NULL || ctx->pid <= 0) { | ||
271 | free(ctx); | ||
272 | return; | ||
273 | } | ||
274 | kill(ctx->pid, SIGTERM); | ||
275 | while ((ret = waitpid(ctx->pid, NULL, 0)) == -1) { | ||
276 | if (errno != EINTR) | ||
277 | break; | ||
278 | } | ||
279 | if (ret == -1) | ||
280 | fatal("%s: waitpid: %s", __func__, strerror(errno)); | ||
281 | signal(SIGCHLD, ctx->osigchld); | ||
282 | free(ctx); | ||
283 | } | ||