Blame SOURCES/0008-subman-Don-t-send-secrets-through-command-line.patch

6486b0
From b73800da7f384eea66b6eb67f5f40129f3dfc372 Mon Sep 17 00:00:00 2001
6486b0
From: Ray Strode <rstrode@redhat.com>
6486b0
Date: Tue, 25 Aug 2020 16:20:42 -0400
6486b0
Subject: [PATCH 08/15] subman: Don't send secrets through command line
6486b0
6486b0
The command line is introspectable with "ps", and it even gets logged
6486b0
to syslog, so it's not suitable for passing secrets.
6486b0
6486b0
Unfortunately, the user's password is currently passed.
6486b0
6486b0
This commit addresses that problem by passing the password through
6486b0
stdin, instead.
6486b0
---
6486b0
 plugins/subman/gsd-subman-helper.c        | 32 ++++++++------
6486b0
 plugins/subman/gsd-subscription-manager.c | 52 ++++++++++++++++++++---
6486b0
 plugins/subman/meson.build                |  2 +-
6486b0
 3 files changed, 66 insertions(+), 20 deletions(-)
6486b0
6486b0
diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c
6486b0
index 3931ef2e..edf1e41f 100644
6486b0
--- a/plugins/subman/gsd-subman-helper.c
6486b0
+++ b/plugins/subman/gsd-subman-helper.c
6486b0
@@ -1,59 +1,61 @@
6486b0
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
6486b0
  *
6486b0
  * Copyright (C) 2019 Richard Hughes <rhughes@redhat.com>
6486b0
  *
6486b0
  * Licensed under the GNU General Public License Version 2
6486b0
  *
6486b0
  * This program is free software; you can redistribute it and/or modify
6486b0
  * it under the terms of the GNU General Public License as published by
6486b0
  * the Free Software Foundation; either version 2 of the License, or
6486b0
  * (at your option) any later version.
6486b0
  *
6486b0
  * This program is distributed in the hope that it will be useful,
6486b0
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
6486b0
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6486b0
  * GNU General Public License for more details.
6486b0
  *
6486b0
  * You should have received a copy of the GNU General Public License
6486b0
  * along with this program; if not, write to the Free Software
6486b0
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6486b0
  */
6486b0
 
6486b0
 #include "config.h"
6486b0
 
6486b0
+
6486b0
 #include <sys/types.h>
6486b0
 #include <unistd.h>
6486b0
 #include <stdlib.h>
6486b0
 #include <locale.h>
6486b0
 
6486b0
 #include <gio/gio.h>
6486b0
+#include <gio/gunixinputstream.h>
6486b0
 #include <json-glib/json-glib.h>
6486b0
 
6486b0
 #define DBUS_TIMEOUT 300000 /* 5 minutes */
6486b0
 static const char *locale;
6486b0
 
6486b0
 static void
6486b0
 _helper_convert_error (const gchar *json_txt, GError **error)
6486b0
 {
6486b0
 	JsonNode *json_root;
6486b0
 	JsonObject *json_obj;
6486b0
 	const gchar *message;
6486b0
 	g_autoptr(JsonParser) json_parser = json_parser_new ();
6486b0
 
6486b0
 	/* this may be plain text or JSON :| */
6486b0
 	if (!json_parser_load_from_data (json_parser, json_txt, -1, NULL)) {
6486b0
 		g_set_error_literal (error,
6486b0
 				     G_IO_ERROR,
6486b0
 				     G_IO_ERROR_NOT_SUPPORTED,
6486b0
 				     json_txt);
6486b0
 		return;
6486b0
 	}
6486b0
 	json_root = json_parser_get_root (json_parser);
6486b0
 	json_obj = json_node_get_object (json_root);
6486b0
 	if (!json_object_has_member (json_obj, "message")) {
6486b0
 		g_set_error (error,
6486b0
 			     G_IO_ERROR,
6486b0
 			     G_IO_ERROR_INVALID_DATA,
6486b0
 			     "no message' in %s", json_txt);
6486b0
 		return;
6486b0
 	}
6486b0
@@ -149,86 +151,82 @@ _helper_save_config (const gchar *key, const gchar *value, GError **error)
6486b0
 					       G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
6486b0
 					       G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
6486b0
 					       NULL,
6486b0
 					       "com.redhat.RHSM1",
6486b0
 					       "/com/redhat/RHSM1/Config",
6486b0
 					       "com.redhat.RHSM1.Config",
6486b0
 					       NULL, error);
