summary refs log tree commit diff
path: root/src/libnm-client-impl/nm-remote-connection.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
committerMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
commite74c568b07b50b97873fb4ee1d776dedefbd54d6 (patch)
tree3469f17ea9af91f7ff169b890633bda68b0cf76e /src/libnm-client-impl/nm-remote-connection.c
parentbfe522304da217296e2a61040f58e35ec5d6f3f2 (diff)
New upstream version 1.32.12 upstream/1.32.12
Diffstat (limited to 'src/libnm-client-impl/nm-remote-connection.c')
-rw-r--r--src/libnm-client-impl/nm-remote-connection.c839
1 files changed, 839 insertions, 0 deletions
diff --git a/src/libnm-client-impl/nm-remote-connection.c b/src/libnm-client-impl/nm-remote-connection.c
new file mode 100644
index 00000000..8e36cf6d
--- /dev/null
+++ b/src/libnm-client-impl/nm-remote-connection.c
@@ -0,0 +1,839 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2007 - 2008 Novell, Inc.
+ * Copyright (C) 2007 - 2011 Red Hat, Inc.
+ */
+
+#include "libnm-client-impl/nm-default-libnm.h"
+
+#include "nm-remote-connection.h"
+
+#include "libnm-glib-aux/nm-dbus-aux.h"
+#include "nm-dbus-interface.h"
+#include "nm-utils.h"
+#include "nm-setting-connection.h"
+#include "libnm-core-intern/nm-core-internal.h"
+#include "nm-remote-connection-private.h"
+#include "nm-object-private.h"
+#include "nm-dbus-helpers.h"
+
+/**
+ * SECTION:nm-remote-connection
+ * @short_description: A connection managed by NetworkManager server
+ *
+ * A #NMRemoteConnection represents a connection that is exported via
+ * NetworkManager D-Bus interface.
+ **/
+
+/*****************************************************************************/
+
+NM_GOBJECT_PROPERTIES_DEFINE(NMRemoteConnection,
+                             PROP_UNSAVED,
+                             PROP_FLAGS,
+                             PROP_FILENAME,
+                             PROP_VISIBLE, );
+
+typedef struct {
+    GCancellable *get_settings_cancellable;
+
+    char *  filename;
+    guint32 flags;
+    bool    unsaved;
+
+    bool visible : 1;
+    bool is_initialized : 1;
+} NMRemoteConnectionPrivate;
+
+struct _NMRemoteConnection {
+    NMObject                  parent;
+    NMRemoteConnectionPrivate _priv;
+};
+
+struct _NMRemoteConnectionClass {
+    NMObjectClass parent_class;
+};
+
+static void nm_remote_connection_connection_iface_init(NMConnectionInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(NMRemoteConnection,
+                        nm_remote_connection,
+                        NM_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE(NM_TYPE_CONNECTION,
+                                              nm_remote_connection_connection_iface_init);)
+
+#define NM_REMOTE_CONNECTION_GET_PRIVATE(self) \
+    _NM_GET_PRIVATE(self, NMRemoteConnection, NM_IS_REMOTE_CONNECTION, NMObject)
+
+/*****************************************************************************/
+
+/**
+ * nm_remote_connection_update2:
+ * @connection: the #NMRemoteConnection
+ * @settings: (allow-none): optional connection to update the settings.
+ * @flags: update-flags
+ * @args: (allow-none): optional arguments.
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to be called when the commit operation completes
+ * @user_data: caller-specific data passed to @callback
+ *
+ * Asynchronously calls the Update2() D-Bus method.
+ *
+ * Since: 1.12
+ **/
+void
+nm_remote_connection_update2(NMRemoteConnection *   connection,
+                             GVariant *             settings,
+                             NMSettingsUpdate2Flags flags,
+                             GVariant *             args,
+                             GCancellable *         cancellable,
+                             GAsyncReadyCallback    callback,
+                             gpointer               user_data)
+{
+    g_return_if_fail(NM_IS_REMOTE_CONNECTION(connection));
+    g_return_if_fail(!settings || g_variant_is_of_type(settings, NM_VARIANT_TYPE_CONNECTION));
+    g_return_if_fail(!args || g_variant_is_of_type(args, G_VARIANT_TYPE("a{sv}")));
+    g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable));
+
+    if (!settings)
+        settings = nm_g_variant_singleton_aLsaLsvII();
+    if (!args)
+        args = nm_g_variant_singleton_aLsvI();
+
+    _nm_client_dbus_call(_nm_object_get_client(connection),
+                         connection,
+                         nm_remote_connection_update2,
+                         cancellable,
+                         callback,
+                         user_data,
+                         _nm_object_get_path(connection),
+                         NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+                         "Update2",
+                         g_variant_new("(@a{sa{sv}}u@a{sv})", settings, (guint32) flags, args),
+                         G_VARIANT_TYPE("(a{sv})"),
+                         G_DBUS_CALL_FLAGS_NONE,
+                         NM_DBUS_DEFAULT_TIMEOUT_MSEC,
+                         nm_dbus_connection_call_finish_variant_strip_dbus_error_cb);
+}
+
+/**
+ * nm_remote_connection_update2_finish:
+ * @connection: the #NMRemoteConnection
+ * @result: the result passed to the #GAsyncReadyCallback
+ * @error: location for a #GError, or %NULL
+ *
+ * Gets the result of a call to nm_remote_connection_commit_changes_async().
+ *
+ * Returns: (transfer full): on success, a #GVariant of type "a{sv}" with the result. On failure,
+ *   %NULL.
+ **/
+GVariant *
+nm_remote_connection_update2_finish(NMRemoteConnection *connection,
+                                    GAsyncResult *      result,
+                                    GError **           error)
+{
+    gs_unref_variant GVariant *ret = NULL;
+    GVariant *                 v_result;
+
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), NULL);
+    g_return_val_if_fail(nm_g_task_is_valid(result, connection, nm_remote_connection_update2),
+                         NULL);
+
+    ret = g_task_propagate_pointer(G_TASK(result), error);
+    if (!ret)
+        return NULL;
+
+    g_variant_get(ret, "(@a{sv})", &v_result);
+
+    return v_result;
+}
+
+/*****************************************************************************/
+
+/**
+ * nm_remote_connection_commit_changes:
+ * @connection: the #NMRemoteConnection
+ * @save_to_disk: whether to persist the changes to disk
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: location for a #GError, or %NULL
+ *
+ * Send any local changes to the settings and properties of @connection to
+ * NetworkManager. If @save_to_disk is %TRUE, the updated connection will be saved to
+ * disk; if %FALSE, then only the in-memory representation will be changed.
+ *
+ * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
+ *
+ * Deprecated: 1.22: Use nm_remote_connection_commit_changes_async() or GDBusConnection.
+ **/
+gboolean
+nm_remote_connection_commit_changes(NMRemoteConnection *connection,
+                                    gboolean            save_to_disk,
+                                    GCancellable *      cancellable,
+                                    GError **           error)
+{
+    gs_unref_variant GVariant *ret = NULL;
+
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), FALSE);
+    g_return_val_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable), FALSE);
+
+    ret = _nm_client_dbus_call_sync(
+        _nm_object_get_client(connection),
+        cancellable,
+        _nm_object_get_path(connection),
+        NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+        "Update2",
+        g_variant_new("(@a{sa{sv}}u@a{sv})",
+                      nm_connection_to_dbus(NM_CONNECTION(connection), NM_CONNECTION_SERIALIZE_ALL),
+                      (guint32) (save_to_disk ? NM_SETTINGS_UPDATE2_FLAG_TO_DISK
+                                              : NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY),
+                      nm_g_variant_singleton_aLsvI()),
+        G_VARIANT_TYPE("(a{sv})"),
+        G_DBUS_CALL_FLAGS_NONE,
+        NM_DBUS_DEFAULT_TIMEOUT_MSEC,
+        TRUE,
+        error);
+    if (!ret)
+        return FALSE;
+
+    return TRUE;
+}
+
+/**
+ * nm_remote_connection_commit_changes_async:
+ * @connection: the #NMRemoteConnection
+ * @save_to_disk: whether to save the changes to persistent storage
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to be called when the commit operation completes
+ * @user_data: caller-specific data passed to @callback
+ *
+ * Asynchronously sends any local changes to the settings and properties of
+ * @connection to NetworkManager. If @save is %TRUE, the updated connection will
+ * be saved to disk; if %FALSE, then only the in-memory representation will be
+ * changed.
+ **/
+void
+nm_remote_connection_commit_changes_async(NMRemoteConnection *connection,
+                                          gboolean            save_to_disk,
+                                          GCancellable *      cancellable,
+                                          GAsyncReadyCallback callback,
+                                          gpointer            user_data)
+{
+    g_return_if_fail(NM_IS_REMOTE_CONNECTION(connection));
+    g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable));
+
+    nm_remote_connection_update2(
+        connection,
+        nm_connection_to_dbus(NM_CONNECTION(connection), NM_CONNECTION_SERIALIZE_ALL),
+        save_to_disk ? NM_SETTINGS_UPDATE2_FLAG_TO_DISK : NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY,
+        NULL,
+        cancellable,
+        callback,
+        user_data);
+}
+
+/**
+ * nm_remote_connection_commit_changes_finish:
+ * @connection: the #NMRemoteConnection
+ * @result: the result passed to the #GAsyncReadyCallback
+ * @error: location for a #GError, or %NULL
+ *
+ * Gets the result of a call to nm_remote_connection_commit_changes_async().
+ *
+ * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
+ **/
+gboolean
+nm_remote_connection_commit_changes_finish(NMRemoteConnection *connection,
+                                           GAsyncResult *      result,
+                                           GError **           error)
+{
+    gs_unref_variant GVariant *v_result = NULL;
+
+    v_result = nm_remote_connection_update2_finish(connection, result, error);
+    return !!v_result;
+}
+
+/*****************************************************************************/
+
+/**
+ * nm_remote_connection_save:
+ * @connection: the #NMRemoteConnection
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: location for a #GError, or %NULL
+ *
+ * Saves the connection to disk if the connection has changes that have not yet
+ * been written to disk, or if the connection has never been saved.
+ *
+ * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
+ *
+ * Deprecated: 1.22: Use nm_remote_connection_save_async() or GDBusConnection.
+ **/
+gboolean
+nm_remote_connection_save(NMRemoteConnection *connection, GCancellable *cancellable, GError **error)
+{
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), FALSE);
+    g_return_val_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable), FALSE);
+
+    return _nm_client_dbus_call_sync_void(_nm_object_get_client(connection),
+                                          cancellable,
+                                          _nm_object_get_path(connection),
+                                          NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+                                          "Save",
+                                          g_variant_new("()"),
+                                          G_DBUS_CALL_FLAGS_NONE,
+                                          NM_DBUS_DEFAULT_TIMEOUT_MSEC,
+                                          TRUE,
+                                          error);
+}
+
+/**
+ * nm_remote_connection_save_async:
+ * @connection: the #NMRemoteConnection
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to be called when the save operation completes
+ * @user_data: caller-specific data passed to @callback
+ *
+ * Saves the connection to disk if the connection has changes that have not yet
+ * been written to disk, or if the connection has never been saved.
+ **/
+void
+nm_remote_connection_save_async(NMRemoteConnection *connection,
+                                GCancellable *      cancellable,
+                                GAsyncReadyCallback callback,
+                                gpointer            user_data)
+{
+    g_return_if_fail(NM_IS_REMOTE_CONNECTION(connection));
+    g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable));
+
+    _nm_client_dbus_call(_nm_object_get_client(connection),
+                         connection,
+                         nm_remote_connection_save_async,
+                         cancellable,
+                         callback,
+                         user_data,
+                         _nm_object_get_path(connection),
+                         NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+                         "Save",
+                         g_variant_new("()"),
+                         G_VARIANT_TYPE("()"),
+                         G_DBUS_CALL_FLAGS_NONE,
+                         NM_DBUS_DEFAULT_TIMEOUT_MSEC,
+                         nm_dbus_connection_call_finish_void_strip_dbus_error_cb);
+}
+
+/**
+ * nm_remote_connection_save_finish:
+ * @connection: the #NMRemoteConnection
+ * @result: the result passed to the #GAsyncReadyCallback
+ * @error: location for a #GError, or %NULL
+ *
+ * Gets the result of a call to nm_remote_connection_save_async().
+ *
+ * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
+ **/
+gboolean
+nm_remote_connection_save_finish(NMRemoteConnection *connection,
+                                 GAsyncResult *      result,
+                                 GError **           error)
+{
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), FALSE);
+    g_return_val_if_fail(nm_g_task_is_valid(result, connection, nm_remote_connection_save_async),
+                         FALSE);
+
+    return g_task_propagate_boolean(G_TASK(result), error);
+}
+
+/*****************************************************************************/
+
+/**
+ * nm_remote_connection_delete:
+ * @connection: the #NMRemoteConnection
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: location for a #GError, or %NULL
+ *
+ * Deletes the connection.
+ *
+ * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
+ *
+ * Deprecated: 1.22: Use nm_remote_connection_delete_async() or GDBusConnection.
+ **/
+gboolean
+nm_remote_connection_delete(NMRemoteConnection *connection,
+                            GCancellable *      cancellable,
+                            GError **           error)
+{
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), FALSE);
+
+    return _nm_client_dbus_call_sync_void(_nm_object_get_client(connection),
+                                          cancellable,
+                                          _nm_object_get_path(connection),
+                                          NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+                                          "Delete",
+                                          g_variant_new("()"),
+                                          G_DBUS_CALL_FLAGS_NONE,
+                                          NM_DBUS_DEFAULT_TIMEOUT_MSEC,
+                                          TRUE,
+                                          error);
+}
+
+/**
+ * nm_remote_connection_delete_async:
+ * @connection: the #NMRemoteConnection
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to be called when the delete operation completes
+ * @user_data: caller-specific data passed to @callback
+ *
+ * Asynchronously deletes the connection.
+ **/
+void
+nm_remote_connection_delete_async(NMRemoteConnection *connection,
+                                  GCancellable *      cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer            user_data)
+{
+    g_return_if_fail(NM_IS_REMOTE_CONNECTION(connection));
+    g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable));
+
+    _nm_client_dbus_call(_nm_object_get_client(connection),
+                         connection,
+                         nm_remote_connection_delete_async,
+                         cancellable,
+                         callback,
+                         user_data,
+                         _nm_object_get_path(connection),
+                         NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+                         "Delete",
+                         g_variant_new("()"),
+                         G_VARIANT_TYPE("()"),
+                         G_DBUS_CALL_FLAGS_NONE,
+                         NM_DBUS_DEFAULT_TIMEOUT_MSEC,
+                         nm_dbus_connection_call_finish_void_strip_dbus_error_cb);
+}
+
+/**
+ * nm_remote_connection_delete_finish:
+ * @connection: the #NMRemoteConnection
+ * @result: the result passed to the #GAsyncReadyCallback
+ * @error: location for a #GError, or %NULL
+ *
+ * Gets the result of a call to nm_remote_connection_delete_async().
+ *
+ * Returns: %TRUE on success, %FALSE on error, in which case @error will be set.
+ **/
+gboolean
+nm_remote_connection_delete_finish(NMRemoteConnection *connection,
+                                   GAsyncResult *      result,
+                                   GError **           error)
+{
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), FALSE);
+    g_return_val_if_fail(nm_g_task_is_valid(result, connection, nm_remote_connection_delete_async),
+                         FALSE);
+
+    return g_task_propagate_boolean(G_TASK(result), error);
+}
+
+/**
+ * nm_remote_connection_get_secrets:
+ * @connection: the #NMRemoteConnection
+ * @setting_name: the #NMSetting object name to get secrets for
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: location for a #GError, or %NULL
+ *
+ * Request the connection's secrets. Note that this is a blocking D-Bus call,
+ * not a simple property accessor.
+ *
+ * Returns: (transfer full): a #GVariant of type %NM_VARIANT_TYPE_CONNECTION containing
+ * @connection's secrets, or %NULL on error.
+ *
+ * Deprecated: 1.22: Use nm_remote_connection_get_secrets_async() or GDBusConnection.
+ **/
+GVariant *
+nm_remote_connection_get_secrets(NMRemoteConnection *connection,
+                                 const char *        setting_name,
+                                 GCancellable *      cancellable,
+                                 GError **           error)
+{
+    gs_unref_variant GVariant *ret = NULL;
+    GVariant *                 secrets;
+
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), NULL);
+    g_return_val_if_fail(setting_name, NULL);
+    g_return_val_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable), NULL);
+
+    ret = _nm_client_dbus_call_sync(_nm_object_get_client(connection),
+                                    cancellable,
+                                    _nm_object_get_path(connection),
+                                    NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+                                    "GetSecrets",
+                                    g_variant_new("(s)", setting_name),
+                                    G_VARIANT_TYPE("(a{sa{sv}})"),
+                                    G_DBUS_CALL_FLAGS_NONE,
+                                    NM_DBUS_DEFAULT_TIMEOUT_MSEC,
+                                    TRUE,
+                                    error);
+    if (!ret)
+        return NULL;
+
+    g_variant_get(ret, "(@a{sa{sv}})", &secrets);
+
+    return secrets;
+}
+
+/**
+ * nm_remote_connection_get_secrets_async:
+ * @connection: the #NMRemoteConnection
+ * @setting_name: the #NMSetting object name to get secrets for
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to be called when the secret request completes
+ * @user_data: caller-specific data passed to @callback
+ *
+ * Asynchronously requests the connection's secrets.
+ **/
+void
+nm_remote_connection_get_secrets_async(NMRemoteConnection *connection,
+                                       const char *        setting_name,
+                                       GCancellable *      cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer            user_data)
+{
+    g_return_if_fail(NM_IS_REMOTE_CONNECTION(connection));
+    g_return_if_fail(setting_name);
+    g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable));
+
+    _nm_client_dbus_call(_nm_object_get_client(connection),
+                         connection,
+                         nm_remote_connection_get_secrets_async,
+                         cancellable,
+                         callback,
+                         user_data,
+                         _nm_object_get_path(connection),
+                         NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+                         "GetSecrets",
+                         g_variant_new("(s)", setting_name),
+                         G_VARIANT_TYPE("(a{sa{sv}})"),
+                         G_DBUS_CALL_FLAGS_NONE,
+                         NM_DBUS_DEFAULT_TIMEOUT_MSEC,
+                         nm_dbus_connection_call_finish_variant_strip_dbus_error_cb);
+}
+
+/**
+ * nm_remote_connection_get_secrets_finish:
+ * @connection: the #NMRemoteConnection
+ * @result: the result passed to the #GAsyncReadyCallback
+ * @error: location for a #GError, or %NULL
+ *
+ * Gets the result of a call to nm_remote_connection_get_secrets_async().
+ *
+ * Returns: (transfer full): a #GVariant of type %NM_VARIANT_TYPE_CONNECTION
+ *   containing @connection's secrets, or %NULL on error.
+ **/
+GVariant *
+nm_remote_connection_get_secrets_finish(NMRemoteConnection *connection,
+                                        GAsyncResult *      result,
+                                        GError **           error)
+{
+    gs_unref_variant GVariant *ret = NULL;
+    GVariant *                 secrets;
+
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), NULL);
+    g_return_val_if_fail(
+        nm_g_task_is_valid(result, connection, nm_remote_connection_get_secrets_async),
+        FALSE);
+
+    ret = g_task_propagate_pointer(G_TASK(result), error);
+    if (!ret)
+        return NULL;
+
+    g_variant_get(ret, "(@a{sa{sv}})", &secrets);
+
+    return secrets;
+}
+
+/**
+ * nm_remote_connection_get_unsaved:
+ * @connection: the #NMRemoteConnection
+ *
+ * Returns: %TRUE if the remote connection contains changes that have not
+ * been saved to disk, %FALSE if the connection is the same as its on-disk
+ * representation.
+ **/
+gboolean
+nm_remote_connection_get_unsaved(NMRemoteConnection *connection)
+{
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), FALSE);
+
+    return NM_REMOTE_CONNECTION_GET_PRIVATE(connection)->unsaved;
+}
+
+/**
+ * nm_remote_connection_get_flags:
+ * @connection: the #NMRemoteConnection
+ *
+ * Returns: the flags of the connection of type #NMSettingsConnectionFlags.
+ *
+ * Since: 1.12
+ **/
+NMSettingsConnectionFlags
+nm_remote_connection_get_flags(NMRemoteConnection *connection)
+{
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), FALSE);
+
+    return (NMSettingsConnectionFlags) NM_REMOTE_CONNECTION_GET_PRIVATE(connection)->flags;
+}
+
+/**
+ * nm_remote_connection_get_filename:
+ * @connection: the #NMRemoteConnection
+ *
+ * Returns: file that stores the connection in case the connection is file-backed.
+ *
+ * Since: 1.12
+ **/
+const char *
+nm_remote_connection_get_filename(NMRemoteConnection *connection)
+{
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), NULL);
+
+    return NM_REMOTE_CONNECTION_GET_PRIVATE(connection)->filename;
+}
+
+/**
+ * nm_remote_connection_get_visible:
+ * @connection: the #NMRemoteConnection
+ *
+ * Checks if the connection is visible to the current user.  If the
+ * connection is not visible then it is essentially useless; it will
+ * not contain any settings, and operations such as
+ * nm_remote_connection_save() and nm_remote_connection_delete() will
+ * always fail. (#NMRemoteSettings will not normally return
+ * non-visible connections to callers, but it is possible for a
+ * connection's visibility to change after you already have a
+ * reference to it.)
+ *
+ * Returns: %TRUE if the remote connection is visible to the current
+ * user, %FALSE if not.
+ **/
+gboolean
+nm_remote_connection_get_visible(NMRemoteConnection *connection)
+{
+    g_return_val_if_fail(NM_IS_REMOTE_CONNECTION(connection), FALSE);
+
+    return NM_REMOTE_CONNECTION_GET_PRIVATE(connection)->visible;
+}
+
+/*****************************************************************************/
+
+GCancellable *
+_nm_remote_settings_get_settings_prepare(NMRemoteConnection *self)
+{
+    NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE(self);
+
+    nm_clear_g_cancellable(&priv->get_settings_cancellable);
+    priv->get_settings_cancellable = g_cancellable_new();
+    return priv->get_settings_cancellable;
+}
+
+void
+_nm_remote_settings_get_settings_commit(NMRemoteConnection *self, GVariant *settings)
+{
+    NMRemoteConnectionPrivate *priv    = NM_REMOTE_CONNECTION_GET_PRIVATE(self);
+    GError *                   error   = NULL;
+    gboolean                   visible = FALSE;
+    gboolean                   changed = FALSE;
+
+    g_clear_object(&priv->get_settings_cancellable);
+
+    if (!priv->is_initialized) {
+        changed              = TRUE;
+        priv->is_initialized = TRUE;
+    }
+
+    if (settings) {
+        if (!_nm_connection_replace_settings((NMConnection *) self,
+                                             settings,
+                                             NM_SETTING_PARSE_FLAGS_BEST_EFFORT,
+                                             &error)) {
+            NML_NMCLIENT_LOG_E(_nm_object_get_client(self),
+                               "[%s] failure to update settings: %s",
+                               _nm_object_get_path(self),
+                               error->message);
+            g_clear_error(&error);
+        } else
+            visible = TRUE;
+    } else
+        nm_connection_clear_settings(NM_CONNECTION(self));
+
+    if (priv->visible != visible) {
+        priv->visible = visible;
+        _nm_client_queue_notify_object(_nm_object_get_client(self),
+                                       self,
+                                       obj_properties[PROP_VISIBLE]);
+        changed = TRUE;
+    }
+
+    if (changed)
+        _nm_client_notify_object_changed(_nm_object_get_client(self), _nm_object_get_dbobj(self));
+}
+
+/*****************************************************************************/
+
+static gboolean
+is_ready(NMObject *nmobj)
+{
+    NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE(nmobj);
+
+    if (!priv->is_initialized)
+        return FALSE;
+
+    return NM_OBJECT_CLASS(nm_remote_connection_parent_class)->is_ready(nmobj);
+}
+
+/*****************************************************************************/
+
+static void
+register_client(NMObject *nmobj, NMClient *client, NMLDBusObject *dbobj)
+{
+    NM_OBJECT_CLASS(nm_remote_connection_parent_class)->register_client(nmobj, client, dbobj);
+    nm_connection_set_path(NM_CONNECTION(nmobj), dbobj->dbus_path->str);
+    _nm_client_get_settings_call(client, dbobj);
+}
+
+static void
+unregister_client(NMObject *nmobj, NMClient *client, NMLDBusObject *dbobj)
+{
+    nm_clear_g_cancellable(&NM_REMOTE_CONNECTION_GET_PRIVATE(nmobj)->get_settings_cancellable);
+    NM_OBJECT_CLASS(nm_remote_connection_parent_class)->unregister_client(nmobj, client, dbobj);
+}
+
+/*****************************************************************************/
+
+static void
+get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+    switch (prop_id) {
+    case PROP_UNSAVED:
+        g_value_set_boolean(value, NM_REMOTE_CONNECTION_GET_PRIVATE(object)->unsaved);
+        break;
+    case PROP_FLAGS:
+        g_value_set_uint(value, NM_REMOTE_CONNECTION_GET_PRIVATE(object)->flags);
+        break;
+    case PROP_FILENAME:
+        g_value_set_string(value, NM_REMOTE_CONNECTION_GET_PRIVATE(object)->filename);
+        break;
+    case PROP_VISIBLE:
+        g_value_set_boolean(value, NM_REMOTE_CONNECTION_GET_PRIVATE(object)->visible);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+/*****************************************************************************/
+
+static void
+nm_remote_connection_init(NMRemoteConnection *self)
+{}
+
+static void
+dispose(GObject *object)
+{
+    NMRemoteConnectionPrivate *priv = NM_REMOTE_CONNECTION_GET_PRIVATE(object);
+
+    nm_clear_g_free(&priv->filename);
+
+    G_OBJECT_CLASS(nm_remote_connection_parent_class)->dispose(object);
+}
+
+const NMLDBusMetaIface _nml_dbus_meta_iface_nm_settings_connection = NML_DBUS_META_IFACE_INIT_PROP(
+    NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
+    nm_remote_connection_get_type,
+    NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_30,
+    NML_DBUS_META_IFACE_DBUS_PROPERTIES(
+        NML_DBUS_META_PROPERTY_INIT_S("Filename",
+                                      PROP_FILENAME,
+                                      NMRemoteConnection,
+                                      _priv.filename),
+        NML_DBUS_META_PROPERTY_INIT_U("Flags", PROP_FLAGS, NMRemoteConnection, _priv.flags),
+        NML_DBUS_META_PROPERTY_INIT_B("Unsaved",
+                                      PROP_UNSAVED,
+                                      NMRemoteConnection,
+                                      _priv.unsaved), ), );
+
+static void
+nm_remote_connection_class_init(NMRemoteConnectionClass *klass)
+{
+    GObjectClass * object_class    = G_OBJECT_CLASS(klass);
+    NMObjectClass *nm_object_class = NM_OBJECT_CLASS(klass);
+
+    object_class->get_property = get_property;
+    object_class->dispose      = dispose;
+
+    nm_object_class->is_ready          = is_ready;
+    nm_object_class->register_client   = register_client;
+    nm_object_class->unregister_client = unregister_client;
+
+    /**
+     * NMRemoteConnection:unsaved:
+     *
+     * %TRUE if the remote connection contains changes that have not been saved
+     * to disk, %FALSE if the connection is the same as its on-disk representation.
+     **/
+    obj_properties[PROP_UNSAVED] = g_param_spec_boolean(NM_REMOTE_CONNECTION_UNSAVED,
+                                                        "",
+                                                        "",
+                                                        FALSE,
+                                                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
+     * NMRemoteConnection:flags:
+     *
+     * The flags of the connection as unsigned integer. The values
+     * correspond to the #NMSettingsConnectionFlags enum.
+     *
+     * Since: 1.12
+     **/
+    obj_properties[PROP_FLAGS] = g_param_spec_uint(NM_REMOTE_CONNECTION_FLAGS,
+                                                   "",
+                                                   "",
+                                                   0,
+                                                   G_MAXUINT32,
+                                                   0,
+                                                   G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
+     * NMRemoteConnection:filename:
+     *
+     * File that stores the connection in case the connection is
+     * file-backed.
+     *
+     * Since: 1.12
+     **/
+    obj_properties[PROP_FILENAME] = g_param_spec_string(NM_REMOTE_CONNECTION_FILENAME,
+                                                        "",
+                                                        "",
+                                                        NULL,
+                                                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    /**
+     * NMRemoteConnection:visible:
+     *
+     * %TRUE if the remote connection is visible to the current user, %FALSE if
+     * not.  If the connection is not visible then it is essentially useless; it
+     * will not contain any settings, and operations such as
+     * nm_remote_connection_save() and nm_remote_connection_delete() will always
+     * fail. (#NMRemoteSettings will not normally return non-visible connections
+     * to callers, but it is possible for a connection's visibility to change
+     * after you already have a reference to it.)
+     **/
+    obj_properties[PROP_VISIBLE] = g_param_spec_boolean(NM_REMOTE_CONNECTION_VISIBLE,
+                                                        "",
+                                                        "",
+                                                        FALSE,
+                                                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+    _nml_dbus_meta_class_init_with_properties(object_class,
+                                              &_nml_dbus_meta_iface_nm_settings_connection);
+}
+
+static void
+nm_remote_connection_connection_iface_init(NMConnectionInterface *iface)
+{}