summaryrefslogtreecommitdiffstats
path: root/usr.bin/ssh/readpass.c
diff options
context:
space:
mode:
authordjm <djm@openbsd.org>2019-11-12 22:34:20 +0000
committerdjm <djm@openbsd.org>2019-11-12 22:34:20 +0000
commit247ed3860e172f1eed9ccd1ac9732f755d71bb3c (patch)
treee873c868472a84c3b23a2e01bf7d236868630cdd /usr.bin/ssh/readpass.c
parentadd xvasprintf() (diff)
downloadwireguard-openbsd-247ed3860e172f1eed9ccd1ac9732f755d71bb3c.tar.xz
wireguard-openbsd-247ed3860e172f1eed9ccd1ac9732f755d71bb3c.zip
dd API for performing one-shot notifications via tty or SSH_ASKPASS
Diffstat (limited to 'usr.bin/ssh/readpass.c')
-rw-r--r--usr.bin/ssh/readpass.c86
1 files changed, 85 insertions, 1 deletions
diff --git a/usr.bin/ssh/readpass.c b/usr.bin/ssh/readpass.c
index 57b91aa4a2f..37ae0a5312f 100644
--- a/usr.bin/ssh/readpass.c
+++ b/usr.bin/ssh/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.
*
@@ -194,3 +194,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);
+}