diff options
Diffstat (limited to 'daemon/dbus/gkd-dbus.c')
-rw-r--r-- | daemon/dbus/gkd-dbus.c | 157 |
1 files changed, 140 insertions, 17 deletions
diff --git a/daemon/dbus/gkd-dbus.c b/daemon/dbus/gkd-dbus.c index 6644a790..3d304bd4 100644 --- a/daemon/dbus/gkd-dbus.c +++ b/daemon/dbus/gkd-dbus.c @@ -32,6 +32,7 @@ #include "egg/egg-cleanup.h" #include <glib.h> +#include <glib-unix.h> #include <gio/gio.h> static GDBusConnection *dbus_conn = NULL; @@ -112,6 +113,142 @@ handle_get_control_directory (GkdExportedDaemon *skeleton, return TRUE; } +struct SecretHelperData +{ + GPid pid; + GMainLoop *loop; + GIOChannel *channel; + gchar *name; + guint output_id; + guint child_id; + guint timeout_id; +}; + +static gboolean +on_secrets_helper_output (GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + struct SecretHelperData *data = user_data; + gchar *line; + gsize terminator_pos; + GError *error = NULL; + + if (g_io_channel_read_line (source, &line, NULL, + &terminator_pos, &error) == + G_IO_STATUS_NORMAL) { + line[terminator_pos] = '\0'; + data->name = line; + } + + data->output_id = 0; + g_main_loop_quit (data->loop); + return FALSE; +} + +static void +on_secrets_helper_child (GPid pid, + gint status, + gpointer user_data) +{ + struct SecretHelperData *data = user_data; + + g_spawn_close_pid (pid); + if (data->output_id > 0) + g_source_remove (data->output_id); + if (data->timeout_id > 0) + g_source_remove (data->timeout_id); + + data->child_id = 0; + g_main_loop_quit (data->loop); +} + +static gboolean +on_secrets_helper_timeout (gpointer user_data) +{ + struct SecretHelperData *data = user_data; + + kill (data->pid, SIGTERM); + data->timeout_id = 0; + g_main_loop_quit (data->loop); + return FALSE; +} + +static void +on_secrets_helper_peer_vanished (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + GPid pid = GPOINTER_TO_INT (user_data); + kill (pid, SIGTERM); +} + +static gboolean +handle_get_secret_service (GkdExportedDaemon *object, + GDBusMethodInvocation *invocation, + const gchar *arg_AppID) +{ + gchar *args[] = { + GKD_SECRETS_HELPER, + (gchar *) arg_AppID, + NULL + }; + gint standard_output; + GError *error = NULL; + struct SecretHelperData data; + const gchar *sender; + + memset (&data, 0, sizeof (data)); + + if (!g_spawn_async_with_pipes (NULL, args, NULL, G_SPAWN_DEFAULT, NULL, + NULL, &data.pid, NULL, &standard_output, NULL, &error)) { + g_dbus_method_invocation_return_gerror (invocation, error); + return FALSE; + } + + data.loop = g_main_loop_new (NULL, FALSE); + data.channel = g_io_channel_unix_new (standard_output); + data.name = NULL; + data.output_id = g_io_add_watch (data.channel, G_IO_IN, on_secrets_helper_output, &data); + data.child_id = g_child_watch_add (data.pid, on_secrets_helper_child, &data); + data.timeout_id = g_timeout_add (10000, on_secrets_helper_timeout, &data); + + g_main_loop_run (data.loop); + + if (data.output_id > 0) + g_source_remove (data.output_id); + if (data.child_id > 0) + g_source_remove (data.child_id); + if (data.timeout_id > 0) + g_source_remove (data.timeout_id); + + g_main_loop_unref (data.loop); + g_io_channel_unref (data.channel); + + if (data.name == NULL) { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "couldn't launch gkd-secrets-service"); + return FALSE; + } + + sender = g_dbus_method_invocation_get_sender (invocation); + g_bus_watch_name_on_connection (g_dbus_method_invocation_get_connection (invocation), + sender, + G_BUS_NAME_WATCHER_FLAGS_NONE, + NULL, + on_secrets_helper_peer_vanished, + GINT_TO_POINTER (data.pid), + NULL); + + gkd_exported_daemon_complete_get_secret_service (object, + invocation, + data.name); + g_free (data.name); + return TRUE; +} + static void cleanup_singleton (gpointer user_data) { @@ -149,6 +286,9 @@ gkd_dbus_singleton_acquire (gboolean *acquired) g_signal_connect (skeleton, "handle-get-environment", G_CALLBACK (handle_get_environment), NULL); + g_signal_connect (skeleton, "handle-get-secret-service", + G_CALLBACK (handle_get_secret_service), NULL); + g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton), dbus_conn, GNOME_KEYRING_DAEMON_PATH, &error); @@ -282,20 +422,3 @@ gkd_dbus_setup (void) egg_cleanup_register (dbus_cleanup, NULL); return TRUE; } - -gboolean -gkd_dbus_invocation_matches_caller (GDBusMethodInvocation *invocation, - const char *caller) -{ - const char *invocation_caller; - - invocation_caller = g_dbus_method_invocation_get_sender (invocation); - if (!g_str_equal (invocation_caller, caller)) { - g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, - G_DBUS_ERROR_ACCESS_DENIED, - "Invalid caller"); - return FALSE; - } - - return TRUE; -} |