6486b0
 	if (proxy == NULL) {
6486b0
 		g_prefix_error (error, "Failed to get proxy: ");
6486b0
 		return FALSE;
6486b0
 	}
6486b0
 	res = g_dbus_proxy_call_sync (proxy, "Set",
6486b0
 				      g_variant_new ("(svs)",
6486b0
 						     key,
6486b0
 						     g_variant_new_string (value),
6486b0
 						     locale),
6486b0
 				      G_DBUS_CALL_FLAGS_NONE,
6486b0
 				      DBUS_TIMEOUT,
6486b0
 				      NULL, error);
6486b0
 	return res != NULL;
6486b0
 }
6486b0
 
6486b0
 int
6486b0
 main (int argc, char *argv[])
6486b0
 {
6486b0
 	g_autofree gchar *activation_key = NULL;
6486b0
 	g_autofree gchar *address = NULL;
6486b0
 	g_autofree gchar *hostname = NULL;
6486b0
 	g_autofree gchar *kind = NULL;
6486b0
 	g_autofree gchar *organisation = NULL;
6486b0
-	g_autofree gchar *password = NULL;
6486b0
 	g_autofree gchar *port = NULL;
6486b0
 	g_autofree gchar *prefix = NULL;
6486b0
 	g_autofree gchar *proxy_server = NULL;
6486b0
 	g_autofree gchar *username = NULL;
6486b0
 	g_autoptr(GDBusConnection) conn_private = NULL;
6486b0
 	g_autoptr(GDBusProxy) proxy = NULL;
6486b0
 	g_autoptr(GError) error = NULL;
6486b0
 	g_autoptr(GOptionContext) context = g_option_context_new (NULL);
6486b0
 	g_autoptr(GVariantBuilder) proxy_options = NULL;
6486b0
 	g_autoptr(GVariantBuilder) subman_conopts = NULL;
6486b0
 	g_autoptr(GVariantBuilder) subman_options = NULL;
6486b0
+	g_autoptr(GInputStream) standard_input_stream = g_unix_input_stream_new (STDIN_FILENO, FALSE);
6486b0
 
6486b0
 	const GOptionEntry options[] = {
6486b0
 		{ "kind", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING,
6486b0
 			&kind, "Kind, e.g. 'username' or 'key'", NULL },
6486b0
 		{ "address", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING,
6486b0
 			&address, "UNIX address", NULL },
6486b0
 		{ "username", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING,
6486b0
 			&username, "Username", NULL },
6486b0
-		{ "password", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING,
6486b0
-			&password, "Password", NULL },
6486b0
 		{ "organisation", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING,
6486b0
 			&organisation, "Organisation", NULL },
6486b0
-		{ "activation-key", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING,
6486b0
-			&activation_key, "Activation keys", NULL },
6486b0
 		{ "hostname", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING,
6486b0
 			&hostname, "Registration server hostname", NULL },
6486b0
 		{ "prefix", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING,
6486b0
 			&prefix, "Registration server prefix", NULL },
6486b0
 		{ "port", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING,
6486b0
 			&port, "Registration server port", NULL },
6486b0
 		{ "proxy", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING,
6486b0
 			&proxy_server, "Proxy settings", NULL },
6486b0
 		{ NULL}
6486b0
 	};
6486b0
 
6486b0
 	/* check calling UID */
6486b0
 	if (getuid () != 0 || geteuid () != 0) {
6486b0
 		g_printerr ("This program can only be used by the root user\n");
6486b0
 		return G_IO_ERROR_NOT_SUPPORTED;
6486b0
 	}
6486b0
 
6486b0
 	setlocale (LC_ALL, "");
6486b0
 	locale = setlocale (LC_MESSAGES, NULL);
6486b0
 
6486b0
 	g_option_context_add_main_entries (context, options, NULL);
6486b0
 	if (!g_option_context_parse (context, &argc, &argv, &error)) {
6486b0
 		g_printerr ("Failed to parse arguments: %s\n", error->message);
6486b0
 		return G_IO_ERROR_NOT_SUPPORTED;
6486b0
 	}
6486b0
 
6486b0
 	/* uncommon actions */
6486b0
 	if (kind == NULL) {
6486b0
 		g_printerr ("No --kind specified\n");
6486b0
 		return G_IO_ERROR_INVALID_DATA;
6486b0
@@ -267,109 +265,117 @@ main (int argc, char *argv[])
6486b0
 				       NULL, /* GDBusInterfaceInfo */
6486b0
 				       NULL, /* name */
6486b0
 				       "/com/redhat/RHSM1/Register",
6486b0
 				       "com.redhat.RHSM1.Register",
6486b0
 				       NULL, &error);
6486b0
 	if (proxy == NULL) {
6486b0
 		g_printerr ("Count not contact RHSM: %s\n", error->message);
6486b0
 		return G_IO_ERROR_NOT_FOUND;
6486b0
 	}
6486b0
 
6486b0
 	/* no options */
6486b0
 	subman_options = g_variant_builder_new (G_VARIANT_TYPE("a{ss}"));
6486b0
 
6486b0
 	/* set registration server */
6486b0
 	if (hostname == NULL || hostname[0] == '\0')
6486b0
 		hostname = g_strdup ("subscription.rhsm.redhat.com");
6486b0
 	if (prefix == NULL || prefix[0] == '\0')
6486b0
 		prefix = g_strdup ("/subscription");
6486b0
 	if (port == NULL || port[0] == '\0')
6486b0
 		port = g_strdup ("443");
6486b0
 	subman_conopts = g_variant_builder_new (G_VARIANT_TYPE("a{ss}"));
6486b0
 	g_variant_builder_add (subman_conopts, "{ss}", "host", hostname);
6486b0
 	g_variant_builder_add (subman_conopts, "{ss}", "handler", prefix);
6486b0
 	g_variant_builder_add (subman_conopts, "{ss}", "port", port);
6486b0
 
6486b0
 	/* call into RHSM */
6486b0
 	if (g_strcmp0 (kind, "register-with-key") == 0) {
6486b0
 		g_auto(GStrv) activation_keys = NULL;
6486b0
 		g_autoptr(GError) error_local = NULL;
6486b0
 		g_autoptr(GVariant) res = NULL;
6486b0
+		gchar activation_key[PIPE_BUF + 1] = "";
6486b0
 
6486b0
-		if (activation_key == NULL) {
6486b0
-			g_printerr ("Required --activation-key\n");
6486b0
-			return G_IO_ERROR_INVALID_DATA;
6486b0
-		}
6486b0
 		if (organisation == NULL) {
6486b0
 			g_printerr ("Required --organisation\n");
6486b0
 			return G_IO_ERROR_INVALID_DATA;
6486b0
 		}
6486b0
 
6486b0
+		g_input_stream_read (standard_input_stream, activation_key, sizeof (activation_key) - 1, NULL, &error_local);
6486b0
+
6486b0
+		if (error_local != NULL) {
6486b0
+			g_printerr ("Could not read activation key: %s\n", error_local->message);
6486b0
+			return G_IO_ERROR_INVALID_DATA;
6486b0
+		}
6486b0
+
6486b0
 		g_debug ("trying to unregister in case machine is already registered");
6486b0
 		_helper_unregister (NULL);
6486b0
 
6486b0
 		g_debug ("registering using activation key");
6486b0
 		activation_keys = g_strsplit (activation_key, ",", -1);
6486b0
 		res = g_dbus_proxy_call_sync (proxy,
6486b0
 					      "RegisterWithActivationKeys",
6486b0
 					      g_variant_new ("(s^asa{ss}a{ss}s)",
6486b0
 							     organisation,
6486b0
 							     activation_keys,
6486b0
 							     subman_options,
6486b0
 							     subman_conopts,
6486b0
 							     locale),
6486b0
 					      G_DBUS_CALL_FLAGS_NO_AUTO_START,
6486b0
 					      DBUS_TIMEOUT,
6486b0
 					      NULL, &error_local);
6486b0
 		if (res == NULL) {
6486b0
 			g_dbus_error_strip_remote_error (error_local);
6486b0
 			_helper_convert_error (error_local->message, &error);
6486b0
 			g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message);
6486b0
 			return error->code;
6486b0
 		}
6486b0
 	} else if (g_strcmp0 (kind, "register-with-username") == 0) {
6486b0
 		g_autoptr(GError) error_local = NULL;
6486b0
 		g_autoptr(GVariant) res = NULL;
6486b0
+		gchar password[PIPE_BUF + 1] = "";
6486b0
 
6486b0
 		if (username == NULL) {
6486b0
 			g_printerr ("Required --username\n");
6486b0
 			return G_IO_ERROR_INVALID_DATA;
6486b0
 		}
6486b0
-		if (password == NULL) {
6486b0
-			g_printerr ("Required --password\n");
6486b0
-			return G_IO_ERROR_INVALID_DATA;
6486b0
-		}
6486b0
 		if (organisation == NULL) {
6486b0
 			g_printerr ("Required --organisation\n");
6486b0
 			return G_IO_ERROR_INVALID_DATA;
6486b0
 		}
6486b0
 
6486b0
+		g_input_stream_read (standard_input_stream, password, sizeof (password) - 1, NULL, &error_local);
6486b0
+
6486b0
+		if (error_local != NULL) {
6486b0
+			g_printerr ("Could not read password: %s\n", error_local->message);
6486b0
+			return G_IO_ERROR_INVALID_DATA;
6486b0
+		}
6486b0
+
6486b0
 		g_debug ("trying to unregister in case machine is already registered");
6486b0
 		_helper_unregister (NULL);
6486b0
 
6486b0
 		g_debug ("registering using username and password");
6486b0
 		res = g_dbus_proxy_call_sync (proxy,
6486b0
 					      "Register",
6486b0
 					      g_variant_new ("(sssa{ss}a{ss}s)",
6486b0
 							     organisation,
6486b0
 							     username,
6486b0
 							     password,
6486b0
 							     subman_options,
6486b0
 							     subman_conopts,
6486b0
 							     locale),
6486b0
 					      G_DBUS_CALL_FLAGS_NO_AUTO_START,
6486b0
 					      DBUS_TIMEOUT,
6486b0
 					      NULL, &error_local);
6486b0
 		if (res == NULL) {
6486b0
 			g_dbus_error_strip_remote_error (error_local);
6486b0
 			_helper_convert_error (error_local->message, &error);
6486b0
 			g_printerr ("Failed to Register: %s\n", error->message);
6486b0
 			return error->code;
6486b0
 		}
6486b0
 	} else {
6486b0
 		g_printerr ("Invalid --kind specified: %s\n", kind);
6486b0
 		return G_IO_ERROR_INVALID_DATA;
6486b0
 	}
