mirror of
https://github.com/morgan9e/grd
synced 2026-04-13 16:04:13 +09:00
912 lines
30 KiB
C
912 lines
30 KiB
C
/*
|
|
* Copyright (C) 2023 SUSE Software Solutions Germany GmbH
|
|
*
|
|
* 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., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*
|
|
* Written by:
|
|
* Joan Torres <joan.torres@suse.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "grd-daemon-handover.h"
|
|
|
|
#include <gio/gunixfdlist.h>
|
|
#include <glib/gi18n.h>
|
|
#include <unistd.h>
|
|
|
|
#include "grd-context.h"
|
|
#include "grd-daemon.h"
|
|
#include "grd-daemon-utils.h"
|
|
#include "grd-dbus-remote-desktop.h"
|
|
#include "grd-private.h"
|
|
#include "grd-prompt.h"
|
|
#include "grd-rdp-server.h"
|
|
#include "grd-session-rdp.h"
|
|
#include "grd-settings.h"
|
|
#include "grd-shell-dialog.h"
|
|
|
|
struct _GrdDaemonHandover
|
|
{
|
|
GrdDaemon parent;
|
|
|
|
GrdDBusRemoteDesktopRdpDispatcher *remote_desktop_dispatcher;
|
|
GrdDBusRemoteDesktopRdpHandover *remote_desktop_handover;
|
|
|
|
GDBusObjectManager *handover_object_manager;
|
|
|
|
GrdSession *session;
|
|
|
|
gboolean use_system_credentials;
|
|
GrdPrompt *prompt;
|
|
GCancellable *prompt_cancellable;
|
|
|
|
GrdShellDialog *dialog;
|
|
|
|
unsigned int gnome_remote_desktop_watch_name_id;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GrdDaemonHandover, grd_daemon_handover, GRD_TYPE_DAEMON)
|
|
|
|
static void
|
|
on_remote_desktop_rdp_dispatcher_handover_requested (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data);
|
|
|
|
static gboolean
|
|
grd_daemon_handover_is_ready (GrdDaemon *daemon)
|
|
{
|
|
GrdContext *context = grd_daemon_get_context (daemon);
|
|
|
|
if (!grd_context_get_mutter_remote_desktop_proxy (context) ||
|
|
!grd_context_get_mutter_screen_cast_proxy (context) ||
|
|
!GRD_DAEMON_HANDOVER (daemon)->remote_desktop_handover)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
on_take_client_finished (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
int fd;
|
|
int fd_idx = -1;
|
|
g_autoptr (GError) error = NULL;
|
|
g_autoptr (GSocket) socket = NULL;
|
|
g_autoptr (GVariant) fd_variant = NULL;
|
|
g_autoptr (GUnixFDList) fd_list = NULL;
|
|
GrdDBusRemoteDesktopRdpHandover *proxy;
|
|
GrdDaemonHandover *daemon_handover;
|
|
GrdRdpServer *rdp_server;
|
|
GSocketConnection *socket_connection;
|
|
|
|
proxy = GRD_DBUS_REMOTE_DESKTOP_RDP_HANDOVER (object);
|
|
if (!grd_dbus_remote_desktop_rdp_handover_call_take_client_finish (
|
|
proxy, &fd_variant, &fd_list, result, &error))
|
|
{
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
return;
|
|
|
|
g_warning ("[DaemonHandover] An error occurred while calling "
|
|
"TakeClient: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
g_variant_get (fd_variant, "h", &fd_idx);
|
|
if (!G_IS_UNIX_FD_LIST (fd_list) ||
|
|
fd_idx < 0 || fd_idx >= g_unix_fd_list_get_length (fd_list))
|
|
{
|
|
g_warning ("Failed to acquire file descriptor: The fd list or fd index "
|
|
"is invalid");
|
|
return;
|
|
}
|
|
|
|
fd = g_unix_fd_list_get (fd_list, fd_idx, &error);
|
|
if (fd == -1)
|
|
{
|
|
g_warning ("[DaemonHandover] Failed to acquire file descriptor: %s",
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
socket = g_socket_new_from_fd (fd, &error);
|
|
if (!socket)
|
|
{
|
|
g_warning ("[DaemonHandover] Failed to create socket from fd: %s",
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
rdp_server = grd_daemon_get_rdp_server (GRD_DAEMON (daemon_handover));
|
|
socket_connection = g_socket_connection_factory_create_connection (socket);
|
|
|
|
grd_rdp_server_notify_incoming (G_SOCKET_SERVICE (rdp_server),
|
|
socket_connection);
|
|
}
|
|
|
|
static void
|
|
on_get_system_credentials_finished (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GrdDBusRemoteDesktopRdpHandover *remote_desktop_handover;
|
|
g_autoptr (GError) error = NULL;
|
|
g_autofree char *username = NULL;
|
|
g_autofree char *password = NULL;
|
|
GrdDaemonHandover *daemon_handover;
|
|
GrdContext *context;
|
|
GrdSettings *settings;
|
|
GCancellable *cancellable;
|
|
const char* object_path;
|
|
|
|
remote_desktop_handover = GRD_DBUS_REMOTE_DESKTOP_RDP_HANDOVER (object);
|
|
if (!grd_dbus_remote_desktop_rdp_handover_call_get_system_credentials_finish (
|
|
remote_desktop_handover,
|
|
&username,
|
|
&password,
|
|
result,
|
|
&error))
|
|
{
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
return;
|
|
|
|
g_warning ("[DaemonHandover] Failed to get system credentials: %s",
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
context = grd_daemon_get_context (GRD_DAEMON (daemon_handover));
|
|
settings = grd_context_get_settings (context);
|
|
|
|
if (!grd_settings_set_rdp_credentials (settings, username, password, &error))
|
|
{
|
|
g_warning ("[DaemonHanodver] Failed to overwrite credentials: %s",
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
object_path =
|
|
g_dbus_proxy_get_object_path (G_DBUS_PROXY (remote_desktop_handover));
|
|
|
|
g_debug ("[DaemonHandover] At: %s, calling TakeClient", object_path);
|
|
|
|
cancellable = grd_daemon_get_cancellable (GRD_DAEMON (daemon_handover));
|
|
grd_dbus_remote_desktop_rdp_handover_call_take_client (
|
|
remote_desktop_handover,
|
|
NULL,
|
|
cancellable,
|
|
on_take_client_finished,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_take_client_ready (GrdDBusRemoteDesktopRdpHandover *interface,
|
|
gboolean use_system_credentials,
|
|
GrdDaemonHandover *daemon_handover)
|
|
{
|
|
GCancellable *cancellable =
|
|
grd_daemon_get_cancellable (GRD_DAEMON (daemon_handover));
|
|
const char* object_path;
|
|
|
|
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (interface));
|
|
|
|
g_debug ("[DaemonHandover] At: %s, received TakeClientReady signal",
|
|
object_path);
|
|
|
|
daemon_handover->use_system_credentials = use_system_credentials;
|
|
|
|
if (use_system_credentials)
|
|
{
|
|
g_debug ("[DaemonHandover] At: %s, calling GetSystemCredentials",
|
|
object_path);
|
|
|
|
grd_dbus_remote_desktop_rdp_handover_call_get_system_credentials (
|
|
interface,
|
|
cancellable,
|
|
on_get_system_credentials_finished,
|
|
daemon_handover);
|
|
|
|
return;
|
|
}
|
|
|
|
g_debug ("[DaemonHandover] At: %s, calling TakeClient", object_path);
|
|
|
|
grd_dbus_remote_desktop_rdp_handover_call_take_client (
|
|
interface,
|
|
NULL,
|
|
cancellable,
|
|
on_take_client_finished,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_start_handover_finished (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GrdDBusRemoteDesktopRdpHandover *proxy;
|
|
g_autofree char *certificate = NULL;
|
|
g_autofree char *key = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
GrdDaemonHandover *daemon_handover;
|
|
GrdContext *context;
|
|
GrdSettings *settings;
|
|
|
|
proxy = GRD_DBUS_REMOTE_DESKTOP_RDP_HANDOVER (object);
|
|
if (!grd_dbus_remote_desktop_rdp_handover_call_start_handover_finish (
|
|
proxy, &certificate, &key, result, &error))
|
|
{
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
return;
|
|
|
|
g_warning ("[DaemonHandover] Failed to start handover: %s",
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
context = grd_daemon_get_context (GRD_DAEMON (daemon_handover));
|
|
settings = grd_context_get_settings (context);
|
|
|
|
g_object_set (G_OBJECT (settings),
|
|
"rdp-server-cert", certificate,
|
|
"rdp-server-key", key,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
start_handover (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
GrdDaemon *daemon = GRD_DAEMON (daemon_handover);
|
|
GrdContext *context = grd_daemon_get_context (daemon);
|
|
GrdSettings *settings = grd_context_get_settings (context);
|
|
GCancellable *cancellable = grd_daemon_get_cancellable (daemon);
|
|
g_autofree char *username = NULL;
|
|
g_autofree char *password = NULL;
|
|
const char *object_path;
|
|
|
|
if (!grd_settings_get_rdp_credentials (settings,
|
|
&username, &password,
|
|
NULL))
|
|
g_assert_not_reached ();
|
|
|
|
object_path = g_dbus_proxy_get_object_path (
|
|
G_DBUS_PROXY (daemon_handover->remote_desktop_handover));
|
|
|
|
g_debug ("[DaemonHandover] At: %s, calling StartHandover", object_path);
|
|
|
|
grd_dbus_remote_desktop_rdp_handover_call_start_handover (
|
|
daemon_handover->remote_desktop_handover,
|
|
username,
|
|
password,
|
|
cancellable,
|
|
on_start_handover_finished,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_session_stopped (GrdSession *session,
|
|
GrdDaemonHandover *daemon_handover)
|
|
{
|
|
if (grd_is_remote_login ())
|
|
grd_session_manager_call_logout_sync ();
|
|
|
|
daemon_handover->session = NULL;
|
|
}
|
|
|
|
static gboolean
|
|
show_insecure_connection_dialog (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
GCancellable *cancellable =
|
|
grd_daemon_get_cancellable (GRD_DAEMON (daemon_handover));
|
|
|
|
g_assert (!daemon_handover->dialog);
|
|
|
|
daemon_handover->dialog = grd_shell_dialog_new (cancellable);
|
|
if (!daemon_handover->dialog)
|
|
return FALSE;
|
|
|
|
g_signal_connect_swapped (daemon_handover->dialog, "cancelled",
|
|
G_CALLBACK (grd_session_stop),
|
|
daemon_handover->session);
|
|
|
|
grd_shell_dialog_open (daemon_handover->dialog,
|
|
_("Continue With Insecure Connection?"),
|
|
/* Translators: Don't translate “use redirection server name:i:1”.
|
|
* It's a menu option, and it's the same for all languages. */
|
|
_("This Remote Desktop connection is insecure. "
|
|
"To secure this connection, enable RDSTLS Security "
|
|
"in your client by saving the connection settings "
|
|
"in your client as an RDP file and set "
|
|
"“use redirection server name:i:1” in it."),
|
|
_("Disconnect"),
|
|
_("Continue"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
prompt_response_callback (GObject *source_object,
|
|
GAsyncResult *async_result,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemonHandover *daemon_handover;
|
|
g_autoptr (GError) error = NULL;
|
|
GrdPromptResponse response;
|
|
|
|
if (!grd_prompt_query_finish (GRD_PROMPT (source_object),
|
|
async_result,
|
|
&response,
|
|
&error))
|
|
{
|
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
{
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
|
|
g_warning ("Failed to query user about session: %s", error->message);
|
|
grd_session_stop (daemon_handover->session);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
|
|
switch (response)
|
|
{
|
|
case GRD_PROMPT_RESPONSE_ACCEPT:
|
|
return;
|
|
case GRD_PROMPT_RESPONSE_CANCEL:
|
|
grd_session_stop (daemon_handover->session);
|
|
return;
|
|
}
|
|
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static void
|
|
show_insecure_connection_prompt (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
g_autoptr (GrdPromptDefinition) prompt_definition = NULL;
|
|
|
|
g_assert (!daemon_handover->prompt);
|
|
|
|
daemon_handover->prompt = g_object_new (GRD_TYPE_PROMPT, NULL);
|
|
daemon_handover->prompt_cancellable = g_cancellable_new ();
|
|
|
|
prompt_definition = g_new0 (GrdPromptDefinition, 1);
|
|
prompt_definition->summary =
|
|
g_strdup_printf (_("Continue With Insecure Connection?"));
|
|
prompt_definition->body =
|
|
/* Translators: Don't translate “use redirection server name:i:1”.
|
|
* It's a menu option, and it's the same for all languages. */
|
|
g_strdup_printf (_("This Remote Desktop connection is insecure. "
|
|
"To secure this connection, enable RDSTLS Security "
|
|
"in your client by saving the connection settings "
|
|
"in your client as an RDP file and set "
|
|
"“use redirection server name:i:1” in it."));
|
|
prompt_definition->cancel_label = g_strdup_printf (_("Disconnect"));
|
|
prompt_definition->accept_label = g_strdup_printf (_("Continue"));
|
|
|
|
grd_prompt_query_async (daemon_handover->prompt,
|
|
prompt_definition,
|
|
daemon_handover->prompt_cancellable,
|
|
prompt_response_callback,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
inform_about_insecure_connection (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
gboolean could_display_dialog;
|
|
|
|
could_display_dialog = show_insecure_connection_dialog (daemon_handover);
|
|
if (!could_display_dialog)
|
|
show_insecure_connection_prompt (daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_redirect_client (GrdDBusRemoteDesktopRdpHandover *interface,
|
|
const char *routing_token,
|
|
const char *username,
|
|
const char *password,
|
|
GrdDaemonHandover *daemon_handover)
|
|
{
|
|
const char *object_path =
|
|
g_dbus_proxy_get_object_path (G_DBUS_PROXY (interface));
|
|
GrdContext *context = grd_daemon_get_context (GRD_DAEMON (daemon_handover));
|
|
GrdSettings *settings = grd_context_get_settings (context);
|
|
GrdSessionRdp *session_rdp = GRD_SESSION_RDP (daemon_handover->session);
|
|
g_autofree char *certificate = NULL;
|
|
|
|
g_debug ("[DaemonHandover] At: %s, received RedirectClient signal",
|
|
object_path);
|
|
|
|
g_object_get (G_OBJECT (settings),
|
|
"rdp-server-cert", &certificate,
|
|
NULL);
|
|
|
|
if (!grd_session_rdp_send_server_redirection (session_rdp, routing_token,
|
|
username, password,
|
|
certificate))
|
|
grd_session_stop (daemon_handover->session);
|
|
}
|
|
|
|
static void
|
|
on_handover_is_waiting_changed (GrdDBusRemoteDesktopRdpHandover *proxy,
|
|
GParamSpec *pspec,
|
|
GrdDaemonHandover *daemon_handover)
|
|
{
|
|
gboolean handover_is_waiting;
|
|
|
|
handover_is_waiting =
|
|
grd_dbus_remote_desktop_rdp_handover_get_handover_is_waiting (
|
|
daemon_handover->remote_desktop_handover);
|
|
|
|
if (!handover_is_waiting)
|
|
return;
|
|
|
|
start_handover (daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_incoming_new_connection (GrdRdpServer *rdp_server,
|
|
GrdSession *session,
|
|
GrdDaemonHandover *daemon_handover)
|
|
{
|
|
GrdContext *context = grd_daemon_get_context (GRD_DAEMON (daemon_handover));
|
|
GrdSettings *settings = grd_context_get_settings (context);
|
|
|
|
if (daemon_handover->session)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (daemon_handover->session,
|
|
G_CALLBACK (on_session_stopped),
|
|
daemon_handover);
|
|
grd_session_stop (daemon_handover->session);
|
|
}
|
|
|
|
g_signal_connect (session, "stopped",
|
|
G_CALLBACK (on_session_stopped),
|
|
daemon_handover);
|
|
|
|
daemon_handover->session = session;
|
|
|
|
grd_settings_recreate_rdp_credentials (settings);
|
|
|
|
if (daemon_handover->use_system_credentials && grd_is_remote_login ())
|
|
inform_about_insecure_connection (daemon_handover);
|
|
}
|
|
|
|
static void
|
|
setup_handover (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
GrdRdpServer *rdp_server;
|
|
gboolean handover_is_waiting;
|
|
|
|
if (!daemon_handover->remote_desktop_handover)
|
|
return;
|
|
|
|
rdp_server = grd_daemon_get_rdp_server (GRD_DAEMON (daemon_handover));
|
|
if (!rdp_server)
|
|
return;
|
|
|
|
g_signal_connect (daemon_handover->remote_desktop_handover, "take-client-ready",
|
|
G_CALLBACK (on_take_client_ready), daemon_handover);
|
|
g_signal_connect (daemon_handover->remote_desktop_handover, "redirect-client",
|
|
G_CALLBACK (on_redirect_client), daemon_handover);
|
|
g_signal_connect (daemon_handover->remote_desktop_handover, "notify::handover-is-waiting",
|
|
G_CALLBACK (on_handover_is_waiting_changed), daemon_handover);
|
|
|
|
g_signal_connect (rdp_server, "incoming-new-connection",
|
|
G_CALLBACK (on_incoming_new_connection), daemon_handover);
|
|
|
|
handover_is_waiting = grd_dbus_remote_desktop_rdp_handover_get_handover_is_waiting (
|
|
daemon_handover->remote_desktop_handover);
|
|
|
|
if (handover_is_waiting)
|
|
start_handover (daemon_handover);
|
|
}
|
|
|
|
static void
|
|
teardown_handover (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
GrdRdpServer *rdp_server =
|
|
grd_daemon_get_rdp_server (GRD_DAEMON (daemon_handover));
|
|
|
|
if (daemon_handover->remote_desktop_handover)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (daemon_handover->remote_desktop_handover,
|
|
G_CALLBACK (on_take_client_ready),
|
|
daemon_handover);
|
|
g_signal_handlers_disconnect_by_func (daemon_handover->remote_desktop_handover,
|
|
G_CALLBACK (on_redirect_client),
|
|
daemon_handover);
|
|
g_signal_handlers_disconnect_by_func (daemon_handover->remote_desktop_handover,
|
|
G_CALLBACK (on_handover_is_waiting_changed),
|
|
daemon_handover);
|
|
}
|
|
|
|
if (rdp_server)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (rdp_server,
|
|
G_CALLBACK (on_incoming_new_connection),
|
|
daemon_handover);
|
|
}
|
|
}
|
|
|
|
static void
|
|
on_rdp_server_started (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
setup_handover (daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_rdp_server_stopped (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
teardown_handover (daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_handover_object_added (GDBusObjectManager *manager,
|
|
GDBusObject *object,
|
|
GrdDaemonHandover *daemon_handover)
|
|
{
|
|
g_autofree char *session_id = NULL;
|
|
g_autofree char *expected_object_path = NULL;
|
|
const char *object_path;
|
|
GCancellable *cancellable;
|
|
|
|
session_id = grd_get_session_id_from_pid (getpid ());
|
|
if (!session_id)
|
|
{
|
|
g_warning ("[DaemonHandover] Could not get session id");
|
|
return;
|
|
}
|
|
|
|
expected_object_path = g_strdup_printf ("%s/session%s",
|
|
REMOTE_DESKTOP_HANDOVERS_OBJECT_PATH,
|
|
session_id);
|
|
object_path = g_dbus_object_get_object_path (object);
|
|
|
|
if (g_strcmp0 (object_path, expected_object_path) != 0)
|
|
{
|
|
g_debug ("[DaemonHandover] Ignoring handover object at: %s, "
|
|
"expected: %s", object_path, expected_object_path);
|
|
return;
|
|
}
|
|
|
|
cancellable = grd_daemon_get_cancellable (GRD_DAEMON (daemon_handover));
|
|
grd_dbus_remote_desktop_rdp_dispatcher_call_request_handover (
|
|
daemon_handover->remote_desktop_dispatcher,
|
|
cancellable,
|
|
on_remote_desktop_rdp_dispatcher_handover_requested,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_handover_object_manager_acquired (GObject *source_object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr (GDBusObjectManager) manager = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
GrdDaemonHandover *daemon_handover;
|
|
|
|
manager =
|
|
grd_dbus_remote_desktop_object_manager_client_new_for_bus_finish (result,
|
|
&error);
|
|
if (!manager)
|
|
{
|
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
g_warning ("[DaemonHandover] Failed to create handover object manager: %s",
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
daemon_handover->handover_object_manager = g_steal_pointer (&manager);
|
|
|
|
g_debug ("[DaemonHandover] Watching handover objects");
|
|
|
|
g_signal_connect (daemon_handover->handover_object_manager, "object-added",
|
|
G_CALLBACK (on_handover_object_added), daemon_handover);
|
|
}
|
|
|
|
static void
|
|
start_watching_handover_objects (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
GCancellable *cancellable;
|
|
|
|
if (daemon_handover->handover_object_manager)
|
|
return;
|
|
|
|
cancellable = grd_daemon_get_cancellable (GRD_DAEMON (daemon_handover));
|
|
|
|
grd_dbus_remote_desktop_object_manager_client_new_for_bus (
|
|
G_BUS_TYPE_SYSTEM,
|
|
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START,
|
|
REMOTE_DESKTOP_BUS_NAME,
|
|
REMOTE_DESKTOP_HANDOVERS_OBJECT_PATH,
|
|
cancellable,
|
|
on_handover_object_manager_acquired,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
stop_watching_handover_objects (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
if (!daemon_handover->handover_object_manager)
|
|
return;
|
|
|
|
g_signal_handlers_disconnect_by_func (daemon_handover->handover_object_manager,
|
|
G_CALLBACK (on_handover_object_added),
|
|
daemon_handover);
|
|
|
|
g_clear_object (&daemon_handover->handover_object_manager);
|
|
}
|
|
|
|
static void
|
|
on_remote_desktop_rdp_handover_proxy_acquired (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemonHandover *daemon_handover;
|
|
g_autoptr (GrdDBusRemoteDesktopRdpHandover) proxy = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
proxy =
|
|
grd_dbus_remote_desktop_rdp_handover_proxy_new_for_bus_finish (result,
|
|
&error);
|
|
if (!proxy)
|
|
{
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
return;
|
|
|
|
g_warning ("[DaemonHandover] Failed to create remote desktop handover "
|
|
"proxy: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
|
|
stop_watching_handover_objects (daemon_handover);
|
|
|
|
daemon_handover->remote_desktop_handover = g_steal_pointer (&proxy);
|
|
|
|
setup_handover (daemon_handover);
|
|
|
|
grd_daemon_maybe_enable_services (GRD_DAEMON (daemon_handover));
|
|
}
|
|
|
|
static void
|
|
on_remote_desktop_rdp_dispatcher_handover_requested (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GrdDBusRemoteDesktopRdpDispatcher *remote_desktop_dispatcher;
|
|
g_autofree char *object_path = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
GrdDaemonHandover *daemon_handover;
|
|
GCancellable *cancellable;
|
|
gboolean success;
|
|
|
|
remote_desktop_dispatcher = GRD_DBUS_REMOTE_DESKTOP_RDP_DISPATCHER (object);
|
|
success =
|
|
grd_dbus_remote_desktop_rdp_dispatcher_call_request_handover_finish (
|
|
remote_desktop_dispatcher,
|
|
&object_path,
|
|
result,
|
|
&error);
|
|
if (!success)
|
|
{
|
|
if (g_error_matches (error, GRD_DBUS_ERROR, GRD_DBUS_ERROR_NO_HANDOVER))
|
|
{
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
start_watching_handover_objects (daemon_handover);
|
|
}
|
|
else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
{
|
|
g_warning ("[DaemonHandover] Failed to request remote desktop "
|
|
"handover: %s", error->message);
|
|
}
|
|
return;
|
|
}
|
|
|
|
g_debug ("[DaemonHandover] Using: %s, from dispatcher request",
|
|
object_path);
|
|
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
cancellable = grd_daemon_get_cancellable (GRD_DAEMON (daemon_handover));
|
|
|
|
grd_dbus_remote_desktop_rdp_handover_proxy_new_for_bus (
|
|
G_BUS_TYPE_SYSTEM,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
REMOTE_DESKTOP_BUS_NAME,
|
|
object_path,
|
|
cancellable,
|
|
on_remote_desktop_rdp_handover_proxy_acquired,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_remote_desktop_rdp_dispatcher_proxy_acquired (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr (GrdDBusRemoteDesktopRdpDispatcher) proxy = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
GrdDaemonHandover *daemon_handover;
|
|
GCancellable *cancellable;
|
|
|
|
proxy =
|
|
grd_dbus_remote_desktop_rdp_dispatcher_proxy_new_finish (result, &error);
|
|
if (!proxy)
|
|
{
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
return;
|
|
|
|
g_warning ("[DaemonHandover] Failed to create remote desktop "
|
|
"dispatcher proxy: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
daemon_handover = GRD_DAEMON_HANDOVER (user_data);
|
|
|
|
g_assert (!daemon_handover->remote_desktop_dispatcher);
|
|
daemon_handover->remote_desktop_dispatcher = g_steal_pointer (&proxy);
|
|
|
|
cancellable = grd_daemon_get_cancellable (GRD_DAEMON (daemon_handover));
|
|
grd_dbus_remote_desktop_rdp_dispatcher_call_request_handover (
|
|
daemon_handover->remote_desktop_dispatcher,
|
|
cancellable,
|
|
on_remote_desktop_rdp_dispatcher_handover_requested,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_gnome_remote_desktop_name_appeared (GDBusConnection *connection,
|
|
const char *name,
|
|
const char *name_owner,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemonHandover *daemon_handover = user_data;
|
|
GCancellable *cancellable =
|
|
grd_daemon_get_cancellable (GRD_DAEMON (daemon_handover));
|
|
|
|
g_debug ("[DaemonHandover] %s name appeared", name);
|
|
|
|
grd_dbus_remote_desktop_rdp_dispatcher_proxy_new (
|
|
connection,
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
|
REMOTE_DESKTOP_BUS_NAME,
|
|
REMOTE_DESKTOP_DISPATCHER_OBJECT_PATH,
|
|
cancellable,
|
|
on_remote_desktop_rdp_dispatcher_proxy_acquired,
|
|
daemon_handover);
|
|
}
|
|
|
|
static void
|
|
on_gnome_remote_desktop_name_vanished (GDBusConnection *connection,
|
|
const char *name,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemonHandover *daemon_handover = user_data;
|
|
|
|
g_warning ("[DaemonHandover] %s name vanished", name);
|
|
|
|
teardown_handover (daemon_handover);
|
|
|
|
g_clear_object (&daemon_handover->remote_desktop_handover);
|
|
g_clear_object (&daemon_handover->remote_desktop_dispatcher);
|
|
|
|
stop_watching_handover_objects (daemon_handover);
|
|
|
|
if (grd_is_remote_login ())
|
|
grd_session_manager_call_logout_sync ();
|
|
}
|
|
|
|
GrdDaemonHandover *
|
|
grd_daemon_handover_new (GError **error)
|
|
{
|
|
GrdContext *context;
|
|
|
|
context = grd_context_new (GRD_RUNTIME_MODE_HANDOVER, error);
|
|
if (!context)
|
|
return NULL;
|
|
|
|
return g_object_new (GRD_TYPE_DAEMON_HANDOVER,
|
|
"application-id", GRD_DAEMON_HANDOVER_APPLICATION_ID,
|
|
"flags", G_APPLICATION_IS_SERVICE,
|
|
"context", context,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
grd_daemon_handover_init (GrdDaemonHandover *daemon_handover)
|
|
{
|
|
}
|
|
|
|
static void
|
|
grd_daemon_handover_startup (GApplication *app)
|
|
{
|
|
GrdDaemonHandover *daemon_handover = GRD_DAEMON_HANDOVER (app);
|
|
|
|
grd_daemon_acquire_mutter_dbus_proxies (GRD_DAEMON (daemon_handover));
|
|
|
|
g_signal_connect (daemon_handover, "mutter-proxy-acquired",
|
|
G_CALLBACK (grd_daemon_maybe_enable_services), NULL);
|
|
|
|
daemon_handover->gnome_remote_desktop_watch_name_id =
|
|
g_bus_watch_name (G_BUS_TYPE_SYSTEM,
|
|
REMOTE_DESKTOP_BUS_NAME,
|
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
on_gnome_remote_desktop_name_appeared,
|
|
on_gnome_remote_desktop_name_vanished,
|
|
daemon_handover, NULL);
|
|
|
|
g_signal_connect (daemon_handover, "rdp-server-started",
|
|
G_CALLBACK (on_rdp_server_started), NULL);
|
|
|
|
g_signal_connect (daemon_handover, "rdp-server-stopped",
|
|
G_CALLBACK (on_rdp_server_stopped), NULL);
|
|
|
|
G_APPLICATION_CLASS (grd_daemon_handover_parent_class)->startup (app);
|
|
}
|
|
|
|
static void
|
|
grd_daemon_handover_shutdown (GApplication *app)
|
|
{
|
|
GrdDaemonHandover *daemon_handover = GRD_DAEMON_HANDOVER (app);
|
|
GrdDaemon *daemon = GRD_DAEMON (daemon_handover);
|
|
|
|
g_cancellable_cancel (grd_daemon_get_cancellable (daemon));
|
|
|
|
g_clear_object (&daemon_handover->remote_desktop_handover);
|
|
g_clear_object (&daemon_handover->remote_desktop_dispatcher);
|
|
|
|
stop_watching_handover_objects (daemon_handover);
|
|
|
|
g_clear_handle_id (&daemon_handover->gnome_remote_desktop_watch_name_id,
|
|
g_bus_unwatch_name);
|
|
|
|
if (daemon_handover->prompt_cancellable)
|
|
{
|
|
g_cancellable_cancel (daemon_handover->prompt_cancellable);
|
|
g_clear_object (&daemon_handover->prompt_cancellable);
|
|
}
|
|
g_clear_object (&daemon_handover->prompt);
|
|
|
|
g_clear_object (&daemon_handover->dialog);
|
|
|
|
G_APPLICATION_CLASS (grd_daemon_handover_parent_class)->shutdown (app);
|
|
}
|
|
|
|
static void
|
|
grd_daemon_handover_class_init (GrdDaemonHandoverClass *klass)
|
|
{
|
|
GApplicationClass *g_application_class = G_APPLICATION_CLASS (klass);
|
|
GrdDaemonClass *daemon_class = GRD_DAEMON_CLASS (klass);
|
|
|
|
g_application_class->startup = grd_daemon_handover_startup;
|
|
g_application_class->shutdown = grd_daemon_handover_shutdown;
|
|
|
|
daemon_class->is_daemon_ready = grd_daemon_handover_is_ready;
|
|
}
|