=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/readpass.c,v retrieving revision 1.54 retrieving revision 1.55 diff -u -r1.54 -r1.55 --- src/usr.bin/ssh/readpass.c 2019/06/28 13:35:04 1.54 +++ src/usr.bin/ssh/readpass.c 2019/11/12 22:34:20 1.55 @@ -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. * @@ -193,4 +193,88 @@ } 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); }