6486b0
 
6486b0
 	/* set the new hostname */
6486b0
 	if (!_helper_save_config ("server.hostname", hostname, &error)) {
6486b0
 		g_printerr ("Failed to save hostname: %s\n", error->message);
6486b0
diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c
6486b0
index e2c16056..0838d490 100644
6486b0
--- a/plugins/subman/gsd-subscription-manager.c
6486b0
+++ b/plugins/subman/gsd-subscription-manager.c
6486b0
@@ -1,53 +1,54 @@
6486b0
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
6486b0
  *
6486b0
  * Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
6486b0
  * Copyright (C) 2019 Kalev Lember <klember@redhat.com>
6486b0
  *
6486b0
  * This program is free software; you can redistribute it and/or modify
6486b0
  * it under the terms of the GNU General Public License as published by
6486b0
  * the Free Software Foundation; either version 2 of the License, or
6486b0
  * (at your option) any later version.
6486b0
  *
6486b0
  * This program is distributed in the hope that it will be useful,
6486b0
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
6486b0
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
6486b0
  * GNU General Public License for more details.
6486b0
  *
6486b0
  * You should have received a copy of the GNU General Public License
6486b0
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
6486b0
  *
6486b0
  */
6486b0
 
6486b0
 #include "config.h"
6486b0
 
6486b0
 #include <glib/gi18n.h>
6486b0
+#include <gio/gunixinputstream.h>
6486b0
 #include <gdk/gdk.h>
6486b0
 #include <gtk/gtk.h>
6486b0
 #include <json-glib/json-glib.h>
6486b0
 #include <libnotify/notify.h>
6486b0
 
6486b0
 #include "gnome-settings-profile.h"
6486b0
 #include "gsd-subman-common.h"
6486b0
 #include "gsd-subscription-manager.h"
6486b0
 
6486b0
 #define GSD_DBUS_NAME "org.gnome.SettingsDaemon"
6486b0
 #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
6486b0
 #define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon"
6486b0
 
6486b0
 #define GSD_SUBSCRIPTION_DBUS_NAME		GSD_DBUS_NAME ".Subscription"
6486b0
 #define GSD_SUBSCRIPTION_DBUS_PATH		GSD_DBUS_PATH "/Subscription"
6486b0
 #define GSD_SUBSCRIPTION_DBUS_INTERFACE		GSD_DBUS_BASE_INTERFACE ".Subscription"
6486b0
 
6486b0
 static const gchar introspection_xml[] =
6486b0
 "<node>"
6486b0
 "  <interface name='org.gnome.SettingsDaemon.Subscription'>"
6486b0
 "    <method name='Register'>"
6486b0
 "      <arg type='a{sv}' name='options' direction='in'/>"
6486b0
 "    </method>"
6486b0
 "    <method name='Unregister'/>"
6486b0
 "    <property name='InstalledProducts' type='aa{sv}' access='read'/>"
6486b0
 "    <property name='SubscriptionStatus' type='u' access='read'/>"
6486b0
 "  </interface>"
6486b0
 "</node>";
6486b0
 
6486b0
 #define GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManagerPrivate))
6486b0
@@ -517,129 +518,168 @@ _client_maybe__show_notification (GsdSubscriptionManager *manager)
6486b0
 		}
