751739
From 51d5c9e9baec33aa74a60a4ac11f1de8f71acb2a Mon Sep 17 00:00:00 2001
751739
From: Ray Strode <rstrode@redhat.com>
751739
Date: Fri, 12 Oct 2018 15:53:52 -0400
751739
Subject: [PATCH] lib: save os when creating user
751739
751739
In order to identify that a user has upgraded from rhel 7 to
751739
rhel 8, we need to know what os they were using when created.
751739
751739
This commit saves that information using a red hat specific
751739
extension to accountsservice.
751739
---
751739
 data/Makefile.am                              |  14 +-
751739
 .../com.redhat.AccountsServiceUser.System.xml |  10 ++
751739
 src/libaccountsservice/Makefile.am            |  12 +-
751739
 src/libaccountsservice/act-user-manager.c     | 123 ++++++++++++++++++
751739
 4 files changed, 157 insertions(+), 2 deletions(-)
751739
 create mode 100644 data/com.redhat.AccountsServiceUser.System.xml
751739
751739
diff --git a/data/Makefile.am b/data/Makefile.am
751739
index 6cf5e30..648774c 100644
751739
--- a/data/Makefile.am
751739
+++ b/data/Makefile.am
751739
@@ -1,45 +1,57 @@
751739
 
751739
 dbusifdir   = $(datadir)/dbus-1/interfaces
751739
 dbusif_DATA = \
751739
 	org.freedesktop.Accounts.xml 		\
751739
-	org.freedesktop.Accounts.User.xml
751739
+	org.freedesktop.Accounts.User.xml	\
751739
+	com.redhat.AccountsServiceUser.System.xml
751739
 
751739
 dbusconfdir   = $(sysconfdir)/dbus-1/system.d
751739
 dbusconf_DATA = org.freedesktop.Accounts.conf
751739
 
751739
+accountsserviceifdir = $(datadir)/accountsservice/interfaces
751739
+
751739
 servicedir       = $(datadir)/dbus-1/system-services
751739
 service_in_files = org.freedesktop.Accounts.service.in
751739
 service_DATA     = $(service_in_files:.service.in=.service)
751739
 
751739
 $(service_DATA): $(service_in_files) Makefile
751739
 	@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< >$@
751739
 
751739
 policydir       = $(datadir)/polkit-1/actions
751739
 policy_in_files = org.freedesktop.accounts.policy.in
751739
 policy_DATA     = $(policy_in_files:.policy.in=.policy)
751739
 
751739
 @INTLTOOL_POLICY_RULE@
751739
 
751739
 if HAVE_SYSTEMD
751739
 systemdsystemunit_DATA = \
751739
 	accounts-daemon.service
751739
 
751739
 accounts-daemon.service: accounts-daemon.service.in
751739
 	@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< >$@
751739
 
751739
 endif
751739
 
751739
 EXTRA_DIST = 			\
751739
 	$(dbusif_DATA)		\
751739
 	$(dbusconf_DATA)	\
751739
 	$(service_in_files)	\
751739
 	$(policy_in_files)      \
751739
 	org.freedesktop.realmd.xml	\
751739
 	accounts-daemon.service.in
751739
 
751739
 DISTCLEANFILES = 		\
751739
 	$(service_DATA)		\
751739
 	$(policy_DATA)
751739
 
751739
 CLEANFILES = \
751739
 	accounts-daemon.service
