From 5d1c1590d736694f41b03e686045f08fcae20d62 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 12 Nov 2019 22:34:20 +0000 Subject: upstream: dd API for performing one-shot notifications via tty or SSH_ASKPASS OpenBSD-Commit-ID: 9484aea33aff5b62ce3642bf259546c7639f23f3 --- readpass.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) (limited to 'readpass.c') diff --git a/readpass.c b/readpass.c index 7e52cae9c..33fc03bb7 100644 --- a/readpass.c +++ b/readpass.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readpass.c,v 1.54 2019/06/28 13:35:04 deraadt Exp $ */ +/* $OpenBSD: readpass.c,v 1.55 2019/11/12 22:34:20 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -197,3 +197,87 @@ ask_permission(const char *fmt, ...) return (allowed); } + +struct notifier_ctx { + pid_t pid; + void (*osigchld)(int); +}; + +struct notifier_ctx * +notify_start(int force_askpass, const char *fmt, ...) +{ + va_list args; + char *prompt = NULL; + int devnull; + pid_t pid; + void (*osigchld)(int); + const char *askpass; + struct notifier_ctx *ret; + + va_start(args, fmt); + xvasprintf(&prompt, fmt, args); + va_end(args); + + if (fflush(NULL) != 0) + error("%s: fflush: %s", __func__, strerror(errno)); + if (!force_askpass && isatty(STDERR_FILENO)) { + (void)write(STDERR_FILENO, "\r", 1); + (void)write(STDERR_FILENO, prompt, strlen(prompt)); + (void)write(STDERR_FILENO, "\r\n", 2); + free(prompt); + return NULL; + } + if (getenv("DISPLAY") == NULL || + (askpass = getenv("SSH_ASKPASS")) == NULL || *askpass == '\0') { + debug3("%s: cannot notify", __func__); + free(prompt); + return NULL; + } + osigchld = signal(SIGCHLD, SIG_DFL); + if ((pid = fork()) == -1) { + error("%s: fork: %s", __func__, strerror(errno)); + signal(SIGCHLD, osigchld); + free(prompt); + return NULL; + } + if (pid == 0) { + if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) + fatal("%s: open %s", __func__, strerror(errno)); + if (dup2(devnull, STDIN_FILENO) == -1 || + dup2(devnull, STDOUT_FILENO) == -1) + fatal("%s: dup2: %s", __func__, strerror(errno)); + closefrom(STDERR_FILENO + 1); + setenv("SSH_ASKPASS_PROMPT", "none", 1); /* hint to UI */ + execlp(askpass, askpass, prompt, (char *)NULL); + fatal("%s: exec(%s): %s", __func__, askpass, strerror(errno)); + /* NOTREACHED */ + } + if ((ret = calloc(1, sizeof(*ret))) == NULL) { + kill(pid, SIGTERM); + fatal("%s: calloc failed", __func__); + } + ret->pid = pid; + ret->osigchld = osigchld; + free(prompt); + return ret; +} + +void +notify_complete(struct notifier_ctx *ctx) +{ + int ret; + + if (ctx == NULL || ctx->pid <= 0) { + free(ctx); + return; + } + kill(ctx->pid, SIGTERM); + while ((ret = waitpid(ctx->pid, NULL, 0)) == -1) { + if (errno != EINTR) + break; + } + if (ret == -1) + fatal("%s: waitpid: %s", __func__, strerror(errno)); + signal(SIGCHLD, ctx->osigchld); + free(ctx); +} -- cgit v1.2.3