6486b0
 	}
6486b0
 
6486b0
 	/* nag again */
6486b0
 	if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN &&
6486b0
 	    g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) {
6486b0
 		_show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED);
6486b0
 		return;
6486b0
 	}
6486b0
 	if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID &&
6486b0
 	    g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) {
6486b0
 		_show_notification (manager, _NOTIFY_EXPIRED);
6486b0
 		return;
6486b0
 	}
6486b0
 	if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID &&
6486b0
 	    g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) {
6486b0
 		_show_notification (manager, _NOTIFY_EXPIRED);
6486b0
 		return;
6486b0
 	}
6486b0
 }
6486b0
 
6486b0
 static gboolean
6486b0
 _client_register_with_keys (GsdSubscriptionManager *manager,
6486b0
 				  const gchar *hostname,
6486b0
 				  const gchar *organisation,
6486b0
 				  const gchar *activation_key,
6486b0
 				  GError **error)
6486b0
 {
6486b0
 	GsdSubscriptionManagerPrivate *priv = manager->priv;
6486b0
 	g_autoptr(GSubprocess) subprocess = NULL;
6486b0
+	g_autoptr(GBytes) stdin_buf = g_bytes_new (activation_key, strlen (activation_key) + 1);
6486b0
+	g_autoptr(GBytes) stderr_buf = NULL;
6486b0
+	gint rc;
6486b0
 
6486b0
 	/* apparently: "we can't send registration credentials over the regular
6486b0
 	 * system or session bus since those aren't really locked down..." */
6486b0
 	if (!_client_register_start (manager, error))
6486b0
 		return FALSE;
6486b0
 	g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper");
6486b0
-	subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error,
6486b0
+	subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, error,
6486b0
 				       "pkexec", LIBEXECDIR "/gsd-subman-helper",
6486b0
 				       "--kind", "register-with-key",
6486b0
 				       "--address", priv->address,
6486b0
 				       "--hostname", hostname,
6486b0
 				       "--organisation", organisation,
6486b0
-				       "--activation-key", activation_key,
6486b0
 				       NULL);