751739
+
751739
+install-data-hook: com.redhat.AccountsServiceUser.System.xml
751739
+	if test '!' -d $(DESTDIR)$(accountsserviceifdir); then \
751739
+	        $(mkinstalldirs) $(DESTDIR)$(accountsserviceifdir); \
751739
+	        chmod 755 $(DESTDIR)$(accountsserviceifdir); \
751739
+	fi
751739
+	if test '!' -L $(DESTDIR)$(accountsserviceifdir)/com.redhat.AccountsServiceUser.System.xml; then \
751739
+	        (cd $(DESTDIR)$(accountsserviceifdir); $(LN_S) ../../dbus-1/interfaces/com.redhat.AccountsServiceUser.System.xml) \
751739
+	fi
751739
diff --git a/data/com.redhat.AccountsServiceUser.System.xml b/data/com.redhat.AccountsServiceUser.System.xml
751739
new file mode 100644
751739
index 0000000..67f5f30
751739
--- /dev/null
751739
+++ b/data/com.redhat.AccountsServiceUser.System.xml
751739
@@ -0,0 +1,10 @@
751739
+<node>
751739
+  <interface name="com.redhat.AccountsServiceUser.System">
751739
+
751739
+    <annotation name="org.freedesktop.Accounts.VendorExtension" value="true"/>
751739
+
751739
+    <property name="id" type="s" access="readwrite"/>
751739
+    <property name="version-id" type="s" access="readwrite"/>
751739
+
751739
+  </interface>
751739
+</node>
751739
diff --git a/src/libaccountsservice/Makefile.am b/src/libaccountsservice/Makefile.am
751739
index 408d91f..d711d65 100644
751739
--- a/src/libaccountsservice/Makefile.am
751739
+++ b/src/libaccountsservice/Makefile.am
751739
@@ -20,69 +20,79 @@ act-user-enum-types.h: act-user.h act-user-manager.h
751739
 	$(AM_V_GEN) (cd $(srcdir) && \
751739
 	         glib-mkenums \
751739
 	          --fhead "#ifndef __ACT_USER_ENUM_TYPES_H__\n#define __ACT_USER_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
751739
 	          --fprod "/* enumerations from \"@filename@\" */\n" \
751739
 	          --vhead "GType @enum_name@_get_type (void);\n#define ACT_USER_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n"    \
751739
 	          --ftail "G_END_DECLS\n\n#endif /* __ACT_USER_ENUM_TYPES_H__ */" \
751739
 	          $(^F) ) > $@
751739
 
751739
 act-user-enum-types.c: act-user.h act-user-manager.h act-user-enum-types.h
751739
 	$(AM_V_GEN) (cd $(srcdir) && \
751739
 	         glib-mkenums \
751739
 	          --fhead "#include \"act-user.h\"\n" \
751739
 	          --fhead "#include \"act-user-manager.h\"\n" \
751739
 	          --fhead "#include \"act-user-enum-types.h\"\n" \
751739
 	          --fhead "#include <glib-object.h>" \
751739
 	          --fprod "\n/* enumerations from \"@filename@\" */" \
751739
 	          --vhead "GType\n@enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if (etype == 0) {\n    static const G@Type@Value values[] = {"    \
751739
 	          --vprod "      { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
751739
 	          --vtail "      { 0, NULL, NULL }\n    };\n    etype = g_@type@_register_static (\"@EnumName@\", values);\n  }\n  return etype;\n}\n" \
751739
 	         $(^F) ) > $@
751739
 
751739
 ck-manager-generated.c ck-manager-generated.h: org.freedesktop.ConsoleKit.Manager.xml Makefile
751739
 	$(AM_V_GEN) gdbus-codegen --generate-c-code ck-manager-generated --c-namespace ConsoleKit --interface-prefix=org.freedesktop.ConsoleKit $(srcdir)/org.freedesktop.ConsoleKit.Manager.xml
751739
 
751739
 ck-seat-generated.c ck-seat-generated.h: org.freedesktop.ConsoleKit.Seat.xml Makefile
751739
 	$(AM_V_GEN) gdbus-codegen --generate-c-code ck-seat-generated --c-namespace ConsoleKit --interface-prefix=org.freedesktop.ConsoleKit $(srcdir)/org.freedesktop.ConsoleKit.Seat.xml
751739
 
751739
 ck-session-generated.c ck-session-generated.h: org.freedesktop.ConsoleKit.Session.xml Makefile
751739
 	$(AM_V_GEN) gdbus-codegen --generate-c-code ck-session-generated --c-namespace ConsoleKit --interface-prefix=org.freedesktop.ConsoleKit $(srcdir)/org.freedesktop.ConsoleKit.Session.xml
751739
 
751739
+com.redhat.AccountsServiceUser.System.c com.redhat.AccountsServiceUser.System.h: $(top_srcdir)/data/com.redhat.AccountsServiceUser.System.xml Makefile
751739
+	$(AM_V_GEN)gdbus-codegen                                        \
751739
+	        --c-namespace=Act                                       \
751739
+	        --interface-prefix=com.redhat.AccountsService           \
751739
+	        --generate-c-code=com.redhat.AccountsServiceUser.System \
751739
+	        $(top_srcdir)/data/com.redhat.AccountsServiceUser.System.xml
751739
+
751739
+
751739
 BUILT_SOURCES += \
751739
 	act-user-enum-types.c	\
751739
 	act-user-enum-types.h	\
751739
 	ck-manager-generated.c		\
751739
 	ck-manager-generated.h		\
751739
 	ck-seat-generated.c			\
751739
 	ck-seat-generated.h			\
751739
 	ck-session-generated.c		\
