~ubuntu-branches/ubuntu/natty/gnome-keyring/natty

« back to all changes in this revision

Viewing changes to daemon/gkr-daemon-dbus.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2010-02-16 19:00:06 UTC
  • mfrom: (1.1.58 upstream)
  • Revision ID: james.westby@ubuntu.com-20100216190006-cqpnic4zxlkmmi0o
Tags: 2.29.90git20100218-0ubuntu1
Updated to a git snapshot version

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
 
/* gnome-keyring-daemon-dbus.c - daemon usage of dbus
3
 
 
4
 
   Copyright (C) 2007, Stefan Walter
5
 
 
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.
10
 
  
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.
15
 
  
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.
19
 
 
20
 
   Author: Stef Walter <stef@memberwebs.com>
21
 
*/
22
 
 
23
 
#include "config.h"
24
 
 
25
 
#include "gkr-daemon.h"
26
 
 
27
 
#include "egg/egg-cleanup.h"
28
 
#include "egg/egg-dbus.h"
29
 
 
30
 
#include "library/gnome-keyring.h"
31
 
#include "library/gnome-keyring-private.h"
32
 
 
33
 
#include "util/gkr-daemon-util.h"
34
 
 
35
 
#include <dbus/dbus.h>
36
 
 
37
 
#include <string.h>
38
 
 
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"
44
 
 
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;
49
 
 
50
 
/* -----------------------------------------------------------------------------------
51
 
 * 
52
 
 */
53
 
 
54
 
static void
55
 
send_end_session_response ()
56
 
{
57
 
        DBusMessageIter args;
58
 
        DBusMessage *msg;
59
 
        DBusMessage *reply;
60
 
        DBusError derr = { 0 };
61
 
        const gchar *reason = "";
62
 
        dbus_bool_t is_ok = TRUE;
63
 
        
64
 
        g_return_if_fail (client_session_path);
65
 
        g_return_if_fail (dbus_conn);
66
 
        
67
 
        msg = dbus_message_new_method_call (SERVICE_SESSION_MANAGER,
68
 
                                            client_session_path,
69
 
                                            IFACE_SESSION_PRIVATE,
70
 
                                            "EndSessionResponse");
71
 
        g_return_if_fail (msg);
72
 
        
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 ();
77
 
        
78
 
        reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
79
 
        dbus_message_unref (msg);
80
 
        
81
 
        if (!reply) {
82
 
                g_message ("dbus failure responding to ending session: %s", derr.message);
83
 
                return;
84
 
        }
85
 
 
86
 
        dbus_message_unref (reply);
87
 
}
88
 
 
89
 
static void 
90
 
unregister_daemon_in_session (void)
91
 
{
92
 
        DBusMessageIter args;
93
 
        DBusMessage *msg;
94
 
        DBusMessage *reply;
95
 
        DBusError derr = { 0 };
96
 
 
97
 
        g_return_if_fail (dbus_conn);
98
 
 
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;
103
 
        }
104
 
 
105
 
        if (!client_session_path)
106
 
                return;
107
 
        
108
 
        msg = dbus_message_new_method_call (SERVICE_SESSION_MANAGER,
109
 
                                            PATH_SESSION_MANAGER,
110
 
                                            IFACE_SESSION_MANAGER,
111
 
                                            "UnregisterClient");
112
 
        g_return_if_fail (msg);
113
 
        
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 ();
117
 
        
118
 
        reply = dbus_connection_send_with_reply_and_block (dbus_conn, msg, 1000, &derr);
119
 
        dbus_message_unref (msg);
120
 
        
121
 
        if (!reply) {
122
 
                g_message ("dbus failure unregistering from session: %s", derr.message);
123
 
                return;
124
 
        }
125
 
        
126
 
        dbus_message_unref (reply);
127
 
        
128
 
        g_free (client_session_path);
129
 
        client_session_path = NULL;
130
 
}
131
 
 
132
 
static DBusHandlerResult
133
 
signal_filter (DBusConnection *conn, DBusMessage *msg, void *user_data)
134
 
{
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 ();
138
 
                gkr_daemon_quit ();
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 ();
146
 
                gkr_daemon_quit ();
147
 
                return DBUS_HANDLER_RESULT_HANDLED;
148
 
        }
149
 
        
150
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
151
 
}
152
 
 
153
 