6486b0
 	if (subprocess == NULL) {
6486b0
 		g_prefix_error (error, "failed to find pkexec: ");
6486b0
 		return FALSE;
6486b0
 	}
6486b0
-	if (!_client_subprocess_wait_check (subprocess, error))
6486b0
+
6486b0
+	if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) {
6486b0
+		g_prefix_error (error, "failed to run pkexec: ");
6486b0
 		return FALSE;
6486b0
+	}
6486b0
+
6486b0
+	rc = g_subprocess_get_exit_status (subprocess);
6486b0
+	if (rc != 0) {
6486b0
+		if (g_bytes_get_size (stderr_buf) == 0) {
6486b0
+			g_set_error_literal (error, G_IO_ERROR, rc,
6486b0
+			                     "Failed to run helper without stderr");
6486b0
+			return FALSE;
6486b0
+		}
6486b0
+
6486b0
+		g_set_error (error, G_IO_ERROR, rc,
6486b0
+			     "%.*s",
6486b0
+			     g_bytes_get_size (stderr_buf),
6486b0
+			     g_bytes_get_data (stderr_buf, NULL));
6486b0
+	}
6486b0
 
6486b0
 	/* FIXME: also do on error? */
6486b0
 	if (!_client_register_stop (manager, error))
6486b0
 		return FALSE;
