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