Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2012 Red Hat, Inc.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This 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 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General
17 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Authors: Alexander Larsson <alexl@redhat.com>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include <string.h>
25 : : #include <stdlib.h>
26 : :
27 : : #include <gstdio.h>
28 : : #include <gio/gio.h>
29 : : #include <gio/gunixsocketaddress.h>
30 : : #include "gdbusdaemon.h"
31 : : #include "glibintl.h"
32 : :
33 : : #include "gdbus-daemon-generated.h"
34 : :
35 : : #define DBUS_SERVICE_NAME "org.freedesktop.DBus"
36 : :
37 : : /* Owner flags */
38 : : #define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 /**< Allow another service to become the primary owner if requested */
39 : : #define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 /**< Request to replace the current primary owner */
40 : : #define DBUS_NAME_FLAG_DO_NOT_QUEUE 0x4 /**< If we can not become the primary owner do not place us in the queue */
41 : :
42 : : /* Replies to request for a name */
43 : : #define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 /**< Service has become the primary owner of the requested name */
44 : : #define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 /**< Service could not become the primary owner and has been placed in the queue */
45 : : #define DBUS_REQUEST_NAME_REPLY_EXISTS 3 /**< Service is already in the queue */
46 : : #define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 /**< Service is already the primary owner */
47 : :
48 : : /* Replies to releasing a name */
49 : : #define DBUS_RELEASE_NAME_REPLY_RELEASED 1 /**< Service was released from the given name */
50 : : #define DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2 /**< The given name does not exist on the bus */
51 : : #define DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3 /**< Service is not an owner of the given name */
52 : :
53 : : /* Replies to service starts */
54 : : #define DBUS_START_REPLY_SUCCESS 1 /**< Service was auto started */
55 : : #define DBUS_START_REPLY_ALREADY_RUNNING 2 /**< Service was already running */
56 : :
57 : : #define IDLE_TIMEOUT_MSEC 3000
58 : :
59 : : struct _GDBusDaemon
60 : : {
61 : : _GFreedesktopDBusSkeleton parent_instance;
62 : :
63 : : gchar *address;
64 : : guint timeout;
65 : : gchar *tmpdir;
66 : : GDBusServer *server;
67 : : gchar *guid;
68 : : GHashTable *clients;
69 : : GHashTable *names;
70 : : guint32 next_major_id;
71 : : guint32 next_minor_id;
72 : : };
73 : :
74 : : struct _GDBusDaemonClass
75 : : {
76 : : _GFreedesktopDBusSkeletonClass parent_class;
77 : : };
78 : :
79 : : enum {
80 : : PROP_0,
81 : : PROP_ADDRESS,
82 : : };
83 : :
84 : : enum
85 : : {
86 : : SIGNAL_IDLE_TIMEOUT,
87 : : NR_SIGNALS
88 : : };
89 : :
90 : : static guint g_dbus_daemon_signals[NR_SIGNALS];
91 : :
92 : :
93 : : static void initable_iface_init (GInitableIface *initable_iface);
94 : : static void g_dbus_daemon_iface_init (_GFreedesktopDBusIface *iface);
95 : :
96 : : #define g_dbus_daemon_get_type _g_dbus_daemon_get_type
97 [ # # # # : 0 : G_DEFINE_TYPE_WITH_CODE (GDBusDaemon, g_dbus_daemon, _G_TYPE_FREEDESKTOP_DBUS_SKELETON,
# # ]
98 : : G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
99 : : G_IMPLEMENT_INTERFACE (_G_TYPE_FREEDESKTOP_DBUS, g_dbus_daemon_iface_init))
100 : :
101 : : typedef struct {
102 : : GDBusDaemon *daemon;
103 : : char *id;
104 : : GDBusConnection *connection;
105 : : GList *matches;
106 : : } Client;
107 : :
108 : : typedef struct {
109 : : Client *client;
110 : : guint32 flags;
111 : : } NameOwner;
112 : :
113 : : typedef struct {
114 : : int refcount;
115 : :
116 : : char *name;
117 : : GDBusDaemon *daemon;
118 : :
119 : : NameOwner *owner;
120 : : GList *queue;
121 : : } Name;
122 : :
123 : : enum {
124 : : MATCH_ELEMENT_TYPE,
125 : : MATCH_ELEMENT_SENDER,
126 : : MATCH_ELEMENT_INTERFACE,
127 : : MATCH_ELEMENT_MEMBER,
128 : : MATCH_ELEMENT_PATH,
129 : : MATCH_ELEMENT_PATH_NAMESPACE,
130 : : MATCH_ELEMENT_DESTINATION,
131 : : MATCH_ELEMENT_ARG0NAMESPACE,
132 : : MATCH_ELEMENT_EAVESDROP,
133 : : MATCH_ELEMENT_ARGN,
134 : : MATCH_ELEMENT_ARGNPATH,
135 : : };
136 : :
137 : : typedef struct {
138 : : guint16 type;
139 : : guint16 arg;
140 : : char *value;
141 : : } MatchElement;
142 : :
143 : : typedef struct {
144 : : gboolean eavesdrop;
145 : : GDBusMessageType type;
146 : : int n_elements;
147 : : MatchElement *elements;
148 : : } Match;
149 : :
150 : : static GDBusMessage *filter_function (GDBusConnection *connection,
151 : : GDBusMessage *message,
152 : : gboolean incoming,
153 : : gpointer user_data);
154 : : static void connection_closed (GDBusConnection *connection,
155 : : gboolean remote_peer_vanished,
156 : : GError *error,
157 : : Client *client);
158 : :
159 : : static NameOwner *
160 : 0 : name_owner_new (Client *client, guint32 flags)
161 : : {
162 : : NameOwner *owner;
163 : :
164 : 0 : owner = g_new0 (NameOwner, 1);
165 : 0 : owner->client = client;
166 : 0 : owner->flags = flags;
167 : 0 : return owner;
168 : : }
169 : :
170 : : static void
171 : 0 : name_owner_free (NameOwner *owner)
172 : : {
173 : 0 : g_free (owner);
174 : 0 : }
175 : :
176 : : static Name *
177 : 0 : name_new (GDBusDaemon *daemon, const char *str)
178 : : {
179 : : Name *name;
180 : :
181 : 0 : name = g_new0 (Name, 1);
182 : 0 : name->refcount = 1;
183 : 0 : name->daemon = daemon;
184 : 0 : name->name = g_strdup (str);
185 : :
186 : 0 : g_hash_table_insert (daemon->names, name->name, name);
187 : :
188 : 0 : return name;
189 : : }
190 : :
191 : : static Name *
192 : 0 : name_ref (Name *name)
193 : : {
194 : 0 : g_assert (name->refcount > 0);
195 : 0 : name->refcount++;
196 : 0 : return name;
197 : : }
198 : :
199 : : static void
200 : 0 : name_unref (Name *name)
201 : : {
202 : 0 : g_assert (name->refcount > 0);
203 [ # # ]: 0 : if (--name->refcount == 0)
204 : : {
205 : 0 : g_hash_table_remove (name->daemon->names, name->name);
206 : 0 : g_free (name->name);
207 : 0 : g_free (name);
208 : : }
209 : 0 : }
210 : :
211 : : static Name *
212 : 0 : name_ensure (GDBusDaemon *daemon, const char *str)
213 : : {
214 : : Name *name;
215 : :
216 : 0 : name = g_hash_table_lookup (daemon->names, str);
217 : :
218 [ # # ]: 0 : if (name != NULL)
219 : 0 : return name_ref (name);
220 : 0 : return name_new (daemon, str);
221 : : }
222 : :
223 : : static Name *
224 : 0 : name_lookup (GDBusDaemon *daemon, const char *str)
225 : : {
226 : 0 : return g_hash_table_lookup (daemon->names, str);
227 : : }
228 : :
229 : : static gboolean
230 : 0 : is_key (const char *key_start, const char *key_end, const char *value)
231 : : {
232 : 0 : gsize len = strlen (value);
233 : :
234 : 0 : g_assert (key_end >= key_start);
235 [ # # ]: 0 : if (len != (gsize) (key_end - key_start))
236 : 0 : return FALSE;
237 : :
238 : 0 : return strncmp (key_start, value, len) == 0;
239 : : }
240 : :
241 : : static gboolean
242 : 0 : parse_key (MatchElement *element, const char *key_start, const char *key_end)
243 : : {
244 : 0 : gboolean res = TRUE;
245 : :
246 [ # # ]: 0 : if (is_key (key_start, key_end, "type"))
247 : : {
248 : 0 : element->type = MATCH_ELEMENT_TYPE;
249 : : }
250 [ # # ]: 0 : else if (is_key (key_start, key_end, "sender"))
251 : : {
252 : 0 : element->type = MATCH_ELEMENT_SENDER;
253 : : }
254 [ # # ]: 0 : else if (is_key (key_start, key_end, "interface"))
255 : : {
256 : 0 : element->type = MATCH_ELEMENT_INTERFACE;
257 : : }
258 [ # # ]: 0 : else if (is_key (key_start, key_end, "member"))
259 : : {
260 : 0 : element->type = MATCH_ELEMENT_MEMBER;
261 : : }
262 [ # # ]: 0 : else if (is_key (key_start, key_end, "path"))
263 : : {
264 : 0 : element->type = MATCH_ELEMENT_PATH;
265 : : }
266 [ # # ]: 0 : else if (is_key (key_start, key_end, "path_namespace"))
267 : : {
268 : 0 : element->type = MATCH_ELEMENT_PATH_NAMESPACE;
269 : : }
270 [ # # ]: 0 : else if (is_key (key_start, key_end, "destination"))
271 : : {
272 : 0 : element->type = MATCH_ELEMENT_DESTINATION;
273 : : }
274 [ # # ]: 0 : else if (is_key (key_start, key_end, "arg0namespace"))
275 : : {
276 : 0 : element->type = MATCH_ELEMENT_ARG0NAMESPACE;
277 : : }
278 [ # # ]: 0 : else if (is_key (key_start, key_end, "eavesdrop"))
279 : : {
280 : 0 : element->type = MATCH_ELEMENT_EAVESDROP;
281 : : }
282 [ # # # # ]: 0 : else if (key_end - key_start > 3 && is_key (key_start, key_start + 3, "arg"))
283 : 0 : {
284 : 0 : const char *digits = key_start + 3;
285 : 0 : const char *end_digits = digits;
286 : :
287 [ # # # # ]: 0 : while (end_digits < key_end && g_ascii_isdigit (*end_digits))
288 : 0 : end_digits++;
289 : :
290 [ # # ]: 0 : if (end_digits == key_end) /* argN */
291 : : {
292 : 0 : element->type = MATCH_ELEMENT_ARGN;
293 : 0 : element->arg = atoi (digits);
294 : : }
295 [ # # ]: 0 : else if (is_key (end_digits, key_end, "path")) /* argNpath */
296 : : {
297 : 0 : element->type = MATCH_ELEMENT_ARGNPATH;
298 : 0 : element->arg = atoi (digits);
299 : : }
300 : : else
301 : 0 : res = FALSE;
302 : : }
303 : : else
304 : 0 : res = FALSE;
305 : :
306 : 0 : return res;
307 : : }
308 : :
309 : : static const char *
310 : 0 : parse_value (MatchElement *element, const char *s)
311 : : {
312 : : char quote_char;
313 : : GString *value;
314 : :
315 : 0 : value = g_string_new ("");
316 : :
317 : 0 : quote_char = 0;
318 : :
319 [ # # ]: 0 : for (;*s; s++)
320 : : {
321 [ # # ]: 0 : if (quote_char == 0)
322 : : {
323 [ # # # # ]: 0 : switch (*s)
324 : : {
325 : 0 : case '\'':
326 : 0 : quote_char = '\'';
327 : 0 : break;
328 : :
329 : 0 : case ',':
330 : 0 : s++;
331 : 0 : goto out;
332 : :
333 : 0 : case '\\':
334 : 0 : quote_char = '\\';
335 : 0 : break;
336 : :
337 : 0 : default:
338 [ # # ]: 0 : g_string_append_c (value, *s);
339 : 0 : break;
340 : : }
341 : : }
342 [ # # ]: 0 : else if (quote_char == '\\')
343 : : {
344 : : /* \ only counts as an escape if escaping a quote mark */
345 [ # # ]: 0 : if (*s != '\'')
346 : : g_string_append_c (value, '\\');
347 : :
348 [ # # ]: 0 : g_string_append_c (value, *s);
349 : 0 : quote_char = 0;
350 : : }
351 : : else /* quote_char == ' */
352 : : {
353 [ # # ]: 0 : if (*s == '\'')
354 : 0 : quote_char = 0;
355 : : else
356 [ # # ]: 0 : g_string_append_c (value, *s);
357 : : }
358 : : }
359 : :
360 : 0 : out:
361 : :
362 [ # # ]: 0 : if (quote_char == '\\')
363 : : g_string_append_c (value, '\\');
364 [ # # ]: 0 : else if (quote_char == '\'')
365 : : {
366 : 0 : g_string_free (value, TRUE);
367 : 0 : return NULL;
368 : : }
369 : :
370 : 0 : element->value = g_string_free (value, FALSE);
371 : 0 : return s;
372 : : }
373 : :
374 : : static Match *
375 : 0 : match_new (const char *str)
376 : : {
377 : : Match *match;
378 : : GArray *elements;
379 : : const char *p;
380 : : const char *key_start;
381 : : const char *key_end;
382 : : MatchElement element;
383 : : gboolean eavesdrop;
384 : : GDBusMessageType type;
385 : : gsize i;
386 : :
387 : 0 : eavesdrop = FALSE;
388 : 0 : type = G_DBUS_MESSAGE_TYPE_INVALID;
389 : 0 : elements = g_array_new (TRUE, TRUE, sizeof (MatchElement));
390 : :
391 : 0 : p = str;
392 : :
393 [ # # ]: 0 : while (*p != 0)
394 : : {
395 : 0 : memset (&element, 0, sizeof (element));
396 : :
397 : : /* Skip initial whitespace */
398 [ # # # # ]: 0 : while (*p && g_ascii_isspace (*p))
399 : 0 : p++;
400 : :
401 : 0 : key_start = p;
402 : :
403 : : /* Read non-whitespace non-equals chars */
404 [ # # # # : 0 : while (*p && *p != '=' && !g_ascii_isspace (*p))
# # ]
405 : 0 : p++;
406 : :
407 : 0 : key_end = p;
408 : :
409 : : /* Skip any whitespace after key */
410 [ # # # # ]: 0 : while (*p && g_ascii_isspace (*p))
411 : 0 : p++;
412 : :
413 [ # # ]: 0 : if (key_start == key_end)
414 : 0 : continue; /* Allow trailing whitespace */
415 : :
416 [ # # ]: 0 : if (*p != '=')
417 : 0 : goto error;
418 : :
419 : 0 : ++p;
420 : :
421 [ # # ]: 0 : if (!parse_key (&element, key_start, key_end))
422 : 0 : goto error;
423 : :
424 : 0 : p = parse_value (&element, p);
425 [ # # ]: 0 : if (p == NULL)
426 : 0 : goto error;
427 : :
428 [ # # ]: 0 : if (element.type == MATCH_ELEMENT_EAVESDROP)
429 : : {
430 [ # # ]: 0 : if (strcmp (element.value, "true") == 0)
431 : 0 : eavesdrop = TRUE;
432 [ # # ]: 0 : else if (strcmp (element.value, "false") == 0)
433 : 0 : eavesdrop = FALSE;
434 : : else
435 : : {
436 : 0 : g_free (element.value);
437 : 0 : goto error;
438 : : }
439 : 0 : g_free (element.value);
440 : : }
441 [ # # ]: 0 : else if (element.type == MATCH_ELEMENT_TYPE)
442 : : {
443 [ # # ]: 0 : if (strcmp (element.value, "signal") == 0)
444 : 0 : type = G_DBUS_MESSAGE_TYPE_SIGNAL;
445 [ # # ]: 0 : else if (strcmp (element.value, "method_call") == 0)
446 : 0 : type = G_DBUS_MESSAGE_TYPE_METHOD_CALL;
447 [ # # ]: 0 : else if (strcmp (element.value, "method_return") == 0)
448 : 0 : type = G_DBUS_MESSAGE_TYPE_METHOD_RETURN;
449 [ # # ]: 0 : else if (strcmp (element.value, "error") == 0)
450 : 0 : type = G_DBUS_MESSAGE_TYPE_ERROR;
451 : : else
452 : : {
453 : 0 : g_free (element.value);
454 : 0 : goto error;
455 : : }
456 : 0 : g_free (element.value);
457 : : }
458 : : else
459 : 0 : g_array_append_val (elements, element);
460 : : }
461 : :
462 : 0 : match = g_new0 (Match, 1);
463 : 0 : match->n_elements = elements->len;
464 : 0 : match->elements = (MatchElement *)g_array_free (elements, FALSE);
465 : 0 : match->eavesdrop = eavesdrop;
466 : 0 : match->type = type;
467 : :
468 : 0 : return match;
469 : :
470 : 0 : error:
471 [ # # ]: 0 : for (i = 0; i < elements->len; i++)
472 : 0 : g_free (g_array_index (elements, MatchElement, i).value);
473 : 0 : g_array_free (elements, TRUE);
474 : 0 : return NULL;
475 : : }
476 : :
477 : : static void
478 : 0 : match_free (Match *match)
479 : : {
480 : : int i;
481 [ # # ]: 0 : for (i = 0; i < match->n_elements; i++)
482 : 0 : g_free (match->elements[i].value);
483 : 0 : g_free (match->elements);
484 : 0 : g_free (match);
485 : 0 : }
486 : :
487 : : static gboolean
488 : 0 : match_equal (Match *a, Match *b)
489 : : {
490 : : int i;
491 : :
492 [ # # ]: 0 : if (a->eavesdrop != b->eavesdrop)
493 : 0 : return FALSE;
494 [ # # ]: 0 : if (a->type != b->type)
495 : 0 : return FALSE;
496 [ # # ]: 0 : if (a->n_elements != b->n_elements)
497 : 0 : return FALSE;
498 [ # # ]: 0 : for (i = 0; i < a->n_elements; i++)
499 : : {
500 [ # # ]: 0 : if (a->elements[i].type != b->elements[i].type ||
501 [ # # ]: 0 : a->elements[i].arg != b->elements[i].arg ||
502 [ # # ]: 0 : strcmp (a->elements[i].value, b->elements[i].value) != 0)
503 : 0 : return FALSE;
504 : : }
505 : 0 : return TRUE;
506 : : }
507 : :
508 : : static const gchar *
509 : 0 : message_get_argN (GDBusMessage *message, int n, gboolean allow_path)
510 : : {
511 : : const gchar *ret;
512 : : GVariant *body;
513 : :
514 : 0 : ret = NULL;
515 : :
516 : 0 : body = g_dbus_message_get_body (message);
517 : :
518 [ # # # # ]: 0 : if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE_TUPLE))
519 : : {
520 : : GVariant *item;
521 : 0 : item = g_variant_get_child_value (body, n);
522 [ # # # # ]: 0 : if (g_variant_is_of_type (item, G_VARIANT_TYPE_STRING) ||
523 [ # # ]: 0 : (allow_path && g_variant_is_of_type (item, G_VARIANT_TYPE_OBJECT_PATH)))
524 : 0 : ret = g_variant_get_string (item, NULL);
525 : 0 : g_variant_unref (item);
526 : : }
527 : :
528 : 0 : return ret;
529 : : }
530 : :
531 : : enum {
532 : : CHECK_TYPE_STRING,
533 : : CHECK_TYPE_NAME,
534 : : CHECK_TYPE_PATH_PREFIX,
535 : : CHECK_TYPE_PATH_RELATED,
536 : : CHECK_TYPE_NAMESPACE_PREFIX
537 : : };
538 : :
539 : : static gboolean
540 : 0 : match_matches (GDBusDaemon *daemon,
541 : : Match *match, GDBusMessage *message,
542 : : gboolean has_destination)
543 : : {
544 : : MatchElement *element;
545 : : Name *name;
546 : : int i, len, len2;
547 : : const char *value;
548 : : int check_type;
549 : :
550 [ # # # # ]: 0 : if (has_destination && !match->eavesdrop)
551 : 0 : return FALSE;
552 : :
553 [ # # ]: 0 : if (match->type != G_DBUS_MESSAGE_TYPE_INVALID &&
554 [ # # ]: 0 : g_dbus_message_get_message_type (message) != match->type)
555 : 0 : return FALSE;
556 : :
557 [ # # ]: 0 : for (i = 0; i < match->n_elements; i++)
558 : : {
559 : 0 : element = &match->elements[i];
560 : 0 : check_type = CHECK_TYPE_STRING;
561 [ # # # # : 0 : switch (element->type)
# # # # #
# ]
562 : : {
563 : 0 : case MATCH_ELEMENT_SENDER:
564 : 0 : check_type = CHECK_TYPE_NAME;
565 : 0 : value = g_dbus_message_get_sender (message);
566 [ # # ]: 0 : if (value == NULL)
567 : 0 : value = DBUS_SERVICE_NAME;
568 : 0 : break;
569 : 0 : case MATCH_ELEMENT_DESTINATION:
570 : 0 : check_type = CHECK_TYPE_NAME;
571 : 0 : value = g_dbus_message_get_destination (message);
572 : 0 : break;
573 : 0 : case MATCH_ELEMENT_INTERFACE:
574 : 0 : value = g_dbus_message_get_interface (message);
575 : 0 : break;
576 : 0 : case MATCH_ELEMENT_MEMBER:
577 : 0 : value = g_dbus_message_get_member (message);
578 : 0 : break;
579 : 0 : case MATCH_ELEMENT_PATH:
580 : 0 : value = g_dbus_message_get_path (message);
581 : 0 : break;
582 : 0 : case MATCH_ELEMENT_PATH_NAMESPACE:
583 : 0 : check_type = CHECK_TYPE_PATH_PREFIX;
584 : 0 : value = g_dbus_message_get_path (message);
585 : 0 : break;
586 : 0 : case MATCH_ELEMENT_ARG0NAMESPACE:
587 : 0 : check_type = CHECK_TYPE_NAMESPACE_PREFIX;
588 : 0 : value = message_get_argN (message, 0, FALSE);
589 : 0 : break;
590 : 0 : case MATCH_ELEMENT_ARGN:
591 : 0 : value = message_get_argN (message, element->arg, FALSE);
592 : 0 : break;
593 : 0 : case MATCH_ELEMENT_ARGNPATH:
594 : 0 : check_type = CHECK_TYPE_PATH_RELATED;
595 : 0 : value = message_get_argN (message, element->arg, TRUE);
596 : 0 : break;
597 : 0 : default:
598 : : case MATCH_ELEMENT_TYPE:
599 : : case MATCH_ELEMENT_EAVESDROP:
600 : : g_assert_not_reached ();
601 : : }
602 : :
603 [ # # ]: 0 : if (value == NULL)
604 : 0 : return FALSE;
605 : :
606 [ # # # # : 0 : switch (check_type)
# # ]
607 : : {
608 : 0 : case CHECK_TYPE_STRING:
609 [ # # ]: 0 : if (strcmp (element->value, value) != 0)
610 : 0 : return FALSE;
611 : 0 : break;
612 : 0 : case CHECK_TYPE_NAME:
613 : 0 : name = name_lookup (daemon, element->value);
614 [ # # # # ]: 0 : if (name != NULL && name->owner != NULL)
615 : : {
616 [ # # ]: 0 : if (strcmp (name->owner->client->id, value) != 0)
617 : 0 : return FALSE;
618 : : }
619 [ # # ]: 0 : else if (strcmp (element->value, value) != 0)
620 : 0 : return FALSE;
621 : 0 : break;
622 : 0 : case CHECK_TYPE_PATH_PREFIX:
623 : 0 : len = strlen (element->value);
624 : :
625 : : /* Make sure to handle the case of element->value == '/'. */
626 [ # # ]: 0 : if (len == 1)
627 : 0 : break;
628 : :
629 : : /* Fail if there's no prefix match, or if the prefix match doesn't
630 : : * finish at the end of or at a separator in the @value. */
631 [ # # ]: 0 : if (!g_str_has_prefix (value, element->value))
632 : 0 : return FALSE;
633 [ # # # # ]: 0 : if (value[len] != 0 && value[len] != '/')
634 : 0 : return FALSE;
635 : :
636 : 0 : break;
637 : 0 : case CHECK_TYPE_PATH_RELATED:
638 : 0 : len = strlen (element->value);
639 : 0 : len2 = strlen (value);
640 : :
641 [ # # # # : 0 : if (!(strcmp (value, element->value) == 0 ||
# # ]
642 [ # # # # ]: 0 : (len2 > 0 && value[len2-1] == '/' && g_str_has_prefix (element->value, value)) ||
643 [ # # # # ]: 0 : (len > 0 && element->value[len-1] == '/' && g_str_has_prefix (value, element->value))))
644 : 0 : return FALSE;
645 : 0 : break;
646 : 0 : case CHECK_TYPE_NAMESPACE_PREFIX:
647 : 0 : len = strlen (element->value);
648 [ # # ]: 0 : if (!(g_str_has_prefix (value, element->value) &&
649 [ # # # # ]: 0 : (value[len] == 0 || value[len] == '.')))
650 : 0 : return FALSE;
651 : 0 : break;
652 : 0 : default:
653 : : g_assert_not_reached ();
654 : : }
655 : : }
656 : :
657 : 0 : return TRUE;
658 : : }
659 : :
660 : : static void
661 : 0 : broadcast_message (GDBusDaemon *daemon,
662 : : GDBusMessage *message,
663 : : gboolean has_destination,
664 : : gboolean preserve_serial,
665 : : Client *not_to)
666 : : {
667 : : GList *clients, *l, *ll;
668 : : GDBusMessage *copy;
669 : :
670 : 0 : clients = g_hash_table_get_values (daemon->clients);
671 [ # # ]: 0 : for (l = clients; l != NULL; l = l->next)
672 : : {
673 : 0 : Client *client = l->data;
674 : :
675 [ # # ]: 0 : if (client == not_to)
676 : 0 : continue;
677 : :
678 [ # # ]: 0 : for (ll = client->matches; ll != NULL; ll = ll->next)
679 : : {
680 : 0 : Match *match = ll->data;
681 : :
682 [ # # ]: 0 : if (match_matches (daemon, match, message, has_destination))
683 : 0 : break;
684 : : }
685 : :
686 [ # # ]: 0 : if (ll != NULL)
687 : : {
688 : 0 : copy = g_dbus_message_copy (message, NULL);
689 [ # # ]: 0 : if (copy)
690 : : {
691 : 0 : g_dbus_connection_send_message (client->connection, copy,
692 : : preserve_serial?G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL:0, NULL, NULL);
693 : 0 : g_object_unref (copy);
694 : : }
695 : : }
696 : : }
697 : :
698 : 0 : g_list_free (clients);
699 : 0 : }
700 : :
701 : : static void
702 : 0 : send_name_owner_changed (GDBusDaemon *daemon,
703 : : const char *name,
704 : : const char *old_owner,
705 : : const char *new_owner)
706 : : {
707 : : GDBusMessage *signal_message;
708 : :
709 : 0 : signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
710 : : "org.freedesktop.DBus",
711 : : "NameOwnerChanged");
712 [ # # # # ]: 0 : g_dbus_message_set_body (signal_message,
713 : : g_variant_new ("(sss)",
714 : : name,
715 : : old_owner ? old_owner : "",
716 : : new_owner ? new_owner : ""));
717 : :
718 : 0 : broadcast_message (daemon, signal_message, FALSE, FALSE, NULL);
719 : 0 : g_object_unref (signal_message);
720 : :
721 : 0 : }
722 : :
723 : : static gboolean
724 : 0 : name_unqueue_owner (Name *name, Client *client)
725 : : {
726 : : GList *l;
727 : :
728 [ # # ]: 0 : for (l = name->queue; l != NULL; l = l->next)
729 : : {
730 : 0 : NameOwner *other = l->data;
731 : :
732 [ # # ]: 0 : if (other->client == client)
733 : : {
734 : 0 : name->queue = g_list_delete_link (name->queue, l);
735 : 0 : name_unref (name);
736 : 0 : name_owner_free (other);
737 : 0 : return TRUE;
738 : : }
739 : : }
740 : :
741 : 0 : return FALSE;
742 : : }
743 : :
744 : : static void
745 : 0 : name_replace_owner (Name *name, NameOwner *owner)
746 : : {
747 : 0 : GDBusDaemon *daemon = name->daemon;
748 : : NameOwner *old_owner;
749 : 0 : char *old_name = NULL, *new_name = NULL;
750 : 0 : Client *new_client = NULL;
751 : :
752 [ # # ]: 0 : if (owner)
753 : 0 : new_client = owner->client;
754 : :
755 : 0 : name_ref (name);
756 : :
757 : 0 : old_owner = name->owner;
758 [ # # ]: 0 : if (old_owner)
759 : : {
760 : 0 : Client *old_client = old_owner->client;
761 : :
762 : 0 : g_assert (old_owner->client != new_client);
763 : :
764 : 0 : g_dbus_connection_emit_signal (old_client->connection,
765 : : NULL, "/org/freedesktop/DBus",
766 : : "org.freedesktop.DBus", "NameLost",
767 : : g_variant_new ("(s)",
768 : : name->name), NULL);
769 : :
770 : 0 : old_name = g_strdup (old_client->id);
771 [ # # ]: 0 : if (old_owner->flags & DBUS_NAME_FLAG_DO_NOT_QUEUE)
772 : : {
773 : 0 : name_unref (name);
774 : 0 : name_owner_free (old_owner);
775 : : }
776 : : else
777 : 0 : name->queue = g_list_prepend (name->queue, old_owner);
778 : : }
779 : :
780 : 0 : name->owner = owner;
781 [ # # ]: 0 : if (owner)
782 : : {
783 : 0 : name_unqueue_owner (name, owner->client);
784 : 0 : name_ref (name);
785 : 0 : new_name = new_client->id;
786 : :
787 : 0 : g_dbus_connection_emit_signal (new_client->connection,
788 : : NULL, "/org/freedesktop/DBus",
789 : : "org.freedesktop.DBus", "NameAcquired",
790 : : g_variant_new ("(s)",
791 : : name->name), NULL);
792 : : }
793 : :
794 : 0 : send_name_owner_changed (daemon, name->name, old_name, new_name);
795 : :
796 : 0 : g_free (old_name);
797 : :
798 : 0 : name_unref (name);
799 : 0 : }
800 : :
801 : : static void
802 : 0 : name_release_owner (Name *name)
803 : : {
804 : 0 : NameOwner *next_owner = NULL;
805 : :
806 : 0 : name_ref (name);
807 : :
808 : : /* Will someone else take over? */
809 [ # # ]: 0 : if (name->queue)
810 : : {
811 : 0 : next_owner = name->queue->data;
812 : 0 : name_unref (name);
813 : 0 : name->queue = g_list_delete_link (name->queue, name->queue);
814 : : }
815 : :
816 : 0 : name->owner->flags |= DBUS_NAME_FLAG_DO_NOT_QUEUE;
817 : 0 : name_replace_owner (name, next_owner);
818 : :
819 : 0 : name_unref (name);
820 : 0 : }
821 : :
822 : : static void
823 : 0 : name_queue_owner (Name *name, NameOwner *owner)
824 : : {
825 : : GList *l;
826 : :
827 [ # # ]: 0 : for (l = name->queue; l != NULL; l = l->next)
828 : : {
829 : 0 : NameOwner *other = l->data;
830 : :
831 [ # # ]: 0 : if (other->client == owner->client)
832 : : {
833 : 0 : other->flags = owner->flags;
834 : 0 : name_owner_free (owner);
835 : 0 : return;
836 : : }
837 : : }
838 : :
839 : 0 : name->queue = g_list_append (name->queue, owner);
840 : 0 : name_ref (name);
841 : : }
842 : :
843 : : static Client *
844 : 0 : client_new (GDBusDaemon *daemon, GDBusConnection *connection)
845 : : {
846 : : Client *client;
847 : 0 : GError *error = NULL;
848 : :
849 : 0 : client = g_new0 (Client, 1);
850 : 0 : client->daemon = daemon;
851 : 0 : client->id = g_strdup_printf (":%d.%d", daemon->next_major_id, daemon->next_minor_id);
852 : 0 : client->connection = g_object_ref (connection);
853 : :
854 [ # # ]: 0 : if (daemon->next_minor_id == G_MAXUINT32)
855 : : {
856 : 0 : daemon->next_minor_id = 0;
857 : 0 : daemon->next_major_id++;
858 : : }
859 : : else
860 : 0 : daemon->next_minor_id++;
861 : :
862 : 0 : g_object_set_data (G_OBJECT (connection), "client", client);
863 : 0 : g_hash_table_insert (daemon->clients, client->id, client);
864 : :
865 : 0 : g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (daemon), connection,
866 : : "/org/freedesktop/DBus", &error);
867 : 0 : g_assert_no_error (error);
868 : :
869 : 0 : g_signal_connect (connection, "closed", G_CALLBACK (connection_closed), client);
870 : 0 : g_dbus_connection_add_filter (connection,
871 : : filter_function,
872 : : client, NULL);
873 : :
874 : 0 : send_name_owner_changed (daemon, client->id, NULL, client->id);
875 : :
876 : 0 : return client;
877 : : }
878 : :
879 : : static void
880 : 0 : client_free (Client *client)
881 : : {
882 : 0 : GDBusDaemon *daemon = client->daemon;
883 : : GList *l, *names;
884 : :
885 : 0 : g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (daemon),
886 : : client->connection);
887 : :
888 : 0 : g_hash_table_remove (daemon->clients, client->id);
889 : :
890 : 0 : names = g_hash_table_get_values (daemon->names);
891 [ # # ]: 0 : for (l = names; l != NULL; l = l->next)
892 : : {
893 : 0 : Name *name = l->data;
894 : :
895 : 0 : name_ref (name);
896 : :
897 [ # # # # ]: 0 : if (name->owner && name->owner->client == client)
898 : : {
899 : : /* Help static analysers with the refcount at this point. */
900 : 0 : g_assert (name->refcount >= 2);
901 : 0 : name_release_owner (name);
902 : : }
903 : :
904 : 0 : name_unqueue_owner (name, client);
905 : :
906 : 0 : name_unref (name);
907 : : }
908 : 0 : g_list_free (names);
909 : :
910 : 0 : send_name_owner_changed (daemon, client->id, client->id, NULL);
911 : :
912 : 0 : g_object_unref (client->connection);
913 : :
914 [ # # ]: 0 : for (l = client->matches; l != NULL; l = l->next)
915 : 0 : match_free (l->data);
916 : 0 : g_list_free (client->matches);
917 : :
918 : 0 : g_free (client->id);
919 : 0 : g_free (client);
920 : 0 : }
921 : :
922 : : static gboolean
923 : 0 : idle_timeout_cb (gpointer user_data)
924 : : {
925 : 0 : GDBusDaemon *daemon = user_data;
926 : :
927 : 0 : daemon->timeout = 0;
928 : :
929 : 0 : g_signal_emit (daemon,
930 : : g_dbus_daemon_signals[SIGNAL_IDLE_TIMEOUT],
931 : : 0);
932 : :
933 : 0 : return G_SOURCE_REMOVE;
934 : : }
935 : :
936 : : static void
937 : 0 : connection_closed (GDBusConnection *connection,
938 : : gboolean remote_peer_vanished,
939 : : GError *error,
940 : : Client *client)
941 : : {
942 : 0 : GDBusDaemon *daemon = client->daemon;
943 : :
944 : 0 : client_free (client);
945 : :
946 [ # # ]: 0 : if (g_hash_table_size (daemon->clients) == 0)
947 : 0 : daemon->timeout = g_timeout_add (IDLE_TIMEOUT_MSEC,
948 : : idle_timeout_cb,
949 : : daemon);
950 : 0 : }
951 : :
952 : : static gboolean
953 : 0 : handle_add_match (_GFreedesktopDBus *object,
954 : : GDBusMethodInvocation *invocation,
955 : : const gchar *arg_rule)
956 : : {
957 : 0 : Client *client = g_object_get_data (G_OBJECT (g_dbus_method_invocation_get_connection (invocation)), "client");
958 : : Match *match;
959 : :
960 : 0 : match = match_new (arg_rule);
961 : :
962 [ # # ]: 0 : if (match == NULL)
963 : 0 : g_dbus_method_invocation_return_error (invocation,
964 : : G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_INVALID,
965 : : "Invalid rule: %s", arg_rule);
966 : : else
967 : : {
968 : 0 : client->matches = g_list_prepend (client->matches, match);
969 : 0 : _g_freedesktop_dbus_complete_add_match (object, invocation);
970 : : }
971 : 0 : return TRUE;
972 : : }
973 : :
974 : : static gboolean
975 : 0 : handle_get_connection_selinux_security_context (_GFreedesktopDBus *object,
976 : : GDBusMethodInvocation *invocation,
977 : : const gchar *arg_name)
978 : : {
979 : 0 : g_dbus_method_invocation_return_error (invocation,
980 : : G_DBUS_ERROR, G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN,
981 : : "selinux context not supported");
982 : 0 : _g_freedesktop_dbus_complete_get_connection_selinux_security_context (object, invocation, "");
983 : 0 : return TRUE;
984 : : }
985 : :
986 : : static gboolean
987 : 0 : handle_get_connection_unix_process_id (_GFreedesktopDBus *object,
988 : : GDBusMethodInvocation *invocation,
989 : : const gchar *arg_name)
990 : : {
991 : 0 : g_dbus_method_invocation_return_error (invocation,
992 : : G_DBUS_ERROR, G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
993 : : "connection pid not supported");
994 : 0 : return TRUE;
995 : : }
996 : :
997 : : static gboolean
998 : 0 : handle_get_connection_unix_user (_GFreedesktopDBus *object,
999 : : GDBusMethodInvocation *invocation,
1000 : : const gchar *arg_name)
1001 : : {
1002 : 0 : g_dbus_method_invocation_return_error (invocation,
1003 : : G_DBUS_ERROR, G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
1004 : : "connection user not supported");
1005 : 0 : return TRUE;
1006 : : }
1007 : :
1008 : : static gboolean
1009 : 0 : handle_get_id (_GFreedesktopDBus *object,
1010 : : GDBusMethodInvocation *invocation)
1011 : : {
1012 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1013 : 0 : _g_freedesktop_dbus_complete_get_id (object, invocation,
1014 : 0 : daemon->guid);
1015 : 0 : return TRUE;
1016 : : }
1017 : :
1018 : : static gboolean
1019 : 0 : handle_get_name_owner (_GFreedesktopDBus *object,
1020 : : GDBusMethodInvocation *invocation,
1021 : : const gchar *arg_name)
1022 : : {
1023 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1024 : : Name *name;
1025 : :
1026 [ # # ]: 0 : if (strcmp (arg_name, DBUS_SERVICE_NAME) == 0)
1027 : : {
1028 : 0 : _g_freedesktop_dbus_complete_get_name_owner (object, invocation, DBUS_SERVICE_NAME);
1029 : 0 : return TRUE;
1030 : : }
1031 : :
1032 [ # # ]: 0 : if (arg_name[0] == ':')
1033 : : {
1034 [ # # ]: 0 : if (g_hash_table_lookup (daemon->clients, arg_name) == NULL)
1035 : 0 : g_dbus_method_invocation_return_error (invocation,
1036 : : G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
1037 : : "Could not get owner of name '%s': no such name", arg_name);
1038 : : else
1039 : 0 : _g_freedesktop_dbus_complete_get_name_owner (object, invocation, arg_name);
1040 : 0 : return TRUE;
1041 : : }
1042 : :
1043 : 0 : name = name_lookup (daemon, arg_name);
1044 [ # # # # ]: 0 : if (name == NULL || name->owner == NULL)
1045 : : {
1046 : 0 : g_dbus_method_invocation_return_error (invocation,
1047 : : G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
1048 : : "Could not get owner of name '%s': no such name", arg_name);
1049 : 0 : return TRUE;
1050 : : }
1051 : :
1052 : 0 : _g_freedesktop_dbus_complete_get_name_owner (object, invocation, name->owner->client->id);
1053 : 0 : return TRUE;
1054 : : }
1055 : :
1056 : : static gboolean
1057 : 0 : handle_hello (_GFreedesktopDBus *object,
1058 : : GDBusMethodInvocation *invocation)
1059 : : {
1060 : 0 : Client *client = g_object_get_data (G_OBJECT (g_dbus_method_invocation_get_connection (invocation)), "client");
1061 : 0 : _g_freedesktop_dbus_complete_hello (object, invocation, client->id);
1062 : :
1063 : 0 : g_dbus_connection_emit_signal (client->connection,
1064 : : NULL, "/org/freedesktop/DBus",
1065 : : "org.freedesktop.DBus", "NameAcquired",
1066 : : g_variant_new ("(s)",
1067 : : client->id), NULL);
1068 : :
1069 : 0 : return TRUE;
1070 : : }
1071 : :
1072 : : static gboolean
1073 : 0 : handle_list_activatable_names (_GFreedesktopDBus *object,
1074 : : GDBusMethodInvocation *invocation)
1075 : : {
1076 : 0 : const char *names[] = { NULL };
1077 : :
1078 : 0 : _g_freedesktop_dbus_complete_list_activatable_names (object,
1079 : : invocation,
1080 : : names);
1081 : 0 : return TRUE;
1082 : : }
1083 : :
1084 : : static gboolean
1085 : 0 : handle_list_names (_GFreedesktopDBus *object,
1086 : : GDBusMethodInvocation *invocation)
1087 : : {
1088 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1089 : : GPtrArray *array;
1090 : : GPtrArray *clients, *names;
1091 : :
1092 : 0 : clients = g_hash_table_get_values_as_ptr_array (daemon->clients);
1093 : 0 : array = g_steal_pointer (&clients);
1094 : :
1095 : 0 : names = g_hash_table_get_values_as_ptr_array (daemon->names);
1096 : 0 : g_ptr_array_extend_and_steal (array, g_steal_pointer (&names));
1097 : :
1098 : 0 : g_ptr_array_add (array, NULL);
1099 : :
1100 : 0 : _g_freedesktop_dbus_complete_list_names (object,
1101 : : invocation,
1102 : 0 : (const gchar * const*)array->pdata);
1103 : 0 : g_ptr_array_free (array, TRUE);
1104 : 0 : return TRUE;
1105 : : }
1106 : :
1107 : : static gboolean
1108 : 0 : handle_list_queued_owners (_GFreedesktopDBus *object,
1109 : : GDBusMethodInvocation *invocation,
1110 : : const gchar *arg_name)
1111 : : {
1112 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1113 : : GPtrArray *array;
1114 : : Name *name;
1115 : : GList *l;
1116 : :
1117 : 0 : array = g_ptr_array_new ();
1118 : :
1119 : 0 : name = name_lookup (daemon, arg_name);
1120 [ # # # # ]: 0 : if (name && name->owner)
1121 : : {
1122 [ # # ]: 0 : for (l = name->queue; l != NULL; l = l->next)
1123 : : {
1124 : 0 : Client *client = l->data;
1125 : :
1126 : 0 : g_ptr_array_add (array, client->id);
1127 : : }
1128 : : }
1129 : :
1130 : 0 : g_ptr_array_add (array, NULL);
1131 : :
1132 : 0 : _g_freedesktop_dbus_complete_list_queued_owners (object,
1133 : : invocation,
1134 : 0 : (const gchar * const*)array->pdata);
1135 : 0 : g_ptr_array_free (array, TRUE);
1136 : 0 : return TRUE;
1137 : : }
1138 : :
1139 : : static gboolean
1140 : 0 : handle_name_has_owner (_GFreedesktopDBus *object,
1141 : : GDBusMethodInvocation *invocation,
1142 : : const gchar *arg_name)
1143 : : {
1144 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1145 : : Name *name;
1146 : : Client *client;
1147 : :
1148 : 0 : name = name_lookup (daemon, arg_name);
1149 : 0 : client = g_hash_table_lookup (daemon->clients, arg_name);
1150 : :
1151 [ # # # # ]: 0 : _g_freedesktop_dbus_complete_name_has_owner (object, invocation,
1152 : : name != NULL || client != NULL);
1153 : 0 : return TRUE;
1154 : : }
1155 : :
1156 : : static gboolean
1157 : 0 : handle_release_name (_GFreedesktopDBus *object,
1158 : : GDBusMethodInvocation *invocation,
1159 : : const gchar *arg_name)
1160 : : {
1161 : 0 : Client *client = g_object_get_data (G_OBJECT (g_dbus_method_invocation_get_connection (invocation)), "client");
1162 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1163 : : Name *name;
1164 : : guint32 result;
1165 : :
1166 [ # # ]: 0 : if (!g_dbus_is_name (arg_name))
1167 : : {
1168 : 0 : g_dbus_method_invocation_return_error (invocation,
1169 : : G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1170 : : "Given bus name \"%s\" is not valid", arg_name);
1171 : 0 : return TRUE;
1172 : : }
1173 : :
1174 [ # # ]: 0 : if (*arg_name == ':')
1175 : : {
1176 : 0 : g_dbus_method_invocation_return_error (invocation,
1177 : : G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1178 : : "Cannot release a service starting with ':' such as \"%s\"", arg_name);
1179 : 0 : return TRUE;
1180 : : }
1181 : :
1182 [ # # ]: 0 : if (strcmp (arg_name, DBUS_SERVICE_NAME) == 0)
1183 : : {
1184 : 0 : g_dbus_method_invocation_return_error (invocation,
1185 : : G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1186 : : "Cannot release a service named " DBUS_SERVICE_NAME ", because that is owned by the bus");
1187 : 0 : return TRUE;
1188 : : }
1189 : :
1190 : 0 : name = name_lookup (daemon, arg_name);
1191 : :
1192 [ # # ]: 0 : if (name == NULL)
1193 : 0 : result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT;
1194 [ # # # # ]: 0 : else if (name->owner && name->owner->client == client)
1195 : : {
1196 : 0 : name_release_owner (name);
1197 : 0 : result = DBUS_RELEASE_NAME_REPLY_RELEASED;
1198 : : }
1199 [ # # ]: 0 : else if (name_unqueue_owner (name, client))
1200 : 0 : result = DBUS_RELEASE_NAME_REPLY_RELEASED;
1201 : : else
1202 : 0 : result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER;
1203 : :
1204 : 0 : _g_freedesktop_dbus_complete_release_name (object, invocation, result);
1205 : 0 : return TRUE;
1206 : : }
1207 : :
1208 : : static gboolean
1209 : 0 : handle_reload_config (_GFreedesktopDBus *object,
1210 : : GDBusMethodInvocation *invocation)
1211 : : {
1212 : 0 : _g_freedesktop_dbus_complete_reload_config (object, invocation);
1213 : 0 : return TRUE;
1214 : : }
1215 : :
1216 : : static gboolean
1217 : 0 : handle_update_activation_environment (_GFreedesktopDBus *object,
1218 : : GDBusMethodInvocation *invocation,
1219 : : GVariant *arg_environment)
1220 : : {
1221 : 0 : g_dbus_method_invocation_return_error (invocation,
1222 : : G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1223 : : "UpdateActivationEnvironment not implemented");
1224 : 0 : return TRUE;
1225 : : }
1226 : :
1227 : : static gboolean
1228 : 0 : handle_remove_match (_GFreedesktopDBus *object,
1229 : : GDBusMethodInvocation *invocation,
1230 : : const gchar *arg_rule)
1231 : : {
1232 : 0 : Client *client = g_object_get_data (G_OBJECT (g_dbus_method_invocation_get_connection (invocation)), "client");
1233 : : Match *match, *other_match;
1234 : : GList *l;
1235 : :
1236 : 0 : match = match_new (arg_rule);
1237 : :
1238 [ # # ]: 0 : if (match == NULL)
1239 : 0 : g_dbus_method_invocation_return_error (invocation,
1240 : : G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_INVALID,
1241 : : "Invalid rule: %s", arg_rule);
1242 : : else
1243 : : {
1244 [ # # ]: 0 : for (l = client->matches; l != NULL; l = l->next)
1245 : : {
1246 : 0 : other_match = l->data;
1247 [ # # ]: 0 : if (match_equal (match, other_match))
1248 : : {
1249 : 0 : match_free (other_match);
1250 : 0 : client->matches = g_list_delete_link (client->matches, l);
1251 : 0 : break;
1252 : : }
1253 : : }
1254 : :
1255 [ # # ]: 0 : if (l == NULL)
1256 : 0 : g_dbus_method_invocation_return_error (invocation,
1257 : : G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
1258 : : "The given match rule wasn't found and can't be removed");
1259 : : else
1260 : 0 : _g_freedesktop_dbus_complete_remove_match (object, invocation);
1261 : : }
1262 [ # # ]: 0 : if (match)
1263 : 0 : match_free (match);
1264 : :
1265 : 0 : return TRUE;
1266 : : }
1267 : :
1268 : : static gboolean
1269 : 0 : handle_request_name (_GFreedesktopDBus *object,
1270 : : GDBusMethodInvocation *invocation,
1271 : : const gchar *arg_name,
1272 : : guint flags)
1273 : : {
1274 : 0 : Client *client = g_object_get_data (G_OBJECT (g_dbus_method_invocation_get_connection (invocation)), "client");
1275 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1276 : : Name *name;
1277 : : NameOwner *owner;
1278 : : guint32 result;
1279 : :
1280 [ # # ]: 0 : if (!g_dbus_is_name (arg_name))
1281 : : {
1282 : 0 : g_dbus_method_invocation_return_error (invocation,
1283 : : G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1284 : : "Requested bus name \"%s\" is not valid", arg_name);
1285 : 0 : return TRUE;
1286 : : }
1287 : :
1288 [ # # ]: 0 : if (*arg_name == ':')
1289 : : {
1290 : 0 : g_dbus_method_invocation_return_error (invocation,
1291 : : G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1292 : : "Cannot acquire a service starting with ':' such as \"%s\"", arg_name);
1293 : 0 : return TRUE;
1294 : : }
1295 : :
1296 [ # # ]: 0 : if (strcmp (arg_name, DBUS_SERVICE_NAME) == 0)
1297 : : {
1298 : 0 : g_dbus_method_invocation_return_error (invocation,
1299 : : G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1300 : : "Cannot acquire a service named " DBUS_SERVICE_NAME ", because that is reserved");
1301 : 0 : return TRUE;
1302 : : }
1303 : :
1304 : 0 : name = name_ensure (daemon, arg_name);
1305 [ # # ]: 0 : if (name->owner == NULL)
1306 : : {
1307 : 0 : owner = name_owner_new (client, flags);
1308 : 0 : name_replace_owner (name, owner);
1309 : :
1310 : 0 : result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
1311 : : }
1312 [ # # # # ]: 0 : else if (name->owner && name->owner->client == client)
1313 : : {
1314 : 0 : name->owner->flags = flags;
1315 : 0 : result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
1316 : : }
1317 [ # # ]: 0 : else if ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
1318 [ # # ]: 0 : (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) ||
1319 [ # # ]: 0 : !(name->owner->flags & DBUS_NAME_FLAG_ALLOW_REPLACEMENT)))
1320 : : {
1321 : : /* Unqueue if queued */
1322 : 0 : name_unqueue_owner (name, client);
1323 : 0 : result = DBUS_REQUEST_NAME_REPLY_EXISTS;
1324 : : }
1325 [ # # ]: 0 : else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) &&
1326 [ # # ]: 0 : (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) ||
1327 [ # # ]: 0 : !(name->owner->flags & DBUS_NAME_FLAG_ALLOW_REPLACEMENT)))
1328 : : {
1329 : : /* Queue the connection */
1330 : 0 : owner = name_owner_new (client, flags);
1331 : 0 : name_queue_owner (name, owner);
1332 : 0 : result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE;
1333 : : }
1334 : : else
1335 : : {
1336 : : /* Replace the current owner */
1337 : :
1338 : 0 : owner = name_owner_new (client, flags);
1339 : 0 : name_replace_owner (name, owner);
1340 : :
1341 : 0 : result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
1342 : : }
1343 : :
1344 : 0 : name_unref (name);
1345 : :
1346 : 0 : _g_freedesktop_dbus_complete_request_name (object, invocation, result);
1347 : 0 : return TRUE;
1348 : : }
1349 : :
1350 : : static gboolean
1351 : 0 : handle_start_service_by_name (_GFreedesktopDBus *object,
1352 : : GDBusMethodInvocation *invocation,
1353 : : const gchar *arg_name,
1354 : : guint arg_flags)
1355 : : {
1356 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1357 : : Name *name;
1358 : :
1359 : 0 : name = name_lookup (daemon, arg_name);
1360 [ # # ]: 0 : if (name)
1361 : 0 : _g_freedesktop_dbus_complete_start_service_by_name (object, invocation,
1362 : : DBUS_START_REPLY_ALREADY_RUNNING);
1363 : : else
1364 : 0 : g_dbus_method_invocation_return_error (invocation,
1365 : : G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
1366 : : "No support for activation for name: %s", arg_name);
1367 : :
1368 : 0 : return TRUE;
1369 : : }
1370 : :
1371 : : G_GNUC_PRINTF(5, 6)
1372 : : static void
1373 : 0 : return_error (Client *client, GDBusMessage *message,
1374 : : GQuark domain,
1375 : : gint code,
1376 : : const gchar *format,
1377 : : ...)
1378 : : {
1379 : : GDBusMessage *reply;
1380 : : va_list var_args;
1381 : : char *error_message;
1382 : : GError *error;
1383 : : gchar *dbus_error_name;
1384 : :
1385 : 0 : va_start (var_args, format);
1386 : 0 : error_message = g_strdup_vprintf (format, var_args);
1387 : 0 : va_end (var_args);
1388 : :
1389 : 0 : error = g_error_new_literal (domain, code, "");
1390 : 0 : dbus_error_name = g_dbus_error_encode_gerror (error);
1391 : :
1392 : 0 : reply = g_dbus_message_new_method_error_literal (message,
1393 : : dbus_error_name,
1394 : : error_message);
1395 : :
1396 : 0 : g_error_free (error);
1397 : 0 : g_free (dbus_error_name);
1398 : 0 : g_free (error_message);
1399 : :
1400 [ # # ]: 0 : if (!g_dbus_connection_send_message (client->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL))
1401 : 0 : g_warning ("Error sending reply");
1402 : 0 : g_object_unref (reply);
1403 : 0 : }
1404 : :
1405 : : static GDBusMessage *
1406 : 0 : route_message (Client *source_client, GDBusMessage *message)
1407 : : {
1408 : : const char *dest;
1409 : : Client *dest_client;
1410 : : GDBusDaemon *daemon;
1411 : :
1412 : 0 : daemon = source_client->daemon;
1413 : :
1414 : 0 : dest_client = NULL;
1415 : 0 : dest = g_dbus_message_get_destination (message);
1416 [ # # # # ]: 0 : if (dest != NULL && strcmp (dest, DBUS_SERVICE_NAME) != 0)
1417 : : {
1418 : 0 : dest_client = g_hash_table_lookup (daemon->clients, dest);
1419 : :
1420 [ # # ]: 0 : if (dest_client == NULL)
1421 : : {
1422 : : Name *name;
1423 : 0 : name = name_lookup (daemon, dest);
1424 [ # # # # ]: 0 : if (name && name->owner)
1425 : 0 : dest_client = name->owner->client;
1426 : : }
1427 : :
1428 [ # # ]: 0 : if (dest_client == NULL)
1429 : : {
1430 [ # # ]: 0 : if (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL)
1431 : 0 : return_error (source_client, message,
1432 : : G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
1433 : : "The name %s is unknown", dest);
1434 : : }
1435 : : else
1436 : : {
1437 : 0 : GError *error = NULL;
1438 : :
1439 [ # # ]: 0 : if (!g_dbus_connection_send_message (dest_client->connection, message, G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL, NULL, &error))
1440 : : {
1441 : 0 : g_warning ("Error forwarding message: %s", error->message);
1442 : 0 : g_error_free (error);
1443 : : }
1444 : : }
1445 : : }
1446 : :
1447 : 0 : broadcast_message (daemon, message, dest_client != NULL, TRUE, dest_client);
1448 : :
1449 : : /* Swallow messages not for the bus */
1450 [ # # # # ]: 0 : if (dest == NULL || strcmp (dest, DBUS_SERVICE_NAME) != 0)
1451 : : {
1452 : 0 : g_object_unref (message);
1453 : 0 : message = NULL;
1454 : : }
1455 : :
1456 : 0 : return message;
1457 : : }
1458 : :
1459 : : static GDBusMessage *
1460 : 0 : copy_if_locked (GDBusMessage *message)
1461 : : {
1462 [ # # ]: 0 : if (g_dbus_message_get_locked (message))
1463 : : {
1464 : 0 : GDBusMessage *copy = g_dbus_message_copy (message, NULL);
1465 : 0 : g_object_unref (message);
1466 : 0 : message = copy;
1467 : : }
1468 : 0 : return message;
1469 : : }
1470 : :
1471 : : static GDBusMessage *
1472 : 0 : filter_function (GDBusConnection *connection,
1473 : : GDBusMessage *message,
1474 : : gboolean incoming,
1475 : : gpointer user_data)
1476 : : {
1477 : 0 : Client *client = user_data;
1478 : :
1479 : : if (0)
1480 : : {
1481 : : const char *types[] = {"invalid", "method_call", "method_return", "error", "signal" };
1482 : : g_printerr ("%s%s %s %d(%d) sender: %s destination: %s %s %s.%s\n",
1483 : : client->id,
1484 : : incoming? "->" : "<-",
1485 : : types[g_dbus_message_get_message_type (message)],
1486 : : g_dbus_message_get_serial (message),
1487 : : g_dbus_message_get_reply_serial (message),
1488 : : g_dbus_message_get_sender (message),
1489 : : g_dbus_message_get_destination (message),
1490 : : g_dbus_message_get_path (message),
1491 : : g_dbus_message_get_interface (message),
1492 : : g_dbus_message_get_member (message));
1493 : : }
1494 : :
1495 [ # # ]: 0 : if (incoming)
1496 : : {
1497 : : /* Ensure its not locked so we can set the sender */
1498 : 0 : message = copy_if_locked (message);
1499 [ # # ]: 0 : if (message == NULL)
1500 : : {
1501 : 0 : g_warning ("Failed to copy incoming message");
1502 : 0 : return NULL;
1503 : : }
1504 : 0 : g_dbus_message_set_sender (message, client->id);
1505 : :
1506 : 0 : return route_message (client, message);
1507 : : }
1508 : : else
1509 : : {
1510 [ # # # # ]: 0 : if (g_dbus_message_get_sender (message) == NULL ||
1511 : 0 : g_dbus_message_get_destination (message) == NULL)
1512 : : {
1513 : 0 : message = copy_if_locked (message);
1514 [ # # ]: 0 : if (message == NULL)
1515 : : {
1516 : 0 : g_warning ("Failed to copy outgoing message");
1517 : 0 : return NULL;
1518 : : }
1519 : : }
1520 : :
1521 [ # # ]: 0 : if (g_dbus_message_get_sender (message) == NULL)
1522 : 0 : g_dbus_message_set_sender (message, DBUS_SERVICE_NAME);
1523 [ # # ]: 0 : if (g_dbus_message_get_destination (message) == NULL)
1524 : 0 : g_dbus_message_set_destination (message, client->id);
1525 : : }
1526 : :
1527 : 0 : return message;
1528 : : }
1529 : :
1530 : : static gboolean
1531 : 0 : on_new_connection (GDBusServer *server,
1532 : : GDBusConnection *connection,
1533 : : gpointer user_data)
1534 : : {
1535 : 0 : GDBusDaemon *daemon = user_data;
1536 : :
1537 : 0 : g_dbus_connection_set_exit_on_close (connection, FALSE);
1538 : :
1539 [ # # ]: 0 : if (daemon->timeout)
1540 : : {
1541 : 0 : g_source_remove (daemon->timeout);
1542 : 0 : daemon->timeout = 0;
1543 : : }
1544 : :
1545 : 0 : client_new (daemon, connection);
1546 : :
1547 : 0 : return TRUE;
1548 : : }
1549 : :
1550 : : static void
1551 : 0 : g_dbus_daemon_finalize (GObject *object)
1552 : : {
1553 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1554 : : GList *clients, *l;
1555 : :
1556 [ # # ]: 0 : if (daemon->timeout)
1557 : 0 : g_source_remove (daemon->timeout);
1558 : :
1559 : 0 : clients = g_hash_table_get_values (daemon->clients);
1560 [ # # ]: 0 : for (l = clients; l != NULL; l = l->next)
1561 : 0 : client_free (l->data);
1562 : 0 : g_list_free (clients);
1563 : :
1564 : 0 : g_assert (g_hash_table_size (daemon->clients) == 0);
1565 : 0 : g_assert (g_hash_table_size (daemon->names) == 0);
1566 : :
1567 : 0 : g_hash_table_destroy (daemon->clients);
1568 : 0 : g_hash_table_destroy (daemon->names);
1569 : :
1570 : 0 : g_object_unref (daemon->server);
1571 : :
1572 [ # # ]: 0 : if (daemon->tmpdir)
1573 : : {
1574 : 0 : g_rmdir (daemon->tmpdir);
1575 : 0 : g_free (daemon->tmpdir);
1576 : : }
1577 : :
1578 : 0 : g_free (daemon->guid);
1579 : 0 : g_free (daemon->address);
1580 : :
1581 : 0 : G_OBJECT_CLASS (g_dbus_daemon_parent_class)->finalize (object);
1582 : 0 : }
1583 : :
1584 : : static void
1585 : 0 : g_dbus_daemon_init (GDBusDaemon *daemon)
1586 : : {
1587 : 0 : daemon->next_major_id = 1;
1588 : 0 : daemon->clients = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
1589 : 0 : daemon->names = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
1590 : 0 : daemon->guid = g_dbus_generate_guid ();
1591 : 0 : }
1592 : :
1593 : : static gboolean
1594 : 0 : initable_init (GInitable *initable,
1595 : : GCancellable *cancellable,
1596 : : GError **error)
1597 : : {
1598 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (initable);
1599 : : GDBusServerFlags flags;
1600 : :
1601 : 0 : flags = G_DBUS_SERVER_FLAGS_NONE;
1602 [ # # ]: 0 : if (daemon->address == NULL)
1603 : : {
1604 : : #ifdef G_OS_UNIX
1605 : 0 : daemon->tmpdir = g_dir_make_tmp ("gdbus-daemon-XXXXXX", NULL);
1606 : 0 : daemon->address = g_strdup_printf ("unix:tmpdir=%s", daemon->tmpdir);
1607 : 0 : flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER;
1608 : : #else
1609 : : /* Don’t require authentication on Windows as that hasn’t been
1610 : : * implemented yet. */
1611 : : daemon->address = g_strdup ("nonce-tcp:");
1612 : : flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
1613 : : #endif
1614 : : }
1615 : :
1616 : 0 : daemon->server = g_dbus_server_new_sync (daemon->address,
1617 : : flags,
1618 : 0 : daemon->guid,
1619 : : NULL,
1620 : : cancellable,
1621 : : error);
1622 [ # # ]: 0 : if (daemon->server == NULL)
1623 : 0 : return FALSE;
1624 : :
1625 : :
1626 : 0 : g_dbus_server_start (daemon->server);
1627 : :
1628 : 0 : g_signal_connect (daemon->server, "new-connection",
1629 : : G_CALLBACK (on_new_connection),
1630 : : daemon);
1631 : :
1632 : 0 : return TRUE;
1633 : : }
1634 : :
1635 : : static void
1636 : 0 : g_dbus_daemon_set_property (GObject *object,
1637 : : guint prop_id,
1638 : : const GValue *value,
1639 : : GParamSpec *pspec)
1640 : : {
1641 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1642 : :
1643 [ # # ]: 0 : switch (prop_id)
1644 : : {
1645 : 0 : case PROP_ADDRESS:
1646 : 0 : g_free (daemon->address);
1647 : 0 : daemon->address = g_value_dup_string (value);
1648 : 0 : break;
1649 : :
1650 : 0 : default:
1651 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1652 : : }
1653 : 0 : }
1654 : :
1655 : : static void
1656 : 0 : g_dbus_daemon_get_property (GObject *object,
1657 : : guint prop_id,
1658 : : GValue *value,
1659 : : GParamSpec *pspec)
1660 : : {
1661 : 0 : GDBusDaemon *daemon = G_DBUS_DAEMON (object);
1662 : :
1663 [ # # ]: 0 : switch (prop_id)
1664 : : {
1665 : 0 : case PROP_ADDRESS:
1666 : 0 : g_value_set_string (value, daemon->address);
1667 : 0 : break;
1668 : :
1669 : 0 : default:
1670 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1671 : : }
1672 : 0 : }
1673 : :
1674 : : static void
1675 : 0 : g_dbus_daemon_class_init (GDBusDaemonClass *klass)
1676 : : {
1677 : : GObjectClass *gobject_class;
1678 : :
1679 : 0 : gobject_class = G_OBJECT_CLASS (klass);
1680 : 0 : gobject_class->finalize = g_dbus_daemon_finalize;
1681 : 0 : gobject_class->set_property = g_dbus_daemon_set_property;
1682 : 0 : gobject_class->get_property = g_dbus_daemon_get_property;
1683 : :
1684 : 0 : g_dbus_daemon_signals[SIGNAL_IDLE_TIMEOUT] =
1685 : 0 : g_signal_new (I_("idle-timeout"),
1686 : : G_TYPE_DBUS_DAEMON,
1687 : : G_SIGNAL_RUN_LAST,
1688 : : 0,
1689 : : NULL, NULL,
1690 : : NULL,
1691 : : G_TYPE_NONE, 0);
1692 : :
1693 : 0 : g_object_class_install_property (gobject_class,
1694 : : PROP_ADDRESS,
1695 : : g_param_spec_string ("address", NULL, NULL,
1696 : : NULL,
1697 : : G_PARAM_READWRITE |
1698 : : G_PARAM_CONSTRUCT_ONLY |
1699 : : G_PARAM_STATIC_STRINGS));
1700 : 0 : }
1701 : :
1702 : : static void
1703 : 0 : g_dbus_daemon_iface_init (_GFreedesktopDBusIface *iface)
1704 : : {
1705 : 0 : iface->handle_add_match = handle_add_match;
1706 : 0 : iface->handle_get_connection_selinux_security_context = handle_get_connection_selinux_security_context;
1707 : 0 : iface->handle_get_connection_unix_process_id = handle_get_connection_unix_process_id;
1708 : 0 : iface->handle_get_connection_unix_user = handle_get_connection_unix_user;
1709 : 0 : iface->handle_get_id = handle_get_id;
1710 : 0 : iface->handle_get_name_owner = handle_get_name_owner;
1711 : 0 : iface->handle_hello = handle_hello;
1712 : 0 : iface->handle_list_activatable_names = handle_list_activatable_names;
1713 : 0 : iface->handle_list_names = handle_list_names;
1714 : 0 : iface->handle_list_queued_owners = handle_list_queued_owners;
1715 : 0 : iface->handle_name_has_owner = handle_name_has_owner;
1716 : 0 : iface->handle_release_name = handle_release_name;
1717 : 0 : iface->handle_reload_config = handle_reload_config;
1718 : 0 : iface->handle_update_activation_environment = handle_update_activation_environment;
1719 : 0 : iface->handle_remove_match = handle_remove_match;
1720 : 0 : iface->handle_request_name = handle_request_name;
1721 : 0 : iface->handle_start_service_by_name = handle_start_service_by_name;
1722 : 0 : }
1723 : :
1724 : : static void
1725 : 0 : initable_iface_init (GInitableIface *initable_iface)
1726 : : {
1727 : 0 : initable_iface->init = initable_init;
1728 : 0 : }
1729 : :
1730 : : GDBusDaemon *
1731 : 0 : _g_dbus_daemon_new (const char *address,
1732 : : GCancellable *cancellable,
1733 : : GError **error)
1734 : : {
1735 : 0 : return g_initable_new (G_TYPE_DBUS_DAEMON,
1736 : : cancellable,
1737 : : error,
1738 : : "address", address,
1739 : : NULL);
1740 : : }
1741 : :
1742 : : const char *
1743 : 0 : _g_dbus_daemon_get_address (GDBusDaemon *daemon)
1744 : : {
1745 : 0 : return g_dbus_server_get_client_address (daemon->server);
1746 : : }
|