6486b0
 	if (!_client_subscription_status_update (manager, error))
6486b0
 		return FALSE;
6486b0
 	if (!_client_installed_products_update (manager, error))
6486b0
 		return FALSE;
6486b0
 	_client_maybe__show_notification (manager);
6486b0
 
6486b0
 	/* success */
6486b0
 	return TRUE;
6486b0
 }
6486b0
 
6486b0
 static gboolean
6486b0
 _client_register (GsdSubscriptionManager *manager,
6486b0
 			 const gchar *hostname,
6486b0
 			 const gchar *organisation,
6486b0
 			 const gchar *username,
6486b0
 			 const gchar *password,
6486b0
 			 GError **error)
6486b0
 {
6486b0
 	GsdSubscriptionManagerPrivate *priv = manager->priv;
6486b0
 	g_autoptr(GSubprocess) subprocess = NULL;
6486b0
+	g_autoptr(GBytes) stdin_buf = g_bytes_new (password, strlen (password) + 1);
6486b0
+	g_autoptr(GBytes) stderr_buf = NULL;
6486b0
+	gint rc;
6486b0
 
6486b0
 	/* fallback */
6486b0
 	if (organisation == NULL)
6486b0
 		organisation = "";
6486b0
 
6486b0
 	/* apparently: "we can't send registration credentials over the regular
6486b0
 	 * system or session bus since those aren't really locked down..." */
6486b0
 	if (!_client_register_start (manager, error))
6486b0
 		return FALSE;
6486b0
 	g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper");
6486b0
-	subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error,
6486b0
+	subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE,
6486b0
+				       error,
6486b0
 				       "pkexec", LIBEXECDIR "/gsd-subman-helper",
6486b0
 				       "--kind", "register-with-username",
6486b0
 				       "--address", priv->address,
6486b0
 				       "--hostname", hostname,
6486b0
 				       "--organisation", organisation,
6486b0
 				       "--username", username,
6486b0
-				       "--password", password,
6486b0
 				       NULL);
6486b0
 	if (subprocess == NULL) {
6486b0
 		g_prefix_error (error, "failed to find pkexec: ");
6486b0
 		return FALSE;
6486b0
 	}
