mirror of
https://github.com/morgan9e/grd
synced 2026-04-14 00:14:18 +09:00
.
This commit is contained in:
911
grd-daemon-handover.c
Normal file
911
grd-daemon-handover.c
Normal file
@@ -0,0 +1,911 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user