summaryrefslogtreecommitdiff
path: root/readpass.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-11-12 22:34:20 +0000
committerDamien Miller <djm@mindrot.org>2019-11-13 10:15:46 +1100
commit5d1c1590d736694f41b03e686045f08fcae20d62 (patch)
treea8260a4f40fc44afc14c24a29d26092749910ceb /readpass.c
parent166927fd410823eec8a7b2472463db51e0e6fef5 (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.c86
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
201struct notifier_ctx {
202 pid_t pid;
203 void (*osigchld)(int);
204};
205
206struct notifier_ctx *
207notify_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
265void
266notify_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}