Line data Source code
1 : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 : /* gkd-dbus.c - hook into dbus, call other bits
3 :
4 : Copyright (C) 2007, 2009, Stefan Walter
5 :
6 : The Gnome Keyring Library is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU Library 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 : The Gnome Keyring Library 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 : Library General Public License for more details.
15 :
16 : You should have received a copy of the GNU Library General Public
17 : License along with the Gnome Library; see the file COPYING.LIB. If not,
18 : <http://www.gnu.org/licenses/>.
19 :
20 : Author: Stef Walter <stef@memberwebs.com>
21 : */
22 :
23 : #include "config.h"
24 :
25 : #include "gkd-daemon-generated.h"
26 : #include "gkd-dbus.h"
27 : #include "gkd-dbus-private.h"
28 :
29 : #include "daemon/gkd-main.h"
30 : #include "daemon/gkd-util.h"
31 :
32 : #include "egg/egg-cleanup.h"
33 :
34 : #include <glib.h>
35 : #include <gio/gio.h>
36 :
37 : static GDBusConnection *dbus_conn = NULL;
38 : static gboolean object_registered = FALSE;
39 : static gboolean acquired_asked = FALSE;
40 : static gboolean acquired_service = FALSE;
41 :
42 : #define GNOME_KEYRING_DAEMON_SERVICE "org.gnome.keyring"
43 : #define GNOME_KEYRING_DAEMON_PATH "/org/gnome/keyring/daemon"
44 : #define GNOME_KEYRING_DAEMON_INTERFACE "org.gnome.keyring.Daemon"
45 :
46 : static void
47 27 : cleanup_session_bus (gpointer unused)
48 : {
49 27 : if (!dbus_conn)
50 0 : return;
51 :
52 27 : g_clear_object (&dbus_conn);
53 : }
54 :
55 : static void
56 1 : on_connection_close (gpointer user_data)
57 : {
58 1 : g_debug ("dbus connection closed, exiting");
59 1 : gkd_main_quit ();
60 1 : }
61 :
62 : static gboolean
63 55 : connect_to_session_bus (void)
64 : {
65 55 : GError *error = NULL;
66 :
67 55 : if (dbus_conn)
68 28 : return TRUE;
69 :
70 27 : dbus_conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
71 27 : if (!dbus_conn) {
72 0 : g_message ("couldn't connect to dbus session bus: %s", error->message);
73 0 : g_error_free (error);
74 0 : return FALSE;
75 : }
76 :
77 27 : g_signal_connect (dbus_conn, "closed",
78 : G_CALLBACK (on_connection_close), NULL);
79 27 : egg_cleanup_register (cleanup_session_bus, NULL);
80 27 : return TRUE;
81 : }
82 :
83 : static gboolean
84 0 : handle_get_environment (GkdExportedDaemon *skeleton,
85 : GDBusMethodInvocation *invocation,
86 : gpointer user_data)
87 : {
88 : const gchar **env;
89 : gchar **parts;
90 : GVariantBuilder builder;
91 :
92 0 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
93 :
94 0 : for (env = gkd_util_get_environment (); *env != NULL; env++) {
95 0 : parts = g_strsplit (*env, "=", 2);
96 0 : g_variant_builder_add (&builder, "{ss}", parts[0], parts[1]);
97 0 : g_strfreev (parts);
98 : }
99 :
100 0 : gkd_exported_daemon_complete_get_environment (skeleton, invocation,
101 : g_variant_builder_end (&builder));
102 0 : return TRUE;
103 : }
104 :
105 : static gboolean
106 0 : handle_get_control_directory (GkdExportedDaemon *skeleton,
107 : GDBusMethodInvocation *invocation,
108 : gpointer user_data)
109 : {
110 0 : gkd_exported_daemon_complete_get_control_directory (skeleton, invocation,
111 : gkd_util_get_master_directory ());
112 0 : return TRUE;
113 : }
114 :
115 : static void
116 27 : cleanup_singleton (gpointer user_data)
117 : {
118 27 : GkdExportedDaemon *skeleton = user_data;
119 :
120 27 : g_return_if_fail (dbus_conn);
121 27 : if (object_registered) {
122 27 : g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (skeleton), dbus_conn);
123 27 : g_object_unref (skeleton);
124 : }
125 27 : object_registered = FALSE;
126 : }
127 :
128 : gboolean
129 27 : gkd_dbus_singleton_acquire (gboolean *acquired)
130 : {
131 27 : const gchar *service = NULL;
132 27 : GBusNameOwnerFlags flags = G_BUS_NAME_OWNER_FLAGS_NONE;
133 : GVariant *acquire_variant;
134 : guint res;
135 27 : GError *error = NULL;
136 : GkdExportedDaemon *skeleton;
137 :
138 27 : g_assert (acquired);
139 :
140 27 : if (!connect_to_session_bus ())
141 0 : return FALSE;
142 :
143 : /* First register the object */
144 27 : if (!object_registered) {
145 27 : skeleton = gkd_exported_daemon_skeleton_new ();
146 :
147 27 : g_signal_connect (skeleton, "handle-get-control-directory",
148 : G_CALLBACK (handle_get_control_directory), NULL);
149 27 : g_signal_connect (skeleton, "handle-get-environment",
150 : G_CALLBACK (handle_get_environment), NULL);
151 :
152 27 : g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton), dbus_conn,
153 : GNOME_KEYRING_DAEMON_PATH, &error);
154 :
155 27 : if (error == NULL) {
156 27 : object_registered = TRUE;
157 27 : egg_cleanup_register (cleanup_singleton, skeleton);
158 : } else {
159 0 : g_message ("couldn't register dbus object path: %s", error->message);
160 0 : g_clear_error (&error);
161 : }
162 : }
163 :
164 : /* Try and grab our name */
165 27 : if (!acquired_asked) {
166 : #ifdef WITH_DEBUG
167 27 : service = g_getenv ("GNOME_KEYRING_TEST_SERVICE");
168 27 : if (service && service[0])
169 16 : flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE;
170 : else
171 : #endif
172 11 : service = GNOME_KEYRING_DAEMON_SERVICE;
173 :
174 : /* attempt to acquire the name */
175 27 : acquire_variant = g_dbus_connection_call_sync (dbus_conn,
176 : "org.freedesktop.DBus", /* bus name */
177 : "/org/freedesktop/DBus", /* object path */
178 : "org.freedesktop.DBus", /* interface name */
179 : "RequestName", /* method name */
180 : g_variant_new ("(su)",
181 : service,
182 : flags),
183 : G_VARIANT_TYPE ("(u)"),
184 : G_DBUS_CALL_FLAGS_NONE,
185 : -1, NULL, &error);
186 :
187 27 : if (error != NULL) {
188 0 : g_message ("couldn't request name '%s' on session bus: %s", service, error->message);
189 0 : g_error_free (error);
190 0 : return FALSE;
191 : }
192 :
193 27 : acquired_asked = TRUE;
194 27 : g_variant_get (acquire_variant, "(u)", &res);
195 27 : g_variant_unref (acquire_variant);
196 :
197 27 : switch (res) {
198 : /* We acquired the service name */
199 27 : case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */
200 : case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */
201 27 : acquired_service = TRUE;
202 27 : break;
203 : /* Another daemon is running */
204 0 : case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */
205 : case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */
206 0 : acquired_service = FALSE;
207 0 : break;
208 0 : default:
209 0 : acquired_service = FALSE;
210 0 : g_return_val_if_reached (FALSE);
211 : break;
212 : };
213 : }
214 :
215 27 : *acquired = acquired_service;
216 :
217 27 : return TRUE;
218 : }
219 :
220 : gchar*
221 1 : gkd_dbus_singleton_control (void)
222 : {
223 1 : gchar *control = NULL;
224 1 : GError *error = NULL;
225 : GVariant *control_variant;
226 :
227 : /* If tried to aquire the service must have failed */
228 1 : g_return_val_if_fail (!acquired_service, NULL);
229 :
230 1 : if (!connect_to_session_bus ())
231 0 : return NULL;
232 :
233 1 : control_variant = g_dbus_connection_call_sync (dbus_conn,
234 : GNOME_KEYRING_DAEMON_SERVICE,
235 : GNOME_KEYRING_DAEMON_PATH,
236 : GNOME_KEYRING_DAEMON_INTERFACE,
237 : "GetControlDirectory",
238 : NULL, NULL,
239 : G_DBUS_CALL_FLAGS_NO_AUTO_START,
240 : 1000, NULL, &error);
241 :
242 1 : if (error != NULL) {
243 1 : if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER))
244 0 : g_message ("couldn't communicate with already running daemon: %s", error->message);
245 1 : g_error_free (error);
246 1 : return NULL;
247 : }
248 :
249 0 : g_variant_get (control_variant, "(s)", &control);
250 0 : g_variant_unref (control_variant);
251 :
252 0 : return control;
253 : }
254 :
255 : static void
256 27 : dbus_cleanup (gpointer unused)
257 : {
258 27 : g_return_if_fail (dbus_conn);
259 27 : gkd_dbus_secrets_cleanup (dbus_conn);
260 27 : gkd_dbus_session_cleanup (dbus_conn);
261 27 : gkd_dbus_environment_cleanup (dbus_conn);
262 : }
263 :
264 : gboolean
265 27 : gkd_dbus_setup (void)
266 : {
267 : gboolean unused;
268 :
269 27 : if (!connect_to_session_bus ())
270 0 : return FALSE;
271 :
272 : /* Our singleton, and internal service API */
273 27 : gkd_dbus_singleton_acquire (&unused);
274 :
275 : /* Session stuff */
276 27 : gkd_dbus_environment_init (dbus_conn);
277 27 : gkd_dbus_session_init (dbus_conn);
278 :
279 : /* Secrets API */
280 27 : gkd_dbus_secrets_init (dbus_conn);
281 :
282 27 : egg_cleanup_register (dbus_cleanup, NULL);
283 27 : return TRUE;
284 : }
285 :
286 : gboolean
287 2 : gkd_dbus_invocation_matches_caller (GDBusMethodInvocation *invocation,
288 : const char *caller)
289 : {
290 : const char *invocation_caller;
291 :
292 2 : invocation_caller = g_dbus_method_invocation_get_sender (invocation);
293 2 : if (!g_str_equal (invocation_caller, caller)) {
294 0 : g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
295 : G_DBUS_ERROR_ACCESS_DENIED,
296 : "Invalid caller");
297 0 : return FALSE;
298 : }
299 :
300 2 : return TRUE;
301 : }
|