Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save al3xtjames/5ae94de6463c7bf147406e0b3b429f79 to your computer and use it in GitHub Desktop.
Save al3xtjames/5ae94de6463c7bf147406e0b3b429f79 to your computer and use it in GitHub Desktop.
From 63a7e059e84911556ef4584b9feb39915f8ccd33 Mon Sep 17 00:00:00 2001
From: Damien Miller <djm@mindrot.org>
Date: Fri, 2 Jun 2023 14:09:29 +1000
Subject: [PATCH 1/2] separate force/never flags for askpass and notify
---
readpass.c | 94 ++++++++++++++++++++++++++++++++++++++++++------------
ssh.1 | 20 ++++++++++--
2 files changed, 92 insertions(+), 22 deletions(-)
diff --git a/readpass.c b/readpass.c
index d42b1185d..d15f58828 100644
--- a/readpass.c
+++ b/readpass.c
@@ -110,6 +110,35 @@ ssh_askpass(char *askpass, const char *msg, const char *env_hint)
return pass;
}
+#define FORCE_NONE 0
+#define FORCE_PREFER 1
+#define FORCE_FORCE 2
+#define FORCE_NEVER 3
+
+/*
+ * Check $SSH_ASKPASS_REQUIRE for the given context (askpass or notify),
+ * returns one of the FORCE_* values.
+ */
+static int
+check_forced(int is_notify)
+{
+ const char *s;
+
+ if ((s = getenv(SSH_ASKPASS_REQUIRE_ENV)) == NULL)
+ return FORCE_NONE;
+
+ if (strcasecmp(s, "force") == 0 ||
+ strstr(s, is_notify ? "notify:force" : "askpass:force"))
+ return FORCE_FORCE;
+ if (strcasecmp(s, "never") == 0 ||
+ strstr(s, is_notify ? "notify:never" : "askpass:never"))
+ return FORCE_NEVER;
+ if (strcasecmp(s, "prefer") == 0 ||
+ strstr(s, is_notify ? "notify:prefer" : "askpass:prefer"))
+ return FORCE_PREFER;
+ return FORCE_NONE;
+}
+
/* private/internal read_passphrase flags */
#define RP_ASK_PERMISSION 0x8000 /* pass hint to askpass for confirm UI */
@@ -130,14 +159,18 @@ read_passphrase(const char *prompt, int flags)
if (((s = getenv("DISPLAY")) != NULL && *s != '\0') ||
((s = getenv("WAYLAND_DISPLAY")) != NULL && *s != '\0'))
allow_askpass = 1;
- if ((s = getenv(SSH_ASKPASS_REQUIRE_ENV)) != NULL) {
- if (strcasecmp(s, "force") == 0) {
- use_askpass = 1;
- allow_askpass = 1;
- } else if (strcasecmp(s, "prefer") == 0)
- use_askpass = allow_askpass;
- else if (strcasecmp(s, "never") == 0)
- allow_askpass = 0;
+
+ switch (check_forced(0)) {
+ case FORCE_PREFER:
+ use_askpass = allow_askpass;
+ break;
+ case FORCE_FORCE:
+ use_askpass = 1;
+ allow_askpass = 1;
+ break;
+ case FORCE_NEVER:
+ allow_askpass = 0;
+ break;
}
rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF;
@@ -245,29 +278,50 @@ notify_start(int force_askpass, const char *fmt, ...)
void (*osigchld)(int) = NULL;
const char *askpass, *s;
struct notifier_ctx *ret = NULL;
+ int have_display = 0, use_askpass = 0;
va_start(args, fmt);
xvasprintf(&prompt, fmt, args);
va_end(args);
- if (fflush(NULL) != 0)
- error_f("fflush: %s", strerror(errno));
- if (!force_askpass && isatty(STDERR_FILENO)) {
- writemsg(prompt);
- goto out_ctx;
- }
+ if (((s = getenv("DISPLAY")) != NULL && *s != '\0') ||
+ ((s = getenv("WAYLAND_DISPLAY")) != NULL && *s != '\0'))
+ have_display = 1;
if ((askpass = getenv("SSH_ASKPASS")) == NULL)
askpass = _PATH_SSH_ASKPASS_DEFAULT;
- if (*askpass == '\0') {
+ if (*askpass == '\0')
+ askpass = NULL;
+
+ switch (check_forced(1)) {
+ case FORCE_PREFER:
+ use_askpass = have_display && askpass != NULL;
+ break;
+ case FORCE_FORCE:
+ use_askpass = 1;
+ break;
+ case FORCE_NEVER:
+ use_askpass = 0;
+ break;
+ }
+ use_askpass |= force_askpass;
+ if (use_askpass && askpass == NULL) {
debug3_f("cannot notify: no askpass");
goto out;
}
- if (getenv("DISPLAY") == NULL && getenv("WAYLAND_DISPLAY") == NULL &&
- ((s = getenv(SSH_ASKPASS_REQUIRE_ENV)) == NULL ||
- strcmp(s, "force") != 0)) {
- debug3_f("cannot notify: no display");
- goto out;
+
+ if (fflush(NULL) != 0)
+ error_f("fflush: %s", strerror(errno));
+ if (!use_askpass) {
+ if (isatty(STDERR_FILENO)) {
+ writemsg(prompt);
+ goto out_ctx;
+ }
+ if (!have_display || askpass == NULL) {
+ debug3_f("cannot notify: no askpass/display");
+ goto out;
+ }
}
+ /* using askpass */
osigchld = ssh_signal(SIGCHLD, SIG_DFL);
if ((pid = fork()) == -1) {
error_f("fork: %s", strerror(errno));
diff --git a/ssh.1 b/ssh.1
index f871ff4e4..a7e8b1b24 100644
--- a/ssh.1
+++ b/ssh.1
@@ -101,7 +101,8 @@ A complete command line may be specified as
.Ar command ,
or it may have additional arguments.
If supplied, the arguments will be appended to the command, separated by
-spaces, before it is sent to the server to be executed.
+spaces, before it is sent to the server to be executed, using the remote
+user's shell.
.Pp
The options are as follows:
.Pp
@@ -1451,8 +1452,10 @@ or related script.
may be necessary to redirect the input from
.Pa /dev/null
to make this work.)
+This program may also be used for some notifications for the user, including
+situations where they are required to touch a FIDO token.
.It Ev SSH_ASKPASS_REQUIRE
-Allows further control over the use of an askpass program.
+Allows further control over the use of the askpass program.
If this variable is set to
.Dq never
then
@@ -1470,6 +1473,19 @@ then the askpass program will be used for all passphrase input regardless
of whether
.Ev DISPLAY
is set.
+.Pp
+It is possible to control the use of the askpass program for requesting
+passphrases and issuing notifications separately by prefixing the above
+keywords with either
+.Dq askpass:
+or
+.Dq notify: .
+For example, a
+.Ev SSH_ASKPASS_REQUIRE
+value of
+.Dq askpass:force notify:never
+would require the use of the askpass program for requesting passphrases but
+disable it for notifications.
.It Ev SSH_AUTH_SOCK
Identifies the path of a
.Ux Ns -domain
--
2.45.1
From 8e6cde410de7920950aba07383ec060059406263 Mon Sep 17 00:00:00 2001
From: Damien Miller <djm@mindrot.org>
Date: Fri, 2 Jun 2023 14:20:36 +1000
Subject: [PATCH 2/2] separate SSH_ASKPASS_NOTIFY program
---
readpass.c | 3 ++-
ssh.1 | 7 +++++++
ssh.h | 5 +++++
3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/readpass.c b/readpass.c
index d15f58828..8010812a1 100644
--- a/readpass.c
+++ b/readpass.c
@@ -287,7 +287,8 @@ notify_start(int force_askpass, const char *fmt, ...)
if (((s = getenv("DISPLAY")) != NULL && *s != '\0') ||
((s = getenv("WAYLAND_DISPLAY")) != NULL && *s != '\0'))
have_display = 1;
- if ((askpass = getenv("SSH_ASKPASS")) == NULL)
+ askpass = getenv(SSH_ASKPASS_NOTIFY_ENV);
+ if (askpass == NULL && (askpass = getenv(SSH_ASKPASS_ENV)) == NULL)
askpass = _PATH_SSH_ASKPASS_DEFAULT;
if (*askpass == '\0')
askpass = NULL;
diff --git a/ssh.1 b/ssh.1
index a7e8b1b24..57900a0b3 100644
--- a/ssh.1
+++ b/ssh.1
@@ -1454,6 +1454,13 @@ may be necessary to redirect the input from
to make this work.)
This program may also be used for some notifications for the user, including
situations where they are required to touch a FIDO token.
+.It Ev SSH_ASKPASS_NOTIFY
+Specifies a program to be used instead of the default askpass program (or any
+one set via
+.Ev SSH_ASKPASS )
+that is used only for displaying notifications to the user, and not for
+requesting passphrases.
+By default, the same askpass program is used for both cases.
.It Ev SSH_ASKPASS_REQUIRE
Allows further control over the use of the askpass program.
If this variable is set to
diff --git a/ssh.h b/ssh.h
index 8110c0602..371aa3cba 100644
--- a/ssh.h
+++ b/ssh.h
@@ -67,6 +67,11 @@
*/
#define SSH_ASKPASS_ENV "SSH_ASKPASS"
+/*
+ * Environment variable to set an askpass that is used for notifications only.
+ */
+#define SSH_ASKPASS_NOTIFY_ENV "SSH_ASKPASS_NOTIFY"
+
/*
* Environment variable to control whether or not askpass is used.
*/
--
2.45.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment