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