6486b0
-	if (!_client_subprocess_wait_check (subprocess, error))
6486b0
+
6486b0
+	if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) {
6486b0
+		g_prefix_error (error, "failed to run pkexec: ");
6486b0
 		return FALSE;
6486b0
+	}
6486b0
+
6486b0
+	rc = g_subprocess_get_exit_status (subprocess);
6486b0
+	if (rc != 0) {
6486b0
+		if (g_bytes_get_size (stderr_buf) == 0) {
6486b0
+			g_set_error_literal (error, G_IO_ERROR, rc,
6486b0
+			                     "Failed to run helper without stderr");
6486b0
+			return FALSE;
6486b0
+		}
6486b0
+
6486b0
+		g_set_error (error, G_IO_ERROR, rc,
6486b0
+			     "%.*s",
6486b0
+			     g_bytes_get_size (stderr_buf),
6486b0
+			     g_bytes_get_data (stderr_buf, NULL));
6486b0
+	}
6486b0
 
6486b0
 	/* FIXME: also do on error? */
6486b0
 	if (!_client_register_stop (manager, error))
6486b0
 		return FALSE;
6486b0
 	if (!_client_subscription_status_update (manager, error))
6486b0
 		return FALSE;
6486b0
 	if (!_client_installed_products_update (manager, error))
6486b0
 		return FALSE;
6486b0
 	_client_maybe__show_notification (manager);
6486b0
 	return TRUE;
6486b0
 }
6486b0
 
6486b0
 static gboolean
6486b0
 _client_unregister (GsdSubscriptionManager *manager, GError **error)
6486b0
 {
6486b0
 	g_autoptr(GSubprocess) subprocess = NULL;
6486b0
 
6486b0
 	/* apparently: "we can't send registration credentials over the regular
6486b0
 	 * system or session bus since those aren't really locked down..." */
6486b0
 	if (!_client_register_start (manager, error))
6486b0
 		return FALSE;
6486b0
 	g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper");
6486b0
 	subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error,
6486b0
 				       "pkexec", LIBEXECDIR "/gsd-subman-helper",
6486b0
 				       "--kind", "unregister",
6486b0
 				       NULL);
6486b0
 	if (subprocess == NULL) {
6486b0
 		g_prefix_error (error, "failed to find pkexec: ");
6486b0
 		return FALSE;
6486b0
 	}
6486b0
diff --git a/plugins/subman/meson.build b/plugins/subman/meson.build
6486b0
index bfd073b6..e4b4589d 100644
6486b0
--- a/plugins/subman/meson.build
6486b0
+++ b/plugins/subman/meson.build
6486b0
@@ -22,35 +22,35 @@ executable(
6486b0
   c_args: cflags,
6486b0
   install: true,
6486b0
   install_rpath: gsd_pkglibdir,
6486b0
   install_dir: gsd_libexecdir
6486b0
 )
6486b0
 
6486b0
 # .Register needs to be called from root as subman can't do PolicyKit...
6486b0
 policy = 'org.gnome.settings-daemon.plugins.subman.policy'
6486b0
 policy_in = configure_file(
6486b0
   input: policy + '.in.in',
6486b0
   output: policy + '.in',
6486b0
   configuration: plugins_conf
6486b0
 )
6486b0
 
6486b0
 i18n.merge_file(
6486b0
   policy,
6486b0
   input: policy_in,
6486b0
   output: policy,
6486b0
   po_dir: po_dir,
6486b0
   install: true,
6486b0
   install_dir: join_paths(gsd_datadir, 'polkit-1', 'actions')
6486b0
 )
6486b0
 
6486b0
 install_data('org.gnome.settings-daemon.plugins.subman.rules',
6486b0
              install_dir : join_paths(gsd_datadir, 'polkit-1', 'rules.d'))
6486b0
 
6486b0
 executable(
6486b0
   'gsd-subman-helper',
6486b0
   'gsd-subman-helper.c',
6486b0
   include_directories: top_inc,
6486b0
-  dependencies: [gio_dep, jsonglib_dep],
6486b0
+  dependencies: [gio_dep, gio_unix_dep, jsonglib_dep],
6486b0
   install: true,
6486b0
   install_rpath: gsd_pkglibdir,
6486b0
   install_dir: gsd_libexecdir
6486b0
 )
6486b0
-- 
6486b0
2.30.0
6486b0