From 646ba50930f28d9f12ad9cb9e4060c9d5aa710b0 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 30 Mar 2021 14:43:44 -0400 Subject: [PATCH] import gnome-settings-daemon-3.32.0-13.el8 --- ...screen-cast-as-stopped-if-it-was-sig.patch | 125 +++ ...lledProducts-dbus-property-for-g-c-c.patch | 249 ------ ...-plugin-to-provide-system-subscripti.patch | 653 +++++++-------- ...man-Increase-RHSM-dbus-call-timeouts.patch | 77 -- ...lledProducts-dbus-property-for-g-c-c.patch | 768 ++++++++++++++++++ ...man-Increase-RHSM-dbus-call-timeouts.patch | 313 +++++++ SOURCES/0004-subman-Drop-userlang-field.patch | 454 +++++++++++ ...locale-for-registration-subscription.patch | 373 +++++++++ ...bscription-manager-giving-invalid-st.patch | 236 ++++++ ...subscribe-if-the-admin-already-subsc.patch | 260 ++++++ ...-t-send-secrets-through-command-line.patch | 576 +++++++++++++ ...n-t-treat-failure-to-attach-as-fatal.patch | 310 +++++++ ...-Add-new-no-installed-products-state.patch | 427 ++++++++++ .../0011-subman-Fix-some-build-warnings.patch | 146 ++++ ...API-to-subscribe-for-updates-on-alre.patch | 259 ++++++ ...Improve-subscription-status-handling.patch | 141 ++++ ...14-subman-Drop-LAST-from-status-enum.patch | 56 ++ ...ubman-Clean-up-notification-behavior.patch | 419 ++++++++++ SPECS/gnome-settings-daemon.spec | 59 +- 19 files changed, 5205 insertions(+), 696 deletions(-) create mode 100644 SOURCES/0001-media-keys-Mark-screen-cast-as-stopped-if-it-was-sig.patch delete mode 100644 SOURCES/0001-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch delete mode 100644 SOURCES/0001-subman-Increase-RHSM-dbus-call-timeouts.patch create mode 100644 SOURCES/0002-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch create mode 100644 SOURCES/0003-subman-Increase-RHSM-dbus-call-timeouts.patch create mode 100644 SOURCES/0004-subman-Drop-userlang-field.patch create mode 100644 SOURCES/0005-subman-Use-user-locale-for-registration-subscription.patch create mode 100644 SOURCES/0006-subman-Handle-subscription-manager-giving-invalid-st.patch create mode 100644 SOURCES/0007-subman-Force-re-subscribe-if-the-admin-already-subsc.patch create mode 100644 SOURCES/0008-subman-Don-t-send-secrets-through-command-line.patch create mode 100644 SOURCES/0009-subman-Don-t-treat-failure-to-attach-as-fatal.patch create mode 100644 SOURCES/0010-subman-Add-new-no-installed-products-state.patch create mode 100644 SOURCES/0011-subman-Fix-some-build-warnings.patch create mode 100644 SOURCES/0012-subman-Add-DBus-API-to-subscribe-for-updates-on-alre.patch create mode 100644 SOURCES/0013-subman-Improve-subscription-status-handling.patch create mode 100644 SOURCES/0014-subman-Drop-LAST-from-status-enum.patch create mode 100644 SOURCES/0015-subman-Clean-up-notification-behavior.patch diff --git a/SOURCES/0001-media-keys-Mark-screen-cast-as-stopped-if-it-was-sig.patch b/SOURCES/0001-media-keys-Mark-screen-cast-as-stopped-if-it-was-sig.patch new file mode 100644 index 0000000..e940d66 --- /dev/null +++ b/SOURCES/0001-media-keys-Mark-screen-cast-as-stopped-if-it-was-sig.patch @@ -0,0 +1,125 @@ +From a8115378fd876bfd4c3871428cdc16134ed484b1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 5 Jan 2021 11:11:18 +0100 +Subject: [PATCH] media-keys: Mark screen cast as stopped if it was signalled + as such + +gnome-shell now sends a 'Stopped' signal if it was stopped without +gsd-media-keys itself being the stopper. +--- + plugins/media-keys/gsd-media-keys-manager.c | 52 +++++++++++++++++++-- + 1 file changed, 49 insertions(+), 3 deletions(-) + +diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c +index 4d251f08..a526d5cf 100644 +--- a/plugins/media-keys/gsd-media-keys-manager.c ++++ b/plugins/media-keys/gsd-media-keys-manager.c +@@ -210,6 +210,7 @@ struct GsdMediaKeysManagerPrivate + guint screencast_timeout_id; + gboolean screencast_recording; + GCancellable *screencast_cancellable; ++ guint screencast_stopped_signal_id; + + /* Rotation */ + guint iio_sensor_watch_id; +@@ -2346,20 +2347,26 @@ do_rfkill_action (GsdMediaKeysManager *manager, + } + + static void +-screencast_stop (GsdMediaKeysManager *manager) ++screencast_stopped (GsdMediaKeysManager *manager) + { + if (manager->priv->screencast_timeout_id > 0) { + g_source_remove (manager->priv->screencast_timeout_id); + manager->priv->screencast_timeout_id = 0; + } + ++ manager->priv->screencast_recording = FALSE; ++} ++ ++static void ++screencast_stop (GsdMediaKeysManager *manager) ++{ ++ screencast_stopped (manager); ++ + g_dbus_proxy_call (manager->priv->screencast_proxy, + "StopScreencast", NULL, + G_DBUS_CALL_FLAGS_NONE, -1, + manager->priv->screencast_cancellable, + NULL, NULL); +- +- manager->priv->screencast_recording = FALSE; + } + + static gboolean +@@ -2835,6 +2842,21 @@ initialize_volume_handler (GsdMediaKeysManager *manager) + gnome_settings_profile_end ("gvc_mixer_control_new"); + } + ++ ++static void ++on_screencast_stopped (GDBusConnection *connection, ++ const gchar *sender_name, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *signal_name, ++ GVariant *parameters, ++ gpointer data) ++{ ++ GsdMediaKeysManager *manager = data; ++ ++ screencast_stopped (manager); ++} ++ + static void + on_screencast_proxy_ready (GObject *source, + GAsyncResult *result, +@@ -2850,7 +2872,20 @@ on_screencast_proxy_ready (GObject *source, + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Failed to create proxy for screencast: %s", error->message); + g_error_free (error); ++ return; + } ++ ++ manager->priv->screencast_stopped_signal_id = ++ g_dbus_connection_signal_subscribe (manager->priv->connection, ++ SHELL_DBUS_NAME ".Screencast", ++ SHELL_DBUS_NAME ".Screencast", ++ "Stopped", ++ SHELL_DBUS_PATH "/Screencast", ++ NULL, ++ G_DBUS_SIGNAL_FLAGS_NONE, ++ on_screencast_stopped, ++ manager, ++ NULL); + } + + static void +@@ -2901,6 +2936,11 @@ shell_presence_changed (GsdMediaKeysManager *manager) + on_screencast_proxy_ready, manager); + g_free (name_owner); + } else { ++ if (manager->priv->screencast_stopped_signal_id) ++ g_dbus_connection_signal_unsubscribe (manager->priv->connection, ++ manager->priv->screencast_stopped_signal_id); ++ manager->priv->screencast_stopped_signal_id = 0; ++ + g_ptr_array_set_size (manager->priv->keys, 0); + g_clear_object (&manager->priv->key_grabber); + g_clear_object (&manager->priv->screencast_proxy); +@@ -3091,6 +3131,12 @@ gsd_media_keys_manager_stop (GsdMediaKeysManager *manager) + priv->reenable_power_button_timer_id = 0; + } + ++ if (priv->screencast_stopped_signal_id) { ++ g_dbus_connection_signal_unsubscribe (priv->connection, ++ priv->screencast_stopped_signal_id); ++ priv->screencast_stopped_signal_id = 0; ++ } ++ + g_clear_pointer (&manager->priv->ca, ca_context_destroy); + + #if HAVE_GUDEV +-- +2.27.0 + diff --git a/SOURCES/0001-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch b/SOURCES/0001-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch deleted file mode 100644 index 71b339b..0000000 --- a/SOURCES/0001-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch +++ /dev/null @@ -1,249 +0,0 @@ -From ca35861a54b9f9413e4db8486a2786ba771a0271 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Thu, 27 Jun 2019 16:12:00 +0200 -Subject: [PATCH] subman: Add InstalledProducts dbus property for g-c-c - ---- - plugins/subman/gsd-subscription-manager.c | 135 ++++++++++++++++++++++ - 1 file changed, 135 insertions(+) - -diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c -index 08b13fa6..a8c18a26 100644 ---- a/plugins/subman/gsd-subscription-manager.c -+++ b/plugins/subman/gsd-subscription-manager.c -@@ -1,6 +1,7 @@ - /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2019 Richard Hughes -+ * Copyright (C) 2019 Kalev Lember - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -44,6 +45,7 @@ static const gchar introspection_xml[] = - " " - " " - " " -+" " - " " - " " - ""; -@@ -72,6 +74,7 @@ struct GsdSubscriptionManagerPrivate - GDBusProxy *proxies[_RHSM_INTERFACE_LAST]; - const gchar *userlang; /* owned by GLib internally */ - GHashTable *config; /* str:str */ -+ GPtrArray *installed_products; - gchar *address; - - GTimer *timer_last_notified; -@@ -92,6 +95,32 @@ static void gsd_subscription_manager_finalize (GObject *objec - - G_DEFINE_TYPE (GsdSubscriptionManager, gsd_subscription_manager, G_TYPE_OBJECT) - -+typedef struct -+{ -+ gchar *product_name; -+ gchar *product_id; -+ gchar *version; -+ gchar *arch; -+ gchar *status; -+ gchar *starts; -+ gchar *ends; -+} ProductData; -+ -+static void -+product_data_free (ProductData *product) -+{ -+ g_free (product->product_name); -+ g_free (product->product_id); -+ g_free (product->version); -+ g_free (product->arch); -+ g_free (product->status); -+ g_free (product->starts); -+ g_free (product->ends); -+ g_free (product); -+} -+ -+G_DEFINE_AUTOPTR_CLEANUP_FUNC (ProductData, product_data_free); -+ - static gpointer manager_object = NULL; - - GQuark -@@ -120,6 +149,32 @@ _client_subscription_status_from_text (const gchar *status_txt) - return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; - } - -+static GVariant * -+_make_installed_products_variant (GPtrArray *installed_products) -+{ -+ GVariantBuilder builder; -+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); -+ -+ for (guint i = 0; i < installed_products->len; i++) { -+ ProductData *product = g_ptr_array_index (installed_products, i); -+ g_auto(GVariantDict) dict; -+ -+ g_variant_dict_init (&dict, NULL); -+ -+ g_variant_dict_insert (&dict, "product-name", "s", product->product_name); -+ g_variant_dict_insert (&dict, "product-id", "s", product->product_id); -+ g_variant_dict_insert (&dict, "version", "s", product->version); -+ g_variant_dict_insert (&dict, "arch", "s", product->arch); -+ g_variant_dict_insert (&dict, "status", "s", product->status); -+ g_variant_dict_insert (&dict, "starts", "s", product->starts); -+ g_variant_dict_insert (&dict, "ends", "s", product->ends); -+ -+ g_variant_builder_add_value (&builder, g_variant_dict_end (&dict)); -+ } -+ -+ return g_variant_builder_end (&builder); -+} -+ - static void - _emit_property_changed (GsdSubscriptionManager *manager, - const gchar *property_name, -@@ -154,6 +209,69 @@ _emit_property_changed (GsdSubscriptionManager *manager, - g_variant_builder_clear (&invalidated_builder); - } - -+static gboolean -+_client_installed_products_update (GsdSubscriptionManager *manager, GError **error) -+{ -+ GsdSubscriptionManagerPrivate *priv = manager->priv; -+ JsonNode *json_root; -+ JsonArray *json_products_array; -+ const gchar *json_txt = NULL; -+ g_autoptr(GVariant) val = NULL; -+ g_autoptr(JsonParser) json_parser = json_parser_new (); -+ -+ val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_PRODUCTS], -+ "ListInstalledProducts", -+ g_variant_new ("(sa{sv}s)", -+ "" /* filter_string */, -+ NULL /* proxy_options */, -+ priv->userlang), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, NULL, error); -+ if (val == NULL) -+ return FALSE; -+ g_variant_get (val, "(&s)", &json_txt); -+ g_debug ("Products.ListInstalledProducts JSON: %s", json_txt); -+ if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) -+ return FALSE; -+ json_root = json_parser_get_root (json_parser); -+ json_products_array = json_node_get_array (json_root); -+ if (json_products_array == NULL) { -+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, -+ "no InstalledProducts array in %s", json_txt); -+ return FALSE; -+ } -+ -+ g_ptr_array_set_size (priv->installed_products, 0); -+ -+ for (guint i = 0; i < json_array_get_length (json_products_array); i++) { -+ JsonArray *json_product = json_array_get_array_element (json_products_array, i); -+ g_autoptr(ProductData) product = g_new0 (ProductData, 1); -+ -+ if (json_product == NULL) -+ continue; -+ if (json_array_get_length (json_product) < 8) { -+ g_debug ("Unexpected number of array elements in InstalledProducts JSON"); -+ continue; -+ } -+ -+ product->product_name = g_strdup (json_array_get_string_element (json_product, 0)); -+ product->product_id = g_strdup (json_array_get_string_element (json_product, 1)); -+ product->version = g_strdup (json_array_get_string_element (json_product, 2)); -+ product->arch = g_strdup (json_array_get_string_element (json_product, 3)); -+ product->status = g_strdup (json_array_get_string_element (json_product, 4)); -+ product->starts = g_strdup (json_array_get_string_element (json_product, 6)); -+ product->ends = g_strdup (json_array_get_string_element (json_product, 7)); -+ -+ g_ptr_array_add (priv->installed_products, g_steal_pointer (&product)); -+ } -+ -+ /* emit notification for g-c-c */ -+ _emit_property_changed (manager, "InstalledProducts", -+ _make_installed_products_variant (priv->installed_products)); -+ -+ return TRUE; -+} -+ - static gboolean - _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) - { -@@ -450,6 +568,8 @@ _client_register_with_keys (GsdSubscriptionManager *manager, - return FALSE; - if (!_client_subscription_status_update (manager, error)) - return FALSE; -+ if (!_client_installed_products_update (manager, error)) -+ return FALSE; - _client_maybe__show_notification (manager); - - /* success */ -@@ -497,6 +617,8 @@ _client_register (GsdSubscriptionManager *manager, - return FALSE; - if (!_client_subscription_status_update (manager, error)) - return FALSE; -+ if (!_client_installed_products_update (manager, error)) -+ return FALSE; - _client_maybe__show_notification (manager); - return TRUE; - } -@@ -523,6 +645,8 @@ _client_unregister (GsdSubscriptionManager *manager, GError **error) - return FALSE; - if (!_client_subscription_status_update (manager, error)) - return FALSE; -+ if (!_client_installed_products_update (manager, error)) -+ return FALSE; - _client_maybe__show_notification (manager); - return TRUE; - } -@@ -575,6 +699,10 @@ _subman_proxy_signal_cb (GDBusProxy *proxy, - g_warning ("failed to update subscription status: %s", error->message); - g_clear_error (&error); - } -+ if (!_client_installed_products_update (manager, &error)) { -+ g_warning ("failed to update installed products: %s", error->message); -+ g_clear_error (&error); -+ } - _client_maybe__show_notification (manager); - } - -@@ -640,6 +768,8 @@ _client_load (GsdSubscriptionManager *manager, GError **error) - return FALSE; - if (!_client_subscription_status_update (manager, error)) - return FALSE; -+ if (!_client_installed_products_update (manager, error)) -+ return FALSE; - if (!_client_syspurpose_update (manager, error)) - return FALSE; - -@@ -703,6 +833,7 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) - { - GsdSubscriptionManagerPrivate *priv = manager->priv = GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE (manager); - -+ priv->installed_products = g_ptr_array_new_with_free_func ((GDestroyNotify) product_data_free); - priv->timer_last_notified = g_timer_new (); - - /* expired */ -@@ -767,6 +898,7 @@ gsd_subscription_manager_finalize (GObject *object) - g_clear_object (&manager->priv->bus_cancellable); - } - -+ g_clear_pointer (&manager->priv->installed_products, g_ptr_array_unref); - g_clear_pointer (&manager->priv->introspection_data, g_dbus_node_info_unref); - g_clear_object (&manager->priv->connection); - g_clear_object (&manager->priv->notification_expired); -@@ -884,6 +1016,9 @@ handle_get_property (GDBusConnection *connection, - if (g_strcmp0 (property_name, "SubscriptionStatus") == 0) - return g_variant_new_uint32 (priv->subscription_status); - -+ if (g_strcmp0 (property_name, "InstalledProducts") == 0) -+ return _make_installed_products_variant (priv->installed_products); -+ - g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, - "Failed to get property: %s", property_name); - return NULL; --- -2.21.0 - diff --git a/SOURCES/0001-subman-Add-a-new-plugin-to-provide-system-subscripti.patch b/SOURCES/0001-subman-Add-a-new-plugin-to-provide-system-subscripti.patch index 502aa9f..bc13b55 100644 --- a/SOURCES/0001-subman-Add-a-new-plugin-to-provide-system-subscripti.patch +++ b/SOURCES/0001-subman-Add-a-new-plugin-to-provide-system-subscripti.patch @@ -1,7 +1,68 @@ -diff -urNp gnome-settings-daemon-3.32.0.old/meson.build gnome-settings-daemon-3.32.0/meson.build ---- gnome-settings-daemon-3.32.0.old/meson.build 2019-06-17 13:01:46.867338656 +0100 -+++ gnome-settings-daemon-3.32.0/meson.build 2019-06-17 13:01:59.245311865 +0100 -@@ -97,6 +97,7 @@ libcanberra_gtk_dep = dependency('libcan +From bee6d42503ec9b56f6e10704db02bcedb6a4fdf1 Mon Sep 17 00:00:00 2001 +From: Richard Hughes +Date: Thu, 20 Aug 2020 11:16:09 -0400 +Subject: [PATCH 01/15] subman: Add a new plugin to provide system subscription + registration + +--- + meson.build | 1 + + plugins/meson.build | 1 + + plugins/subman/README.md | 56 + + plugins/subman/gsd-subman-common.c | 36 + + plugins/subman/gsd-subman-common.h | 40 + + plugins/subman/gsd-subman-helper.c | 378 +++++++ + plugins/subman/gsd-subscription-manager.c | 982 ++++++++++++++++++ + plugins/subman/gsd-subscription-manager.h | 63 ++ + plugins/subman/main.c | 8 + + plugins/subman/meson.build | 56 + + ...ome.SettingsDaemon.Subscription.desktop.in | 9 + + ...ettings-daemon.plugins.subman.policy.in.in | 27 + + ...gnome.settings-daemon.plugins.subman.rules | 7 + + 13 files changed, 1664 insertions(+) + create mode 100644 plugins/subman/README.md + create mode 100644 plugins/subman/gsd-subman-common.c + create mode 100644 plugins/subman/gsd-subman-common.h + create mode 100644 plugins/subman/gsd-subman-helper.c + create mode 100644 plugins/subman/gsd-subscription-manager.c + create mode 100644 plugins/subman/gsd-subscription-manager.h + create mode 100644 plugins/subman/main.c + create mode 100644 plugins/subman/meson.build + create mode 100644 plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in + create mode 100644 plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in + create mode 100644 plugins/subman/org.gnome.settings-daemon.plugins.subman.rules + +diff --git a/meson.build b/meson.build +index 1632ea05..27bf8c4c 100644 +--- a/meson.build ++++ b/meson.build +@@ -70,60 +70,61 @@ if gsd_buildtype.contains('debug') + ] + + compiler_flags = cc.get_supported_arguments(test_cflags) + elif gsd_buildtype.contains('release') + common_flags += ['-DG_DISABLE_CAST_CHECKS'] + endif + + # Workaround for meson's bug + # https://github.com/mesonbuild/meson/pull/1896 + if get_option('b_ndebug') == true + common_flags += ['-DG_DISABLE_ASSERT'] + endif + + add_project_arguments(common_flags + compiler_flags, language: 'c') + + glib_dep = dependency('glib-2.0', version: '>= 2.56') + colord_dep = dependency('colord', version: '>= 1.0.2') + geocode_glib_dep = dependency('geocode-glib-1.0', version: '>= 3.10.0') + gio_dep = dependency('gio-2.0', version: '>= 2.53.0') + gio_unix_dep = dependency('gio-unix-2.0') + gnome_desktop_dep = dependency('gnome-desktop-3.0', version: '>= 3.11.1') + gsettings_desktop_dep = dependency('gsettings-desktop-schemas', version: '>= 3.27.90') + gtk_dep = dependency('gtk+-3.0', version: '>= 3.15.3') + gtk_x11_dep = dependency('gtk+-x11-3.0') + gweather_dep = dependency('gweather-3.0', version: '>= 3.9.5') + lcms_dep = dependency('lcms2', version: '>= 2.2') + libcanberra_gtk_dep = dependency('libcanberra-gtk3') libgeoclue_dep = dependency('libgeoclue-2.0', version: '>= 2.3.1') libnotify_dep = dependency('libnotify', version: '>= 0.7.3') libpulse_mainloop_glib_dep = dependency('libpulse-mainloop-glib', version: '>= 2.0') @@ -9,10 +70,40 @@ diff -urNp gnome-settings-daemon-3.32.0.old/meson.build gnome-settings-daemon-3. pango_dep = dependency('pango', version: '>= 1.20.0') polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.103') upower_glib_dep = dependency('upower-glib', version: '>= 0.99.0') -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/meson.build gnome-settings-daemon-3.32.0/plugins/meson.build ---- gnome-settings-daemon-3.32.0.old/plugins/meson.build 2019-06-17 13:01:46.867338656 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/meson.build 2019-06-17 13:01:59.245311865 +0100 -@@ -3,6 +3,7 @@ enabled_plugins = [ + x11_dep = dependency('x11') + + m_dep = cc.find_library('m') + dl_dep = cc.find_library('dl') + + # ALSA integration (default enabled) + enable_alsa = get_option('alsa') + assert(enable_alsa or not host_is_linux, 'ALSA is not optional on Linux platforms') + + libgvc = subproject( + 'gvc', + default_options: [ + 'static=true', + 'alsa=' + enable_alsa.to_string() + ] + ) + libgvc_dep = libgvc.get_variable('libgvc_dep') + + # GUdev integration (default enabled) + enable_gudev = get_option('gudev') + if enable_gudev + gudev_dep = dependency('gudev-1.0') + endif + config_h.set10('HAVE_GUDEV', enable_gudev) + if host_is_linux + assert(enable_gudev, 'GUdev is not optional on Linux platforms') + endif +diff --git a/plugins/meson.build b/plugins/meson.build +index 3c4d42ac..4c9caf47 100644 +--- a/plugins/meson.build ++++ b/plugins/meson.build +@@ -1,35 +1,36 @@ + enabled_plugins = [ + ['a11y-settings', 'A11ySettings'], ['account', 'Account'], ['clipboard', 'Clipboard'], ['color', 'Color'], @@ -20,9 +111,100 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/meson.build gnome-settings-d ['datetime', 'Datetime'], ['dummy', ''], ['power', 'Power'], -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-common.c gnome-settings-daemon-3.32.0/plugins/subman/gsd-subman-common.c ---- gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-common.c 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/gsd-subman-common.c 2019-06-17 13:01:59.246311863 +0100 + ['housekeeping', 'Housekeeping'], + ['keyboard', 'Keyboard'], + ['media-keys', 'MediaKeys'], + ['mouse', 'Mouse'], + ['screensaver-proxy', 'ScreensaverProxy'], + ['sharing', 'Sharing'], + ['sound', 'Sound'], + ['xsettings', 'XSettings'] + ] + + if enable_smartcard + enabled_plugins += [['smartcard', 'Smartcard']] + endif + + if enable_wacom + enabled_plugins += [['wacom', 'Wacom']] + endif + + if enable_cups + enabled_plugins += [['print-notifications', 'PrintNotifications']] + endif + + if enable_rfkill + enabled_plugins += [['rfkill', 'Rfkill']] + endif + + plugins_conf = configuration_data() +diff --git a/plugins/subman/README.md b/plugins/subman/README.md +new file mode 100644 +index 00000000..3e1cc3cd +--- /dev/null ++++ b/plugins/subman/README.md +@@ -0,0 +1,56 @@ ++GNOME Settings Daemon: Subscription Manager Plugin ++================================================== ++ ++Testing: ++ ++To add a test acccount on subscription.rhsm.stage.redhat.com, use Ethel: ++http://account-manager-stage.app.eng.rdu2.redhat.com/#view ++ ++Register with a username and password ++------------------------------------- ++ ++ gdbus call \ ++ --session \ ++ --dest org.gnome.SettingsDaemon.Subscription \ ++ --object-path /org/gnome/SettingsDaemon/Subscription \ ++ --method org.gnome.SettingsDaemon.Subscription.Register "{'kind':<'username'>,'hostname':<'subscription.rhsm.stage.redhat.com'>,'username':<'rhughes_test'>,'password':<'barbaz'>}" ++ ++To register with a certificate ++------------------------------ ++ ++ gdbus call \ ++ --session \ ++ --dest org.gnome.SettingsDaemon.Subscription \ ++ --object-path /org/gnome/SettingsDaemon/Subscription \ ++ --method org.gnome.SettingsDaemon.Subscription.Register "{'kind':<'key'>,'hostname':<'subscription.rhsm.stage.redhat.com'>,'organisation':<'foo'>,'activation-key':<'barbaz'>}" ++ ++To unregister ++------------- ++ ++ gdbus call \ ++ --session \ ++ --dest org.gnome.SettingsDaemon.Subscription \ ++ --object-path /org/gnome/SettingsDaemon/Subscription \ ++ --method org.gnome.SettingsDaemon.Subscription.Unregister ++ ++Debugging ++--------- ++ ++Get the UNIX socket using `Subscription.Register` then call something like: ++ ++ sudo G_MESSAGES_DEBUG=all ./plugins/subman/gsd-subman-helper \ ++ --address="unix:abstract=/var/run/dbus-ulGB1wfnbn,guid=71e6bf329d861ce366df7a1d5d036a5b" \ ++ --kind="register-with-username" \ ++ --username="rhughes_test" \ ++ --password="barbaz" \ ++ --hostname="subscription.rhsm.stage.redhat.com" \ ++ --organisation="" ++ ++You can all see some basic debugging running `rhsmd` in the foreground: ++ ++ sudo /usr/libexec/rhsmd -d -k ++ ++Known Limitations ++================= ++ ++Proxy servers are not supported, nor are custom host ports or prefixes. +diff --git a/plugins/subman/gsd-subman-common.c b/plugins/subman/gsd-subman-common.c +new file mode 100644 +index 00000000..e515131e +--- /dev/null ++++ b/plugins/subman/gsd-subman-common.c @@ -0,0 +1,36 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * @@ -60,9 +242,11 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-common.c g + return "partially-valid"; + return "unknown"; +} -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-common.h gnome-settings-daemon-3.32.0/plugins/subman/gsd-subman-common.h ---- gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-common.h 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/gsd-subman-common.h 2019-06-17 13:01:59.246311863 +0100 +diff --git a/plugins/subman/gsd-subman-common.h b/plugins/subman/gsd-subman-common.h +new file mode 100644 +index 00000000..fccf9f6a +--- /dev/null ++++ b/plugins/subman/gsd-subman-common.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * @@ -104,9 +288,11 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-common.h g +G_END_DECLS + +#endif /* __GSD_SUBMAN_COMMON_H */ -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-helper.c gnome-settings-daemon-3.32.0/plugins/subman/gsd-subman-helper.c ---- gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-helper.c 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/gsd-subman-helper.c 2019-06-17 13:01:59.247311860 +0100 +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +new file mode 100644 +index 00000000..182f7190 +--- /dev/null ++++ b/plugins/subman/gsd-subman-helper.c @@ -0,0 +1,378 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * @@ -486,10 +672,12 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subman-helper.c g + + return EXIT_SUCCESS; +} -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-manager.c gnome-settings-daemon-3.32.0/plugins/subman/gsd-subscription-manager.c ---- gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-manager.c 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/gsd-subscription-manager.c 2019-06-17 13:01:59.247311860 +0100 -@@ -0,0 +1,998 @@ +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +new file mode 100644 +index 00000000..08b13fa6 +--- /dev/null ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -0,0 +1,982 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2019 Richard Hughes @@ -566,7 +754,6 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana + GHashTable *config; /* str:str */ + gchar *address; + -+ guint check_registration_timeout_id; + GTimer *timer_last_notified; + NotifyNotification *notification_expired; + NotifyNotification *notification_registered; @@ -613,6 +800,40 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana + return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; +} + ++static void ++_emit_property_changed (GsdSubscriptionManager *manager, ++ const gchar *property_name, ++ GVariant *property_value) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ GVariantBuilder builder; ++ GVariantBuilder invalidated_builder; ++ ++ /* not yet connected */ ++ if (priv->connection == NULL) ++ return; ++ ++ /* build the dict */ ++ g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); ++ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); ++ g_variant_builder_add (&builder, ++ "{sv}", ++ property_name, ++ property_value); ++ g_dbus_connection_emit_signal (priv->connection, ++ NULL, ++ GSD_SUBSCRIPTION_DBUS_PATH, ++ "org.freedesktop.DBus.Properties", ++ "PropertiesChanged", ++ g_variant_new ("(sa{sv}as)", ++ GSD_SUBSCRIPTION_DBUS_INTERFACE, ++ &builder, ++ &invalidated_builder), ++ NULL); ++ g_variant_builder_clear (&builder); ++ g_variant_builder_clear (&invalidated_builder); ++} ++ +static gboolean +_client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) +{ @@ -651,6 +872,13 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana + status_txt = json_object_get_string_member (json_obj, "status"); + g_debug ("Entitlement.GetStatus: %s", status_txt); + priv->subscription_status = _client_subscription_status_from_text (status_txt); ++ ++ /* emit notification for g-c-c */ ++ if (priv->subscription_status != priv->subscription_status_last) { ++ _emit_property_changed (manager, "SubscriptionStatus", ++ g_variant_new_uint32 (priv->subscription_status)); ++ } ++ + return TRUE; +} + @@ -1128,40 +1356,6 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana +} + +static void -+emit_property_changed (GsdSubscriptionManager *manager, -+ const gchar *property_name, -+ GVariant *property_value) -+{ -+ GsdSubscriptionManagerPrivate *priv = manager->priv; -+ GVariantBuilder builder; -+ GVariantBuilder invalidated_builder; -+ -+ /* not yet connected */ -+ if (priv->connection == NULL) -+ return; -+ -+ /* build the dict */ -+ g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); -+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); -+ g_variant_builder_add (&builder, -+ "{sv}", -+ property_name, -+ property_value); -+ g_dbus_connection_emit_signal (priv->connection, -+ NULL, -+ GSD_SUBSCRIPTION_DBUS_PATH, -+ "org.freedesktop.DBus.Properties", -+ "PropertiesChanged", -+ g_variant_new ("(sa{sv}as)", -+ GSD_SUBSCRIPTION_DBUS_INTERFACE, -+ &builder, -+ &invalidated_builder), -+ NULL); -+ g_variant_builder_clear (&builder); -+ g_variant_builder_clear (&invalidated_builder); -+} -+ -+static void +_launch_info_overview (void) +{ + const gchar *argv[] = { "gnome-control-center", "info-overview", NULL }; @@ -1264,25 +1458,9 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana + manager->priv->name_id = 0; + } + -+ if (manager->priv->check_registration_timeout_id) -+ g_source_remove (manager->priv->check_registration_timeout_id); -+ + G_OBJECT_CLASS (gsd_subscription_manager_parent_class)->finalize (object); +} + -+static gboolean -+nlight_forced_timeout_cb (gpointer user_data) -+{ -+ GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); -+ GsdSubscriptionManagerPrivate *priv = manager->priv; -+ -+ priv->check_registration_timeout_id = 0; -+ emit_property_changed (manager, "SubscriptionStatus", -+ g_variant_new_boolean (TRUE)); -+ -+ return G_SOURCE_REMOVE; -+} -+ +static void +handle_method_call (GDBusConnection *connection, + const gchar *sender, @@ -1294,11 +1472,9 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana + gpointer user_data) +{ + GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); -+ GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GError) error = NULL; + + if (g_strcmp0 (method_name, "Register") == 0) { -+ guint32 duration = 0; + const gchar *organisation = NULL; + const gchar *hostname = NULL; + @@ -1356,10 +1532,6 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana + + return; + } -+ if (priv->check_registration_timeout_id) -+ g_source_remove (priv->check_registration_timeout_id); -+ priv->check_registration_timeout_id = g_timeout_add_seconds (duration, nlight_forced_timeout_cb, manager); -+ + g_dbus_method_invocation_return_value (invocation, NULL); + } else if (g_strcmp0 (method_name, "Unregister") == 0) { + if (!_client_unregister (manager, &error)) { @@ -1488,9 +1660,11 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana + + return GSD_SUBSCRIPTION_MANAGER (manager_object); +} -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-manager.h gnome-settings-daemon-3.32.0/plugins/subman/gsd-subscription-manager.h ---- gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-manager.h 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/gsd-subscription-manager.h 2019-06-17 13:01:59.248311858 +0100 +diff --git a/plugins/subman/gsd-subscription-manager.h b/plugins/subman/gsd-subscription-manager.h +new file mode 100644 +index 00000000..6a524b1b +--- /dev/null ++++ b/plugins/subman/gsd-subscription-manager.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * @@ -1555,9 +1729,11 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/gsd-subscription-mana +G_END_DECLS + +#endif /* __GSD_SUBSCRIPTION_MANAGER_H */ -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/main.c gnome-settings-daemon-3.32.0/plugins/subman/main.c ---- gnome-settings-daemon-3.32.0.old/plugins/subman/main.c 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/main.c 2019-06-17 13:01:59.248311858 +0100 +diff --git a/plugins/subman/main.c b/plugins/subman/main.c +new file mode 100644 +index 00000000..28ac995b +--- /dev/null ++++ b/plugins/subman/main.c @@ -0,0 +1,8 @@ +#define NEW gsd_subscription_manager_new +#define START gsd_subscription_manager_start @@ -1567,9 +1743,11 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/main.c gnome-settings +#include "gsd-subscription-manager.h" + +#include "daemon-skeleton-gtk.h" -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/meson.build gnome-settings-daemon-3.32.0/plugins/subman/meson.build ---- gnome-settings-daemon-3.32.0.old/plugins/subman/meson.build 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/meson.build 2019-06-17 13:01:59.248311858 +0100 +diff --git a/plugins/subman/meson.build b/plugins/subman/meson.build +new file mode 100644 +index 00000000..bfd073b6 +--- /dev/null ++++ b/plugins/subman/meson.build @@ -0,0 +1,56 @@ +sources = files( + 'gsd-subscription-manager.c', @@ -1627,10 +1805,27 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/meson.build gnome-set + install_rpath: gsd_pkglibdir, + install_dir: gsd_libexecdir +) -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in gnome-settings-daemon-3.32.0/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in ---- gnome-settings-daemon-3.32.0.old/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in 2019-06-17 13:01:59.248311858 +0100 -@@ -0,0 +1,28 @@ +diff --git a/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in b/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in +new file mode 100644 +index 00000000..14fe5915 +--- /dev/null ++++ b/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in +@@ -0,0 +1,9 @@ ++[Desktop Entry] ++Type=Application ++Name=GNOME Settings Daemon's subscription manager plugin ++Exec=@libexecdir@/gsd-subman ++OnlyShowIn=GNOME; ++NoDisplay=true ++X-GNOME-Autostart-Phase=Initialization ++X-GNOME-Autostart-Notify=true ++X-GNOME-AutoRestart=true +diff --git a/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in b/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in +new file mode 100644 +index 00000000..59e9fdd4 +--- /dev/null ++++ b/plugins/subman/org.gnome.settings-daemon.plugins.subman.policy.in.in +@@ -0,0 +1,27 @@ + + + + -+ -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules gnome-settings-daemon-3.32.0/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules ---- gnome-settings-daemon-3.32.0.old/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules 2019-06-17 13:01:59.248311858 +0100 +diff --git a/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules b/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules +new file mode 100644 +index 00000000..1ed3a0ea +--- /dev/null ++++ b/plugins/subman/org.gnome.settings-daemon.plugins.subman.rules @@ -0,0 +1,7 @@ +polkit.addRule(function(action, subject) { + if (action.id == "org.gnome.settings-daemon.plugins.subman.register" && @@ -1670,271 +1866,6 @@ diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/org.gnome.settings-da + return polkit.Result.YES; + } +}); -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in gnome-settings-daemon-3.32.0/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in ---- gnome-settings-daemon-3.32.0.old/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/org.gnome.SettingsDaemon.Subscription.desktop.in 2019-06-17 13:01:59.248311858 +0100 -@@ -0,0 +1,9 @@ -+[Desktop Entry] -+Type=Application -+Name=GNOME Settings Daemon's subscription manager plugin -+Exec=@libexecdir@/gsd-subman -+OnlyShowIn=GNOME; -+NoDisplay=true -+X-GNOME-Autostart-Phase=Initialization -+X-GNOME-Autostart-Notify=true -+X-GNOME-AutoRestart=true -diff -urNp gnome-settings-daemon-3.32.0.old/plugins/subman/README.md gnome-settings-daemon-3.32.0/plugins/subman/README.md ---- gnome-settings-daemon-3.32.0.old/plugins/subman/README.md 1970-01-01 01:00:00.000000000 +0100 -+++ gnome-settings-daemon-3.32.0/plugins/subman/README.md 2019-06-17 13:01:59.246311863 +0100 -@@ -0,0 +1,56 @@ -+GNOME Settings Daemon: Subscription Manager Plugin -+================================================== -+ -+Testing: -+ -+To add a test acccount on subscription.rhsm.stage.redhat.com, use Ethel: -+http://account-manager-stage.app.eng.rdu2.redhat.com/#view -+ -+Register with a username and password -+------------------------------------- -+ -+ gdbus call \ -+ --session \ -+ --dest org.gnome.SettingsDaemon.Subscription \ -+ --object-path /org/gnome/SettingsDaemon/Subscription \ -+ --method org.gnome.SettingsDaemon.Subscription.Register "{'kind':<'username'>,'hostname':<'subscription.rhsm.stage.redhat.com'>,'username':<'rhughes_test'>,'password':<'barbaz'>}" -+ -+To register with a certificate -+------------------------------ -+ -+ gdbus call \ -+ --session \ -+ --dest org.gnome.SettingsDaemon.Subscription \ -+ --object-path /org/gnome/SettingsDaemon/Subscription \ -+ --method org.gnome.SettingsDaemon.Subscription.Register "{'kind':<'key'>,'hostname':<'subscription.rhsm.stage.redhat.com'>,'organisation':<'foo'>,'activation-key':<'barbaz'>}" -+ -+To unregister -+------------- -+ -+ gdbus call \ -+ --session \ -+ --dest org.gnome.SettingsDaemon.Subscription \ -+ --object-path /org/gnome/SettingsDaemon/Subscription \ -+ --method org.gnome.SettingsDaemon.Subscription.Unregister -+ -+Debugging -+--------- -+ -+Get the UNIX socket using `Subscription.Register` then call something like: -+ -+ sudo G_MESSAGES_DEBUG=all ./plugins/subman/gsd-subman-helper \ -+ --address="unix:abstract=/var/run/dbus-ulGB1wfnbn,guid=71e6bf329d861ce366df7a1d5d036a5b" \ -+ --kind="register-with-username" \ -+ --username="rhughes_test" \ -+ --password="barbaz" \ -+ --hostname="subscription.rhsm.stage.redhat.com" \ -+ --organisation="" -+ -+You can all see some basic debugging running `rhsmd` in the foreground: -+ -+ sudo /usr/libexec/rhsmd -d -k -+ -+Known Limitations -+================= -+ -+Proxy servers are not supported, nor are custom host ports or prefixes. -From b35d9c75a7d9f51b24b86461a16dde323be91c2b Mon Sep 17 00:00:00 2001 -From: Richard Hughes -Date: Thu, 20 Jun 2019 15:14:29 +0100 -Subject: [PATCH 1/2] f - ---- - plugins/subman/gsd-subscription-manager.c | 98 ++++++++++------------- - 1 file changed, 41 insertions(+), 57 deletions(-) - -diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c -index 0f6466f8..37e53ed9 100644 ---- a/plugins/subman/gsd-subscription-manager.c -+++ b/plugins/subman/gsd-subscription-manager.c -@@ -74,7 +74,6 @@ struct GsdSubscriptionManagerPrivate - GHashTable *config; /* str:str */ - gchar *address; - -- guint check_registration_timeout_id; - GTimer *timer_last_notified; - NotifyNotification *notification_expired; - NotifyNotification *notification_registered; -@@ -121,6 +120,40 @@ _client_subscription_status_from_text (const gchar *status_txt) - return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; - } - -+static void -+_emit_property_changed (GsdSubscriptionManager *manager, -+ const gchar *property_name, -+ GVariant *property_value) -+{ -+ GsdSubscriptionManagerPrivate *priv = manager->priv; -+ GVariantBuilder builder; -+ GVariantBuilder invalidated_builder; -+ -+ /* not yet connected */ -+ if (priv->connection == NULL) -+ return; -+ -+ /* build the dict */ -+ g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); -+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); -+ g_variant_builder_add (&builder, -+ "{sv}", -+ property_name, -+ property_value); -+ g_dbus_connection_emit_signal (priv->connection, -+ NULL, -+ GSD_SUBSCRIPTION_DBUS_PATH, -+ "org.freedesktop.DBus.Properties", -+ "PropertiesChanged", -+ g_variant_new ("(sa{sv}as)", -+ GSD_SUBSCRIPTION_DBUS_INTERFACE, -+ &builder, -+ &invalidated_builder), -+ NULL); -+ g_variant_builder_clear (&builder); -+ g_variant_builder_clear (&invalidated_builder); -+} -+ - static gboolean - _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) - { -@@ -159,6 +192,13 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er - status_txt = json_object_get_string_member (json_obj, "status"); - g_debug ("Entitlement.GetStatus: %s", status_txt); - priv->subscription_status = _client_subscription_status_from_text (status_txt); -+ -+ /* enit notification for g-c-c */ -+ if (priv->subscription_status != priv->subscription_status_last) { -+ _emit_property_changed (manager, "SubscriptionStatus", -+ g_variant_new_uint32 (priv->subscription_status)); -+ } -+ - return TRUE; - } - -@@ -635,40 +675,6 @@ gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass) - g_type_class_add_private (klass, sizeof (GsdSubscriptionManagerPrivate)); - } - --static void --emit_property_changed (GsdSubscriptionManager *manager, -- const gchar *property_name, -- GVariant *property_value) --{ -- GsdSubscriptionManagerPrivate *priv = manager->priv; -- GVariantBuilder builder; -- GVariantBuilder invalidated_builder; -- -- /* not yet connected */ -- if (priv->connection == NULL) -- return; -- -- /* build the dict */ -- g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); -- g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); -- g_variant_builder_add (&builder, -- "{sv}", -- property_name, -- property_value); -- g_dbus_connection_emit_signal (priv->connection, -- NULL, -- GSD_SUBSCRIPTION_DBUS_PATH, -- "org.freedesktop.DBus.Properties", -- "PropertiesChanged", -- g_variant_new ("(sa{sv}as)", -- GSD_SUBSCRIPTION_DBUS_INTERFACE, -- &builder, -- &invalidated_builder), -- NULL); -- g_variant_builder_clear (&builder); -- g_variant_builder_clear (&invalidated_builder); --} -- - static void - _launch_info_overview (void) - { -@@ -772,25 +778,9 @@ gsd_subscription_manager_finalize (GObject *object) - manager->priv->name_id = 0; - } - -- if (manager->priv->check_registration_timeout_id) -- g_source_remove (manager->priv->check_registration_timeout_id); -- - G_OBJECT_CLASS (gsd_subscription_manager_parent_class)->finalize (object); - } - --static gboolean --nlight_forced_timeout_cb (gpointer user_data) --{ -- GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); -- GsdSubscriptionManagerPrivate *priv = manager->priv; -- -- priv->check_registration_timeout_id = 0; -- emit_property_changed (manager, "SubscriptionStatus", -- g_variant_new_boolean (TRUE)); -- -- return G_SOURCE_REMOVE; --} -- - static void - handle_method_call (GDBusConnection *connection, - const gchar *sender, -@@ -802,11 +792,9 @@ handle_method_call (GDBusConnection *connection, - gpointer user_data) - { - GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); -- GsdSubscriptionManagerPrivate *priv = manager->priv; - g_autoptr(GError) error = NULL; - - if (g_strcmp0 (method_name, "Register") == 0) { -- guint32 duration = 0; - const gchar *organisation = NULL; - const gchar *hostname = NULL; - -@@ -864,10 +852,6 @@ handle_method_call (GDBusConnection *connection, - - return; - } -- if (priv->check_registration_timeout_id) -- g_source_remove (priv->check_registration_timeout_id); -- priv->check_registration_timeout_id = g_timeout_add_seconds (duration, nlight_forced_timeout_cb, manager); -- - g_dbus_method_invocation_return_value (invocation, NULL); - } else if (g_strcmp0 (method_name, "Unregister") == 0) { - if (!_client_unregister (manager, &error)) { -- -2.21.0 - - -From 3635202b7039cac15c258674e2170622ed0d5a42 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Tue, 25 Jun 2019 14:12:04 +0200 -Subject: [PATCH 2/2] subman: trivial: Fix typo - ---- - plugins/subman/gsd-subscription-manager.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c -index 37e53ed9..08b13fa6 100644 ---- a/plugins/subman/gsd-subscription-manager.c -+++ b/plugins/subman/gsd-subscription-manager.c -@@ -193,7 +193,7 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er - g_debug ("Entitlement.GetStatus: %s", status_txt); - priv->subscription_status = _client_subscription_status_from_text (status_txt); - -- /* enit notification for g-c-c */ -+ /* emit notification for g-c-c */ - if (priv->subscription_status != priv->subscription_status_last) { - _emit_property_changed (manager, "SubscriptionStatus", - g_variant_new_uint32 (priv->subscription_status)); --- -2.21.0 +2.30.0 diff --git a/SOURCES/0001-subman-Increase-RHSM-dbus-call-timeouts.patch b/SOURCES/0001-subman-Increase-RHSM-dbus-call-timeouts.patch deleted file mode 100644 index 09ac272..0000000 --- a/SOURCES/0001-subman-Increase-RHSM-dbus-call-timeouts.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 298355d8b3d5a85b99e74a06e936a0113797bf2a Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Fri, 28 Jun 2019 18:10:36 +0200 -Subject: [PATCH] subman: Increase RHSM dbus call timeouts - -Increase the dbus timeouts to 5 minutes as the register/unregister calls -seem to routinely take more than a minute. ---- - plugins/subman/gsd-subman-helper.c | 17 ++++++++++++----- - 1 file changed, 12 insertions(+), 5 deletions(-) - -diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c -index 182f7190..af7a82e9 100644 ---- a/plugins/subman/gsd-subman-helper.c -+++ b/plugins/subman/gsd-subman-helper.c -@@ -28,6 +28,8 @@ - #include - #include - -+#define DBUS_TIMEOUT 300000 /* 5 minutes */ -+ - static void - _helper_convert_error (const gchar *json_txt, GError **error) - { -@@ -94,7 +96,8 @@ _helper_unregister (GError **error) - proxy_options, - ""), /* lang */ - G_DBUS_CALL_FLAGS_NONE, -- -1, NULL, error); -+ DBUS_TIMEOUT, -+ NULL, error); - return res != NULL; - } - -@@ -127,7 +130,8 @@ _helper_auto_attach (GError **error) - proxy_options, - ""), /* lang */ - G_DBUS_CALL_FLAGS_NONE, -- -1, NULL, error); -+ DBUS_TIMEOUT, -+ NULL, error); - if (res == NULL) - return FALSE; - g_variant_get (res, "(&s)", &str); -@@ -158,7 +162,8 @@ _helper_save_config (const gchar *key, const gchar *value, GError **error) - g_variant_new_string (value), - ""), /* lang */ - G_DBUS_CALL_FLAGS_NONE, -- -1, NULL, error); -+ DBUS_TIMEOUT, -+ NULL, error); - return res != NULL; - } - -@@ -305,7 +310,8 @@ main (int argc, char *argv[]) - subman_conopts, - userlang), - G_DBUS_CALL_FLAGS_NO_AUTO_START, -- -1, NULL, &error_local); -+ DBUS_TIMEOUT, -+ NULL, &error_local); - if (res == NULL) { - g_dbus_error_strip_remote_error (error_local); - _helper_convert_error (error_local->message, &error); -@@ -339,7 +345,8 @@ main (int argc, char *argv[]) - subman_conopts, - userlang), - G_DBUS_CALL_FLAGS_NO_AUTO_START, -- -1, NULL, &error_local); -+ DBUS_TIMEOUT, -+ NULL, &error_local); - if (res == NULL) { - g_dbus_error_strip_remote_error (error_local); - _helper_convert_error (error_local->message, &error); --- -2.21.0 - diff --git a/SOURCES/0002-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch b/SOURCES/0002-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch new file mode 100644 index 0000000..c7505ab --- /dev/null +++ b/SOURCES/0002-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch @@ -0,0 +1,768 @@ +From f723ed1078e050c4d966d40b2aea74970c74279c Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Thu, 27 Jun 2019 16:12:00 +0200 +Subject: [PATCH 02/15] subman: Add InstalledProducts dbus property for g-c-c + +--- + plugins/subman/gsd-subscription-manager.c | 135 ++++++++++++++++++++++ + 1 file changed, 135 insertions(+) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 08b13fa6..a8c18a26 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -1,186 +1,304 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2019 Richard Hughes ++ * Copyright (C) 2019 Kalev Lember + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + + #include "config.h" + + #include + #include + #include + #include + #include + + #include "gnome-settings-profile.h" + #include "gsd-subman-common.h" + #include "gsd-subscription-manager.h" + + #define GSD_DBUS_NAME "org.gnome.SettingsDaemon" + #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon" + #define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon" + + #define GSD_SUBSCRIPTION_DBUS_NAME GSD_DBUS_NAME ".Subscription" + #define GSD_SUBSCRIPTION_DBUS_PATH GSD_DBUS_PATH "/Subscription" + #define GSD_SUBSCRIPTION_DBUS_INTERFACE GSD_DBUS_BASE_INTERFACE ".Subscription" + + static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " ++" " + " " + " " + ""; + + #define GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManagerPrivate)) + + typedef enum { + _RHSM_INTERFACE_CONFIG, + _RHSM_INTERFACE_REGISTER_SERVER, + _RHSM_INTERFACE_ATTACH, + _RHSM_INTERFACE_ENTITLEMENT, + _RHSM_INTERFACE_PRODUCTS, + _RHSM_INTERFACE_CONSUMER, + _RHSM_INTERFACE_SYSPURPOSE, + _RHSM_INTERFACE_LAST + } _RhsmInterface; + + struct GsdSubscriptionManagerPrivate + { + /* D-Bus */ + guint name_id; + GDBusNodeInfo *introspection_data; + GDBusConnection *connection; + GCancellable *bus_cancellable; + + GDBusProxy *proxies[_RHSM_INTERFACE_LAST]; + const gchar *userlang; /* owned by GLib internally */ + GHashTable *config; /* str:str */ ++ GPtrArray *installed_products; + gchar *address; + + GTimer *timer_last_notified; + NotifyNotification *notification_expired; + NotifyNotification *notification_registered; + NotifyNotification *notification_registration_required; + GsdSubmanSubscriptionStatus subscription_status; + GsdSubmanSubscriptionStatus subscription_status_last; + }; + + enum { + PROP_0, + }; + + static void gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass); + static void gsd_subscription_manager_init (GsdSubscriptionManager *subscription_manager); + static void gsd_subscription_manager_finalize (GObject *object); + + G_DEFINE_TYPE (GsdSubscriptionManager, gsd_subscription_manager, G_TYPE_OBJECT) + ++typedef struct ++{ ++ gchar *product_name; ++ gchar *product_id; ++ gchar *version; ++ gchar *arch; ++ gchar *status; ++ gchar *starts; ++ gchar *ends; ++} ProductData; ++ ++static void ++product_data_free (ProductData *product) ++{ ++ g_free (product->product_name); ++ g_free (product->product_id); ++ g_free (product->version); ++ g_free (product->arch); ++ g_free (product->status); ++ g_free (product->starts); ++ g_free (product->ends); ++ g_free (product); ++} ++ ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (ProductData, product_data_free); ++ + static gpointer manager_object = NULL; + + GQuark + gsd_subscription_manager_error_quark (void) + { + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("gsd_subscription_manager_error"); + return quark; + } + + static GsdSubmanSubscriptionStatus + _client_subscription_status_from_text (const gchar *status_txt) + { + if (g_strcmp0 (status_txt, "Unknown") == 0) + return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; + if (g_strcmp0 (status_txt, "Current") == 0) + return GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID; + if (g_strcmp0 (status_txt, "Invalid") == 0) + return GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; + if (g_strcmp0 (status_txt, "Disabled") == 0) + return GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED; + if (g_strcmp0 (status_txt, "Insufficient") == 0) + return GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID; + g_warning ("Unknown subscription status: %s", status_txt); // 'Current'? + return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; + } + ++static GVariant * ++_make_installed_products_variant (GPtrArray *installed_products) ++{ ++ GVariantBuilder builder; ++ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); ++ ++ for (guint i = 0; i < installed_products->len; i++) { ++ ProductData *product = g_ptr_array_index (installed_products, i); ++ g_auto(GVariantDict) dict; ++ ++ g_variant_dict_init (&dict, NULL); ++ ++ g_variant_dict_insert (&dict, "product-name", "s", product->product_name); ++ g_variant_dict_insert (&dict, "product-id", "s", product->product_id); ++ g_variant_dict_insert (&dict, "version", "s", product->version); ++ g_variant_dict_insert (&dict, "arch", "s", product->arch); ++ g_variant_dict_insert (&dict, "status", "s", product->status); ++ g_variant_dict_insert (&dict, "starts", "s", product->starts); ++ g_variant_dict_insert (&dict, "ends", "s", product->ends); ++ ++ g_variant_builder_add_value (&builder, g_variant_dict_end (&dict)); ++ } ++ ++ return g_variant_builder_end (&builder); ++} ++ + static void + _emit_property_changed (GsdSubscriptionManager *manager, + const gchar *property_name, + GVariant *property_value) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + GVariantBuilder builder; + GVariantBuilder invalidated_builder; + + /* not yet connected */ + if (priv->connection == NULL) + return; + + /* build the dict */ + g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); + g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY); + g_variant_builder_add (&builder, + "{sv}", + property_name, + property_value); + g_dbus_connection_emit_signal (priv->connection, + NULL, + GSD_SUBSCRIPTION_DBUS_PATH, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_variant_new ("(sa{sv}as)", + GSD_SUBSCRIPTION_DBUS_INTERFACE, + &builder, + &invalidated_builder), + NULL); + g_variant_builder_clear (&builder); + g_variant_builder_clear (&invalidated_builder); + } + ++static gboolean ++_client_installed_products_update (GsdSubscriptionManager *manager, GError **error) ++{ ++ GsdSubscriptionManagerPrivate *priv = manager->priv; ++ JsonNode *json_root; ++ JsonArray *json_products_array; ++ const gchar *json_txt = NULL; ++ g_autoptr(GVariant) val = NULL; ++ g_autoptr(JsonParser) json_parser = json_parser_new (); ++ ++ val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_PRODUCTS], ++ "ListInstalledProducts", ++ g_variant_new ("(sa{sv}s)", ++ "" /* filter_string */, ++ NULL /* proxy_options */, ++ priv->userlang), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (val == NULL) ++ return FALSE; ++ g_variant_get (val, "(&s)", &json_txt); ++ g_debug ("Products.ListInstalledProducts JSON: %s", json_txt); ++ if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) ++ return FALSE; ++ json_root = json_parser_get_root (json_parser); ++ json_products_array = json_node_get_array (json_root); ++ if (json_products_array == NULL) { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, ++ "no InstalledProducts array in %s", json_txt); ++ return FALSE; ++ } ++ ++ g_ptr_array_set_size (priv->installed_products, 0); ++ ++ for (guint i = 0; i < json_array_get_length (json_products_array); i++) { ++ JsonArray *json_product = json_array_get_array_element (json_products_array, i); ++ g_autoptr(ProductData) product = g_new0 (ProductData, 1); ++ ++ if (json_product == NULL) ++ continue; ++ if (json_array_get_length (json_product) < 8) { ++ g_debug ("Unexpected number of array elements in InstalledProducts JSON"); ++ continue; ++ } ++ ++ product->product_name = g_strdup (json_array_get_string_element (json_product, 0)); ++ product->product_id = g_strdup (json_array_get_string_element (json_product, 1)); ++ product->version = g_strdup (json_array_get_string_element (json_product, 2)); ++ product->arch = g_strdup (json_array_get_string_element (json_product, 3)); ++ product->status = g_strdup (json_array_get_string_element (json_product, 4)); ++ product->starts = g_strdup (json_array_get_string_element (json_product, 6)); ++ product->ends = g_strdup (json_array_get_string_element (json_product, 7)); ++ ++ g_ptr_array_add (priv->installed_products, g_steal_pointer (&product)); ++ } ++ ++ /* emit notification for g-c-c */ ++ _emit_property_changed (manager, "InstalledProducts", ++ _make_installed_products_variant (priv->installed_products)); ++ ++ return TRUE; ++} ++ + static gboolean + _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; + const gchar *status_txt = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], + "GetStatus", + g_variant_new ("(ss)", + "", /* assumed as 'now' */ + priv->userlang), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(&s)", &json_txt); + g_debug ("Entitlement.GetStatus JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "status")) { +@@ -423,185 +541,195 @@ _client_register_with_keys (GsdSubscriptionManager *manager, + GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-key", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, + "--activation-key", activation_key, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + if (!_client_subprocess_wait_check (subprocess, error)) + return FALSE; + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; ++ if (!_client_installed_products_update (manager, error)) ++ return FALSE; + _client_maybe__show_notification (manager); + + /* success */ + return TRUE; + } + + static gboolean + _client_register (GsdSubscriptionManager *manager, + const gchar *hostname, + const gchar *organisation, + const gchar *username, + const gchar *password, + GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; + + /* fallback */ + if (organisation == NULL) + organisation = ""; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-username", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, + "--username", username, + "--password", password, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + if (!_client_subprocess_wait_check (subprocess, error)) + return FALSE; + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; ++ if (!_client_installed_products_update (manager, error)) ++ return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } + + static gboolean + _client_unregister (GsdSubscriptionManager *manager, GError **error) + { + g_autoptr(GSubprocess) subprocess = NULL; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "unregister", + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + if (!_client_subprocess_wait_check (subprocess, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; ++ if (!_client_installed_products_update (manager, error)) ++ return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } + + static gboolean + _client_update_config (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GVariant) val = NULL; + g_autoptr(GVariant) val_server = NULL; + g_autoptr(GVariantDict) dict = NULL; + GVariantIter iter; + gchar *key; + gchar *value; + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONFIG], + "GetAll", + g_variant_new ("(s)", priv->userlang), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + dict = g_variant_dict_new (g_variant_get_child_value (val, 0)); + val_server = g_variant_dict_lookup_value (dict, "server", G_VARIANT_TYPE("a{ss}")); + if (val_server != NULL) { + g_variant_iter_init (&iter, val_server); + while (g_variant_iter_next (&iter, "{ss}", &key, &value)) { + g_debug ("%s=%s", key, value); + g_hash_table_insert (priv->config, + g_steal_pointer (&key), + g_steal_pointer (&value)); + } + } + return TRUE; + } + + static void + _subman_proxy_signal_cb (GDBusProxy *proxy, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters, + GsdSubscriptionManager *manager) + { + g_autoptr(GError) error = NULL; + if (!_client_syspurpose_update (manager, &error)) { + g_warning ("failed to update syspurpose: %s", error->message); + g_clear_error (&error); + } + if (!_client_subscription_status_update (manager, &error)) { + g_warning ("failed to update subscription status: %s", error->message); + g_clear_error (&error); + } ++ if (!_client_installed_products_update (manager, &error)) { ++ g_warning ("failed to update installed products: %s", error->message); ++ g_clear_error (&error); ++ } + _client_maybe__show_notification (manager); + } + + static void + _client_unload (GsdSubscriptionManager *manager) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + for (guint i = 0; i < _RHSM_INTERFACE_LAST; i++) + g_clear_object (&priv->proxies[i]); + g_hash_table_unref (priv->config); + } + + static const gchar * + _rhsm_interface_to_string (_RhsmInterface kind) + { + if (kind == _RHSM_INTERFACE_CONFIG) + return "Config"; + if (kind == _RHSM_INTERFACE_REGISTER_SERVER) + return "RegisterServer"; + if (kind == _RHSM_INTERFACE_ATTACH) + return "Attach"; + if (kind == _RHSM_INTERFACE_ENTITLEMENT) + return "Entitlement"; + if (kind == _RHSM_INTERFACE_PRODUCTS) + return "Products"; + if (kind == _RHSM_INTERFACE_CONSUMER) + return "Consumer"; + if (kind == _RHSM_INTERFACE_SYSPURPOSE) + return "Syspurpose"; + return NULL; +@@ -613,60 +741,62 @@ _client_load (GsdSubscriptionManager *manager, GError **error) + GsdSubscriptionManagerPrivate *priv = manager->priv; + + priv->config = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + /* connect to all the interfaces on the *different* objects :| */ + for (guint i = 0; i < _RHSM_INTERFACE_LAST; i++) { + const gchar *kind = _rhsm_interface_to_string (i); + g_autofree gchar *opath = g_strdup_printf ("/com/redhat/RHSM1/%s", kind); + g_autofree gchar *iface = g_strdup_printf ("com.redhat.RHSM1.%s", kind); + priv->proxies[i] = + g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "com.redhat.RHSM1", + opath, iface, + NULL, + error); + if (priv->proxies[i] == NULL) + return FALSE; + /* we want to get notified if the status of the system changes */ + g_signal_connect (priv->proxies[i], "g-signal", + G_CALLBACK (_subman_proxy_signal_cb), manager); + } + + /* get initial status */ + priv->userlang = ""; + if (!_client_update_config (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; ++ if (!_client_installed_products_update (manager, error)) ++ return FALSE; + if (!_client_syspurpose_update (manager, error)) + return FALSE; + + /* success */ + return TRUE; + } + + gboolean + gsd_subscription_manager_start (GsdSubscriptionManager *manager, GError **error) + { + gboolean ret; + g_debug ("Starting subscription manager"); + gnome_settings_profile_start (NULL); + ret = _client_load (manager, error); + _client_maybe__show_notification (manager); + gnome_settings_profile_end (NULL); + return ret; + } + + void + gsd_subscription_manager_stop (GsdSubscriptionManager *manager) + { + g_debug ("Stopping subscription manager"); + _client_unload (manager); + } + + static void + gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); +@@ -676,60 +806,61 @@ gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass) + } + + static void + _launch_info_overview (void) + { + const gchar *argv[] = { "gnome-control-center", "info-overview", NULL }; + g_debug ("Running gnome-control-center info-overview"); + g_spawn_async (NULL, (gchar **) argv, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL); + } + + static void + _notify_closed_cb (NotifyNotification *notification, gpointer user_data) + { + /* FIXME: only launch when clicking on the main body, not the window close */ + if (notify_notification_get_closed_reason (notification) == 0x400) + _launch_info_overview (); + } + + static void + _notify_clicked_cb (NotifyNotification *notification, char *action, gpointer user_data) + { + _launch_info_overview (); + } + + static void + gsd_subscription_manager_init (GsdSubscriptionManager *manager) + { + GsdSubscriptionManagerPrivate *priv = manager->priv = GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE (manager); + ++ priv->installed_products = g_ptr_array_new_with_free_func ((GDestroyNotify) product_data_free); + priv->timer_last_notified = g_timer_new (); + + /* expired */ + priv->notification_expired = + notify_notification_new (_("Subscription Has Expired"), + _("Add or renew a subscription to continue receiving software updates."), + NULL); + notify_notification_set_app_name (priv->notification_expired, _("Subscription")); + notify_notification_set_hint_string (priv->notification_expired, "desktop-entry", "subman-panel"); + notify_notification_set_hint_string (priv->notification_expired, "x-gnome-privacy-scope", "system"); + notify_notification_set_urgency (priv->notification_expired, NOTIFY_URGENCY_CRITICAL); + notify_notification_add_action (priv->notification_expired, + "info-overview", _("Subscribe System…"), + _notify_clicked_cb, + manager, NULL); + g_signal_connect (priv->notification_expired, "closed", + G_CALLBACK (_notify_closed_cb), manager); + + /* registered */ + priv->notification_registered = + notify_notification_new (_("Registration Successful"), + _("The system has been registered and software updates have been enabled."), + NULL); + notify_notification_set_app_name (priv->notification_registered, _("Subscription")); + notify_notification_set_hint_string (priv->notification_registered, "desktop-entry", "subman-panel"); + notify_notification_set_hint_string (priv->notification_registered, "x-gnome-privacy-scope", "system"); + notify_notification_set_urgency (priv->notification_registered, NOTIFY_URGENCY_CRITICAL); + g_signal_connect (priv->notification_registered, "closed", + G_CALLBACK (_notify_closed_cb), manager); + +@@ -740,60 +871,61 @@ gsd_subscription_manager_init (GsdSubscriptionManager *manager) + NULL); + notify_notification_set_app_name (priv->notification_registration_required, _("Subscription")); + notify_notification_set_hint_string (priv->notification_registration_required, "desktop-entry", "subman-panel"); + notify_notification_set_hint_string (priv->notification_registration_required, "x-gnome-privacy-scope", "system"); + notify_notification_set_urgency (priv->notification_registration_required, NOTIFY_URGENCY_CRITICAL); + notify_notification_add_action (priv->notification_registration_required, + "info-overview", _("Register System…"), + _notify_clicked_cb, + manager, NULL); + g_signal_connect (priv->notification_registration_required, "closed", + G_CALLBACK (_notify_closed_cb), manager); + } + + static void + gsd_subscription_manager_finalize (GObject *object) + { + GsdSubscriptionManager *manager; + + g_return_if_fail (object != NULL); + g_return_if_fail (GSD_IS_SUBSCRIPTION_MANAGER (object)); + + manager = GSD_SUBSCRIPTION_MANAGER (object); + + gsd_subscription_manager_stop (manager); + + if (manager->priv->bus_cancellable != NULL) { + g_cancellable_cancel (manager->priv->bus_cancellable); + g_clear_object (&manager->priv->bus_cancellable); + } + ++ g_clear_pointer (&manager->priv->installed_products, g_ptr_array_unref); + g_clear_pointer (&manager->priv->introspection_data, g_dbus_node_info_unref); + g_clear_object (&manager->priv->connection); + g_clear_object (&manager->priv->notification_expired); + g_clear_object (&manager->priv->notification_registered); + g_timer_destroy (manager->priv->timer_last_notified); + + if (manager->priv->name_id != 0) { + g_bus_unown_name (manager->priv->name_id); + manager->priv->name_id = 0; + } + + G_OBJECT_CLASS (gsd_subscription_manager_parent_class)->finalize (object); + } + + static void + handle_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) + { + GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); + g_autoptr(GError) error = NULL; + + if (g_strcmp0 (method_name, "Register") == 0) { + const gchar *organisation = NULL; + const gchar *hostname = NULL; +@@ -857,60 +989,63 @@ handle_method_call (GDBusConnection *connection, + if (!_client_unregister (manager, &error)) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } + g_dbus_method_invocation_return_value (invocation, NULL); + } else { + g_assert_not_reached (); + } + } + + static GVariant * + handle_get_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GError **error, gpointer user_data) + { + GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); + GsdSubscriptionManagerPrivate *priv = manager->priv; + + if (g_strcmp0 (interface_name, GSD_SUBSCRIPTION_DBUS_INTERFACE) != 0) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "No such interface: %s", interface_name); + return NULL; + } + + if (g_strcmp0 (property_name, "SubscriptionStatus") == 0) + return g_variant_new_uint32 (priv->subscription_status); + ++ if (g_strcmp0 (property_name, "InstalledProducts") == 0) ++ return _make_installed_products_variant (priv->installed_products); ++ + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Failed to get property: %s", property_name); + return NULL; + } + + static gboolean + handle_set_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GVariant *value, + GError **error, gpointer user_data) + { + if (g_strcmp0 (interface_name, GSD_SUBSCRIPTION_DBUS_INTERFACE) != 0) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "No such interface: %s", interface_name); + return FALSE; + } + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "No such property: %s", property_name); + return FALSE; + } + + static const GDBusInterfaceVTable interface_vtable = + { + handle_method_call, + handle_get_property, + handle_set_property + }; +-- +2.30.0 + diff --git a/SOURCES/0003-subman-Increase-RHSM-dbus-call-timeouts.patch b/SOURCES/0003-subman-Increase-RHSM-dbus-call-timeouts.patch new file mode 100644 index 0000000..b8a4ea4 --- /dev/null +++ b/SOURCES/0003-subman-Increase-RHSM-dbus-call-timeouts.patch @@ -0,0 +1,313 @@ +From 0d88b2133b20957e00b0eeb0c0f48932485cc73d Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Fri, 28 Jun 2019 18:10:36 +0200 +Subject: [PATCH 03/15] subman: Increase RHSM dbus call timeouts + +Increase the dbus timeouts to 5 minutes as the register/unregister calls +seem to routinely take more than a minute. +--- + plugins/subman/gsd-subman-helper.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index 182f7190..af7a82e9 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -1,60 +1,62 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2019 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + #include "config.h" + + #include + #include + #include + + #include + #include + ++#define DBUS_TIMEOUT 300000 /* 5 minutes */ ++ + static void + _helper_convert_error (const gchar *json_txt, GError **error) + { + JsonNode *json_root; + JsonObject *json_obj; + const gchar *message; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* this may be plain text or JSON :| */ + if (!json_parser_load_from_data (json_parser, json_txt, -1, NULL)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + json_txt); + return; + } + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "message")) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no message' in %s", json_txt); + return; + } + message = json_object_get_string_member (json_obj, "message"); + if (g_strstr_len (message, -1, "Invalid user credentials") != NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED, +@@ -67,125 +69,128 @@ _helper_convert_error (const gchar *json_txt, GError **error) + message); + } + + static gboolean + _helper_unregister (GError **error) + { + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; + + g_debug ("unregistering"); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Unregister", + "com.redhat.RHSM1.Unregister", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); + res = g_dbus_proxy_call_sync (proxy, + "Unregister", + g_variant_new ("(a{sv}s)", + proxy_options, + ""), /* lang */ + G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, error); ++ DBUS_TIMEOUT, ++ NULL, error); + return res != NULL; + } + + static gboolean + _helper_auto_attach (GError **error) + { + const gchar *str = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; + + g_debug ("auto-attaching subscriptions"); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Attach", + "com.redhat.RHSM1.Attach", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); + res = g_dbus_proxy_call_sync (proxy, + "AutoAttach", + g_variant_new ("(sa{sv}s)", + "", /* now? */ + proxy_options, + ""), /* lang */ + G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, error); ++ DBUS_TIMEOUT, ++ NULL, error); + if (res == NULL) + return FALSE; + g_variant_get (res, "(&s)", &str); + g_debug ("Attach.AutoAttach: %s", str); + return TRUE; + } + + static gboolean + _helper_save_config (const gchar *key, const gchar *value, GError **error) + { + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariant) res = NULL; + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Config", + "com.redhat.RHSM1.Config", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + res = g_dbus_proxy_call_sync (proxy, "Set", + g_variant_new ("(svs)", + key, + g_variant_new_string (value), + ""), /* lang */ + G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, error); ++ DBUS_TIMEOUT, ++ NULL, error); + return res != NULL; + } + + int + main (int argc, char *argv[]) + { + const gchar *userlang = ""; /* as root, so no translations */ + g_autofree gchar *activation_key = NULL; + g_autofree gchar *address = NULL; + g_autofree gchar *hostname = NULL; + g_autofree gchar *kind = NULL; + g_autofree gchar *organisation = NULL; + g_autofree gchar *password = NULL; + g_autofree gchar *port = NULL; + g_autofree gchar *prefix = NULL; + g_autofree gchar *proxy_server = NULL; + g_autofree gchar *username = NULL; + g_autoptr(GDBusConnection) conn_private = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GOptionContext) context = g_option_context_new (NULL); + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariantBuilder) subman_conopts = NULL; + g_autoptr(GVariantBuilder) subman_options = NULL; + + const GOptionEntry options[] = { + { "kind", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &kind, "Kind, e.g. 'username' or 'key'", NULL }, + { "address", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &address, "UNIX address", NULL }, +@@ -278,95 +283,97 @@ main (int argc, char *argv[]) + g_variant_builder_add (subman_conopts, "{ss}", "host", hostname); + g_variant_builder_add (subman_conopts, "{ss}", "handler", prefix); + g_variant_builder_add (subman_conopts, "{ss}", "port", port); + + /* call into RHSM */ + if (g_strcmp0 (kind, "register-with-key") == 0) { + g_auto(GStrv) activation_keys = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; + + if (activation_key == NULL) { + g_printerr ("Required --activation-key\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + + g_debug ("registering using activation key"); + activation_keys = g_strsplit (activation_key, ",", -1); + res = g_dbus_proxy_call_sync (proxy, + "RegisterWithActivationKeys", + g_variant_new ("(s^asa{ss}a{ss}s)", + organisation, + activation_keys, + subman_options, + subman_conopts, + userlang), + G_DBUS_CALL_FLAGS_NO_AUTO_START, +- -1, NULL, &error_local); ++ DBUS_TIMEOUT, ++ NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); + g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); + return error->code; + } + } else if (g_strcmp0 (kind, "register-with-username") == 0) { + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; + + g_debug ("registering using username and password"); + if (username == NULL) { + g_printerr ("Required --username\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (password == NULL) { + g_printerr ("Required --password\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + res = g_dbus_proxy_call_sync (proxy, + "Register", + g_variant_new ("(sssa{ss}a{ss}s)", + organisation, + username, + password, + subman_options, + subman_conopts, + userlang), + G_DBUS_CALL_FLAGS_NO_AUTO_START, +- -1, NULL, &error_local); ++ DBUS_TIMEOUT, ++ NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); + g_printerr ("Failed to Register: %s\n", error->message); + return error->code; + } + } else { + g_printerr ("Invalid --kind specified: %s\n", kind); + return G_IO_ERROR_INVALID_DATA; + } + + /* set the new hostname */ + if (!_helper_save_config ("server.hostname", hostname, &error)) { + g_printerr ("Failed to save hostname: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + if (!_helper_save_config ("server.prefix", prefix, &error)) { + g_printerr ("Failed to save prefix: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + if (!_helper_save_config ("server.port", port, &error)) { + g_printerr ("Failed to save port: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + + /* wait for rhsmd to notice the new config */ + g_usleep (G_USEC_PER_SEC * 5); + + /* auto-attach */ + if (!_helper_auto_attach (&error)) { +-- +2.30.0 + diff --git a/SOURCES/0004-subman-Drop-userlang-field.patch b/SOURCES/0004-subman-Drop-userlang-field.patch new file mode 100644 index 0000000..559be02 --- /dev/null +++ b/SOURCES/0004-subman-Drop-userlang-field.patch @@ -0,0 +1,454 @@ +From df08a65d86626ff135a12d96cff6f48f3f1864ae Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 20 Aug 2020 11:20:47 -0400 +Subject: [PATCH 04/15] subman: Drop userlang field + +It's currently always erroneously set to empty string. + +This commit drops it, and just uses "C.UTF-8" everywhere, +which is what we actually want. +--- + plugins/subman/gsd-subscription-manager.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index a8c18a26..46f051a5 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -45,61 +45,60 @@ static const gchar introspection_xml[] = + " " + " " + " " + " " + " " + " " + ""; + + #define GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManagerPrivate)) + + typedef enum { + _RHSM_INTERFACE_CONFIG, + _RHSM_INTERFACE_REGISTER_SERVER, + _RHSM_INTERFACE_ATTACH, + _RHSM_INTERFACE_ENTITLEMENT, + _RHSM_INTERFACE_PRODUCTS, + _RHSM_INTERFACE_CONSUMER, + _RHSM_INTERFACE_SYSPURPOSE, + _RHSM_INTERFACE_LAST + } _RhsmInterface; + + struct GsdSubscriptionManagerPrivate + { + /* D-Bus */ + guint name_id; + GDBusNodeInfo *introspection_data; + GDBusConnection *connection; + GCancellable *bus_cancellable; + + GDBusProxy *proxies[_RHSM_INTERFACE_LAST]; +- const gchar *userlang; /* owned by GLib internally */ + GHashTable *config; /* str:str */ + GPtrArray *installed_products; + gchar *address; + + GTimer *timer_last_notified; + NotifyNotification *notification_expired; + NotifyNotification *notification_registered; + NotifyNotification *notification_registration_required; + GsdSubmanSubscriptionStatus subscription_status; + GsdSubmanSubscriptionStatus subscription_status_last; + }; + + enum { + PROP_0, + }; + + static void gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass); + static void gsd_subscription_manager_init (GsdSubscriptionManager *subscription_manager); + static void gsd_subscription_manager_finalize (GObject *object); + + G_DEFINE_TYPE (GsdSubscriptionManager, gsd_subscription_manager, G_TYPE_OBJECT) + + typedef struct + { + gchar *product_name; + gchar *product_id; + gchar *version; + gchar *arch; + gchar *status; + gchar *starts; +@@ -197,61 +196,61 @@ _emit_property_changed (GsdSubscriptionManager *manager, + property_value); + g_dbus_connection_emit_signal (priv->connection, + NULL, + GSD_SUBSCRIPTION_DBUS_PATH, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_variant_new ("(sa{sv}as)", + GSD_SUBSCRIPTION_DBUS_INTERFACE, + &builder, + &invalidated_builder), + NULL); + g_variant_builder_clear (&builder); + g_variant_builder_clear (&invalidated_builder); + } + + static gboolean + _client_installed_products_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + JsonNode *json_root; + JsonArray *json_products_array; + const gchar *json_txt = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_PRODUCTS], + "ListInstalledProducts", + g_variant_new ("(sa{sv}s)", + "" /* filter_string */, + NULL /* proxy_options */, +- priv->userlang), ++ "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(&s)", &json_txt); + g_debug ("Products.ListInstalledProducts JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; + json_root = json_parser_get_root (json_parser); + json_products_array = json_node_get_array (json_root); + if (json_products_array == NULL) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "no InstalledProducts array in %s", json_txt); + return FALSE; + } + + g_ptr_array_set_size (priv->installed_products, 0); + + for (guint i = 0; i < json_array_get_length (json_products_array); i++) { + JsonArray *json_product = json_array_get_array_element (json_products_array, i); + g_autoptr(ProductData) product = g_new0 (ProductData, 1); + + if (json_product == NULL) + continue; + if (json_array_get_length (json_product) < 8) { + g_debug ("Unexpected number of array elements in InstalledProducts JSON"); + continue; + } + + product->product_name = g_strdup (json_array_get_string_element (json_product, 0)); +@@ -263,179 +262,179 @@ _client_installed_products_update (GsdSubscriptionManager *manager, GError **err + product->ends = g_strdup (json_array_get_string_element (json_product, 7)); + + g_ptr_array_add (priv->installed_products, g_steal_pointer (&product)); + } + + /* emit notification for g-c-c */ + _emit_property_changed (manager, "InstalledProducts", + _make_installed_products_variant (priv->installed_products)); + + return TRUE; + } + + static gboolean + _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; + const gchar *status_txt = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], + "GetStatus", + g_variant_new ("(ss)", + "", /* assumed as 'now' */ +- priv->userlang), ++ "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(&s)", &json_txt); + g_debug ("Entitlement.GetStatus JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "status")) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "no Entitlement.GetStatus status in %s", json_txt); + return FALSE; + } + + status_txt = json_object_get_string_member (json_obj, "status"); + g_debug ("Entitlement.GetStatus: %s", status_txt); + priv->subscription_status = _client_subscription_status_from_text (status_txt); + + /* emit notification for g-c-c */ + if (priv->subscription_status != priv->subscription_status_last) { + _emit_property_changed (manager, "SubscriptionStatus", + g_variant_new_uint32 (priv->subscription_status)); + } + + return TRUE; + } + + static gboolean + _client_syspurpose_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_SYSPURPOSE], + "GetSyspurpose", +- g_variant_new ("(s)", priv->userlang), ++ g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(&s)", &json_txt); + g_debug ("Syspurpose.GetSyspurpose JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "status")) { + g_debug ("Syspurpose.GetSyspurpose: Unknown"); + return TRUE; + } + g_debug ("Syspurpose.GetSyspurpose: '%s", json_object_get_string_member (json_obj, "status")); + return TRUE; + } + + static gboolean + _client_register_start (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + const gchar *address = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariant) val = NULL; + + /* already started */ + if (priv->address != NULL) + return TRUE; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/RegisterServer", + "com.redhat.RHSM1.RegisterServer", + NULL, error); + if (proxy == NULL) + return FALSE; + val = g_dbus_proxy_call_sync (proxy, "Start", +- g_variant_new ("(s)", priv->userlang), ++ g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(&s)", &address); + g_debug ("RegisterServer.Start: %s", address); + priv->address = g_strdup (address); + return TRUE; + } + + static gboolean + _client_register_stop (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariant) val = NULL; + + /* already started */ + if (priv->address == NULL) + return TRUE; + + /* stop registration server */ + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/RegisterServer", + "com.redhat.RHSM1.RegisterServer", + NULL, error); + if (proxy == NULL) + return FALSE; + val = g_dbus_proxy_call_sync (proxy, "Stop", +- g_variant_new ("(s)", priv->userlang), ++ g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_clear_pointer (&priv->address, g_free); + return TRUE; + } + + static gboolean + _client_subprocess_wait_check (GSubprocess *subprocess, GError **error) + { + gint rc; + if (!g_subprocess_wait (subprocess, NULL, error)) { + g_prefix_error (error, "failed to run pkexec: "); + return FALSE; + } + rc = g_subprocess_get_exit_status (subprocess); + if (rc != 0) { + GInputStream *istream = g_subprocess_get_stderr_pipe (subprocess); + gchar buf[1024] = { 0x0 }; + gsize sz = 0; + g_input_stream_read_all (istream, buf, sizeof(buf) - 1, &sz, NULL, NULL); + if (sz == 0) { + g_set_error_literal (error, G_IO_ERROR, rc, + "Failed to run helper without stderr"); + return FALSE; + } + g_set_error_literal (error, G_IO_ERROR, rc, buf); + return FALSE; + } +@@ -637,61 +636,61 @@ _client_unregister (GsdSubscriptionManager *manager, GError **error) + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "unregister", + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + if (!_client_subprocess_wait_check (subprocess, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; + if (!_client_installed_products_update (manager, error)) + return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } + + static gboolean + _client_update_config (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GVariant) val = NULL; + g_autoptr(GVariant) val_server = NULL; + g_autoptr(GVariantDict) dict = NULL; + GVariantIter iter; + gchar *key; + gchar *value; + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONFIG], + "GetAll", +- g_variant_new ("(s)", priv->userlang), ++ g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + dict = g_variant_dict_new (g_variant_get_child_value (val, 0)); + val_server = g_variant_dict_lookup_value (dict, "server", G_VARIANT_TYPE("a{ss}")); + if (val_server != NULL) { + g_variant_iter_init (&iter, val_server); + while (g_variant_iter_next (&iter, "{ss}", &key, &value)) { + g_debug ("%s=%s", key, value); + g_hash_table_insert (priv->config, + g_steal_pointer (&key), + g_steal_pointer (&value)); + } + } + return TRUE; + } + + static void + _subman_proxy_signal_cb (GDBusProxy *proxy, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters, + GsdSubscriptionManager *manager) + { + g_autoptr(GError) error = NULL; + if (!_client_syspurpose_update (manager, &error)) { + g_warning ("failed to update syspurpose: %s", error->message); + g_clear_error (&error); + } +@@ -736,61 +735,60 @@ _rhsm_interface_to_string (_RhsmInterface kind) + } + + static gboolean + _client_load (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + + priv->config = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + /* connect to all the interfaces on the *different* objects :| */ + for (guint i = 0; i < _RHSM_INTERFACE_LAST; i++) { + const gchar *kind = _rhsm_interface_to_string (i); + g_autofree gchar *opath = g_strdup_printf ("/com/redhat/RHSM1/%s", kind); + g_autofree gchar *iface = g_strdup_printf ("com.redhat.RHSM1.%s", kind); + priv->proxies[i] = + g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "com.redhat.RHSM1", + opath, iface, + NULL, + error); + if (priv->proxies[i] == NULL) + return FALSE; + /* we want to get notified if the status of the system changes */ + g_signal_connect (priv->proxies[i], "g-signal", + G_CALLBACK (_subman_proxy_signal_cb), manager); + } + + /* get initial status */ +- priv->userlang = ""; + if (!_client_update_config (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; + if (!_client_installed_products_update (manager, error)) + return FALSE; + if (!_client_syspurpose_update (manager, error)) + return FALSE; + + /* success */ + return TRUE; + } + + gboolean + gsd_subscription_manager_start (GsdSubscriptionManager *manager, GError **error) + { + gboolean ret; + g_debug ("Starting subscription manager"); + gnome_settings_profile_start (NULL); + ret = _client_load (manager, error); + _client_maybe__show_notification (manager); + gnome_settings_profile_end (NULL); + return ret; + } + + void + gsd_subscription_manager_stop (GsdSubscriptionManager *manager) + { + g_debug ("Stopping subscription manager"); + _client_unload (manager); +-- +2.30.0 + diff --git a/SOURCES/0005-subman-Use-user-locale-for-registration-subscription.patch b/SOURCES/0005-subman-Use-user-locale-for-registration-subscription.patch new file mode 100644 index 0000000..fa6973b --- /dev/null +++ b/SOURCES/0005-subman-Use-user-locale-for-registration-subscription.patch @@ -0,0 +1,373 @@ +From db73e2211ecc746434d78d23d801c92581fa8824 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 15:04:17 -0500 +Subject: [PATCH 05/15] subman: Use user locale for registration/subscription + operations + +This makes sure that error messages are in the correct locale. +--- + plugins/subman/gsd-subman-helper.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index af7a82e9..f84e91bf 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -1,61 +1,63 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2019 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + #include "config.h" + + #include + #include + #include ++#include + + #include + #include + + #define DBUS_TIMEOUT 300000 /* 5 minutes */ ++static const char *locale; + + static void + _helper_convert_error (const gchar *json_txt, GError **error) + { + JsonNode *json_root; + JsonObject *json_obj; + const gchar *message; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* this may be plain text or JSON :| */ + if (!json_parser_load_from_data (json_parser, json_txt, -1, NULL)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + json_txt); + return; + } + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "message")) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no message' in %s", json_txt); + return; + } + message = json_object_get_string_member (json_obj, "message"); + if (g_strstr_len (message, -1, "Invalid user credentials") != NULL) { + g_set_error_literal (error, + G_IO_ERROR, +@@ -67,184 +69,187 @@ _helper_convert_error (const gchar *json_txt, GError **error) + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + message); + } + + static gboolean + _helper_unregister (GError **error) + { + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; + + g_debug ("unregistering"); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Unregister", + "com.redhat.RHSM1.Unregister", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); + res = g_dbus_proxy_call_sync (proxy, + "Unregister", + g_variant_new ("(a{sv}s)", + proxy_options, +- ""), /* lang */ ++ locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); + return res != NULL; + } + + static gboolean + _helper_auto_attach (GError **error) + { + const gchar *str = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; + + g_debug ("auto-attaching subscriptions"); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Attach", + "com.redhat.RHSM1.Attach", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); + res = g_dbus_proxy_call_sync (proxy, + "AutoAttach", + g_variant_new ("(sa{sv}s)", + "", /* now? */ + proxy_options, +- ""), /* lang */ ++ locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); + if (res == NULL) + return FALSE; + g_variant_get (res, "(&s)", &str); + g_debug ("Attach.AutoAttach: %s", str); + return TRUE; + } + + static gboolean + _helper_save_config (const gchar *key, const gchar *value, GError **error) + { + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariant) res = NULL; + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Config", + "com.redhat.RHSM1.Config", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + res = g_dbus_proxy_call_sync (proxy, "Set", + g_variant_new ("(svs)", + key, + g_variant_new_string (value), +- ""), /* lang */ ++ locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); + return res != NULL; + } + + int + main (int argc, char *argv[]) + { +- const gchar *userlang = ""; /* as root, so no translations */ + g_autofree gchar *activation_key = NULL; + g_autofree gchar *address = NULL; + g_autofree gchar *hostname = NULL; + g_autofree gchar *kind = NULL; + g_autofree gchar *organisation = NULL; + g_autofree gchar *password = NULL; + g_autofree gchar *port = NULL; + g_autofree gchar *prefix = NULL; + g_autofree gchar *proxy_server = NULL; + g_autofree gchar *username = NULL; + g_autoptr(GDBusConnection) conn_private = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GOptionContext) context = g_option_context_new (NULL); + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariantBuilder) subman_conopts = NULL; + g_autoptr(GVariantBuilder) subman_options = NULL; + + const GOptionEntry options[] = { + { "kind", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &kind, "Kind, e.g. 'username' or 'key'", NULL }, + { "address", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &address, "UNIX address", NULL }, + { "username", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &username, "Username", NULL }, + { "password", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &password, "Password", NULL }, + { "organisation", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &organisation, "Organisation", NULL }, + { "activation-key", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &activation_key, "Activation keys", NULL }, + { "hostname", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &hostname, "Registration server hostname", NULL }, + { "prefix", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &prefix, "Registration server prefix", NULL }, + { "port", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &port, "Registration server port", NULL }, + { "proxy", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &proxy_server, "Proxy settings", NULL }, + { NULL} + }; + + /* check calling UID */ + if (getuid () != 0 || geteuid () != 0) { + g_printerr ("This program can only be used by the root user\n"); + return G_IO_ERROR_NOT_SUPPORTED; + } ++ ++ setlocale (LC_ALL, ""); ++ locale = setlocale (LC_MESSAGES, NULL); ++ + g_option_context_add_main_entries (context, options, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_printerr ("Failed to parse arguments: %s\n", error->message); + return G_IO_ERROR_NOT_SUPPORTED; + } + + /* uncommon actions */ + if (kind == NULL) { + g_printerr ("No --kind specified\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (g_strcmp0 (kind, "unregister") == 0) { + if (!_helper_unregister (&error)) { + g_printerr ("Failed to Unregister: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + return EXIT_SUCCESS; + } + if (g_strcmp0 (kind, "auto-attach") == 0) { + if (!_helper_auto_attach (&error)) { + g_printerr ("Failed to AutoAttach: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + return EXIT_SUCCESS; + } + + /* connect to abstract socket for reasons */ + if (address == NULL) { + g_printerr ("No --address specified\n"); + return G_IO_ERROR_INVALID_DATA; +@@ -281,96 +286,96 @@ main (int argc, char *argv[]) + port = g_strdup ("443"); + subman_conopts = g_variant_builder_new (G_VARIANT_TYPE("a{ss}")); + g_variant_builder_add (subman_conopts, "{ss}", "host", hostname); + g_variant_builder_add (subman_conopts, "{ss}", "handler", prefix); + g_variant_builder_add (subman_conopts, "{ss}", "port", port); + + /* call into RHSM */ + if (g_strcmp0 (kind, "register-with-key") == 0) { + g_auto(GStrv) activation_keys = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; + + if (activation_key == NULL) { + g_printerr ("Required --activation-key\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + + g_debug ("registering using activation key"); + activation_keys = g_strsplit (activation_key, ",", -1); + res = g_dbus_proxy_call_sync (proxy, + "RegisterWithActivationKeys", + g_variant_new ("(s^asa{ss}a{ss}s)", + organisation, + activation_keys, + subman_options, + subman_conopts, +- userlang), ++ locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); + g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); + return error->code; + } + } else if (g_strcmp0 (kind, "register-with-username") == 0) { + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; + + g_debug ("registering using username and password"); + if (username == NULL) { + g_printerr ("Required --username\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (password == NULL) { + g_printerr ("Required --password\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + res = g_dbus_proxy_call_sync (proxy, + "Register", + g_variant_new ("(sssa{ss}a{ss}s)", + organisation, + username, + password, + subman_options, + subman_conopts, +- userlang), ++ locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); + g_printerr ("Failed to Register: %s\n", error->message); + return error->code; + } + } else { + g_printerr ("Invalid --kind specified: %s\n", kind); + return G_IO_ERROR_INVALID_DATA; + } + + /* set the new hostname */ + if (!_helper_save_config ("server.hostname", hostname, &error)) { + g_printerr ("Failed to save hostname: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + if (!_helper_save_config ("server.prefix", prefix, &error)) { + g_printerr ("Failed to save prefix: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + if (!_helper_save_config ("server.port", port, &error)) { + g_printerr ("Failed to save port: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + + /* wait for rhsmd to notice the new config */ + g_usleep (G_USEC_PER_SEC * 5); +-- +2.30.0 + diff --git a/SOURCES/0006-subman-Handle-subscription-manager-giving-invalid-st.patch b/SOURCES/0006-subman-Handle-subscription-manager-giving-invalid-st.patch new file mode 100644 index 0000000..cfd9b7c --- /dev/null +++ b/SOURCES/0006-subman-Handle-subscription-manager-giving-invalid-st.patch @@ -0,0 +1,236 @@ +From f8ddd2c711cd502c74eb9d45360914fe2e6e1b3f Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 20 Aug 2020 13:34:19 -0400 +Subject: [PATCH 06/15] subman: Handle subscription-manager giving invalid + status better + +subscription-manager potentially returns status messages that the +subman plugin treats as enum values translated in some unknown +other language. It could be tied to system locale, or due to a +caching bug a previous locale used. + +This commit tries to work around that bug, by instead relying on +the GetUUID() method and valid attribute. If there's no UUID we +know the system is unregistered. If there's a UUID but the valid +attribute is FALSE we know the system is registered, but hasn't +got proper entitlements. +--- + plugins/subman/gsd-subscription-manager.c | 69 ++++++++++++----------- + 1 file changed, 36 insertions(+), 33 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 46f051a5..e2c16056 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -104,77 +104,60 @@ typedef struct + gchar *starts; + gchar *ends; + } ProductData; + + static void + product_data_free (ProductData *product) + { + g_free (product->product_name); + g_free (product->product_id); + g_free (product->version); + g_free (product->arch); + g_free (product->status); + g_free (product->starts); + g_free (product->ends); + g_free (product); + } + + G_DEFINE_AUTOPTR_CLEANUP_FUNC (ProductData, product_data_free); + + static gpointer manager_object = NULL; + + GQuark + gsd_subscription_manager_error_quark (void) + { + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("gsd_subscription_manager_error"); + return quark; + } + +-static GsdSubmanSubscriptionStatus +-_client_subscription_status_from_text (const gchar *status_txt) +-{ +- if (g_strcmp0 (status_txt, "Unknown") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; +- if (g_strcmp0 (status_txt, "Current") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID; +- if (g_strcmp0 (status_txt, "Invalid") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; +- if (g_strcmp0 (status_txt, "Disabled") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED; +- if (g_strcmp0 (status_txt, "Insufficient") == 0) +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID; +- g_warning ("Unknown subscription status: %s", status_txt); // 'Current'? +- return GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; +-} +- + static GVariant * + _make_installed_products_variant (GPtrArray *installed_products) + { + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); + + for (guint i = 0; i < installed_products->len; i++) { + ProductData *product = g_ptr_array_index (installed_products, i); + g_auto(GVariantDict) dict; + + g_variant_dict_init (&dict, NULL); + + g_variant_dict_insert (&dict, "product-name", "s", product->product_name); + g_variant_dict_insert (&dict, "product-id", "s", product->product_id); + g_variant_dict_insert (&dict, "version", "s", product->version); + g_variant_dict_insert (&dict, "arch", "s", product->arch); + g_variant_dict_insert (&dict, "status", "s", product->status); + g_variant_dict_insert (&dict, "starts", "s", product->starts); + g_variant_dict_insert (&dict, "ends", "s", product->ends); + + g_variant_builder_add_value (&builder, g_variant_dict_end (&dict)); + } + + return g_variant_builder_end (&builder); + } + + static void + _emit_property_changed (GsdSubscriptionManager *manager, + const gchar *property_name, + GVariant *property_value) +@@ -248,94 +231,114 @@ _client_installed_products_update (GsdSubscriptionManager *manager, GError **err + + if (json_product == NULL) + continue; + if (json_array_get_length (json_product) < 8) { + g_debug ("Unexpected number of array elements in InstalledProducts JSON"); + continue; + } + + product->product_name = g_strdup (json_array_get_string_element (json_product, 0)); + product->product_id = g_strdup (json_array_get_string_element (json_product, 1)); + product->version = g_strdup (json_array_get_string_element (json_product, 2)); + product->arch = g_strdup (json_array_get_string_element (json_product, 3)); + product->status = g_strdup (json_array_get_string_element (json_product, 4)); + product->starts = g_strdup (json_array_get_string_element (json_product, 6)); + product->ends = g_strdup (json_array_get_string_element (json_product, 7)); + + g_ptr_array_add (priv->installed_products, g_steal_pointer (&product)); + } + + /* emit notification for g-c-c */ + _emit_property_changed (manager, "InstalledProducts", + _make_installed_products_variant (priv->installed_products)); + + return TRUE; + } + + static gboolean + _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; ++ g_autoptr(GVariant) uuid = NULL; ++ const gchar *uuid_txt = NULL; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; +- const gchar *status_txt = NULL; +- g_autoptr(GVariant) val = NULL; ++ g_autoptr(GVariant) status = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; + +- val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], +- "GetStatus", +- g_variant_new ("(ss)", +- "", /* assumed as 'now' */ +- "C.UTF-8"), +- G_DBUS_CALL_FLAGS_NONE, +- -1, NULL, error); +- if (val == NULL) ++ uuid = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONSUMER], ++ "GetUuid", ++ g_variant_new ("(s)", ++ "C.UTF-8"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (uuid == NULL) + return FALSE; +- g_variant_get (val, "(&s)", &json_txt); ++ ++ g_variant_get (uuid, "(&s)", &uuid_txt); ++ ++ status = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], ++ "GetStatus", ++ g_variant_new ("(ss)", ++ "", /* assumed as 'now' */ ++ "C.UTF-8"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, NULL, error); ++ if (status == NULL) ++ return FALSE; ++ g_variant_get (status, "(&s)", &json_txt); + g_debug ("Entitlement.GetStatus JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); +- if (!json_object_has_member (json_obj, "status")) { ++ if (!json_object_has_member (json_obj, "valid")) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, +- "no Entitlement.GetStatus status in %s", json_txt); ++ "no Entitlement.GetStatus valid in %s", json_txt); + return FALSE; + } + +- status_txt = json_object_get_string_member (json_obj, "status"); +- g_debug ("Entitlement.GetStatus: %s", status_txt); +- priv->subscription_status = _client_subscription_status_from_text (status_txt); ++ gboolean is_valid = json_object_get_boolean_member (json_obj, "valid"); ++ ++ if (uuid_txt[0] != '\0') { ++ if (is_valid) { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID; ++ } else { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; ++ } ++ } else { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; ++ } + + /* emit notification for g-c-c */ + if (priv->subscription_status != priv->subscription_status_last) { + _emit_property_changed (manager, "SubscriptionStatus", + g_variant_new_uint32 (priv->subscription_status)); + } + + return TRUE; + } + + static gboolean + _client_syspurpose_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_SYSPURPOSE], + "GetSyspurpose", + g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(&s)", &json_txt); + g_debug ("Syspurpose.GetSyspurpose JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) +-- +2.30.0 + diff --git a/SOURCES/0007-subman-Force-re-subscribe-if-the-admin-already-subsc.patch b/SOURCES/0007-subman-Force-re-subscribe-if-the-admin-already-subsc.patch new file mode 100644 index 0000000..73acafa --- /dev/null +++ b/SOURCES/0007-subman-Force-re-subscribe-if-the-admin-already-subsc.patch @@ -0,0 +1,260 @@ +From 477dc8accccab568002bd19caa3fbf898bc05aad Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 25 Aug 2020 10:34:03 -0400 +Subject: [PATCH 07/15] subman: Force re-subscribe if the admin already + subscribed + +It's possible for an admin to to half-enroll the system with RHN, +using the CLI tools. + +Meaning, it's possible for them to register the system with the +service, but not attach to a purchased license for the machine, +the, so called, entitlements. + +The subman module always does both halves of the registration process +in lock step. This means, if an admin tries to register using GNOME +while in a half-registered state, subman will fail because the first +step, the registration step, is already finished. + +This commit addresses that problem by trying to unregister up front +before registering. +--- + plugins/subman/gsd-subman-helper.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index f84e91bf..3931ef2e 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -51,61 +51,60 @@ _helper_convert_error (const gchar *json_txt, GError **error) + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "message")) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no message' in %s", json_txt); + return; + } + message = json_object_get_string_member (json_obj, "message"); + if (g_strstr_len (message, -1, "Invalid user credentials") != NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED, + message); + return; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + message); + } + + static gboolean + _helper_unregister (GError **error) + { + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; + +- g_debug ("unregistering"); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Unregister", + "com.redhat.RHSM1.Unregister", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); + res = g_dbus_proxy_call_sync (proxy, + "Unregister", + g_variant_new ("(a{sv}s)", + proxy_options, + locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); + return res != NULL; + } + + static gboolean + _helper_auto_attach (GError **error) + { + const gchar *str = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; +@@ -208,60 +207,61 @@ main (int argc, char *argv[]) + { "prefix", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &prefix, "Registration server prefix", NULL }, + { "port", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &port, "Registration server port", NULL }, + { "proxy", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &proxy_server, "Proxy settings", NULL }, + { NULL} + }; + + /* check calling UID */ + if (getuid () != 0 || geteuid () != 0) { + g_printerr ("This program can only be used by the root user\n"); + return G_IO_ERROR_NOT_SUPPORTED; + } + + setlocale (LC_ALL, ""); + locale = setlocale (LC_MESSAGES, NULL); + + g_option_context_add_main_entries (context, options, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_printerr ("Failed to parse arguments: %s\n", error->message); + return G_IO_ERROR_NOT_SUPPORTED; + } + + /* uncommon actions */ + if (kind == NULL) { + g_printerr ("No --kind specified\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (g_strcmp0 (kind, "unregister") == 0) { ++ g_debug ("unregistering"); + if (!_helper_unregister (&error)) { + g_printerr ("Failed to Unregister: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + return EXIT_SUCCESS; + } + if (g_strcmp0 (kind, "auto-attach") == 0) { + if (!_helper_auto_attach (&error)) { + g_printerr ("Failed to AutoAttach: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + return EXIT_SUCCESS; + } + + /* connect to abstract socket for reasons */ + if (address == NULL) { + g_printerr ("No --address specified\n"); + return G_IO_ERROR_INVALID_DATA; + } + conn_private = g_dbus_connection_new_for_address_sync (address, + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, + NULL, NULL, + &error); + if (conn_private == NULL) { + g_printerr ("Invalid --address specified: %s\n", error->message); + return G_IO_ERROR_INVALID_DATA; + } + proxy = g_dbus_proxy_new_sync (conn_private, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, /* GDBusInterfaceInfo */ +@@ -277,96 +277,103 @@ main (int argc, char *argv[]) + /* no options */ + subman_options = g_variant_builder_new (G_VARIANT_TYPE("a{ss}")); + + /* set registration server */ + if (hostname == NULL || hostname[0] == '\0') + hostname = g_strdup ("subscription.rhsm.redhat.com"); + if (prefix == NULL || prefix[0] == '\0') + prefix = g_strdup ("/subscription"); + if (port == NULL || port[0] == '\0') + port = g_strdup ("443"); + subman_conopts = g_variant_builder_new (G_VARIANT_TYPE("a{ss}")); + g_variant_builder_add (subman_conopts, "{ss}", "host", hostname); + g_variant_builder_add (subman_conopts, "{ss}", "handler", prefix); + g_variant_builder_add (subman_conopts, "{ss}", "port", port); + + /* call into RHSM */ + if (g_strcmp0 (kind, "register-with-key") == 0) { + g_auto(GStrv) activation_keys = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; + + if (activation_key == NULL) { + g_printerr ("Required --activation-key\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + ++ g_debug ("trying to unregister in case machine is already registered"); ++ _helper_unregister (NULL); ++ + g_debug ("registering using activation key"); + activation_keys = g_strsplit (activation_key, ",", -1); + res = g_dbus_proxy_call_sync (proxy, + "RegisterWithActivationKeys", + g_variant_new ("(s^asa{ss}a{ss}s)", + organisation, + activation_keys, + subman_options, + subman_conopts, + locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); + g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); + return error->code; + } + } else if (g_strcmp0 (kind, "register-with-username") == 0) { + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; + +- g_debug ("registering using username and password"); + if (username == NULL) { + g_printerr ("Required --username\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (password == NULL) { + g_printerr ("Required --password\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } ++ ++ g_debug ("trying to unregister in case machine is already registered"); ++ _helper_unregister (NULL); ++ ++ g_debug ("registering using username and password"); + res = g_dbus_proxy_call_sync (proxy, + "Register", + g_variant_new ("(sssa{ss}a{ss}s)", + organisation, + username, + password, + subman_options, + subman_conopts, + locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); + g_printerr ("Failed to Register: %s\n", error->message); + return error->code; + } + } else { + g_printerr ("Invalid --kind specified: %s\n", kind); + return G_IO_ERROR_INVALID_DATA; + } + + /* set the new hostname */ + if (!_helper_save_config ("server.hostname", hostname, &error)) { + g_printerr ("Failed to save hostname: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + if (!_helper_save_config ("server.prefix", prefix, &error)) { + g_printerr ("Failed to save prefix: %s\n", error->message); +-- +2.30.0 + diff --git a/SOURCES/0008-subman-Don-t-send-secrets-through-command-line.patch b/SOURCES/0008-subman-Don-t-send-secrets-through-command-line.patch new file mode 100644 index 0000000..bd85eaf --- /dev/null +++ b/SOURCES/0008-subman-Don-t-send-secrets-through-command-line.patch @@ -0,0 +1,576 @@ +From b73800da7f384eea66b6eb67f5f40129f3dfc372 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 25 Aug 2020 16:20:42 -0400 +Subject: [PATCH 08/15] subman: Don't send secrets through command line + +The command line is introspectable with "ps", and it even gets logged +to syslog, so it's not suitable for passing secrets. + +Unfortunately, the user's password is currently passed. + +This commit addresses that problem by passing the password through +stdin, instead. +--- + plugins/subman/gsd-subman-helper.c | 32 ++++++++------ + plugins/subman/gsd-subscription-manager.c | 52 ++++++++++++++++++++--- + plugins/subman/meson.build | 2 +- + 3 files changed, 66 insertions(+), 20 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index 3931ef2e..edf1e41f 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -1,59 +1,61 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2019 Richard Hughes + * + * Licensed under the GNU General Public License Version 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + #include "config.h" + ++ + #include + #include + #include + #include + + #include ++#include + #include + + #define DBUS_TIMEOUT 300000 /* 5 minutes */ + static const char *locale; + + static void + _helper_convert_error (const gchar *json_txt, GError **error) + { + JsonNode *json_root; + JsonObject *json_obj; + const gchar *message; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* this may be plain text or JSON :| */ + if (!json_parser_load_from_data (json_parser, json_txt, -1, NULL)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + json_txt); + return; + } + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "message")) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no message' in %s", json_txt); + return; + } +@@ -149,86 +151,82 @@ _helper_save_config (const gchar *key, const gchar *value, GError **error) + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Config", + "com.redhat.RHSM1.Config", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + res = g_dbus_proxy_call_sync (proxy, "Set", + g_variant_new ("(svs)", + key, + g_variant_new_string (value), + locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); + return res != NULL; + } + + int + main (int argc, char *argv[]) + { + g_autofree gchar *activation_key = NULL; + g_autofree gchar *address = NULL; + g_autofree gchar *hostname = NULL; + g_autofree gchar *kind = NULL; + g_autofree gchar *organisation = NULL; +- g_autofree gchar *password = NULL; + g_autofree gchar *port = NULL; + g_autofree gchar *prefix = NULL; + g_autofree gchar *proxy_server = NULL; + g_autofree gchar *username = NULL; + g_autoptr(GDBusConnection) conn_private = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GOptionContext) context = g_option_context_new (NULL); + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariantBuilder) subman_conopts = NULL; + g_autoptr(GVariantBuilder) subman_options = NULL; ++ g_autoptr(GInputStream) standard_input_stream = g_unix_input_stream_new (STDIN_FILENO, FALSE); + + const GOptionEntry options[] = { + { "kind", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &kind, "Kind, e.g. 'username' or 'key'", NULL }, + { "address", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &address, "UNIX address", NULL }, + { "username", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &username, "Username", NULL }, +- { "password", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, +- &password, "Password", NULL }, + { "organisation", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, + &organisation, "Organisation", NULL }, +- { "activation-key", '\0', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, +- &activation_key, "Activation keys", NULL }, + { "hostname", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &hostname, "Registration server hostname", NULL }, + { "prefix", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &prefix, "Registration server prefix", NULL }, + { "port", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &port, "Registration server port", NULL }, + { "proxy", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, + &proxy_server, "Proxy settings", NULL }, + { NULL} + }; + + /* check calling UID */ + if (getuid () != 0 || geteuid () != 0) { + g_printerr ("This program can only be used by the root user\n"); + return G_IO_ERROR_NOT_SUPPORTED; + } + + setlocale (LC_ALL, ""); + locale = setlocale (LC_MESSAGES, NULL); + + g_option_context_add_main_entries (context, options, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_printerr ("Failed to parse arguments: %s\n", error->message); + return G_IO_ERROR_NOT_SUPPORTED; + } + + /* uncommon actions */ + if (kind == NULL) { + g_printerr ("No --kind specified\n"); + return G_IO_ERROR_INVALID_DATA; +@@ -267,109 +265,117 @@ main (int argc, char *argv[]) + NULL, /* GDBusInterfaceInfo */ + NULL, /* name */ + "/com/redhat/RHSM1/Register", + "com.redhat.RHSM1.Register", + NULL, &error); + if (proxy == NULL) { + g_printerr ("Count not contact RHSM: %s\n", error->message); + return G_IO_ERROR_NOT_FOUND; + } + + /* no options */ + subman_options = g_variant_builder_new (G_VARIANT_TYPE("a{ss}")); + + /* set registration server */ + if (hostname == NULL || hostname[0] == '\0') + hostname = g_strdup ("subscription.rhsm.redhat.com"); + if (prefix == NULL || prefix[0] == '\0') + prefix = g_strdup ("/subscription"); + if (port == NULL || port[0] == '\0') + port = g_strdup ("443"); + subman_conopts = g_variant_builder_new (G_VARIANT_TYPE("a{ss}")); + g_variant_builder_add (subman_conopts, "{ss}", "host", hostname); + g_variant_builder_add (subman_conopts, "{ss}", "handler", prefix); + g_variant_builder_add (subman_conopts, "{ss}", "port", port); + + /* call into RHSM */ + if (g_strcmp0 (kind, "register-with-key") == 0) { + g_auto(GStrv) activation_keys = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; ++ gchar activation_key[PIPE_BUF + 1] = ""; + +- if (activation_key == NULL) { +- g_printerr ("Required --activation-key\n"); +- return G_IO_ERROR_INVALID_DATA; +- } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + ++ g_input_stream_read (standard_input_stream, activation_key, sizeof (activation_key) - 1, NULL, &error_local); ++ ++ if (error_local != NULL) { ++ g_printerr ("Could not read activation key: %s\n", error_local->message); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ + g_debug ("trying to unregister in case machine is already registered"); + _helper_unregister (NULL); + + g_debug ("registering using activation key"); + activation_keys = g_strsplit (activation_key, ",", -1); + res = g_dbus_proxy_call_sync (proxy, + "RegisterWithActivationKeys", + g_variant_new ("(s^asa{ss}a{ss}s)", + organisation, + activation_keys, + subman_options, + subman_conopts, + locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); + g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); + return error->code; + } + } else if (g_strcmp0 (kind, "register-with-username") == 0) { + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; ++ gchar password[PIPE_BUF + 1] = ""; + + if (username == NULL) { + g_printerr ("Required --username\n"); + return G_IO_ERROR_INVALID_DATA; + } +- if (password == NULL) { +- g_printerr ("Required --password\n"); +- return G_IO_ERROR_INVALID_DATA; +- } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + ++ g_input_stream_read (standard_input_stream, password, sizeof (password) - 1, NULL, &error_local); ++ ++ if (error_local != NULL) { ++ g_printerr ("Could not read password: %s\n", error_local->message); ++ return G_IO_ERROR_INVALID_DATA; ++ } ++ + g_debug ("trying to unregister in case machine is already registered"); + _helper_unregister (NULL); + + g_debug ("registering using username and password"); + res = g_dbus_proxy_call_sync (proxy, + "Register", + g_variant_new ("(sssa{ss}a{ss}s)", + organisation, + username, + password, + subman_options, + subman_conopts, + locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); + g_printerr ("Failed to Register: %s\n", error->message); + return error->code; + } + } else { + g_printerr ("Invalid --kind specified: %s\n", kind); + return G_IO_ERROR_INVALID_DATA; + } + + /* set the new hostname */ + if (!_helper_save_config ("server.hostname", hostname, &error)) { + g_printerr ("Failed to save hostname: %s\n", error->message); +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index e2c16056..0838d490 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -1,53 +1,54 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2019 Richard Hughes + * Copyright (C) 2019 Kalev Lember + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + + #include "config.h" + + #include ++#include + #include + #include + #include + #include + + #include "gnome-settings-profile.h" + #include "gsd-subman-common.h" + #include "gsd-subscription-manager.h" + + #define GSD_DBUS_NAME "org.gnome.SettingsDaemon" + #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon" + #define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon" + + #define GSD_SUBSCRIPTION_DBUS_NAME GSD_DBUS_NAME ".Subscription" + #define GSD_SUBSCRIPTION_DBUS_PATH GSD_DBUS_PATH "/Subscription" + #define GSD_SUBSCRIPTION_DBUS_INTERFACE GSD_DBUS_BASE_INTERFACE ".Subscription" + + static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + #define GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManagerPrivate)) +@@ -517,129 +518,168 @@ _client_maybe__show_notification (GsdSubscriptionManager *manager) + } + } + + /* nag again */ + if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && + g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { + _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); + return; + } + if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID && + g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { + _show_notification (manager, _NOTIFY_EXPIRED); + return; + } + if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID && + g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { + _show_notification (manager, _NOTIFY_EXPIRED); + return; + } + } + + static gboolean + _client_register_with_keys (GsdSubscriptionManager *manager, + const gchar *hostname, + const gchar *organisation, + const gchar *activation_key, + GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; ++ g_autoptr(GBytes) stdin_buf = g_bytes_new (activation_key, strlen (activation_key) + 1); ++ g_autoptr(GBytes) stderr_buf = NULL; ++ gint rc; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); +- subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-key", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, +- "--activation-key", activation_key, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } +- if (!_client_subprocess_wait_check (subprocess, error)) ++ ++ if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) { ++ g_prefix_error (error, "failed to run pkexec: "); + return FALSE; ++ } ++ ++ rc = g_subprocess_get_exit_status (subprocess); ++ if (rc != 0) { ++ if (g_bytes_get_size (stderr_buf) == 0) { ++ g_set_error_literal (error, G_IO_ERROR, rc, ++ "Failed to run helper without stderr"); ++ return FALSE; ++ } ++ ++ g_set_error (error, G_IO_ERROR, rc, ++ "%.*s", ++ g_bytes_get_size (stderr_buf), ++ g_bytes_get_data (stderr_buf, NULL)); ++ } + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; + if (!_client_installed_products_update (manager, error)) + return FALSE; + _client_maybe__show_notification (manager); + + /* success */ + return TRUE; + } + + static gboolean + _client_register (GsdSubscriptionManager *manager, + const gchar *hostname, + const gchar *organisation, + const gchar *username, + const gchar *password, + GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; ++ g_autoptr(GBytes) stdin_buf = g_bytes_new (password, strlen (password) + 1); ++ g_autoptr(GBytes) stderr_buf = NULL; ++ gint rc; + + /* fallback */ + if (organisation == NULL) + organisation = ""; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); +- subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, ++ error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-username", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, + "--username", username, +- "--password", password, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } +- if (!_client_subprocess_wait_check (subprocess, error)) ++ ++ if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) { ++ g_prefix_error (error, "failed to run pkexec: "); + return FALSE; ++ } ++ ++ rc = g_subprocess_get_exit_status (subprocess); ++ if (rc != 0) { ++ if (g_bytes_get_size (stderr_buf) == 0) { ++ g_set_error_literal (error, G_IO_ERROR, rc, ++ "Failed to run helper without stderr"); ++ return FALSE; ++ } ++ ++ g_set_error (error, G_IO_ERROR, rc, ++ "%.*s", ++ g_bytes_get_size (stderr_buf), ++ g_bytes_get_data (stderr_buf, NULL)); ++ } + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; + if (!_client_installed_products_update (manager, error)) + return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } + + static gboolean + _client_unregister (GsdSubscriptionManager *manager, GError **error) + { + g_autoptr(GSubprocess) subprocess = NULL; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "unregister", + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } +diff --git a/plugins/subman/meson.build b/plugins/subman/meson.build +index bfd073b6..e4b4589d 100644 +--- a/plugins/subman/meson.build ++++ b/plugins/subman/meson.build +@@ -22,35 +22,35 @@ executable( + c_args: cflags, + install: true, + install_rpath: gsd_pkglibdir, + install_dir: gsd_libexecdir + ) + + # .Register needs to be called from root as subman can't do PolicyKit... + policy = 'org.gnome.settings-daemon.plugins.subman.policy' + policy_in = configure_file( + input: policy + '.in.in', + output: policy + '.in', + configuration: plugins_conf + ) + + i18n.merge_file( + policy, + input: policy_in, + output: policy, + po_dir: po_dir, + install: true, + install_dir: join_paths(gsd_datadir, 'polkit-1', 'actions') + ) + + install_data('org.gnome.settings-daemon.plugins.subman.rules', + install_dir : join_paths(gsd_datadir, 'polkit-1', 'rules.d')) + + executable( + 'gsd-subman-helper', + 'gsd-subman-helper.c', + include_directories: top_inc, +- dependencies: [gio_dep, jsonglib_dep], ++ dependencies: [gio_dep, gio_unix_dep, jsonglib_dep], + install: true, + install_rpath: gsd_pkglibdir, + install_dir: gsd_libexecdir + ) +-- +2.30.0 + diff --git a/SOURCES/0009-subman-Don-t-treat-failure-to-attach-as-fatal.patch b/SOURCES/0009-subman-Don-t-treat-failure-to-attach-as-fatal.patch new file mode 100644 index 0000000..5edb2ae --- /dev/null +++ b/SOURCES/0009-subman-Don-t-treat-failure-to-attach-as-fatal.patch @@ -0,0 +1,310 @@ +From 1255b2b83284d262f6b8c3ceb23d499ddbf77d48 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 21 Jan 2021 09:52:19 -0500 +Subject: [PATCH 09/15] subman: Don't treat failure to attach as fatal + +Many organizations don't require specific subscriptions to get +updates (called "simple content access"). At the moment, +those systems get an error when registering. + +This commit quiets the error. +--- + plugins/subman/gsd-subman-helper.c | 46 ++++++++++++++++++++++++------ + 1 file changed, 37 insertions(+), 9 deletions(-) + +diff --git a/plugins/subman/gsd-subman-helper.c b/plugins/subman/gsd-subman-helper.c +index edf1e41f..53a4d56b 100644 +--- a/plugins/subman/gsd-subman-helper.c ++++ b/plugins/subman/gsd-subman-helper.c +@@ -25,145 +25,169 @@ + #include + #include + #include + #include + + #include + #include + #include + + #define DBUS_TIMEOUT 300000 /* 5 minutes */ + static const char *locale; + + static void + _helper_convert_error (const gchar *json_txt, GError **error) + { + JsonNode *json_root; + JsonObject *json_obj; + const gchar *message; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* this may be plain text or JSON :| */ + if (!json_parser_load_from_data (json_parser, json_txt, -1, NULL)) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + json_txt); + return; + } + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); ++ if (json_object_has_member (json_obj, "severity")) { ++ const gchar *severity; ++ ++ /* warnings are non-fatal so we ignore them ++ */ ++ severity = json_object_get_string_member (json_obj, "severity"); ++ if (g_strstr_len (severity, -1, "warning") != NULL) { ++ return; ++ } ++ } ++ + if (!json_object_has_member (json_obj, "message")) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no message' in %s", json_txt); + return; + } + message = json_object_get_string_member (json_obj, "message"); + if (g_strstr_len (message, -1, "Invalid user credentials") != NULL) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED, + message); + return; + } + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + message); + } + + static gboolean + _helper_unregister (GError **error) + { + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; + + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Unregister", + "com.redhat.RHSM1.Unregister", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); + res = g_dbus_proxy_call_sync (proxy, + "Unregister", + g_variant_new ("(a{sv}s)", + proxy_options, + locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); + return res != NULL; + } + + static gboolean + _helper_auto_attach (GError **error) + { + const gchar *str = NULL; ++ g_autoptr(GError) error_local = NULL; + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariantBuilder) proxy_options = NULL; + g_autoptr(GVariant) res = NULL; + + g_debug ("auto-attaching subscriptions"); + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Attach", + "com.redhat.RHSM1.Attach", +- NULL, error); ++ NULL, &error_local); + if (proxy == NULL) { +- g_prefix_error (error, "Failed to get proxy: "); ++ g_dbus_error_strip_remote_error (error_local); ++ g_propagate_prefixed_error (error, ++ g_steal_pointer (&error_local), ++ "Failed to get proxy: "); + return FALSE; + } + proxy_options = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); + res = g_dbus_proxy_call_sync (proxy, + "AutoAttach", + g_variant_new ("(sa{sv}s)", + "", /* now? */ + proxy_options, + locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, +- NULL, error); +- if (res == NULL) +- return FALSE; ++ NULL, &error_local); ++ if (res == NULL) { ++ g_dbus_error_strip_remote_error (error_local); ++ _helper_convert_error (error_local->message, error); ++ ++ if (*error != NULL) { ++ g_prefix_error (error, "Failed to get proxy: "); ++ return FALSE; ++ } ++ ++ return TRUE; ++ } + g_variant_get (res, "(&s)", &str); + g_debug ("Attach.AutoAttach: %s", str); + return TRUE; + } + + static gboolean + _helper_save_config (const gchar *key, const gchar *value, GError **error) + { + g_autoptr(GDBusProxy) proxy = NULL; + g_autoptr(GVariant) res = NULL; + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + "com.redhat.RHSM1", + "/com/redhat/RHSM1/Config", + "com.redhat.RHSM1.Config", + NULL, error); + if (proxy == NULL) { + g_prefix_error (error, "Failed to get proxy: "); + return FALSE; + } + res = g_dbus_proxy_call_sync (proxy, "Set", + g_variant_new ("(svs)", + key, + g_variant_new_string (value), + locale), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + NULL, error); +@@ -298,105 +322,109 @@ main (int argc, char *argv[]) + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + + g_input_stream_read (standard_input_stream, activation_key, sizeof (activation_key) - 1, NULL, &error_local); + + if (error_local != NULL) { + g_printerr ("Could not read activation key: %s\n", error_local->message); + return G_IO_ERROR_INVALID_DATA; + } + + g_debug ("trying to unregister in case machine is already registered"); + _helper_unregister (NULL); + + g_debug ("registering using activation key"); + activation_keys = g_strsplit (activation_key, ",", -1); + res = g_dbus_proxy_call_sync (proxy, + "RegisterWithActivationKeys", + g_variant_new ("(s^asa{ss}a{ss}s)", + organisation, + activation_keys, + subman_options, + subman_conopts, + locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); +- g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); +- return error->code; ++ if (error != NULL) { ++ g_printerr ("Failed to RegisterWithActivationKeys: %s\n", error->message); ++ return error->code; ++ } + } + } else if (g_strcmp0 (kind, "register-with-username") == 0) { + g_autoptr(GError) error_local = NULL; + g_autoptr(GVariant) res = NULL; + gchar password[PIPE_BUF + 1] = ""; + + if (username == NULL) { + g_printerr ("Required --username\n"); + return G_IO_ERROR_INVALID_DATA; + } + if (organisation == NULL) { + g_printerr ("Required --organisation\n"); + return G_IO_ERROR_INVALID_DATA; + } + + g_input_stream_read (standard_input_stream, password, sizeof (password) - 1, NULL, &error_local); + + if (error_local != NULL) { + g_printerr ("Could not read password: %s\n", error_local->message); + return G_IO_ERROR_INVALID_DATA; + } + + g_debug ("trying to unregister in case machine is already registered"); + _helper_unregister (NULL); + + g_debug ("registering using username and password"); + res = g_dbus_proxy_call_sync (proxy, + "Register", + g_variant_new ("(sssa{ss}a{ss}s)", + organisation, + username, + password, + subman_options, + subman_conopts, + locale), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + DBUS_TIMEOUT, + NULL, &error_local); + if (res == NULL) { + g_dbus_error_strip_remote_error (error_local); + _helper_convert_error (error_local->message, &error); +- g_printerr ("Failed to Register: %s\n", error->message); +- return error->code; ++ if (error != NULL) { ++ g_printerr ("Failed to Register: %s\n", error->message); ++ return error->code; ++ } + } + } else { + g_printerr ("Invalid --kind specified: %s\n", kind); + return G_IO_ERROR_INVALID_DATA; + } + + /* set the new hostname */ + if (!_helper_save_config ("server.hostname", hostname, &error)) { + g_printerr ("Failed to save hostname: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + if (!_helper_save_config ("server.prefix", prefix, &error)) { + g_printerr ("Failed to save prefix: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + if (!_helper_save_config ("server.port", port, &error)) { + g_printerr ("Failed to save port: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + + /* wait for rhsmd to notice the new config */ + g_usleep (G_USEC_PER_SEC * 5); + + /* auto-attach */ + if (!_helper_auto_attach (&error)) { + g_printerr ("Failed to AutoAttach: %s\n", error->message); + return G_IO_ERROR_NOT_INITIALIZED; + } + + return EXIT_SUCCESS; +-- +2.30.0 + diff --git a/SOURCES/0010-subman-Add-new-no-installed-products-state.patch b/SOURCES/0010-subman-Add-new-no-installed-products-state.patch new file mode 100644 index 0000000..efe9990 --- /dev/null +++ b/SOURCES/0010-subman-Add-new-no-installed-products-state.patch @@ -0,0 +1,427 @@ +From d53c27802c69773d63d108f57912035fd3caabf9 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:24:36 -0500 +Subject: [PATCH 10/15] subman: Add new no-installed-products state + +It's possible, though unlikley, the system has +no packages installed from Red Hat supported package sets. + +This commit adds a new state to track that situation. +--- + plugins/subman/gsd-subman-common.c | 2 ++ + plugins/subman/gsd-subman-common.h | 1 + + plugins/subman/gsd-subscription-manager.c | 17 +++++++---------- + 3 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/plugins/subman/gsd-subman-common.c b/plugins/subman/gsd-subman-common.c +index e515131e..eef5175d 100644 +--- a/plugins/subman/gsd-subman-common.c ++++ b/plugins/subman/gsd-subman-common.c +@@ -5,32 +5,34 @@ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + + #include "config.h" + + #include "gsd-subman-common.h" + + const gchar * + gsd_subman_subscription_status_to_string (GsdSubmanSubscriptionStatus status) + { + if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID) + return "valid"; + if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID) + return "invalid"; + if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED) + return "disabled"; + if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID) + return "partially-valid"; ++ if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS) ++ return "no-installed-products"; + return "unknown"; + } +diff --git a/plugins/subman/gsd-subman-common.h b/plugins/subman/gsd-subman-common.h +index fccf9f6a..f8a3d9f4 100644 +--- a/plugins/subman/gsd-subman-common.h ++++ b/plugins/subman/gsd-subman-common.h +@@ -3,38 +3,39 @@ + * Copyright (C) 2019 Richard Hughes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + + #ifndef __GSD_SUBMAN_COMMON_H + #define __GSD_SUBMAN_COMMON_H + + #include + + G_BEGIN_DECLS + + typedef enum { + GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN, + GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED, + GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID, ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS, + GSD_SUBMAN_SUBSCRIPTION_STATUS_LAST + } GsdSubmanSubscriptionStatus; + + const gchar *gsd_subman_subscription_status_to_string (GsdSubmanSubscriptionStatus status); + + G_END_DECLS + + #endif /* __GSD_SUBMAN_COMMON_H */ +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 0838d490..46f8d35c 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -242,60 +242,67 @@ _client_installed_products_update (GsdSubscriptionManager *manager, GError **err + product->version = g_strdup (json_array_get_string_element (json_product, 2)); + product->arch = g_strdup (json_array_get_string_element (json_product, 3)); + product->status = g_strdup (json_array_get_string_element (json_product, 4)); + product->starts = g_strdup (json_array_get_string_element (json_product, 6)); + product->ends = g_strdup (json_array_get_string_element (json_product, 7)); + + g_ptr_array_add (priv->installed_products, g_steal_pointer (&product)); + } + + /* emit notification for g-c-c */ + _emit_property_changed (manager, "InstalledProducts", + _make_installed_products_variant (priv->installed_products)); + + return TRUE; + } + + static gboolean + _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GVariant) uuid = NULL; + const gchar *uuid_txt = NULL; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; + g_autoptr(GVariant) status = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; ++ if (!_client_installed_products_update (manager, error)) ++ goto out; ++ ++ if (priv->installed_products->len == 0) { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS; ++ goto out; ++ } + + uuid = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONSUMER], + "GetUuid", + g_variant_new ("(s)", + "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (uuid == NULL) + return FALSE; + + g_variant_get (uuid, "(&s)", &uuid_txt); + + status = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], + "GetStatus", + g_variant_new ("(ss)", + "", /* assumed as 'now' */ + "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (status == NULL) + return FALSE; + g_variant_get (status, "(&s)", &json_txt); + g_debug ("Entitlement.GetStatus JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); + if (!json_object_has_member (json_obj, "valid")) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "no Entitlement.GetStatus valid in %s", json_txt); +@@ -563,62 +570,60 @@ _client_register_with_keys (GsdSubscriptionManager *manager, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + + if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) { + g_prefix_error (error, "failed to run pkexec: "); + return FALSE; + } + + rc = g_subprocess_get_exit_status (subprocess); + if (rc != 0) { + if (g_bytes_get_size (stderr_buf) == 0) { + g_set_error_literal (error, G_IO_ERROR, rc, + "Failed to run helper without stderr"); + return FALSE; + } + + g_set_error (error, G_IO_ERROR, rc, + "%.*s", + g_bytes_get_size (stderr_buf), + g_bytes_get_data (stderr_buf, NULL)); + } + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; +- if (!_client_installed_products_update (manager, error)) +- return FALSE; + _client_maybe__show_notification (manager); + + /* success */ + return TRUE; + } + + static gboolean + _client_register (GsdSubscriptionManager *manager, + const gchar *hostname, + const gchar *organisation, + const gchar *username, + const gchar *password, + GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; + g_autoptr(GBytes) stdin_buf = g_bytes_new (password, strlen (password) + 1); + g_autoptr(GBytes) stderr_buf = NULL; + gint rc; + + /* fallback */ + if (organisation == NULL) + organisation = ""; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, +@@ -632,62 +637,60 @@ _client_register (GsdSubscriptionManager *manager, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + + if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) { + g_prefix_error (error, "failed to run pkexec: "); + return FALSE; + } + + rc = g_subprocess_get_exit_status (subprocess); + if (rc != 0) { + if (g_bytes_get_size (stderr_buf) == 0) { + g_set_error_literal (error, G_IO_ERROR, rc, + "Failed to run helper without stderr"); + return FALSE; + } + + g_set_error (error, G_IO_ERROR, rc, + "%.*s", + g_bytes_get_size (stderr_buf), + g_bytes_get_data (stderr_buf, NULL)); + } + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; +- if (!_client_installed_products_update (manager, error)) +- return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } + + static gboolean + _client_unregister (GsdSubscriptionManager *manager, GError **error) + { + g_autoptr(GSubprocess) subprocess = NULL; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "unregister", + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + if (!_client_subprocess_wait_check (subprocess, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; + if (!_client_installed_products_update (manager, error)) + return FALSE; + _client_maybe__show_notification (manager); + return TRUE; +@@ -714,64 +717,60 @@ _client_update_config (GsdSubscriptionManager *manager, GError **error) + dict = g_variant_dict_new (g_variant_get_child_value (val, 0)); + val_server = g_variant_dict_lookup_value (dict, "server", G_VARIANT_TYPE("a{ss}")); + if (val_server != NULL) { + g_variant_iter_init (&iter, val_server); + while (g_variant_iter_next (&iter, "{ss}", &key, &value)) { + g_debug ("%s=%s", key, value); + g_hash_table_insert (priv->config, + g_steal_pointer (&key), + g_steal_pointer (&value)); + } + } + return TRUE; + } + + static void + _subman_proxy_signal_cb (GDBusProxy *proxy, + const gchar *sender_name, + const gchar *signal_name, + GVariant *parameters, + GsdSubscriptionManager *manager) + { + g_autoptr(GError) error = NULL; + if (!_client_syspurpose_update (manager, &error)) { + g_warning ("failed to update syspurpose: %s", error->message); + g_clear_error (&error); + } + if (!_client_subscription_status_update (manager, &error)) { + g_warning ("failed to update subscription status: %s", error->message); + g_clear_error (&error); + } +- if (!_client_installed_products_update (manager, &error)) { +- g_warning ("failed to update installed products: %s", error->message); +- g_clear_error (&error); +- } + _client_maybe__show_notification (manager); + } + + static void + _client_unload (GsdSubscriptionManager *manager) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + for (guint i = 0; i < _RHSM_INTERFACE_LAST; i++) + g_clear_object (&priv->proxies[i]); + g_hash_table_unref (priv->config); + } + + static const gchar * + _rhsm_interface_to_string (_RhsmInterface kind) + { + if (kind == _RHSM_INTERFACE_CONFIG) + return "Config"; + if (kind == _RHSM_INTERFACE_REGISTER_SERVER) + return "RegisterServer"; + if (kind == _RHSM_INTERFACE_ATTACH) + return "Attach"; + if (kind == _RHSM_INTERFACE_ENTITLEMENT) + return "Entitlement"; + if (kind == _RHSM_INTERFACE_PRODUCTS) + return "Products"; + if (kind == _RHSM_INTERFACE_CONSUMER) + return "Consumer"; + if (kind == _RHSM_INTERFACE_SYSPURPOSE) + return "Syspurpose"; + return NULL; +@@ -782,62 +781,60 @@ _client_load (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + + priv->config = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + /* connect to all the interfaces on the *different* objects :| */ + for (guint i = 0; i < _RHSM_INTERFACE_LAST; i++) { + const gchar *kind = _rhsm_interface_to_string (i); + g_autofree gchar *opath = g_strdup_printf ("/com/redhat/RHSM1/%s", kind); + g_autofree gchar *iface = g_strdup_printf ("com.redhat.RHSM1.%s", kind); + priv->proxies[i] = + g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "com.redhat.RHSM1", + opath, iface, + NULL, + error); + if (priv->proxies[i] == NULL) + return FALSE; + /* we want to get notified if the status of the system changes */ + g_signal_connect (priv->proxies[i], "g-signal", + G_CALLBACK (_subman_proxy_signal_cb), manager); + } + + /* get initial status */ + if (!_client_update_config (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; +- if (!_client_installed_products_update (manager, error)) +- return FALSE; + if (!_client_syspurpose_update (manager, error)) + return FALSE; + + /* success */ + return TRUE; + } + + gboolean + gsd_subscription_manager_start (GsdSubscriptionManager *manager, GError **error) + { + gboolean ret; + g_debug ("Starting subscription manager"); + gnome_settings_profile_start (NULL); + ret = _client_load (manager, error); + _client_maybe__show_notification (manager); + gnome_settings_profile_end (NULL); + return ret; + } + + void + gsd_subscription_manager_stop (GsdSubscriptionManager *manager) + { + g_debug ("Stopping subscription manager"); + _client_unload (manager); + } + + static void + gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); +-- +2.30.0 + diff --git a/SOURCES/0011-subman-Fix-some-build-warnings.patch b/SOURCES/0011-subman-Fix-some-build-warnings.patch new file mode 100644 index 0000000..2d70f9b --- /dev/null +++ b/SOURCES/0011-subman-Fix-some-build-warnings.patch @@ -0,0 +1,146 @@ +From 432850e943d72daedb1d352a0332d3fdee6078e2 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:26:40 -0500 +Subject: [PATCH 11/15] subman: Fix some build warnings + +--- + plugins/subman/gsd-subscription-manager.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 46f8d35c..1f9ca447 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -561,62 +561,62 @@ _client_register_with_keys (GsdSubscriptionManager *manager, + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-key", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + + if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) { + g_prefix_error (error, "failed to run pkexec: "); + return FALSE; + } + + rc = g_subprocess_get_exit_status (subprocess); + if (rc != 0) { + if (g_bytes_get_size (stderr_buf) == 0) { + g_set_error_literal (error, G_IO_ERROR, rc, + "Failed to run helper without stderr"); + return FALSE; + } + + g_set_error (error, G_IO_ERROR, rc, + "%.*s", +- g_bytes_get_size (stderr_buf), +- g_bytes_get_data (stderr_buf, NULL)); ++ (int) g_bytes_get_size (stderr_buf), ++ (char *) g_bytes_get_data (stderr_buf, NULL)); + } + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; + _client_maybe__show_notification (manager); + + /* success */ + return TRUE; + } + + static gboolean + _client_register (GsdSubscriptionManager *manager, + const gchar *hostname, + const gchar *organisation, + const gchar *username, + const gchar *password, + GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; + g_autoptr(GBytes) stdin_buf = g_bytes_new (password, strlen (password) + 1); + g_autoptr(GBytes) stderr_buf = NULL; + gint rc; + + /* fallback */ + if (organisation == NULL) + organisation = ""; +@@ -628,62 +628,62 @@ _client_register (GsdSubscriptionManager *manager, + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, + error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-username", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, + "--username", username, + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + + if (!g_subprocess_communicate (subprocess, stdin_buf, NULL, NULL, &stderr_buf, error)) { + g_prefix_error (error, "failed to run pkexec: "); + return FALSE; + } + + rc = g_subprocess_get_exit_status (subprocess); + if (rc != 0) { + if (g_bytes_get_size (stderr_buf) == 0) { + g_set_error_literal (error, G_IO_ERROR, rc, + "Failed to run helper without stderr"); + return FALSE; + } + + g_set_error (error, G_IO_ERROR, rc, + "%.*s", +- g_bytes_get_size (stderr_buf), +- g_bytes_get_data (stderr_buf, NULL)); ++ (int) g_bytes_get_size (stderr_buf), ++ (char *) g_bytes_get_data (stderr_buf, NULL)); + } + + /* FIXME: also do on error? */ + if (!_client_register_stop (manager, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } + + static gboolean + _client_unregister (GsdSubscriptionManager *manager, GError **error) + { + g_autoptr(GSubprocess) subprocess = NULL; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "unregister", + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + if (!_client_subprocess_wait_check (subprocess, error)) +-- +2.30.0 + diff --git a/SOURCES/0012-subman-Add-DBus-API-to-subscribe-for-updates-on-alre.patch b/SOURCES/0012-subman-Add-DBus-API-to-subscribe-for-updates-on-alre.patch new file mode 100644 index 0000000..30758fb --- /dev/null +++ b/SOURCES/0012-subman-Add-DBus-API-to-subscribe-for-updates-on-alre.patch @@ -0,0 +1,259 @@ +From 3bb3b2b09d34deafadd3cfe3355137afab20cb23 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:27:42 -0500 +Subject: [PATCH 12/15] subman: Add DBus API to subscribe for updates on + already registered system + +It's possible an admin may have registered their system without +attaching any subscriptions to it. + +At the moment, gnome-settings-daemon only provides a way to register +and subscribe in one step. + +This commit adds an API to support doing the last half of the process +on its own. +--- + plugins/subman/gsd-subscription-manager.c | 51 +++++++++++++++++++++++ + 1 file changed, 51 insertions(+) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 1f9ca447..705f8b11 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -19,60 +19,61 @@ + */ + + #include "config.h" + + #include + #include + #include + #include + #include + #include + + #include "gnome-settings-profile.h" + #include "gsd-subman-common.h" + #include "gsd-subscription-manager.h" + + #define GSD_DBUS_NAME "org.gnome.SettingsDaemon" + #define GSD_DBUS_PATH "/org/gnome/SettingsDaemon" + #define GSD_DBUS_BASE_INTERFACE "org.gnome.SettingsDaemon" + + #define GSD_SUBSCRIPTION_DBUS_NAME GSD_DBUS_NAME ".Subscription" + #define GSD_SUBSCRIPTION_DBUS_PATH GSD_DBUS_PATH "/Subscription" + #define GSD_SUBSCRIPTION_DBUS_INTERFACE GSD_DBUS_BASE_INTERFACE ".Subscription" + + static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " ++" " + " " + " " + " " + ""; + + #define GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SUBSCRIPTION_MANAGER, GsdSubscriptionManagerPrivate)) + + typedef enum { + _RHSM_INTERFACE_CONFIG, + _RHSM_INTERFACE_REGISTER_SERVER, + _RHSM_INTERFACE_ATTACH, + _RHSM_INTERFACE_ENTITLEMENT, + _RHSM_INTERFACE_PRODUCTS, + _RHSM_INTERFACE_CONSUMER, + _RHSM_INTERFACE_SYSPURPOSE, + _RHSM_INTERFACE_LAST + } _RhsmInterface; + + struct GsdSubscriptionManagerPrivate + { + /* D-Bus */ + guint name_id; + GDBusNodeInfo *introspection_data; + GDBusConnection *connection; + GCancellable *bus_cancellable; + + GDBusProxy *proxies[_RHSM_INTERFACE_LAST]; + GHashTable *config; /* str:str */ + GPtrArray *installed_products; + gchar *address; +@@ -669,60 +670,104 @@ _client_register (GsdSubscriptionManager *manager, + } + + static gboolean + _client_unregister (GsdSubscriptionManager *manager, GError **error) + { + g_autoptr(GSubprocess) subprocess = NULL; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "unregister", + NULL); + if (subprocess == NULL) { + g_prefix_error (error, "failed to find pkexec: "); + return FALSE; + } + if (!_client_subprocess_wait_check (subprocess, error)) + return FALSE; + if (!_client_subscription_status_update (manager, error)) + return FALSE; + if (!_client_installed_products_update (manager, error)) + return FALSE; + _client_maybe__show_notification (manager); + return TRUE; + } + ++static gboolean ++_client_attach (GsdSubscriptionManager *manager, ++ GError **error) ++{ ++ g_autoptr(GSubprocess) subprocess = NULL; ++ g_autoptr(GBytes) stderr_buf = NULL; ++ gint rc; ++ ++ g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); ++ subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDERR_PIPE, ++ error, ++ "pkexec", LIBEXECDIR "/gsd-subman-helper", ++ "--kind", "auto-attach", ++ NULL); ++ if (subprocess == NULL) { ++ g_prefix_error (error, "failed to find pkexec: "); ++ return FALSE; ++ } ++ ++ if (!g_subprocess_communicate (subprocess, NULL, NULL, NULL, &stderr_buf, error)) { ++ g_prefix_error (error, "failed to run pkexec: "); ++ return FALSE; ++ } ++ ++ rc = g_subprocess_get_exit_status (subprocess); ++ if (rc != 0) { ++ if (g_bytes_get_size (stderr_buf) == 0) { ++ g_set_error_literal (error, G_IO_ERROR, rc, ++ "Failed to run helper without stderr"); ++ return FALSE; ++ } ++ ++ g_set_error (error, G_IO_ERROR, rc, ++ "%.*s", ++ (int) g_bytes_get_size (stderr_buf), ++ (char *) g_bytes_get_data (stderr_buf, NULL)); ++ } ++ ++ if (!_client_subscription_status_update (manager, error)) ++ return FALSE; ++ _client_maybe__show_notification (manager); ++ return TRUE; ++} ++ + static gboolean + _client_update_config (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GVariant) val = NULL; + g_autoptr(GVariant) val_server = NULL; + g_autoptr(GVariantDict) dict = NULL; + GVariantIter iter; + gchar *key; + gchar *value; + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONFIG], + "GetAll", + g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + dict = g_variant_dict_new (g_variant_get_child_value (val, 0)); + val_server = g_variant_dict_lookup_value (dict, "server", G_VARIANT_TYPE("a{ss}")); + if (val_server != NULL) { + g_variant_iter_init (&iter, val_server); + while (g_variant_iter_next (&iter, "{ss}", &key, &value)) { + g_debug ("%s=%s", key, value); + g_hash_table_insert (priv->config, + g_steal_pointer (&key), + g_steal_pointer (&value)); + } + } + return TRUE; +@@ -1002,60 +1047,66 @@ handle_method_call (GDBusConnection *connection, + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } + } else if (g_strcmp0 (kind, "key") == 0) { + const gchar *activation_key = NULL; + g_variant_dict_lookup (dict, "hostname", "&s", &hostname); + g_variant_dict_lookup (dict, "organisation", "&s", &organisation); + g_variant_dict_lookup (dict, "activation-key", "&s", &activation_key); + if (!_client_register_with_keys (manager, + hostname, + organisation, + activation_key, + &error)) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } + } else { + g_dbus_method_invocation_return_error_literal (invocation, + G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid kind specified"); + + return; + } + g_dbus_method_invocation_return_value (invocation, NULL); + } else if (g_strcmp0 (method_name, "Unregister") == 0) { + if (!_client_unregister (manager, &error)) { + g_dbus_method_invocation_return_gerror (invocation, error); + return; + } + g_dbus_method_invocation_return_value (invocation, NULL); ++ } else if (g_strcmp0 (method_name, "Attach") == 0) { ++ if (!_client_attach (manager, &error)) { ++ g_dbus_method_invocation_return_gerror (invocation, error); ++ return; ++ } ++ g_dbus_method_invocation_return_value (invocation, NULL); + } else { + g_assert_not_reached (); + } + } + + static GVariant * + handle_get_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GError **error, gpointer user_data) + { + GsdSubscriptionManager *manager = GSD_SUBSCRIPTION_MANAGER (user_data); + GsdSubscriptionManagerPrivate *priv = manager->priv; + + if (g_strcmp0 (interface_name, GSD_SUBSCRIPTION_DBUS_INTERFACE) != 0) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "No such interface: %s", interface_name); + return NULL; + } + + if (g_strcmp0 (property_name, "SubscriptionStatus") == 0) + return g_variant_new_uint32 (priv->subscription_status); + + if (g_strcmp0 (property_name, "InstalledProducts") == 0) + return _make_installed_products_variant (priv->installed_products); + + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Failed to get property: %s", property_name); +-- +2.30.0 + diff --git a/SOURCES/0013-subman-Improve-subscription-status-handling.patch b/SOURCES/0013-subman-Improve-subscription-status-handling.patch new file mode 100644 index 0000000..40d6c68 --- /dev/null +++ b/SOURCES/0013-subman-Improve-subscription-status-handling.patch @@ -0,0 +1,141 @@ +From d9eb6331efa92cd28a8ba3ccc1665c3744296465 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:34:03 -0500 +Subject: [PATCH 13/15] subman: Improve subscription status handling + +This commit improves how subscription-manager status is +parsed to give more detailed information about subscription +state. +--- + plugins/subman/gsd-subscription-manager.c | 33 +++++++++++++++++++---- + 1 file changed, 28 insertions(+), 5 deletions(-) + +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 705f8b11..6d80bfa9 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -262,93 +262,116 @@ _client_subscription_status_update (GsdSubscriptionManager *manager, GError **er + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GVariant) uuid = NULL; + const gchar *uuid_txt = NULL; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; + g_autoptr(GVariant) status = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; + if (!_client_installed_products_update (manager, error)) + goto out; + + if (priv->installed_products->len == 0) { + priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS; + goto out; + } + + uuid = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONSUMER], + "GetUuid", + g_variant_new ("(s)", + "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (uuid == NULL) + return FALSE; + + g_variant_get (uuid, "(&s)", &uuid_txt); + ++ if (uuid_txt[0] == '\0') { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; ++ goto out; ++ } ++ + status = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], + "GetStatus", + g_variant_new ("(ss)", + "", /* assumed as 'now' */ + "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (status == NULL) + return FALSE; + g_variant_get (status, "(&s)", &json_txt); + g_debug ("Entitlement.GetStatus JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; + json_root = json_parser_get_root (json_parser); + json_obj = json_node_get_object (json_root); ++ ++ const gchar *status_id = NULL; ++ ++ if (json_object_has_member (json_obj, "status_id")) { ++ status_id = json_object_get_string_member (json_obj, "status_id"); ++ } ++ + if (!json_object_has_member (json_obj, "valid")) { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "no Entitlement.GetStatus valid in %s", json_txt); + return FALSE; + } + + gboolean is_valid = json_object_get_boolean_member (json_obj, "valid"); + +- if (uuid_txt[0] != '\0') { +- if (is_valid) { ++ if (is_valid) { ++ if (g_strcmp0 (status_id, "disabled") != 0) { + priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID; + } else { +- priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED; ++ } ++ goto out; ++ } ++ ++ for (guint i = 0; i < priv->installed_products->len; i++) { ++ ProductData *product = g_ptr_array_index (priv->installed_products, i); ++ ++ if (g_strcmp0 (product->status, "subscribed") == 0) { ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID; ++ goto out; + } +- } else { +- priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; + } + ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID; ++ ++out: + /* emit notification for g-c-c */ + if (priv->subscription_status != priv->subscription_status_last) { + _emit_property_changed (manager, "SubscriptionStatus", + g_variant_new_uint32 (priv->subscription_status)); + } + + return TRUE; + } + + static gboolean + _client_syspurpose_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; + g_autoptr(GVariant) val = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + val = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_SYSPURPOSE], + "GetSyspurpose", + g_variant_new ("(s)", "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (val == NULL) + return FALSE; + g_variant_get (val, "(&s)", &json_txt); + g_debug ("Syspurpose.GetSyspurpose JSON: %s", json_txt); + if (!json_parser_load_from_data (json_parser, json_txt, -1, error)) + return FALSE; +-- +2.30.0 + diff --git a/SOURCES/0014-subman-Drop-LAST-from-status-enum.patch b/SOURCES/0014-subman-Drop-LAST-from-status-enum.patch new file mode 100644 index 0000000..4f5c99e --- /dev/null +++ b/SOURCES/0014-subman-Drop-LAST-from-status-enum.patch @@ -0,0 +1,56 @@ +From a78b25b9507edb958a46779f2bb808bf678fa4a7 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 11:55:19 -0500 +Subject: [PATCH 14/15] subman: Drop "LAST" from status enum + +It's unused, so get rid of it. +--- + plugins/subman/gsd-subman-common.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/plugins/subman/gsd-subman-common.h b/plugins/subman/gsd-subman-common.h +index f8a3d9f4..88226564 100644 +--- a/plugins/subman/gsd-subman-common.h ++++ b/plugins/subman/gsd-subman-common.h +@@ -4,38 +4,37 @@ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + + #ifndef __GSD_SUBMAN_COMMON_H + #define __GSD_SUBMAN_COMMON_H + + #include + + G_BEGIN_DECLS + + typedef enum { + GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN, + GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED, + GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS, +- GSD_SUBMAN_SUBSCRIPTION_STATUS_LAST + } GsdSubmanSubscriptionStatus; + + const gchar *gsd_subman_subscription_status_to_string (GsdSubmanSubscriptionStatus status); + + G_END_DECLS + + #endif /* __GSD_SUBMAN_COMMON_H */ +-- +2.30.0 + diff --git a/SOURCES/0015-subman-Clean-up-notification-behavior.patch b/SOURCES/0015-subman-Clean-up-notification-behavior.patch new file mode 100644 index 0000000..96585cd --- /dev/null +++ b/SOURCES/0015-subman-Clean-up-notification-behavior.patch @@ -0,0 +1,419 @@ +From 3412be1f63df2a5967ef92c27028368df1646b5c Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Sun, 24 Jan 2021 12:41:20 -0500 +Subject: [PATCH 15/15] subman: Clean up notification behavior + +Notifications were only displayed for some status transitions. + +This commit introduces some booleans based on the old and new +statuses to make the code clearer and to make it easier to hit +all the cases. +--- + plugins/subman/gsd-subman-common.h | 1 + + plugins/subman/gsd-subscription-manager.c | 141 ++++++++++++++++++---- + 2 files changed, 120 insertions(+), 22 deletions(-) + +diff --git a/plugins/subman/gsd-subman-common.h b/plugins/subman/gsd-subman-common.h +index 88226564..9397dbe4 100644 +--- a/plugins/subman/gsd-subman-common.h ++++ b/plugins/subman/gsd-subman-common.h +@@ -1,40 +1,41 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2019 Richard Hughes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + + #ifndef __GSD_SUBMAN_COMMON_H + #define __GSD_SUBMAN_COMMON_H + + #include + + G_BEGIN_DECLS + + typedef enum { ++ GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ = -1, + GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN, + GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED, + GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS, + } GsdSubmanSubscriptionStatus; + + const gchar *gsd_subman_subscription_status_to_string (GsdSubmanSubscriptionStatus status); + + G_END_DECLS + + #endif /* __GSD_SUBMAN_COMMON_H */ +diff --git a/plugins/subman/gsd-subscription-manager.c b/plugins/subman/gsd-subscription-manager.c +index 6d80bfa9..aaccbbc6 100644 +--- a/plugins/subman/gsd-subscription-manager.c ++++ b/plugins/subman/gsd-subscription-manager.c +@@ -243,60 +243,61 @@ _client_installed_products_update (GsdSubscriptionManager *manager, GError **err + product->version = g_strdup (json_array_get_string_element (json_product, 2)); + product->arch = g_strdup (json_array_get_string_element (json_product, 3)); + product->status = g_strdup (json_array_get_string_element (json_product, 4)); + product->starts = g_strdup (json_array_get_string_element (json_product, 6)); + product->ends = g_strdup (json_array_get_string_element (json_product, 7)); + + g_ptr_array_add (priv->installed_products, g_steal_pointer (&product)); + } + + /* emit notification for g-c-c */ + _emit_property_changed (manager, "InstalledProducts", + _make_installed_products_variant (priv->installed_products)); + + return TRUE; + } + + static gboolean + _client_subscription_status_update (GsdSubscriptionManager *manager, GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GVariant) uuid = NULL; + const gchar *uuid_txt = NULL; + JsonNode *json_root; + JsonObject *json_obj; + const gchar *json_txt = NULL; + g_autoptr(GVariant) status = NULL; + g_autoptr(JsonParser) json_parser = json_parser_new (); + + /* save old value */ + priv->subscription_status_last = priv->subscription_status; ++ + if (!_client_installed_products_update (manager, error)) + goto out; + + if (priv->installed_products->len == 0) { + priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS; + goto out; + } + + uuid = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_CONSUMER], + "GetUuid", + g_variant_new ("(s)", + "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, error); + if (uuid == NULL) + return FALSE; + + g_variant_get (uuid, "(&s)", &uuid_txt); + + if (uuid_txt[0] == '\0') { + priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; + goto out; + } + + status = g_dbus_proxy_call_sync (priv->proxies[_RHSM_INTERFACE_ENTITLEMENT], + "GetStatus", + g_variant_new ("(ss)", + "", /* assumed as 'now' */ + "C.UTF-8"), + G_DBUS_CALL_FLAGS_NONE, +@@ -485,109 +486,203 @@ typedef enum { + static void + _show_notification (GsdSubscriptionManager *manager, _NotifyKind notify_kind) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + switch (notify_kind) { + case _NOTIFY_EXPIRED: + notify_notification_close (priv->notification_registered, NULL); + notify_notification_close (priv->notification_registration_required, NULL); + notify_notification_show (priv->notification_expired, NULL); + break; + case _NOTIFY_REGISTRATION_REQUIRED: + notify_notification_close (priv->notification_registered, NULL); + notify_notification_close (priv->notification_expired, NULL); + notify_notification_show (priv->notification_registration_required, NULL); + break; + case _NOTIFY_REGISTERED: + notify_notification_close (priv->notification_expired, NULL); + notify_notification_close (priv->notification_registration_required, NULL); + notify_notification_show (priv->notification_registered, NULL); + break; + default: + break; + } + g_timer_reset (priv->timer_last_notified); + } + + static void + _client_maybe__show_notification (GsdSubscriptionManager *manager) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; ++ gboolean was_read, was_registered, had_subscriptions, needed_subscriptions; ++ gboolean is_read, is_registered, has_subscriptions, needs_subscriptions; ++ ++ switch (priv->subscription_status_last) { ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ: ++ was_read = FALSE; ++ was_registered = FALSE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN: ++ was_read = TRUE; ++ was_registered = FALSE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID: ++ was_read = TRUE; ++ was_registered = TRUE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = TRUE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID: ++ was_read = TRUE; ++ was_registered = TRUE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED: ++ was_read = TRUE; ++ was_registered = TRUE; ++ needed_subscriptions = FALSE; ++ had_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID: ++ was_read = TRUE; ++ was_registered = TRUE; ++ needed_subscriptions = TRUE; ++ had_subscriptions = FALSE; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS: ++ was_read = TRUE; ++ was_registered = FALSE; ++ needed_subscriptions = FALSE; ++ had_subscriptions = FALSE; ++ break; ++ } ++ ++ switch (priv->subscription_status) { ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ: ++ is_read = FALSE; ++ is_registered = FALSE; ++ needs_subscriptions = TRUE; ++ has_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN: ++ is_read = TRUE; ++ is_registered = FALSE; ++ needs_subscriptions = TRUE; ++ has_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID: ++ is_read = TRUE; ++ is_registered = TRUE; ++ needs_subscriptions = TRUE; ++ has_subscriptions = TRUE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID: ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID: ++ is_read = TRUE; ++ is_registered = TRUE; ++ needs_subscriptions = TRUE; ++ has_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED: ++ is_read = TRUE; ++ is_registered = TRUE; ++ needs_subscriptions = FALSE; ++ has_subscriptions = FALSE; ++ break; ++ case GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS: ++ is_read = TRUE; ++ is_registered = FALSE; ++ needs_subscriptions = FALSE; ++ has_subscriptions = FALSE; ++ break; ++ } + + /* startup */ +- if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && +- priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN) { ++ if (!was_read && is_read && priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN) { + _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); + return; + } + + /* something changed */ +- if (priv->subscription_status_last != priv->subscription_status) { ++ if (was_read && is_read && priv->subscription_status_last != priv->subscription_status) { + g_debug ("transisition from subscription status '%s' to '%s'", + gsd_subman_subscription_status_to_string (priv->subscription_status_last), + gsd_subman_subscription_status_to_string (priv->subscription_status)); + +- /* needs registration */ +- if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && +- priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID) { +- _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); ++ /* needs subscription */ ++ if (is_registered && needs_subscriptions && !has_subscriptions) { ++ _show_notification (manager, _NOTIFY_EXPIRED); + return; + } + + /* was unregistered */ +- if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && +- priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN) { ++ if (was_registered && !is_registered) { + _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); + return; + } + +- /* registered */ +- if (priv->subscription_status_last == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && +- priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID && +- g_timer_elapsed (priv->timer_last_notified, NULL) > 60) { +- _show_notification (manager, _NOTIFY_REGISTERED); +- return; ++ /* just registered */ ++ if (!was_registered && is_registered) { ++ if (!needs_subscriptions || has_subscriptions) { ++ _show_notification (manager, _NOTIFY_REGISTERED); ++ return; ++ } ++ } ++ ++ /* subscriptions changed */ ++ if (was_registered && is_registered) { ++ /* subscribed */ ++ if (!had_subscriptions && ++ needs_subscriptions && has_subscriptions) { ++ _show_notification (manager, _NOTIFY_REGISTERED); ++ return; ++ } ++ ++ /* simple content access enabled */ ++ if (needed_subscriptions && !had_subscriptions && !needs_subscriptions) { ++ _show_notification (manager, _NOTIFY_REGISTERED); ++ return; ++ } + } + } + + /* nag again */ +- if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN && ++ if (!is_registered && + g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { + _show_notification (manager, _NOTIFY_REGISTRATION_REQUIRED); + return; + } +- if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID && +- g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { +- _show_notification (manager, _NOTIFY_EXPIRED); +- return; +- } +- if (priv->subscription_status == GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID && ++ if (is_registered && !has_subscriptions && needs_subscriptions && + g_timer_elapsed (priv->timer_last_notified, NULL) > 60 * 60 * 24) { + _show_notification (manager, _NOTIFY_EXPIRED); + return; + } + } + + static gboolean + _client_register_with_keys (GsdSubscriptionManager *manager, + const gchar *hostname, + const gchar *organisation, + const gchar *activation_key, + GError **error) + { + GsdSubscriptionManagerPrivate *priv = manager->priv; + g_autoptr(GSubprocess) subprocess = NULL; + g_autoptr(GBytes) stdin_buf = g_bytes_new (activation_key, strlen (activation_key) + 1); + g_autoptr(GBytes) stderr_buf = NULL; + gint rc; + + /* apparently: "we can't send registration credentials over the regular + * system or session bus since those aren't really locked down..." */ + if (!_client_register_start (manager, error)) + return FALSE; + g_debug ("spawning %s", LIBEXECDIR "/gsd-subman-helper"); + subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDERR_PIPE, error, + "pkexec", LIBEXECDIR "/gsd-subman-helper", + "--kind", "register-with-key", + "--address", priv->address, + "--hostname", hostname, + "--organisation", organisation, +@@ -914,60 +1009,62 @@ gsd_subscription_manager_class_init (GsdSubscriptionManagerClass *klass) + static void + _launch_info_overview (void) + { + const gchar *argv[] = { "gnome-control-center", "info-overview", NULL }; + g_debug ("Running gnome-control-center info-overview"); + g_spawn_async (NULL, (gchar **) argv, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL); + } + + static void + _notify_closed_cb (NotifyNotification *notification, gpointer user_data) + { + /* FIXME: only launch when clicking on the main body, not the window close */ + if (notify_notification_get_closed_reason (notification) == 0x400) + _launch_info_overview (); + } + + static void + _notify_clicked_cb (NotifyNotification *notification, char *action, gpointer user_data) + { + _launch_info_overview (); + } + + static void + gsd_subscription_manager_init (GsdSubscriptionManager *manager) + { + GsdSubscriptionManagerPrivate *priv = manager->priv = GSD_SUBSCRIPTION_MANAGER_GET_PRIVATE (manager); + + priv->installed_products = g_ptr_array_new_with_free_func ((GDestroyNotify) product_data_free); + priv->timer_last_notified = g_timer_new (); ++ priv->subscription_status = GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ; ++ priv->subscription_status_last = GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ; + + /* expired */ + priv->notification_expired = + notify_notification_new (_("Subscription Has Expired"), + _("Add or renew a subscription to continue receiving software updates."), + NULL); + notify_notification_set_app_name (priv->notification_expired, _("Subscription")); + notify_notification_set_hint_string (priv->notification_expired, "desktop-entry", "subman-panel"); + notify_notification_set_hint_string (priv->notification_expired, "x-gnome-privacy-scope", "system"); + notify_notification_set_urgency (priv->notification_expired, NOTIFY_URGENCY_CRITICAL); + notify_notification_add_action (priv->notification_expired, + "info-overview", _("Subscribe System…"), + _notify_clicked_cb, + manager, NULL); + g_signal_connect (priv->notification_expired, "closed", + G_CALLBACK (_notify_closed_cb), manager); + + /* registered */ + priv->notification_registered = + notify_notification_new (_("Registration Successful"), + _("The system has been registered and software updates have been enabled."), + NULL); + notify_notification_set_app_name (priv->notification_registered, _("Subscription")); + notify_notification_set_hint_string (priv->notification_registered, "desktop-entry", "subman-panel"); + notify_notification_set_hint_string (priv->notification_registered, "x-gnome-privacy-scope", "system"); + notify_notification_set_urgency (priv->notification_registered, NOTIFY_URGENCY_CRITICAL); + g_signal_connect (priv->notification_registered, "closed", + G_CALLBACK (_notify_closed_cb), manager); + + /* registration required */ +-- +2.30.0 + diff --git a/SPECS/gnome-settings-daemon.spec b/SPECS/gnome-settings-daemon.spec index 8eaa46f..3faa344 100644 --- a/SPECS/gnome-settings-daemon.spec +++ b/SPECS/gnome-settings-daemon.spec @@ -6,9 +6,13 @@ %global libgweather_version 3.9.5 %global geoclue_version 2.3.1 +%if %{undefined centos} +%bcond_without subman +%endif + Name: gnome-settings-daemon Version: 3.32.0 -Release: 9%{?dist} +Release: 13%{?dist} Summary: The daemon sharing settings from GNOME to GTK+/KDE applications License: GPLv2+ @@ -21,6 +25,7 @@ BuildRequires: gcc BuildRequires: cups-devel BuildRequires: gettext BuildRequires: perl-interpreter +BuildRequires: git BuildRequires: pkgconfig(alsa) BuildRequires: pkgconfig(colord) >= 1.0.2 BuildRequires: pkgconfig(fontconfig) @@ -32,7 +37,9 @@ BuildRequires: pkgconfig(gsettings-desktop-schemas) >= %{gsettings_desktop_sche BuildRequires: pkgconfig(gtk+-3.0) >= %{gtk3_version} BuildRequires: pkgconfig(gudev-1.0) BuildRequires: pkgconfig(gweather-3.0) >= %{libgweather_version} +%if %{with subman} BuildRequires: pkgconfig(json-glib-1.0) +%endif BuildRequires: pkgconfig(lcms2) >= 2.2 BuildRequires: pkgconfig(libcanberra-gtk3) BuildRequires: pkgconfig(libgeoclue-2.0) @@ -76,19 +83,37 @@ Conflicts: gnome-session < 3.27.90 # older gdm, gnome-session and gnome-shell releases that expect the functionality Conflicts: gnome-shell < 3.25.4 +# account plugin Patch00001: 0001-account-first-cut-at-account-plugin.patch Patch00002: 0002-account-reshow-the-notification-when-screen-unlocks.patch Patch00003: 0003-account-display-nag-screen-periodically.patch Patch00004: 0004-account-don-t-poll-more-frequently-than-notification.patch -Patch00005: 0001-smartcard-Cancel-cancellable-when-stopping.patch -Patch00006: 0001-xsettings-Add-an-entry-for-the-overlay-scrolling-set.patch -Patch10001: 0001-housekeeping-Add-a-GPU-memory-usage-notification.patch +Patch10001: 0001-smartcard-Cancel-cancellable-when-stopping.patch -# Subscription manager integration -Patch10002: 0001-subman-Add-a-new-plugin-to-provide-system-subscripti.patch -Patch10003: 0001-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch -Patch10004: 0001-subman-Increase-RHSM-dbus-call-timeouts.patch +Patch20001: 0001-xsettings-Add-an-entry-for-the-overlay-scrolling-set.patch + +# Handle org.gnome.Shell.Screencast Stopped signal (#1705392) +Patch30001: 0001-media-keys-Mark-screen-cast-as-stopped-if-it-was-sig.patch + +Patch40001: 0001-housekeeping-Add-a-GPU-memory-usage-notification.patch + +# subscription manager integration +Patch50001: 0001-subman-Add-a-new-plugin-to-provide-system-subscripti.patch +Patch50002: 0002-subman-Add-InstalledProducts-dbus-property-for-g-c-c.patch +Patch50003: 0003-subman-Increase-RHSM-dbus-call-timeouts.patch +Patch50004: 0004-subman-Drop-userlang-field.patch +Patch50005: 0005-subman-Use-user-locale-for-registration-subscription.patch +Patch50006: 0006-subman-Handle-subscription-manager-giving-invalid-st.patch +Patch50007: 0007-subman-Force-re-subscribe-if-the-admin-already-subsc.patch +Patch50008: 0008-subman-Don-t-send-secrets-through-command-line.patch +Patch50009: 0009-subman-Don-t-treat-failure-to-attach-as-fatal.patch +Patch50010: 0010-subman-Add-new-no-installed-products-state.patch +Patch50011: 0011-subman-Fix-some-build-warnings.patch +Patch50012: 0012-subman-Add-DBus-API-to-subscribe-for-updates-on-alre.patch +Patch50013: 0013-subman-Improve-subscription-status-handling.patch +Patch50014: 0014-subman-Drop-LAST-from-status-enum.patch +Patch50015: 0015-subman-Clean-up-notification-behavior.patch %description A daemon to share settings from GNOME to other applications. It also @@ -103,7 +128,7 @@ The %{name}-devel package contains libraries and header files for developing applications that use %{name}. %prep -%autosetup -p1 +%autosetup -S git %build %meson @@ -220,6 +245,22 @@ mkdir $RPM_BUILD_ROOT%{_libdir}/gnome-settings-daemon-3.0/gtk-modules %{_libdir}/pkgconfig/gnome-settings-daemon.pc %changelog +* Thu Jan 21 2021 Ray Strode - 3.32.0-13 +- Add back subscription-manager plugin + Related: #1870837 + +* Tue Jan 05 2021 Jonas Ådahl - 3.32.0-12 +- Handle org.gnome.Shell.Screencast Stopped signal + Related: #1705392 + +* Wed Sep 02 2020 Ray Strode - 3.32.0-11 +- Remove subman plugin for now + Resolves: #1872457 + +* Thu Aug 13 2020 Carl George - 3.32.0-10 +- Disable subman plugin on CentOS + Resolves: #1827030 + * Fri Nov 22 2019 Benjamin Otte - 3.32.0-9 - Update gsettings-deskto-schemas dependency for new setting Resolves: #1775683, #1723462