751739
-	ck-session-generated.h
751739
+	ck-session-generated.h	\
751739
+	com.redhat.AccountsServiceUser.System.h \
751739
+	com.redhat.AccountsServiceUser.System.c
751739
 
751739
 CLEANFILES += $(BUILT_SOURCES)
751739
 
751739
 libaccountsservicedir = $(includedir)/accountsservice-1.0/act
751739
 libaccountsservice_headers =                                                  \
751739
         act-user.h                                                            \
751739
         act-user-manager.h                                                    \
751739
         act-user-enum-types.h                                                 \
751739
         $(END_OF_LIST)
751739
 
751739
 libaccountsservice_HEADERS =                                                  \
751739
         act.h                                                                 \
751739
         $(libaccountsservice_headers)                                         \
751739
         $(END_OF_LIST)
751739
 
751739
 
751739
 libaccountsservice_la_CFLAGS = $(LIBACCOUNTSSERVICE_CFLAGS)
751739
 libaccountsservice_la_LDFLAGS =                                               \
751739
         -export-symbols-regex '^[^_].*'                                       \
751739
         -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)                  \
751739
         -no-undefined                                                         \
751739
         $(END_OF_LIST)
751739
 
751739
 libaccountsservice_la_LIBADD =                                                \
751739
 	../libaccounts-generated.la						\
751739
         $(LIBACCOUNTSSERVICE_LIBS)                                            \
751739
         -lcrypt                                                               \
751739
         $(END_OF_LIST)
751739
 
751739
 libaccountsservice_la_sources =                                               \
751739
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c
751739
index e7e26b1..9f3d6e5 100644
751739
--- a/src/libaccountsservice/act-user-manager.c
751739
+++ b/src/libaccountsservice/act-user-manager.c
751739
@@ -27,60 +27,61 @@
751739
 #include <string.h>
751739
 #include <signal.h>
751739
 #include <errno.h>
751739
 #include <sys/stat.h>
751739
 #include <sys/types.h>
751739
 
751739
 #ifdef HAVE_PATHS_H
751739
 #include <paths.h>
751739
 #endif /* HAVE_PATHS_H */
751739
 
751739
 #include <glib.h>
751739
 #include <glib/gi18n-lib.h>
751739
 #include <glib/gstdio.h>
751739
 #include <glib-object.h>
751739
 #include <gio/gio.h>
751739
 #include <gio/gunixinputstream.h>
751739
 
751739
 #ifdef WITH_SYSTEMD
751739
 #include <systemd/sd-login.h>
751739
 
751739
 /* check if logind is running */
751739
 #define LOGIND_RUNNING() (access("/run/systemd/seats/", F_OK) >= 0)
751739
 #endif
751739
 
751739
 #include "act-user-manager.h"
751739
 #include "act-user-private.h"
751739
 #include "accounts-generated.h"
751739
 #include "ck-manager-generated.h"
751739
 #include "ck-seat-generated.h"
751739
 #include "ck-session-generated.h"
751739
+#include "com.redhat.AccountsServiceUser.System.h"
751739
 
751739
 /**
751739
  * SECTION:act-user-manager
751739
  * @title: ActUserManager
751739
  * @short_description: manages ActUser objects
751739
  *
751739
  * ActUserManager is a manager object that gives access to user
751739
  * creation, deletion, enumeration, etc.
751739
  *
751739
  * There is typically a singleton ActUserManager object, which
751739
  * can be obtained by act_user_manager_get_default().
751739
  */
751739
 
751739
 /**
751739
  * ActUserManager:
751739
  *
751739
  * A user manager object.
751739
  */
751739
 
751739
 /**
751739
  * ACT_USER_MANAGER_ERROR:
751739
  *
751739
  * The GError domain for #ActUserManagerError errors
751739
  */
751739
 
