Blob Blame History Raw
From 87151a68e59f9fe6e8a161148db75a52892c289e Mon Sep 17 00:00:00 2001
From: Martin Pitt <mpitt@redhat.com>
Date: Sun, 2 Jun 2019 22:47:49 +0200
Subject: [PATCH] session: Circumvent user shell stdout noise

Commit a9375441df7 caused Cockpit logins to fail if the user's ~/.bashrc
or ~/.profile writes anything to stdout. That interferes with the
protocol and causes an error like

    incorrect protocol: received invalid length prefix

To avoid this, route the shell's stdout to stderr (so that we can still
see it in the logs) and pass session's stdout to cockpit-bridge through
fd 3. This assumes that the shell supports `>&3` input redirection,
which is the case for any POSIX shell (ash, bash, ksh, dash, zsh) and at
least tcsh.

https://bugzilla.redhat.com/show_bug.cgi?id=1710604

Closes #11978
---
 src/ws/session.c        | 9 ++++++++-
 test/verify/check-login | 9 +++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/src/ws/session.c b/src/ws/session.c
index ec37eda16..7b142d80f 100644
--- a/src/ws/session.c
+++ b/src/ws/session.c
@@ -25,6 +25,7 @@
 #include <gssapi/gssapi_generic.h>
 #include <gssapi/gssapi_krb5.h>
 #include <krb5/krb5.h>
+#include <fcntl.h>
 
 static char *last_txt_msg = NULL;
 static char *conversation = NULL;
@@ -525,7 +526,7 @@ out:
 static int
 session (char **env)
 {
-  char *argv[] = { NULL /* user's shell */, "-c", "exec cockpit-bridge", NULL };
+  char *argv[] = { NULL /* user's shell */, "-c", "exec cockpit-bridge >&3", NULL };
   gss_key_value_set_desc store;
   struct gss_key_value_element_struct element;
   OM_uint32 major, minor;
@@ -568,6 +569,12 @@ session (char **env)
 
   debug ("executing cockpit-bridge through user shell %s", pwd->pw_shell);
 
+  /* connect our and cockpit-bridge's stdout via fd 3, to avoid stdout output
+   * from ~/.profile and friends to interfere with the protocol; route shell's
+   * stdout to its stderr, so that we can still see it in the logs */
+  if (dup2 (1, 3) < 0 || dup2 (2, 1) < 0)
+    err (1, "could not redirect user shell stdout");
+
   if (env)
     execvpe (argv[0], argv, env);
   else