1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
/* gnome-keyring-daemon-dbus.c - daemon usage of dbus
4
Copyright (C) 2007, Stefan Walter
6
Gnome keyring is free software; you can redistribute it and/or
7
modify it under the terms of the GNU General Public License as
8
published by the Free Software Foundation; either version 2 of the
9
License, or (at your option) any later version.
11
Gnome keyring is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
Author: Stef Walter <stef@memberwebs.com>
25
#include "gkr-daemon.h"
27
#include "egg/egg-cleanup.h"
28
#include "egg/egg-dbus.h"
30
#include "library/gnome-keyring.h"
31
#include "library/gnome-keyring-private.h"
33
#include "util/gkr-daemon-util.h"
35
#include <dbus/dbus.h>
39
#define SERVICE_SESSION_MANAGER "org.gnome.SessionManager"
40
#define PATH_SESSION_MANAGER "/org/gnome/SessionManager"
41
#define IFACE_SESSION_MANAGER "org.gnome.SessionManager"
42
#define IFACE_SESSION_CLIENT "org.gnome.SessionManager.Client"
43
#define IFACE_SESSION_PRIVATE "org.gnome.SessionManager.ClientPrivate"
45
static DBusConnection *dbus_conn = NULL;
46
static gchar *client_session_path = NULL;
47
static gchar *client_session_rule = NULL;
48
static gboolean dbus_initialized = FALSE;
50
/* -----------------------------------------------------------------------------------
55
send_end_session_response ()
60
DBusError derr = { 0 };
61
const gchar *reason = "";
62
dbus_bool_t is_ok = TRUE;
64
g_return_if_fail (client_session_path);
65
g_return_if_fail (dbus_conn);
67
msg = dbus_message_new_method_call (SERVICE_SESSION_MANAGER,
69
IFACE_SESSION_PRIVATE,
70
"EndSessionResponse");
71
g_return_if_fail (msg);
73
dbus_message_iter_init_append (msg, &args);
74
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_BOOLEAN, &is_ok) ||
75
!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &reason))
76
g_return_if_reached ();
78
reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
79
dbus_message_unref (msg);
82
g_message ("dbus failure responding to ending session: %s", derr.message);
86
dbus_message_unref (reply);
90
unregister_daemon_in_session (void)
95
DBusError derr = { 0 };
97
g_return_if_fail (dbus_conn);
99
if (client_session_rule) {
100
dbus_bus_remove_match (dbus_conn, client_session_rule, NULL);
101
g_free (client_session_rule);
102
client_session_rule = NULL;
105
if (!client_session_path)
108
msg = dbus_message_new_method_call (SERVICE_SESSION_MANAGER,
109
PATH_SESSION_MANAGER,
110
IFACE_SESSION_MANAGER,
112
g_return_if_fail (msg);
114
dbus_message_iter_init_append (msg, &args);
115
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_OBJECT_PATH, &client_session_path))
116
g_return_if_reached ();
118
reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
119
dbus_message_unref (msg);
122
g_message ("dbus failure unregistering from session: %s", derr.message);
126
dbus_message_unref (reply);
128
g_free (client_session_path);
129
client_session_path = NULL;
132
static DBusHandlerResult
133
signal_filter (DBusConnection *conn, DBusMessage *msg, void *user_data)
135
/* Quit the daemon when the session is over */
136
if (dbus_message_is_signal (msg, IFACE_SESSION_PRIVATE, "Stop")) {
137
unregister_daemon_in_session ();
139
return DBUS_HANDLER_RESULT_HANDLED;
140
} else if (dbus_message_is_signal (msg, IFACE_SESSION_PRIVATE, "QueryEndSession")) {
141
send_end_session_response ();
142
return DBUS_HANDLER_RESULT_HANDLED;
143
} else if (dbus_message_is_signal (msg, IFACE_SESSION_PRIVATE, "EndSession")) {
144
send_end_session_response ();
145
unregister_daemon_in_session ();
147
return DBUS_HANDLER_RESULT_HANDLED;
150
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
154
* Here we register our environment variables with a gnome-session style
155
* session manager via DBus.
158
register_environment_in_session (void)
160
DBusMessageIter args;
163
DBusError derr = { 0 };
168
g_return_if_fail (dbus_conn);
171
* The list of all environment variables registered by
172
* various components in the daemon.
174
envp = gkr_daemon_util_get_environment ();
176
for (; *envp; ++envp) {
178
/* Find the value part of the environment variable */
179
value = strchr (*envp, '=');
183
name = g_strndup (*envp, value - *envp);
186
msg = dbus_message_new_method_call (SERVICE_SESSION_MANAGER,
187
PATH_SESSION_MANAGER,
188
IFACE_SESSION_MANAGER,
190
g_return_if_fail (msg);
192
dbus_message_iter_init_append (msg, &args);
193
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &name) ||
194
!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &value))
195
g_return_if_reached ();
200
/* Send message and get a handle for a reply */
201
reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
202
dbus_message_unref (msg);
205
g_message ("couldn't set environment variable in session: %s", derr.message);
206
dbus_error_free (&derr);
210
dbus_message_unref (reply);
215
* Here we register our desktop autostart id gnome-session style
216
* session manager via DBus.
219
register_daemon_in_session (void)
221
DBusMessageIter args;
224
DBusError derr = { 0 };
225
const gchar *app_id = "gnome-keyring-daemon";
226
const gchar *client_id;
228
client_id = g_getenv ("DESKTOP_AUTOSTART_ID");
232
g_return_if_fail (dbus_conn);
234
msg = dbus_message_new_method_call (SERVICE_SESSION_MANAGER,
235
PATH_SESSION_MANAGER,
236
IFACE_SESSION_MANAGER,
238
g_return_if_fail (msg);
240
dbus_message_iter_init_append (msg, &args);
241
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &app_id) ||
242
!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &client_id))
243
g_return_if_reached ();
245
/* Send message and get a handle for a reply */
246
reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
247
dbus_message_unref (msg);
250
g_message ("couldn't register in session: %s", derr.message);
251
dbus_error_free (&derr);
255
/* Get out our client path */
256
if (!dbus_message_iter_init (reply, &args) ||
257
dbus_message_iter_get_arg_type (&args) != DBUS_TYPE_OBJECT_PATH) {
258
g_message ("invalid register response from session");
260
dbus_message_iter_get_basic (&args, &client_session_path);
261
client_session_path = g_strdup (client_session_path);
264
dbus_message_unref (reply);
267
* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
268
* use the same client id.
270
g_unsetenv ("DESKTOP_AUTOSTART_ID");
273
* Now we register for DBus signals on that client session path
274
* These are fired specifically for us.
276
client_session_rule = g_strdup_printf("type='signal',"
277
"interface='org.gnome.SessionManager.ClientPrivate',"
279
client_session_path);
280
dbus_bus_add_match (dbus_conn, client_session_rule, &derr);
282
if(dbus_error_is_set(&derr)) {
283
g_message ("couldn't listen for signals in session: %s", derr.message);
284
dbus_error_free (&derr);
285
g_free (client_session_rule);
286
client_session_rule = NULL;
290
dbus_connection_add_filter (dbus_conn, signal_filter, NULL, NULL);
293
/* -----------------------------------------------------------------------------------
294
* GNOME-KEYRING DBUS INTERFACES
297
static DBusHandlerResult
298
message_handler_cb (DBusConnection *conn, DBusMessage *message, void *user_data)
301
* Here we handle the requests to our own gnome-keyring DBus interfaces
304
DBusMessageIter args;
305
DBusMessage *reply = NULL;
308
if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
309
dbus_message_is_method_call (message, GNOME_KEYRING_DAEMON_INTERFACE, "GetSocketPath") &&
310
g_str_equal (dbus_message_get_signature (message), "")) {
312
const gchar *socket_path = gkr_daemon_io_get_socket_path ();
313
g_return_val_if_fail (socket_path, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
315
/* Setup the result */
316
reply = dbus_message_new_method_return (message);
317
dbus_message_iter_init_append (reply, &args);
318
if (!dbus_message_iter_append_basic (&args, DBUS_TYPE_STRING, &socket_path))
319
g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
322
} else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
323
dbus_message_is_method_call (message, GNOME_KEYRING_DAEMON_INTERFACE, "GetEnvironment") &&
324
g_str_equal (dbus_message_get_signature (message), "")) {
327
DBusMessageIter items, entry;
330
env = gkr_daemon_util_get_environment ();
331
g_return_val_if_fail (env, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
333
/* Setup the result */
334
reply = dbus_message_new_method_return (message);
335
dbus_message_iter_init_append (reply, &args);
336
if (!dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY, "{ss}", &items))
337
g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
339
parts = g_strsplit (*env, "=", 2);
340
g_return_val_if_fail (parts && parts[0] && parts[1], DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
341
if (!dbus_message_iter_open_container (&items, DBUS_TYPE_DICT_ENTRY, NULL, &entry) ||
342
!dbus_message_iter_append_basic (&entry, DBUS_TYPE_STRING, &parts[0]) ||
343
!dbus_message_iter_append_basic (&entry, DBUS_TYPE_STRING, &parts[1]) ||
344
!dbus_message_iter_close_container (&items, &entry))
345
g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
348
if (!dbus_message_iter_close_container (&args, &items))
349
g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
353
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
357
if (!dbus_connection_send (dbus_conn, reply, NULL))
358
g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
359
dbus_connection_flush (dbus_conn);
361
return DBUS_HANDLER_RESULT_HANDLED;
364
static DBusObjectPathVTable object_vtable = {
371
daemon_dbus_cleanup (gpointer unused)
374
unregister_daemon_in_session ();
376
dbus_connection_unregister_object_path (dbus_conn, GNOME_KEYRING_DAEMON_PATH);
377
egg_dbus_disconnect_from_mainloop (dbus_conn, NULL);
378
dbus_connection_unref (dbus_conn);
382
g_free (client_session_path);
383
client_session_path = NULL;
385
g_free (client_session_rule);
386
client_session_rule = NULL;
390
gkr_daemon_dbus_initialize (void)
392
dbus_uint32_t res = 0;
393
DBusError derr = { 0 };
395
if (dbus_initialized)
400
/* If running as a test, don't do DBUS stuff */
401
const gchar *env = g_getenv ("GNOME_KEYRING_TEST_PATH");
407
dbus_error_init (&derr);
409
/* Get the dbus bus and hook up */
410
dbus_conn = dbus_bus_get (DBUS_BUS_SESSION, &derr);
412
g_message ("couldn't connect to dbus session bus: %s", derr.message);
413
dbus_error_free (&derr);
417
egg_cleanup_register (daemon_dbus_cleanup, NULL);
419
egg_dbus_connect_with_mainloop (dbus_conn, NULL);
421
/* Make sure dbus doesn't kill our app */
422
dbus_connection_set_exit_on_disconnect (dbus_conn, FALSE);
424
/* Try and grab our name */
425
res = dbus_bus_request_name (dbus_conn, GNOME_KEYRING_DAEMON_SERVICE,
426
DBUS_NAME_FLAG_DO_NOT_QUEUE, &derr);
427
if (dbus_error_is_set (&derr)) {
428
g_message ("couldn't request name on session bus: %s", derr.message);
429
dbus_error_free (&derr);
433
/* We acquired the service name */
434
case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
436
/* We already acquired the service name. Odd */
437
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
438
g_return_if_reached ();
440
/* Another daemon is running */
441
case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
442
case DBUS_REQUEST_NAME_REPLY_EXISTS:
443
g_message ("another gnome-keyring-daemon is running");
446
g_return_if_reached ();
450
/* Now register the object */
451
if (!dbus_connection_register_object_path (dbus_conn, GNOME_KEYRING_DAEMON_PATH,
452
&object_vtable, NULL)) {
453
g_message ("couldn't register dbus object path");
457
dbus_initialized = TRUE;
459
/* Register with the session now that DBus is setup */
460
register_environment_in_session ();
461
register_daemon_in_session ();