751739
 /**
751739
  * ActUserManagerError:
751739
  * @ACT_USER_MANAGER_ERROR_FAILED: Generic failure
751739
  * @ACT_USER_MANAGER_ERROR_USER_EXISTS: The user already exists
751739
  * @ACT_USER_MANAGER_ERROR_USER_DOES_NOT_EXIST: The user does not exist
751739
@@ -167,60 +168,63 @@ typedef struct
751739
         ActUser                    *user;
751739
         ActUserManagerFetchUserRequestType type;
751739
         union {
751739
                 char               *username;
751739
                 uid_t               uid;
751739
         };
751739
         char                       *object_path;
751739
         char                       *description;
751739
 } ActUserManagerFetchUserRequest;
751739
 
751739
 struct ActUserManagerPrivate
751739
 {
751739
         GHashTable            *normal_users_by_name;
751739
         GHashTable            *system_users_by_name;
751739
         GHashTable            *users_by_object_path;
751739
         GHashTable            *sessions;
751739
         GDBusConnection       *connection;
751739
         AccountsAccounts      *accounts_proxy;
751739
         ConsoleKitManager     *ck_manager_proxy;
751739
 
751739
         ActUserManagerSeat     seat;
751739
 
751739
         GSList                *new_sessions;
751739
         GSList                *new_users;
751739
         GSList                *new_users_inhibiting_load;
751739
         GSList                *fetch_user_requests;
751739
 
751739
         GSList                *exclude_usernames;
751739
         GSList                *include_usernames;
751739
 
751739
+        char                  *os_id;
751739
+        char                  *os_version_id;
751739
+
751739
         guint                  load_id;
751739
 
751739
         gboolean               is_loaded;
751739
         gboolean               has_multiple_users;
751739
         gboolean               getting_sessions;
751739
         gboolean               list_cached_users_done;
751739
 };
751739
 
751739
 enum {
751739
         PROP_0,
751739
         PROP_INCLUDE_USERNAMES_LIST,
751739
         PROP_EXCLUDE_USERNAMES_LIST,
751739
         PROP_IS_LOADED,
751739
         PROP_HAS_MULTIPLE_USERS
751739
 };
751739
 
751739
 enum {
751739
         USER_ADDED,
751739
         USER_REMOVED,
751739
         USER_IS_LOGGED_IN_CHANGED,
751739
         USER_CHANGED,
751739
         LAST_SIGNAL
751739
 };
751739
 
751739
 static guint signals [LAST_SIGNAL] = { 0, };
751739
 
751739
 static void     act_user_manager_class_init (ActUserManagerClass *klass);
751739
 static void     act_user_manager_init       (ActUserManager      *user_manager);
751739
 static void     act_user_manager_finalize   (GObject             *object);
751739
 
751739
@@ -2763,101 +2767,174 @@ ensure_accounts_proxy (ActUserManager *manager)
751739
                                                                           G_DBUS_PROXY_FLAGS_NONE,
751739
                                                                           ACCOUNTS_NAME,
751739
                                                                           ACCOUNTS_PATH,
751739
                                                                           NULL,
751739
                                                                           &error);
751739
         if (error != NULL) {
751739
                 g_debug ("ActUserManager: getting account proxy failed: %s", error->message);
751739
                 return FALSE;
751739
         }
751739
 
751739
         g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (manager->priv->accounts_proxy), G_MAXINT);
751739
 
751739
         g_object_bind_property (G_OBJECT (manager->priv->accounts_proxy),
751739
                                 "has-multiple-users",
751739
                                 G_OBJECT (manager),
751739
                                 "has-multiple-users",
751739
                                 G_BINDING_SYNC_CREATE);
751739
 
751739
         g_signal_connect (manager->priv->accounts_proxy,
751739
                           "user-added",
751739
                           G_CALLBACK (on_new_user_in_accounts_service),
751739
                           manager);
751739
         g_signal_connect (manager->priv->accounts_proxy,
751739
                           "user-deleted",
751739
                           G_CALLBACK (on_user_removed_in_accounts_service),
751739
                           manager);
751739
 
751739
         return TRUE;
751739
 }
751739
 
751739
+static inline gboolean
751739
+is_valid_char (gchar    c,
751739
+               gboolean first)
751739
+{
751739
+        return (!first && g_ascii_isdigit (c)) ||
751739
+                c == '_' ||
751739
+                g_ascii_isalpha (c);
751739
+}
751739
+
751739
+static void
751739
+load_os_release (ActUserManager *manager)
751739
+{
751739
+        ActUserManagerPrivate *priv = manager->priv;
751739
+        g_autoptr(GFile) file = NULL;
751739
+        g_autoptr(GError) error = NULL;
751739
+        g_autofree char *contents = NULL;
751739
+        g_auto(GStrv) lines = NULL;
751739
+        size_t i;
751739
+
751739
+        file = g_file_new_for_path ("/etc/os-release");
751739
+
751739
+        if (!g_file_load_contents (file, NULL, &contents, NULL, NULL, &error)) {
751739
+                g_debug ("ActUserManager: couldn't load /etc/os-release: %s", error->message);
751739
+                return;
751739
+        }
751739
+
751739
+        lines = g_strsplit (contents, "\n", -1);
751739
+        for (i = 0; lines[i] != NULL; i++) {
751739
+                char *p, *name, *name_end, *value, *value_end;
751739
+
751739
+                p = lines[i];
751739
+
751739
+                while (g_ascii_isspace (*p))
751739
+                        p++;
751739
+
751739
+                if (*p == '#' || *p == '\0')
751739
+                        continue;
751739
+                name = p;
751739
+                while (is_valid_char (*p, p == name))
751739
+                        p++;
751739
+                name_end = p;
751739
+                while (g_ascii_isspace (*p))
751739
+                        p++;
751739
+                if (name == name_end || *p != '=') {
751739
+                        continue;
751739
+                }
751739
+                *name_end = '\0';
751739
+
751739
+                p++;
751739
+
751739
+                while (g_ascii_isspace (*p))
751739
+                        p++;
751739
+
751739
+                value = p;
751739
+                value_end = value + strlen (value) - 1;
751739
+
751739
+                if (value != value_end && *value == '"' && *value_end == '"') {
751739
+                        value++;
751739
+                        *value_end = '\0';
751739
+                }
751739
+
751739
+                if (strcmp (name, "ID") == 0) {
751739
+                        g_debug ("ActUserManager: system OS is '%s'", value);
751739
+                        priv->os_id = g_strdup (value);
751739
+                } else if (strcmp (name, "VERSION_ID") == 0) {
751739
+                        g_debug ("ActUserManager: system OS version is '%s'", value);
751739
+                        priv->os_version_id = g_strdup (value);
751739
+                }
751739
+        }
751739
+}
751739
+
751739
 static void
751739
 act_user_manager_init (ActUserManager *manager)
751739
 {
751739
         g_autoptr(GError) error = NULL;
751739
 
751739
         manager->priv = ACT_USER_MANAGER_GET_PRIVATE (manager);
751739
 
751739
         act_user_manager_error_quark (); /* register dbus errors */