/* 
154
 
 * Here we register our environment variables with a gnome-session style
155
 
 * session manager via DBus. 
156
 
 */
157
 
static void 
158
 
register_environment_in_session (void)
159
 
{
160
 
        DBusMessageIter args;
161
 
        DBusMessage *msg;
162
 
        DBusMessage *reply;
163
 
        DBusError derr = { 0 };
164
 
        const gchar **envp;
165
 
        const gchar *value;
166
 
        gchar *name;
167
 
        
168
 
        g_return_if_fail (dbus_conn);
169
 
        
170
 
        /* 
171
 
         * The list of all environment variables registered by
172
 
         * various components in the daemon.
173
 
         */ 
174
 
        envp = gkr_daemon_util_get_environment ();
175
 
        
176
 
        for (; *envp; ++envp) {
177
 
                
178
 
                /* Find the value part of the environment variable */
179
 
                value = strchr (*envp, '=');
180
 
                if (!value)
181
 
                        continue;
182
 
                
183
 
                name = g_strndup (*envp, value - *envp);
184
 
                ++value;
185
 
                
186
 
                msg = dbus_message_new_method_call (SERVICE_SESSION_MANAGER,
187
 
                                                    PATH_SESSION_MANAGER,
188
 
                                                    IFACE_SESSION_MANAGER,
189
 
                                                    "Setenv");
190
 
                g_return_if_fail (msg);
191
 
                
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 ();
196
 
                
197
 
                g_free (name);
198
 
                value = name = NULL;
199
 
                
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);
203
 
                
204
 
                if (!reply) {
205
 
                        g_message ("couldn't set environment variable in session: %s", derr.message);
206
 
                        dbus_error_free (&derr);
207
 
                        return;
208
 
                }
209
 
                
210
 
                dbus_message_unref (reply);
211
 
        }
212
 
}
213
 
 
214
 
/* 
215
 
 * Here we register our desktop autostart id gnome-session style
216
 
 * session manager via DBus. 
217
 
 */
218
 
static void 
219
 
register_daemon_in_session (void)
220
 
{
221
 
        DBusMessageIter args;
222
 
        DBusMessage *msg;
223
 
        DBusMessage *reply;
224
 
        DBusError derr = { 0 };
225
 
        const gchar *app_id = "gnome-keyring-daemon";
226
 
        const gchar *client_id;
227
 
        
228
 
        client_id = g_getenv ("DESKTOP_AUTOSTART_ID");
229
 
        if(!client_id)
230
 
                return;
231
 
        
232
 
        g_return_if_fail (dbus_conn);
233
 
        
234
 
        msg = dbus_message_new_method_call (SERVICE_SESSION_MANAGER,
235
 
                                            PATH_SESSION_MANAGER,
236
 
                                            IFACE_SESSION_MANAGER,
237
 
                                            "RegisterClient");
238
 
        g_return_if_fail (msg);
239
 
        
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 ();
244
 
        
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);
248
 
        
249
 
        if (!reply) {
250
 
                g_message ("couldn't register in session: %s", derr.message);
251
 
                dbus_error_free (&derr);
252
 
                return;
253
 
        }
254
 
        
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");
259
 
        } else {
260
 
                dbus_message_iter_get_basic (&args, &client_session_path);
261
 
                client_session_path = g_strdup (client_session_path);
262
 
        }
263
 
 
264
 
        dbus_message_unref (reply);
265
 
        
266
 
        /* 
267
 
         * Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
268
 
         * use the same client id. 
269
 
         */
270
 
        g_unsetenv ("DESKTOP_AUTOSTART_ID");
271
 
        
272
 
        /*
273
 
         * Now we register for DBus signals on that client session path
274
 
         * These are fired specifically for us.
275
 
         */
276
 
        client_session_rule = g_strdup_printf("type='signal',"
277
 
                                              "interface='org.gnome.SessionManager.ClientPrivate',"
278
 
                                              "path='%s'", 
279
 
                                              client_session_path);
280
 
        dbus_bus_add_match (dbus_conn, client_session_rule, &derr);
281
 
        
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;
287
 
                return;
288
 
        }
289
 
 
290
 
        dbus_connection_add_filter (dbus_conn, signal_filter, NULL, NULL);
291
 
}
292
 
 
293
 
