driver.c revision 66e1cb9e68ba37980f7a90c396950be1587cdcd7
1/* -*- mode: C; c-file-style: "gnu" -*- */
2/* driver.c  Bus client (driver)
3 *
4 * Copyright (C) 2003 CodeFactory AB
5 * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
6 *
7 * Licensed under the Academic Free License version 2.1
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 *
23 */
24
25#include "activation.h"
26#include "connection.h"
27#include "driver.h"
28#include "dispatch.h"
29#include "services.h"
30#include "selinux.h"
31#include "signals.h"
32#include "utils.h"
33#include <dbus/dbus-string.h>
34#include <dbus/dbus-internals.h>
35#include <dbus/dbus-marshal-recursive.h>
36#include <string.h>
37
38static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
39                                                    DBusMessage    *hello_message,
40                                                    BusTransaction *transaction,
41                                                    DBusError      *error);
42
43dbus_bool_t
44bus_driver_send_service_owner_changed (const char     *service_name,
45				       const char     *old_owner,
46				       const char     *new_owner,
47				       BusTransaction *transaction,
48				       DBusError      *error)
49{
50  DBusMessage *message;
51  dbus_bool_t retval;
52  const char *null_service;
53
54  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
55
56  null_service = "";
57  _dbus_verbose ("sending name owner changed: %s [%s -> %s]\n",
58                 service_name,
59                 old_owner ? old_owner : null_service,
60                 new_owner ? new_owner : null_service);
61
62  message = dbus_message_new_signal (DBUS_PATH_DBUS,
63                                     DBUS_INTERFACE_DBUS,
64                                     "NameOwnerChanged");
65
66  if (message == NULL)
67    {
68      BUS_SET_OOM (error);
69      return FALSE;
70    }
71
72  if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
73    goto oom;
74
75  if (!dbus_message_append_args (message,
76                                 DBUS_TYPE_STRING, &service_name,
77                                 DBUS_TYPE_STRING, old_owner ? &old_owner : &null_service,
78                                 DBUS_TYPE_STRING, new_owner ? &new_owner : &null_service,
79                                 DBUS_TYPE_INVALID))
80    goto oom;
81
82  _dbus_assert (dbus_message_has_signature (message, "sss"));
83
84  retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
85  dbus_message_unref (message);
86
87  return retval;
88
89 oom:
90  dbus_message_unref (message);
91  BUS_SET_OOM (error);
92  return FALSE;
93}
94
95dbus_bool_t
96bus_driver_send_service_lost (DBusConnection *connection,
97			      const char     *service_name,
98                              BusTransaction *transaction,
99                              DBusError      *error)
100{
101  DBusMessage *message;
102
103  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
104
105  message = dbus_message_new_signal (DBUS_PATH_DBUS,
106                                     DBUS_INTERFACE_DBUS,
107                                     "NameLost");
108
109  if (message == NULL)
110    {
111      BUS_SET_OOM (error);
112      return FALSE;
113    }
114
115  if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
116      !dbus_message_append_args (message,
117                                 DBUS_TYPE_STRING, &service_name,
118                                 DBUS_TYPE_INVALID))
119    {
120      dbus_message_unref (message);
121      BUS_SET_OOM (error);
122      return FALSE;
123    }
124
125  if (!bus_transaction_send_from_driver (transaction, connection, message))
126    {
127      dbus_message_unref (message);
128      BUS_SET_OOM (error);
129      return FALSE;
130    }
131  else
132    {
133      dbus_message_unref (message);
134      return TRUE;
135    }
136}
137
138dbus_bool_t
139bus_driver_send_service_acquired (DBusConnection *connection,
140                                  const char     *service_name,
141                                  BusTransaction *transaction,
142                                  DBusError      *error)
143{
144  DBusMessage *message;
145
146  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
147
148  message = dbus_message_new_signal (DBUS_PATH_DBUS,
149                                     DBUS_INTERFACE_DBUS,
150                                     "NameAcquired");
151
152  if (message == NULL)
153    {
154      BUS_SET_OOM (error);
155      return FALSE;
156    }
157
158  if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
159      !dbus_message_append_args (message,
160                                 DBUS_TYPE_STRING, &service_name,
161                                 DBUS_TYPE_INVALID))
162    {
163      dbus_message_unref (message);
164      BUS_SET_OOM (error);
165      return FALSE;
166    }
167
168  if (!bus_transaction_send_from_driver (transaction, connection, message))
169    {
170      dbus_message_unref (message);
171      BUS_SET_OOM (error);
172      return FALSE;
173    }
174  else
175    {
176      dbus_message_unref (message);
177      return TRUE;
178    }
179}
180
181static dbus_bool_t
182create_unique_client_name (BusRegistry *registry,
183                           DBusString  *str)
184{
185  /* We never want to use the same unique client name twice, because
186   * we want to guarantee that if you send a message to a given unique
187   * name, you always get the same application. So we use two numbers
188   * for INT_MAX * INT_MAX combinations, should be pretty safe against
189   * wraparound.
190   */
191  /* FIXME these should be in BusRegistry rather than static vars */
192  static int next_major_number = 0;
193  static int next_minor_number = 0;
194  int len;
195
196  len = _dbus_string_get_length (str);
197
198  while (TRUE)
199    {
200      /* start out with 1-0, go to 1-1, 1-2, 1-3,
201       * up to 1-MAXINT, then 2-0, 2-1, etc.
202       */
203      if (next_minor_number <= 0)
204        {
205          next_major_number += 1;
206          next_minor_number = 0;
207          if (next_major_number <= 0)
208            _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
209        }
210
211      _dbus_assert (next_major_number > 0);
212      _dbus_assert (next_minor_number >= 0);
213
214      /* appname:MAJOR-MINOR */
215
216      if (!_dbus_string_append (str, ":"))
217        return FALSE;
218
219      if (!_dbus_string_append_int (str, next_major_number))
220        return FALSE;
221
222      if (!_dbus_string_append (str, "."))
223        return FALSE;
224
225      if (!_dbus_string_append_int (str, next_minor_number))
226        return FALSE;
227
228      next_minor_number += 1;
229
230      /* Check if a client with the name exists */
231      if (bus_registry_lookup (registry, str) == NULL)
232	break;
233
234      /* drop the number again, try the next one. */
235      _dbus_string_set_length (str, len);
236    }
237
238  return TRUE;
239}
240
241static dbus_bool_t
242bus_driver_handle_hello (DBusConnection *connection,
243                         BusTransaction *transaction,
244                         DBusMessage    *message,
245                         DBusError      *error)
246{
247  DBusString unique_name;
248  BusService *service;
249  dbus_bool_t retval;
250  BusRegistry *registry;
251  BusConnections *connections;
252
253  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
254
255  if (bus_connection_is_active (connection))
256    {
257      /* We already handled an Hello message for this connection. */
258      dbus_set_error (error, DBUS_ERROR_FAILED,
259                      "Already handled an Hello message");
260      return FALSE;
261    }
262
263  /* Note that when these limits are exceeded we don't disconnect the
264   * connection; we just sort of leave it hanging there until it times
265   * out or disconnects itself or is dropped due to the max number of
266   * incomplete connections. It's even OK if the connection wants to
267   * retry the hello message, we support that.
268   */
269  connections = bus_connection_get_connections (connection);
270  if (!bus_connections_check_limits (connections, connection,
271                                     error))
272    {
273      _DBUS_ASSERT_ERROR_IS_SET (error);
274      return FALSE;
275    }
276
277  if (!_dbus_string_init (&unique_name))
278    {
279      BUS_SET_OOM (error);
280      return FALSE;
281    }
282
283  retval = FALSE;
284
285  registry = bus_connection_get_registry (connection);
286
287  if (!create_unique_client_name (registry, &unique_name))
288    {
289      BUS_SET_OOM (error);
290      goto out_0;
291    }
292
293  if (!bus_connection_complete (connection, &unique_name, error))
294    {
295      _DBUS_ASSERT_ERROR_IS_SET (error);
296      goto out_0;
297    }
298
299  if (!dbus_message_set_sender (message,
300                                bus_connection_get_name (connection)))
301    {
302      BUS_SET_OOM (error);
303      goto out_0;
304    }
305
306  if (!bus_driver_send_welcome_message (connection, message, transaction, error))
307    goto out_0;
308
309  /* Create the service */
310  service = bus_registry_ensure (registry,
311                                 &unique_name, connection, transaction, error);
312  if (service == NULL)
313    goto out_0;
314
315  bus_service_set_prohibit_replacement (service, TRUE);
316
317  _dbus_assert (bus_connection_is_active (connection));
318  retval = TRUE;
319
320 out_0:
321  _dbus_string_free (&unique_name);
322  return retval;
323}
324
325static dbus_bool_t
326bus_driver_send_welcome_message (DBusConnection *connection,
327                                 DBusMessage    *hello_message,
328                                 BusTransaction *transaction,
329                                 DBusError      *error)
330{
331  DBusMessage *welcome;
332  const char *name;
333
334  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
335
336  name = bus_connection_get_name (connection);
337  _dbus_assert (name != NULL);
338
339  welcome = dbus_message_new_method_return (hello_message);
340  if (welcome == NULL)
341    {
342      BUS_SET_OOM (error);
343      return FALSE;
344    }
345
346  if (!dbus_message_append_args (welcome,
347                                 DBUS_TYPE_STRING, &name,
348                                 DBUS_TYPE_INVALID))
349    {
350      dbus_message_unref (welcome);
351      BUS_SET_OOM (error);
352      return FALSE;
353    }
354
355  _dbus_assert (dbus_message_has_signature (welcome, DBUS_TYPE_STRING_AS_STRING));
356
357  if (!bus_transaction_send_from_driver (transaction, connection, welcome))
358    {
359      dbus_message_unref (welcome);
360      BUS_SET_OOM (error);
361      return FALSE;
362    }
363  else
364    {
365      dbus_message_unref (welcome);
366      return TRUE;
367    }
368}
369
370static dbus_bool_t
371bus_driver_handle_list_services (DBusConnection *connection,
372                                 BusTransaction *transaction,
373                                 DBusMessage    *message,
374                                 DBusError      *error)
375{
376  DBusMessage *reply;
377  int len;
378  char **services;
379  BusRegistry *registry;
380  int i;
381  DBusMessageIter iter;
382  DBusMessageIter sub;
383
384  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
385
386  registry = bus_connection_get_registry (connection);
387
388  reply = dbus_message_new_method_return (message);
389  if (reply == NULL)
390    {
391      BUS_SET_OOM (error);
392      return FALSE;
393    }
394
395  if (!bus_registry_list_services (registry, &services, &len))
396    {
397      dbus_message_unref (reply);
398      BUS_SET_OOM (error);
399      return FALSE;
400    }
401
402  dbus_message_iter_init_append (reply, &iter);
403
404  if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
405                                         DBUS_TYPE_STRING_AS_STRING,
406                                         &sub))
407    {
408      dbus_free_string_array (services);
409      dbus_message_unref (reply);
410      BUS_SET_OOM (error);
411      return FALSE;
412    }
413
414  {
415    /* Include the bus driver in the list */
416    const char *v_STRING = DBUS_SERVICE_DBUS;
417    if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING,
418                                         &v_STRING))
419      {
420        dbus_free_string_array (services);
421        dbus_message_unref (reply);
422        BUS_SET_OOM (error);
423        return FALSE;
424      }
425  }
426
427  i = 0;
428  while (i < len)
429    {
430      if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING,
431                                           &services[i]))
432        {
433          dbus_free_string_array (services);
434          dbus_message_unref (reply);
435          BUS_SET_OOM (error);
436          return FALSE;
437        }
438      ++i;
439    }
440
441  if (!dbus_message_iter_close_container (&iter, &sub))
442    {
443      dbus_free_string_array (services);
444      dbus_message_unref (reply);
445      BUS_SET_OOM (error);
446      return FALSE;
447    }
448
449  dbus_free_string_array (services);
450
451  if (!bus_transaction_send_from_driver (transaction, connection, reply))
452    {
453      dbus_message_unref (reply);
454      BUS_SET_OOM (error);
455      return FALSE;
456    }
457  else
458    {
459      dbus_message_unref (reply);
460      return TRUE;
461    }
462}
463
464static dbus_bool_t
465bus_driver_handle_acquire_service (DBusConnection *connection,
466                                   BusTransaction *transaction,
467                                   DBusMessage    *message,
468                                   DBusError      *error)
469{
470  DBusMessage *reply;
471  DBusString service_name;
472  const char *name;
473  int service_reply;
474  dbus_uint32_t flags;
475  dbus_bool_t retval;
476  BusRegistry *registry;
477
478  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
479
480  registry = bus_connection_get_registry (connection);
481
482  if (!dbus_message_get_args (message, error,
483                              DBUS_TYPE_STRING, &name,
484                              DBUS_TYPE_UINT32, &flags,
485                              DBUS_TYPE_INVALID))
486    return FALSE;
487
488  _dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags);
489
490  retval = FALSE;
491  reply = NULL;
492
493  _dbus_string_init_const (&service_name, name);
494
495  if (!bus_registry_acquire_service (registry, connection,
496                                     &service_name, flags,
497                                     &service_reply, transaction,
498                                     error))
499    goto out;
500
501  reply = dbus_message_new_method_return (message);
502  if (reply == NULL)
503    {
504      BUS_SET_OOM (error);
505      goto out;
506    }
507
508  if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID))
509    {
510      BUS_SET_OOM (error);
511      goto out;
512    }
513
514  if (!bus_transaction_send_from_driver (transaction, connection, reply))
515    {
516      BUS_SET_OOM (error);
517      goto out;
518    }
519
520  retval = TRUE;
521
522 out:
523  if (reply)
524    dbus_message_unref (reply);
525  return retval;
526}
527
528static dbus_bool_t
529bus_driver_handle_service_exists (DBusConnection *connection,
530                                  BusTransaction *transaction,
531                                  DBusMessage    *message,
532                                  DBusError      *error)
533{
534  DBusMessage *reply;
535  DBusString service_name;
536  BusService *service;
537  dbus_bool_t service_exists;
538  const char *name;
539  dbus_bool_t retval;
540  BusRegistry *registry;
541
542  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
543
544  registry = bus_connection_get_registry (connection);
545
546  if (!dbus_message_get_args (message, error,
547                              DBUS_TYPE_STRING, &name,
548                              DBUS_TYPE_INVALID))
549    return FALSE;
550
551  retval = FALSE;
552
553  if (strcmp (name, DBUS_SERVICE_DBUS) == 0)
554    {
555      service_exists = TRUE;
556    }
557  else
558    {
559      _dbus_string_init_const (&service_name, name);
560      service = bus_registry_lookup (registry, &service_name);
561      service_exists = service != NULL;
562    }
563
564  reply = dbus_message_new_method_return (message);
565  if (reply == NULL)
566    {
567      BUS_SET_OOM (error);
568      goto out;
569    }
570
571  if (!dbus_message_append_args (reply,
572                                 DBUS_TYPE_BOOLEAN, &service_exists,
573                                 0))
574    {
575      BUS_SET_OOM (error);
576      goto out;
577    }
578
579  if (!bus_transaction_send_from_driver (transaction, connection, reply))
580    {
581      BUS_SET_OOM (error);
582      goto out;
583    }
584
585  retval = TRUE;
586
587 out:
588  if (reply)
589    dbus_message_unref (reply);
590
591  return retval;
592}
593
594static dbus_bool_t
595bus_driver_handle_activate_service (DBusConnection *connection,
596                                    BusTransaction *transaction,
597                                    DBusMessage    *message,
598                                    DBusError      *error)
599{
600  dbus_uint32_t flags;
601  const char *name;
602  dbus_bool_t retval;
603  BusActivation *activation;
604
605  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
606
607  activation = bus_connection_get_activation (connection);
608
609  if (!dbus_message_get_args (message, error,
610                              DBUS_TYPE_STRING, &name,
611                              DBUS_TYPE_UINT32, &flags,
612                              DBUS_TYPE_INVALID))
613    {
614      _DBUS_ASSERT_ERROR_IS_SET (error);
615      _dbus_verbose ("No memory to get arguments to StartServiceByName\n");
616      return FALSE;
617    }
618
619  retval = FALSE;
620
621  if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
622                                        message, name, error))
623    {
624      _DBUS_ASSERT_ERROR_IS_SET (error);
625      _dbus_verbose ("bus_activation_activate_service() failed\n");
626      goto out;
627    }
628
629  retval = TRUE;
630
631 out:
632  return retval;
633}
634
635static dbus_bool_t
636send_ack_reply (DBusConnection *connection,
637                BusTransaction *transaction,
638                DBusMessage    *message,
639                DBusError      *error)
640{
641  DBusMessage *reply;
642
643  reply = dbus_message_new_method_return (message);
644  if (reply == NULL)
645    {
646      BUS_SET_OOM (error);
647      return FALSE;
648    }
649
650  if (!bus_transaction_send_from_driver (transaction, connection, reply))
651    {
652      BUS_SET_OOM (error);
653      dbus_message_unref (reply);
654      return FALSE;
655    }
656
657  dbus_message_unref (reply);
658
659  return TRUE;
660}
661
662static dbus_bool_t
663bus_driver_handle_add_match (DBusConnection *connection,
664                             BusTransaction *transaction,
665                             DBusMessage    *message,
666                             DBusError      *error)
667{
668  BusMatchRule *rule;
669  const char *text;
670  DBusString str;
671  BusMatchmaker *matchmaker;
672
673  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
674
675  text = NULL;
676  rule = NULL;
677
678  if (bus_connection_get_n_match_rules (connection) >=
679      bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
680    {
681      dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
682                      "Connection \"%s\" is not allowed to add more match rules "
683                      "(increase limits in configuration file if required)",
684                      bus_connection_is_active (connection) ?
685                      bus_connection_get_name (connection) :
686                      "(inactive)");
687      goto failed;
688    }
689
690  if (!dbus_message_get_args (message, error,
691                              DBUS_TYPE_STRING, &text,
692                              DBUS_TYPE_INVALID))
693    {
694      _dbus_verbose ("No memory to get arguments to AddMatch\n");
695      goto failed;
696    }
697
698  _dbus_string_init_const (&str, text);
699
700  rule = bus_match_rule_parse (connection, &str, error);
701  if (rule == NULL)
702    goto failed;
703
704  matchmaker = bus_connection_get_matchmaker (connection);
705
706  if (!bus_matchmaker_add_rule (matchmaker, rule))
707    {
708      BUS_SET_OOM (error);
709      goto failed;
710    }
711
712  if (!send_ack_reply (connection, transaction,
713                       message, error))
714    {
715      bus_matchmaker_remove_rule (matchmaker, rule);
716      goto failed;
717    }
718
719  bus_match_rule_unref (rule);
720
721  return TRUE;
722
723 failed:
724  _DBUS_ASSERT_ERROR_IS_SET (error);
725  if (rule)
726    bus_match_rule_unref (rule);
727  return FALSE;
728}
729
730static dbus_bool_t
731bus_driver_handle_remove_match (DBusConnection *connection,
732                                BusTransaction *transaction,
733                                DBusMessage    *message,
734                                DBusError      *error)
735{
736  BusMatchRule *rule;
737  const char *text;
738  DBusString str;
739  BusMatchmaker *matchmaker;
740
741  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
742
743  text = NULL;
744  rule = NULL;
745
746  if (!dbus_message_get_args (message, error,
747                              DBUS_TYPE_STRING, &text,
748                              DBUS_TYPE_INVALID))
749    {
750      _dbus_verbose ("No memory to get arguments to RemoveMatch\n");
751      goto failed;
752    }
753
754  _dbus_string_init_const (&str, text);
755
756  rule = bus_match_rule_parse (connection, &str, error);
757  if (rule == NULL)
758    goto failed;
759
760  /* Send the ack before we remove the rule, since the ack is undone
761   * on transaction cancel, but rule removal isn't.
762   */
763  if (!send_ack_reply (connection, transaction,
764                       message, error))
765    goto failed;
766
767  matchmaker = bus_connection_get_matchmaker (connection);
768
769  if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
770    goto failed;
771
772  bus_match_rule_unref (rule);
773
774  return TRUE;
775
776 failed:
777  _DBUS_ASSERT_ERROR_IS_SET (error);
778  if (rule)
779    bus_match_rule_unref (rule);
780  return FALSE;
781}
782
783static dbus_bool_t
784bus_driver_handle_get_service_owner (DBusConnection *connection,
785				     BusTransaction *transaction,
786				     DBusMessage    *message,
787				     DBusError      *error)
788{
789  const char *text;
790  const char *base_name;
791  DBusString str;
792  BusRegistry *registry;
793  BusService *service;
794  DBusMessage *reply;
795
796  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
797
798  registry = bus_connection_get_registry (connection);
799
800  text = NULL;
801  reply = NULL;
802
803  if (! dbus_message_get_args (message, error,
804			       DBUS_TYPE_STRING, &text,
805			       DBUS_TYPE_INVALID))
806      goto failed;
807
808  _dbus_string_init_const (&str, text);
809  service = bus_registry_lookup (registry, &str);
810  if (service == NULL &&
811      _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS))
812    {
813      /* ORG_FREEDESKTOP_DBUS owns itself */
814      base_name = DBUS_SERVICE_DBUS;
815    }
816  else if (service == NULL)
817    {
818      dbus_set_error (error,
819                      DBUS_ERROR_NAME_HAS_NO_OWNER,
820                      "Could not get owner of name '%s': no such name", text);
821      goto failed;
822    }
823  else
824    {
825      base_name = bus_connection_get_name (bus_service_get_primary_owner (service));
826      if (base_name == NULL)
827        {
828          /* FIXME - how is this error possible? */
829          dbus_set_error (error,
830                          DBUS_ERROR_FAILED,
831                          "Could not determine unique name for '%s'", text);
832          goto failed;
833        }
834      _dbus_assert (*base_name == ':');
835    }
836
837  _dbus_assert (base_name != NULL);
838
839  reply = dbus_message_new_method_return (message);
840  if (reply == NULL)
841    goto oom;
842
843  if (! dbus_message_append_args (reply,
844				  DBUS_TYPE_STRING, &base_name,
845				  DBUS_TYPE_INVALID))
846    goto oom;
847
848  if (! bus_transaction_send_from_driver (transaction, connection, reply))
849    goto oom;
850
851  dbus_message_unref (reply);
852
853  return TRUE;
854
855 oom:
856  BUS_SET_OOM (error);
857
858 failed:
859  _DBUS_ASSERT_ERROR_IS_SET (error);
860  if (reply)
861    dbus_message_unref (reply);
862  return FALSE;
863}
864
865static dbus_bool_t
866bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
867                                            BusTransaction *transaction,
868                                            DBusMessage    *message,
869                                            DBusError      *error)
870{
871  const char *service;
872  DBusString str;
873  BusRegistry *registry;
874  BusService *serv;
875  DBusConnection *conn;
876  DBusMessage *reply;
877  unsigned long uid;
878  dbus_uint32_t uid32;
879
880  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
881
882  registry = bus_connection_get_registry (connection);
883
884  service = NULL;
885  reply = NULL;
886
887  if (! dbus_message_get_args (message, error,
888			       DBUS_TYPE_STRING, &service,
889			       DBUS_TYPE_INVALID))
890      goto failed;
891
892  _dbus_verbose ("asked for UID of connection %s\n", service);
893
894  _dbus_string_init_const (&str, service);
895  serv = bus_registry_lookup (registry, &str);
896  if (serv == NULL)
897    {
898      dbus_set_error (error,
899		      DBUS_ERROR_NAME_HAS_NO_OWNER,
900		      "Could not get UID of name '%s': no such name", service);
901      goto failed;
902    }
903
904  conn = bus_service_get_primary_owner (serv);
905
906  reply = dbus_message_new_method_return (message);
907  if (reply == NULL)
908    goto oom;
909
910  if (!dbus_connection_get_unix_user (conn, &uid))
911    {
912      dbus_set_error (error,
913                      DBUS_ERROR_FAILED,
914                      "Could not determine UID for '%s'", service);
915      goto failed;
916    }
917
918  uid32 = uid;
919  if (! dbus_message_append_args (reply,
920                                  DBUS_TYPE_UINT32, &uid32,
921                                  DBUS_TYPE_INVALID))
922    goto oom;
923
924  if (! bus_transaction_send_from_driver (transaction, connection, reply))
925    goto oom;
926
927  dbus_message_unref (reply);
928
929  return TRUE;
930
931 oom:
932  BUS_SET_OOM (error);
933
934 failed:
935  _DBUS_ASSERT_ERROR_IS_SET (error);
936  if (reply)
937    dbus_message_unref (reply);
938  return FALSE;
939}
940
941static dbus_bool_t
942bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
943						  BusTransaction *transaction,
944						  DBusMessage    *message,
945						  DBusError      *error)
946{
947  const char *service;
948  DBusString str;
949  BusRegistry *registry;
950  BusService *serv;
951  DBusConnection *conn;
952  DBusMessage *reply;
953  unsigned long pid;
954  dbus_uint32_t pid32;
955
956  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
957
958  registry = bus_connection_get_registry (connection);
959
960  service = NULL;
961  reply = NULL;
962
963  if (! dbus_message_get_args (message, error,
964			       DBUS_TYPE_STRING, &service,
965			       DBUS_TYPE_INVALID))
966      goto failed;
967
968  _dbus_verbose ("asked for PID of connection %s\n", service);
969
970  _dbus_string_init_const (&str, service);
971  serv = bus_registry_lookup (registry, &str);
972  if (serv == NULL)
973    {
974      dbus_set_error (error,
975		      DBUS_ERROR_NAME_HAS_NO_OWNER,
976		      "Could not get PID of name '%s': no such name", service);
977      goto failed;
978    }
979
980  conn = bus_service_get_primary_owner (serv);
981
982  reply = dbus_message_new_method_return (message);
983  if (reply == NULL)
984    goto oom;
985
986  if (!dbus_connection_get_unix_process_id (conn, &pid))
987    {
988      dbus_set_error (error,
989                      DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
990                      "Could not determine PID for '%s'", service);
991      goto failed;
992    }
993
994  pid32 = pid;
995  if (! dbus_message_append_args (reply,
996                                  DBUS_TYPE_UINT32, &pid32,
997                                  DBUS_TYPE_INVALID))
998    goto oom;
999
1000  if (! bus_transaction_send_from_driver (transaction, connection, reply))
1001    goto oom;
1002
1003  dbus_message_unref (reply);
1004
1005  return TRUE;
1006
1007 oom:
1008  BUS_SET_OOM (error);
1009
1010 failed:
1011  _DBUS_ASSERT_ERROR_IS_SET (error);
1012  if (reply)
1013    dbus_message_unref (reply);
1014  return FALSE;
1015}
1016
1017static dbus_bool_t
1018bus_driver_handle_get_connection_selinux_security_context (DBusConnection *connection,
1019							   BusTransaction *transaction,
1020							   DBusMessage    *message,
1021							   DBusError      *error)
1022{
1023  const char *service;
1024  DBusString str;
1025  BusRegistry *registry;
1026  BusService *serv;
1027  DBusConnection *conn;
1028  DBusMessage *reply;
1029  BusSELinuxID *context;
1030
1031  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1032
1033  registry = bus_connection_get_registry (connection);
1034
1035  service = NULL;
1036  reply = NULL;
1037
1038  if (! dbus_message_get_args (message, error,
1039			       DBUS_TYPE_STRING, &service,
1040			       DBUS_TYPE_INVALID))
1041      goto failed;
1042
1043  _dbus_verbose ("asked for security context of connection %s\n", service);
1044
1045  _dbus_string_init_const (&str, service);
1046  serv = bus_registry_lookup (registry, &str);
1047  if (serv == NULL)
1048    {
1049      dbus_set_error (error,
1050		      DBUS_ERROR_NAME_HAS_NO_OWNER,
1051		      "Could not get security context of name '%s': no such name", service);
1052      goto failed;
1053    }
1054
1055  conn = bus_service_get_primary_owner (serv);
1056
1057  reply = dbus_message_new_method_return (message);
1058  if (reply == NULL)
1059    goto oom;
1060
1061  context = bus_connection_get_selinux_id (conn);
1062  if (!context)
1063    {
1064      dbus_set_error (error,
1065                      DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN,
1066                      "Could not determine security context for '%s'", service);
1067      goto failed;
1068    }
1069
1070  if (! bus_selinux_append_context (reply, context, error))
1071    goto failed;
1072
1073  if (! bus_transaction_send_from_driver (transaction, connection, reply))
1074    goto oom;
1075
1076  dbus_message_unref (reply);
1077
1078  return TRUE;
1079
1080 oom:
1081  BUS_SET_OOM (error);
1082
1083 failed:
1084  _DBUS_ASSERT_ERROR_IS_SET (error);
1085  if (reply)
1086    dbus_message_unref (reply);
1087  return FALSE;
1088}
1089
1090static dbus_bool_t
1091bus_driver_handle_reload_config (DBusConnection *connection,
1092				 BusTransaction *transaction,
1093				 DBusMessage    *message,
1094				 DBusError      *error)
1095{
1096  BusContext *context;
1097  dbus_bool_t retval;
1098
1099  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1100
1101  retval = FALSE;
1102
1103  context = bus_connection_get_context (connection);
1104  if (!bus_context_reload_config (context, error))
1105    {
1106      _DBUS_ASSERT_ERROR_IS_SET (error);
1107      goto out;
1108    }
1109
1110  retval = TRUE;
1111
1112 out:
1113  return retval;
1114}
1115
1116/* For speed it might be useful to sort this in order of
1117 * frequency of use (but doesn't matter with only a few items
1118 * anyhow)
1119 */
1120struct
1121{
1122  const char *name;
1123  const char *in_args;
1124  const char *out_args;
1125  dbus_bool_t (* handler) (DBusConnection *connection,
1126                           BusTransaction *transaction,
1127                           DBusMessage    *message,
1128                           DBusError      *error);
1129} message_handlers[] = {
1130  { "RequestName",
1131    DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
1132    DBUS_TYPE_UINT32_AS_STRING,
1133    bus_driver_handle_acquire_service },
1134  { "StartServiceByName",
1135    DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
1136    DBUS_TYPE_UINT32_AS_STRING,
1137    bus_driver_handle_activate_service },
1138  { "Hello",
1139    "",
1140    DBUS_TYPE_STRING_AS_STRING,
1141    bus_driver_handle_hello },
1142  { "NameHasOwner",
1143    DBUS_TYPE_STRING_AS_STRING,
1144    DBUS_TYPE_BOOLEAN_AS_STRING,
1145    bus_driver_handle_service_exists },
1146  { "ListNames",
1147    "",
1148    DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
1149    bus_driver_handle_list_services },
1150  { "AddMatch",
1151    DBUS_TYPE_STRING_AS_STRING,
1152    "",
1153    bus_driver_handle_add_match },
1154  { "RemoveMatch",
1155    DBUS_TYPE_STRING_AS_STRING,
1156    "",
1157    bus_driver_handle_remove_match },
1158  { "GetNameOwner",
1159    DBUS_TYPE_STRING_AS_STRING,
1160    DBUS_TYPE_STRING_AS_STRING,
1161    bus_driver_handle_get_service_owner },
1162  { "GetConnectionUnixUser",
1163    DBUS_TYPE_STRING_AS_STRING,
1164    DBUS_TYPE_UINT32_AS_STRING,
1165    bus_driver_handle_get_connection_unix_user },
1166  { "GetConnectionUnixProcessID",
1167    DBUS_TYPE_STRING_AS_STRING,
1168    DBUS_TYPE_UINT32_AS_STRING,
1169    bus_driver_handle_get_connection_unix_process_id },
1170  { "GetConnectionSELinuxSecurityContext",
1171    DBUS_TYPE_STRING_AS_STRING,
1172    DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING,
1173    bus_driver_handle_get_connection_selinux_security_context },
1174  { "ReloadConfig",
1175    "",
1176    "",
1177    bus_driver_handle_reload_config }
1178};
1179
1180static dbus_bool_t
1181write_args_for_direction (DBusString *xml,
1182			  const char *signature,
1183			  dbus_bool_t in)
1184{
1185  DBusTypeReader typereader;
1186  DBusString sigstr;
1187  int current_type;
1188
1189  _dbus_string_init_const (&sigstr, signature);
1190  _dbus_type_reader_init_types_only (&typereader, &sigstr, 0);
1191
1192  while ((current_type = _dbus_type_reader_get_current_type (&typereader)) != DBUS_TYPE_INVALID)
1193    {
1194      const DBusString *subsig;
1195      int start, len;
1196
1197      _dbus_type_reader_get_signature (&typereader, &subsig, &start, &len);
1198      if (!_dbus_string_append_printf (xml, "      <arg direction=\"%s\" type=\"",
1199				       in ? "in" : "out"))
1200	goto oom;
1201      if (!_dbus_string_append_len (xml,
1202				    _dbus_string_get_const_data (subsig) + start,
1203				    len))
1204	goto oom;
1205      if (!_dbus_string_append (xml, "\"/>\n"))
1206	goto oom;
1207
1208      _dbus_type_reader_next (&typereader);
1209    }
1210  return TRUE;
1211 oom:
1212  return FALSE;
1213}
1214
1215static dbus_bool_t
1216bus_driver_handle_introspect (DBusConnection *connection,
1217                              BusTransaction *transaction,
1218                              DBusMessage    *message,
1219                              DBusError      *error)
1220{
1221  DBusString xml;
1222  DBusMessage *reply;
1223  const char *v_STRING;
1224  int i;
1225
1226  _dbus_verbose ("Introspect() on bus driver\n");
1227
1228  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1229
1230  reply = NULL;
1231
1232  if (! dbus_message_get_args (message, error,
1233			       DBUS_TYPE_INVALID))
1234    {
1235      _DBUS_ASSERT_ERROR_IS_SET (error);
1236      return FALSE;
1237    }
1238
1239  if (!_dbus_string_init (&xml))
1240    {
1241      BUS_SET_OOM (error);
1242      return FALSE;
1243    }
1244
1245  if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
1246    goto oom;
1247  if (!_dbus_string_append (&xml, "<node>\n"))
1248    goto oom;
1249  if (!_dbus_string_append_printf (&xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE))
1250    goto oom;
1251  if (!_dbus_string_append (&xml, "    <method name=\"Introspect\">\n"))
1252    goto oom;
1253  if (!_dbus_string_append_printf (&xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING))
1254    goto oom;
1255  if (!_dbus_string_append (&xml, "    </method>\n"))
1256    goto oom;
1257  if (!_dbus_string_append (&xml, "  </interface>\n"))
1258    goto oom;
1259
1260  if (!_dbus_string_append_printf (&xml, "  <interface name=\"%s\">\n",
1261                                   DBUS_INTERFACE_DBUS))
1262    goto oom;
1263
1264  i = 0;
1265  while (i < _DBUS_N_ELEMENTS (message_handlers))
1266    {
1267
1268      if (!_dbus_string_append_printf (&xml, "    <method name=\"%s\">\n",
1269                                       message_handlers[i].name))
1270        goto oom;
1271
1272      if (!write_args_for_direction (&xml, message_handlers[i].in_args, TRUE))
1273	goto oom;
1274
1275      if (!write_args_for_direction (&xml, message_handlers[i].out_args, FALSE))
1276	goto oom;
1277
1278      if (!_dbus_string_append (&xml, "    </method>\n"))
1279	goto oom;
1280
1281      ++i;
1282    }
1283
1284  if (!_dbus_string_append_printf (&xml, "    <signal name=\"NameOwnerChanged\">\n"))
1285    goto oom;
1286
1287  if (!_dbus_string_append_printf (&xml, "      <arg type=\"s\"/>\n"))
1288    goto oom;
1289
1290  if (!_dbus_string_append_printf (&xml, "      <arg type=\"s\"/>\n"))
1291    goto oom;
1292
1293  if (!_dbus_string_append_printf (&xml, "      <arg type=\"s\"/>\n"))
1294    goto oom;
1295
1296  if (!_dbus_string_append_printf (&xml, "    </signal>\n"))
1297    goto oom;
1298
1299
1300
1301  if (!_dbus_string_append_printf (&xml, "    <signal name=\"NameLost\">\n"))
1302    goto oom;
1303
1304  if (!_dbus_string_append_printf (&xml, "      <arg type=\"s\"/>\n"))
1305    goto oom;
1306
1307  if (!_dbus_string_append_printf (&xml, "    </signal>\n"))
1308    goto oom;
1309
1310
1311
1312  if (!_dbus_string_append_printf (&xml, "    <signal name=\"NameAcquired\">\n"))
1313    goto oom;
1314
1315  if (!_dbus_string_append_printf (&xml, "      <arg type=\"s\"/>\n"))
1316    goto oom;
1317
1318  if (!_dbus_string_append_printf (&xml, "    </signal>\n"))
1319    goto oom;
1320
1321
1322
1323  if (!_dbus_string_append (&xml, "  </interface>\n"))
1324    goto oom;
1325
1326  if (!_dbus_string_append (&xml, "</node>\n"))
1327    goto oom;
1328
1329  reply = dbus_message_new_method_return (message);
1330  if (reply == NULL)
1331    goto oom;
1332
1333  v_STRING = _dbus_string_get_const_data (&xml);
1334  if (! dbus_message_append_args (reply,
1335                                  DBUS_TYPE_STRING, &v_STRING,
1336                                  DBUS_TYPE_INVALID))
1337    goto oom;
1338
1339  if (! bus_transaction_send_from_driver (transaction, connection, reply))
1340    goto oom;
1341
1342  dbus_message_unref (reply);
1343  _dbus_string_free (&xml);
1344
1345  return TRUE;
1346
1347 oom:
1348  BUS_SET_OOM (error);
1349
1350  if (reply)
1351    dbus_message_unref (reply);
1352
1353  _dbus_string_free (&xml);
1354
1355  return FALSE;
1356}
1357
1358dbus_bool_t
1359bus_driver_handle_message (DBusConnection *connection,
1360                           BusTransaction *transaction,
1361			   DBusMessage    *message,
1362                           DBusError      *error)
1363{
1364  const char *name, *sender, *interface;
1365  int i;
1366
1367  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1368
1369  if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
1370    {
1371      _dbus_verbose ("Driver got a non-method-call message, ignoring\n");
1372      return TRUE; /* we just ignore this */
1373    }
1374
1375  if (dbus_message_is_method_call (message,
1376                                   DBUS_INTERFACE_INTROSPECTABLE,
1377                                   "Introspect"))
1378    return bus_driver_handle_introspect (connection, transaction, message, error);
1379
1380  interface = dbus_message_get_interface (message);
1381  if (interface == NULL)
1382    interface = DBUS_INTERFACE_DBUS;
1383
1384  _dbus_assert (dbus_message_get_member (message) != NULL);
1385
1386  name = dbus_message_get_member (message);
1387  sender = dbus_message_get_sender (message);
1388
1389  if (strcmp (interface,
1390              DBUS_INTERFACE_DBUS) != 0)
1391    {
1392      _dbus_verbose ("Driver got message to unknown interface \"%s\"\n",
1393                     interface);
1394      goto unknown;
1395    }
1396
1397  _dbus_verbose ("Driver got a method call: %s\n",
1398		 dbus_message_get_member (message));
1399
1400  /* security checks should have kept this from getting here */
1401  _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
1402
1403  i = 0;
1404  while (i < _DBUS_N_ELEMENTS (message_handlers))
1405    {
1406      if (strcmp (message_handlers[i].name, name) == 0)
1407        {
1408          _dbus_verbose ("Found driver handler for %s\n", name);
1409
1410          if (!dbus_message_has_signature (message, message_handlers[i].in_args))
1411            {
1412              _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1413              _dbus_verbose ("Call to %s has wrong args (%s, expected %s)\n",
1414                             name, dbus_message_get_signature (message),
1415                             message_handlers[i].in_args);
1416
1417              dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
1418                              "Call to %s has wrong args (%s, expected %s)\n",
1419                              name, dbus_message_get_signature (message),
1420                              message_handlers[i].in_args);
1421              _DBUS_ASSERT_ERROR_IS_SET (error);
1422              return FALSE;
1423            }
1424
1425          if ((* message_handlers[i].handler) (connection, transaction, message, error))
1426            {
1427              _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1428              _dbus_verbose ("Driver handler succeeded\n");
1429              return TRUE;
1430            }
1431          else
1432            {
1433              _DBUS_ASSERT_ERROR_IS_SET (error);
1434              _dbus_verbose ("Driver handler returned failure\n");
1435              return FALSE;
1436            }
1437        }
1438
1439      ++i;
1440    }
1441
1442 unknown:
1443  _dbus_verbose ("No driver handler for message \"%s\"\n",
1444                 name);
1445
1446  dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD,
1447                  "%s does not understand message %s",
1448                  DBUS_SERVICE_DBUS, name);
1449
1450  return FALSE;
1451}
1452
1453void
1454bus_driver_remove_connection (DBusConnection *connection)
1455{
1456  /* FIXME Does nothing for now, should unregister the connection
1457   * with the bus driver.
1458   */
1459}
1460