751739
 
751739
         /* sessions */
751739
         manager->priv->sessions = g_hash_table_new_full (g_str_hash,
751739
                                                          g_str_equal,
751739
                                                          g_free,
751739
                                                          g_object_unref);
751739
 
751739
         /* users */
751739
         manager->priv->normal_users_by_name = g_hash_table_new_full (g_str_hash,
751739
                                                                      g_str_equal,
751739
                                                                      g_free,
751739
                                                                      g_object_unref);
751739
         manager->priv->system_users_by_name = g_hash_table_new_full (g_str_hash,
751739
                                                                      g_str_equal,
751739
                                                                      g_free,
751739
                                                                      g_object_unref);
751739
         manager->priv->users_by_object_path = g_hash_table_new_full (g_str_hash,
751739
                                                                      g_str_equal,
751739
                                                                      NULL,
751739
                                                                      g_object_unref);
751739
 
751739
         manager->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
751739
         if (manager->priv->connection == NULL) {
751739
                 if (error != NULL) {
751739
                         g_warning ("Failed to connect to the D-Bus daemon: %s", error->message);
751739
                 } else {
751739
                         g_warning ("Failed to connect to the D-Bus daemon");
751739
                 }
751739
                 return;
751739
         }
751739
 
751739
         ensure_accounts_proxy (manager);
751739
 
751739
+        load_os_release (manager);
751739
+
751739
         manager->priv->seat.state = ACT_USER_MANAGER_SEAT_STATE_UNLOADED;
751739
 }
751739
 
751739
 static void
751739
 act_user_manager_finalize (GObject *object)