/* -----------------------------------------------------------------------------------
294
 
 * GNOME-KEYRING DBUS INTERFACES
295
 
 */
296
 
 
297
 
static DBusHandlerResult 
298
 
message_handler_cb (DBusConnection *conn, DBusMessage *message, void *user_data)
299
 
{
300
 
        /* 
301
 
         * Here we handle the requests to our own gnome-keyring DBus interfaces
302
 
         */
303
 
        
304
 
        DBusMessageIter args;
305
 
        DBusMessage *reply = NULL;      
306
 
 
307
 
        /* GetSocketPath */
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), "")) {
311
 
                
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);
314
 
                
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);
320
 
                
321
 
        /* GetEnvironment */
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), "")) {
325
 
 
326
 
                const gchar **env;
327
 
                DBusMessageIter items, entry;
328
 
                gchar **parts;
329
 
                
330
 
                env = gkr_daemon_util_get_environment ();
331
 
                g_return_val_if_fail (env, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
332
 
                
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);
338
 
                while (*env) {
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);
346
 
                        ++env;
347
 
                }
348
 
                if (!dbus_message_iter_close_container (&args, &items))
349
 
                        g_return_val_if_reached (DBUS_HANDLER_RESULT_NEED_MEMORY);
350
 
                
351
 
        /* Unknown call */
352
 
        } else {
353
 
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
354
 
        }
355
 
        
356
 
        /* Send the reply */
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);
360
 
 
361
 
        return DBUS_HANDLER_RESULT_HANDLED;
362
 
}
363
 
 
364
 
static DBusObjectPathVTable object_vtable  = {
365
 
        NULL,
366
 
        message_handler_cb,
367
 
        NULL, 
368
 
};
369
 
 
370
 
static void 
371
 
daemon_dbus_cleanup (gpointer unused)
372
 
{
373
 
        if (dbus_conn) {
374
 
                unregister_daemon_in_session ();
375
 
                
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);
379
 
                dbus_conn = NULL;
380
 
        }
381
 
        
382
 
        g_free (client_session_path);
383
 
        client_session_path = NULL;
384
 
        
385
 
        g_free (client_session_rule);
386
 
        client_session_rule = NULL;
387
 
}
388
 
 
389
 
void 
390
 
gkr_daemon_dbus_initialize (void)
391
 
{
392
 
        dbus_uint32_t res = 0;
393
 
        DBusError derr = { 0 };
394
 
        
395
 
        if (dbus_initialized)
396
 
                return;
397
 
        
398
 
#ifdef WITH_TESTS
399
 
        {
400
 
                /* If running as a test, don't do DBUS stuff */
401
 
                const gchar *env = g_getenv ("GNOME_KEYRING_TEST_PATH");
402
 
                if (env && env[0])
403
 
                        return;
404
 
        }
405
 
#endif
406
 
 
407
 
        dbus_error_init (&derr); 
408
 
 
409
 
        /* Get the dbus bus and hook up */
410
 
        dbus_conn = dbus_bus_get (DBUS_BUS_SESSION, &derr);
411
 
        if (!dbus_conn) {
412
 
                g_message ("couldn't connect to dbus session bus: %s", derr.message);
413
 
                dbus_error_free (&derr);
414
 
                return;
415
 
        }
416
 
        
417
 
        egg_cleanup_register (daemon_dbus_cleanup, NULL);
418
 
 
419
 
        egg_dbus_connect_with_mainloop (dbus_conn, NULL);
420
 
 
421
 
        /* Make sure dbus doesn't kill our app */
422
 
        dbus_connection_set_exit_on_disconnect (dbus_conn, FALSE);
423
 
 
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);
430
 
        }       
431
 
 
432
 
        switch (res) {
433
 
        /* We acquired the service name */
434
 
        case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
435
 
                break;
436
 
        /* We already acquired the service name. Odd */
437
 
        case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
438
 
                g_return_if_reached ();
439
 
                break;
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");
444
 
                break;
445
 
        default:
446
 
                g_return_if_reached ();
447
 
                break;
448
 
        };
449
 
 
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");
454
 
                return;
455
 
        }
456
 
        
457
 
        dbus_initialized = TRUE;
458
 
 
459
 
        /* Register with the session now that DBus is setup */
460
 
        register_environment_in_session ();
461
 
        register_daemon_in_session ();
462
 
}