751739
 {
751739
         ActUserManager *manager;
751739
         GSList         *node;
751739
 
751739
         g_debug ("ActUserManager: finalizing user manager");
751739
 
751739
         g_return_if_fail (object != NULL);
751739
         g_return_if_fail (ACT_IS_USER_MANAGER (object));
751739
 
751739
         manager = ACT_USER_MANAGER (object);
751739
 
751739
         g_return_if_fail (manager->priv != NULL);
751739
 
751739
         g_slist_foreach (manager->priv->new_sessions,
751739
                          (GFunc) unload_new_session, NULL);
751739
         g_slist_free (manager->priv->new_sessions);
751739
 
751739
         g_slist_foreach (manager->priv->fetch_user_requests,
751739
                          (GFunc) free_fetch_user_request, NULL);
751739
         g_slist_free (manager->priv->fetch_user_requests);
751739
 
751739
         g_slist_free (manager->priv->new_users_inhibiting_load);
751739
 
751739
         node = manager->priv->new_users;
751739
         while (node != NULL) {
751739
@@ -2899,141 +2976,179 @@ act_user_manager_finalize (GObject *object)
751739
 
751739
 #ifdef WITH_SYSTEMD
751739
         if (manager->priv->seat.session_monitor != NULL) {
751739
                 sd_login_monitor_unref (manager->priv->seat.session_monitor);
751739
         }
751739
 
751739
         if (manager->priv->seat.session_monitor_stream != NULL) {
751739
                 g_object_unref (manager->priv->seat.session_monitor_stream);
751739
         }
751739
 
751739
         if (manager->priv->seat.session_monitor_source_id != 0) {
751739
                 g_source_remove (manager->priv->seat.session_monitor_source_id);
751739
         }
751739
 #endif
751739
 
751739
         if (manager->priv->accounts_proxy != NULL) {
751739
                 g_object_unref (manager->priv->accounts_proxy);
751739
         }
751739
 
751739
         if (manager->priv->load_id > 0) {
751739
                 g_source_remove (manager->priv->load_id);
751739
                 manager->priv->load_id = 0;
751739
         }
751739
 
751739
         g_hash_table_destroy (manager->priv->sessions);
751739
 
751739
         g_hash_table_destroy (manager->priv->normal_users_by_name);
751739
         g_hash_table_destroy (manager->priv->system_users_by_name);
751739
         g_hash_table_destroy (manager->priv->users_by_object_path);
751739
 
751739
+        g_free (manager->priv->os_id);
751739
+        g_free (manager->priv->os_version_id);
751739
+
751739
         G_OBJECT_CLASS (act_user_manager_parent_class)->finalize (object);
751739
 }
751739
 
751739
 /**
751739
  * act_user_manager_get_default:
751739
  *
751739
  * Returns the user manager singleton instance.  Calling this function will
751739
  * automatically being loading the user list if it isn't loaded already.
751739
  * The #ActUserManager:is-loaded property will be set to %TRUE when the users
751739
  * are finished loading and then act_user_manager_list_users() can be called.
751739
  *
751739
  * Returns: (transfer none): user manager object
751739
  */
751739
 ActUserManager *
751739
 act_user_manager_get_default (void)
751739
 {
751739
         if (user_manager_object == NULL) {
751739
                 user_manager_object = g_object_new (ACT_TYPE_USER_MANAGER, NULL);
751739
                 g_object_add_weak_pointer (user_manager_object,
751739
                                            (gpointer *) &user_manager_object);
751739
                 act_user_manager_queue_load (user_manager_object);
751739
         }
751739
 
751739
         return ACT_USER_MANAGER (user_manager_object);
751739
 }
751739
 
751739
 /**
751739
  * act_user_manager_no_service:
751739
  * @manager: a #ActUserManager
751739
  *
751739
  * Check whether or not the accounts service is running.
751739
  *
751739
  * Returns: whether or not accounts service is running
751739
  */
751739
 gboolean
751739
 act_user_manager_no_service (ActUserManager *manager)
751739
 {
751739
        return manager->priv->accounts_proxy == NULL;
751739
 }
751739
 
751739
+static void
751739
+save_system_info (ActUserManager *manager,
751739
+                  const char     *user_path)
751739
+{
751739
+        ActUserManagerPrivate *priv = manager->priv;
751739
+        ActUserSystem *user_system_proxy = NULL;
751739
+        g_autoptr(GError) error = NULL;
751739
+
751739
+        if (priv->os_id == NULL && priv->os_version_id == NULL)
751739
+                return;
751739
+
751739
+        user_system_proxy = act_user_system_proxy_new_sync (priv->connection,
751739
+                                                            G_DBUS_PROXY_FLAGS_NONE,
751739
+                                                            ACCOUNTS_NAME,
751739
+                                                            user_path,
751739
+                                                            NULL,
751739
+                                                            &error);
751739
+        if (user_system_proxy != NULL) {
751739
+                if (priv->os_id != NULL)
751739
+                        act_user_system_set_id (user_system_proxy, priv->os_id);
751739
+
751739
+                if (priv->os_version_id != NULL)
751739
+                        act_user_system_set_version_id (user_system_proxy, priv->os_version_id);
751739
+        } else {
751739
+                /* probably means accountsservice and lib are out of sync */
751739
+                g_debug ("ActUserManager: failed to create user system proxy: %s",
751739
+                         error? error->message: "");
751739
+                g_clear_error (&error);
751739
+        }
751739
+
751739
+        g_clear_object (&user_system_proxy);
751739
+}
751739
+
751739
 /**
751739
  * act_user_manager_create_user:
751739
  * @manager: a #ActUserManager
751739
  * @username: a unix user name
751739
  * @fullname: a unix GECOS value
751739
  * @accounttype: a #ActUserAccountType
751739
  * @error: a #GError
751739
  *
751739
  * Creates a user account on the system.
751739
  *
751739
  * Returns: (transfer full): user object
751739
  */
751739
 ActUser *
751739
 act_user_manager_create_user (ActUserManager      *manager,
751739
                               const char          *username,
751739
                               const char          *fullname,
751739
                               ActUserAccountType   accounttype,
751739
                               GError             **error)
751739
 {
751739
         GError *local_error = NULL;
751739
         gboolean res;
751739
         g_autofree gchar *path = NULL;
751739
         ActUser *user;
751739
 
751739
         g_debug ("ActUserManager: Creating user '%s', '%s', %d",
751739
                  username, fullname, accounttype);
751739
 
751739
         g_assert (manager->priv->accounts_proxy != NULL);
751739
 
751739
         res = accounts_accounts_call_create_user_sync (manager->priv->accounts_proxy,
751739
                                                        username,
751739
                                                        fullname,
751739
                                                        accounttype,
751739
                                                        &path,
751739
                                                        NULL,
751739
                                                        &local_error);
751739
         if (!res) {
751739
                 g_propagate_error (error, local_error);
751739
                 return NULL;
751739
         }
751739
 
751739
+        save_system_info (manager, path);
751739
+
751739
         user = add_new_user_for_object_path (path, manager);
751739
 
751739
         return user;
751739
 }
751739
 
751739
 static void
751739
 act_user_manager_async_complete_handler (GObject      *source,
751739
                                          GAsyncResult *result,
751739
                                          gpointer      user_data)
751739
 {
751739
         GTask *task = user_data;
751739
 
751739
         g_task_return_pointer (task, g_object_ref (result), g_object_unref);
751739
         g_object_unref (task);
751739
 }
751739
 
751739
 /**
751739
  * act_user_manager_create_user_async:
751739
  * @manager: a #ActUserManager
751739
  * @username: a unix user name
751739
  * @fullname: a unix GECOS value
751739
  * @accounttype: a #ActUserAccountType
751739
  * @cancellable: (allow-none): optional #GCancellable object,
751739
  *     %NULL to ignore
751739
  * @callback: (scope async): a #GAsyncReadyCallback to call
751739
  *     when the request is satisfied
751739
  * @user_data: (closure): the data to pass to @callback
751739
  *
751739
  * Asynchronously creates a user account on the system.
751739
  *
751739
@@ -3077,105 +3192,110 @@ act_user_manager_create_user_async (ActUserManager      *manager,
751739
  * act_user_manager_create_user_finish:
751739
  * @manager: a #ActUserManager
751739
  * @result: a #GAsyncResult
751739
  * @error: a #GError
751739
  *
751739
  * Finishes an asynchronous user creation.
751739
  *
751739
  * See act_user_manager_create_user_async().
751739
  *
751739
  * Returns: (transfer full): user object
751739
  *
751739
  * Since: 0.6.27
751739
  */
751739
 ActUser *
751739
 act_user_manager_create_user_finish (ActUserManager  *manager,
751739
                                      GAsyncResult    *result,
751739
                                      GError         **error)
751739
 {
751739
         GAsyncResult *inner_result;
751739
         ActUser *user = NULL;
751739
         g_autofree gchar *path = NULL;
751739
         GError *remote_error = NULL;
751739
 
751739
         inner_result = g_task_propagate_pointer (G_TASK (result), error);
751739
         if (inner_result == NULL) {
751739
                 return FALSE;
751739
         }
751739
 
751739
         if (accounts_accounts_call_create_user_finish (manager->priv->accounts_proxy,
751739
                                                        &path, inner_result, &remote_error)) {
751739
+
751739
+                save_system_info (manager, path);
751739
+
751739
                 user = add_new_user_for_object_path (path, manager);
751739
         }
751739
 
751739
         if (remote_error) {
751739
                 g_dbus_error_strip_remote_error (remote_error);
751739
                 g_propagate_error (error, remote_error);
751739
         }
751739
 
751739
         return user;
751739
 }
751739
 
751739
 /**
751739
  * act_user_manager_cache_user:
751739
  * @manager: a #ActUserManager
751739
  * @username: a user name
751739
  * @error: a #GError
751739
  *
751739
  * Caches a user account so it shows up via act_user_manager_list_users().
751739
  *
751739
  * Returns: (transfer full): user object
751739
  */
751739
 ActUser *
751739
 act_user_manager_cache_user (ActUserManager     *manager,
751739
                              const char         *username,
751739
                              GError            **error)
751739
 {
751739
         GError *local_error = NULL;
751739
         gboolean res;
751739
         g_autofree gchar *path = NULL;
751739
 
751739
         g_debug ("ActUserManager: Caching user '%s'",
751739
                  username);
751739
 
751739
         g_assert (manager->priv->accounts_proxy != NULL);
751739
 
751739
         res = accounts_accounts_call_cache_user_sync (manager->priv->accounts_proxy,
751739
                                                       username,
751739
                                                       &path,
751739
                                                       NULL,
751739
                                                       &local_error);
751739
         if (!res) {
751739
                 g_propagate_error (error, local_error);
751739
                 return NULL;
751739
         }
751739
 
751739
+        save_system_info (manager, path);
751739
+
751739
         return add_new_user_for_object_path (path, manager);
751739
 }
751739
 
751739
 
751739
 /**
751739
  * act_user_manager_cache_user_async:
751739
  * @manager: a #ActUserManager
751739
  * @username: a unix user name
751739
  * @cancellable: (allow-none): optional #GCancellable object,
751739
  *     %NULL to ignore
751739
  * @callback: (scope async): a #GAsyncReadyCallback to call
751739
  *     when the request is satisfied
751739
  * @user_data: (closure): the data to pass to @callback
751739
  *
751739
  * Asynchronously caches a user account so it shows up via
751739
  * act_user_manager_list_users().
751739
  *
751739
  * For more details, see act_user_manager_cache_user(), which
751739
  * is the synchronous version of this call.
751739
  *
751739
  * Since: 0.6.27
751739
  */
751739
 void
751739
 act_user_manager_cache_user_async (ActUserManager      *manager,
751739
                                    const char          *username,
751739
                                    GCancellable        *cancellable,
751739
                                    GAsyncReadyCallback  callback,
751739
                                    gpointer             user_data)
751739
 {
751739
         GTask *task;
751739
@@ -3199,60 +3319,63 @@ act_user_manager_cache_user_async (ActUserManager      *manager,
751739
  * act_user_manager_cache_user_finish:
751739
  * @manager: a #ActUserManager
751739
  * @result: a #GAsyncResult
751739
  * @error: a #GError
751739
  *
751739
  * Finishes an asynchronous user caching.
751739
  *
751739
  * See act_user_manager_cache_user_async().
751739
  *
751739
  * Returns: (transfer full): user object
751739
  *
751739
  * Since: 0.6.27
751739
  */
751739
 ActUser *
751739
 act_user_manager_cache_user_finish (ActUserManager  *manager,
751739
                                     GAsyncResult    *result,
751739
                                     GError         **error)
751739
 {
751739
         GAsyncResult *inner_result;
751739
         ActUser *user = NULL;
751739
         g_autofree gchar *path = NULL;
751739
         GError *remote_error = NULL;
751739
 
751739
         inner_result = g_task_propagate_pointer (G_TASK (result), error);
751739
         if (inner_result == NULL) {
751739
                 return FALSE;
751739
         }
751739
 
751739
         if (accounts_accounts_call_cache_user_finish (manager->priv->accounts_proxy,
751739
                                                       &path, inner_result, &remote_error)) {
751739
+
751739
+                save_system_info (manager, path);
751739
+
751739
                 user = add_new_user_for_object_path (path, manager);
751739
         }
751739
 
751739
         if (remote_error) {
751739
                 g_dbus_error_strip_remote_error (remote_error);
751739
                 g_propagate_error (error, remote_error);
751739
         }
751739
 
751739
         return user;
751739
 }
751739
 
751739
 /**
751739
  * act_user_manager_uncache_user:
751739
  * @manager: a #ActUserManager
751739
  * @username: a user name
751739
  * @error: a #GError
751739
  *
751739
  * Releases all metadata about a user account, including icon,
751739
  * language and session. If the user account is from a remote
751739
  * server and the user has never logged in before, then that
751739
  * account will no longer show up in ListCachedUsers() output.
751739
  *
751739
  * Returns: %TRUE if successful, otherwise %FALSE
751739
  */
751739
 gboolean
751739
 act_user_manager_uncache_user (ActUserManager     *manager,
751739
                                const char         *username,
751739
                                GError            **error)
751739
 {
751739
         GError *local_error = NULL;
751739
-- 
751739
2.21.0
751739