driver.c revision 8873c90f99303f9cc308f15f8d03e637911f5b9e
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 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 "signals.h"
31#include "utils.h"
32#include <dbus/dbus-string.h>
33#include <dbus/dbus-internals.h>
34#include <string.h>
35
36static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
37                                                    DBusMessage    *hello_message,
38                                                    BusTransaction *transaction,
39                                                    DBusError      *error);
40
41dbus_bool_t
42bus_driver_send_service_owner_changed (const char     *service_name,
43				       const char     *old_owner,
44				       const char     *new_owner,
45				       BusTransaction *transaction,
46				       DBusError      *error)
47{
48  DBusMessage *message;
49  dbus_bool_t retval;
50  const char *null_service;
51
52  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
53
54  null_service = "";
55  _dbus_verbose ("sending name owner changed: %s [%s -> %s]\n",
56                 service_name,
57                 old_owner ? old_owner : null_service,
58                 new_owner ? new_owner : null_service);
59
60  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
61                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
62                                     "NameOwnerChanged");
63
64  if (message == NULL)
65    {
66      BUS_SET_OOM (error);
67      return FALSE;
68    }
69
70  if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
71    goto oom;
72
73  if (!dbus_message_append_args (message,
74                                 DBUS_TYPE_STRING, &service_name,
75                                 DBUS_TYPE_STRING, old_owner ? &old_owner : &null_service,
76                                 DBUS_TYPE_STRING, new_owner ? &new_owner : &null_service,
77                                 DBUS_TYPE_INVALID))
78    goto oom;
79
80  _dbus_assert (dbus_message_has_signature (message, "sss"));
81
82  retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
83  dbus_message_unref (message);
84
85  return retval;
86
87 oom:
88  dbus_message_unref (message);
89  BUS_SET_OOM (error);
90  return FALSE;
91}
92
93dbus_bool_t
94bus_driver_send_service_lost (DBusConnection *connection,
95			      const char     *service_name,
96                              BusTransaction *transaction,
97                              DBusError      *error)
98{
99  DBusMessage *message;
100
101  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
102
103  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
104                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
105                                     "NameLost");
106
107  if (message == NULL)
108    {
109      BUS_SET_OOM (error);
110      return FALSE;
111    }
112
113  if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
114      !dbus_message_append_args (message,
115                                 DBUS_TYPE_STRING, &service_name,
116                                 DBUS_TYPE_INVALID))
117    {
118      dbus_message_unref (message);
119      BUS_SET_OOM (error);
120      return FALSE;
121    }
122
123  if (!bus_transaction_send_from_driver (transaction, connection, message))
124    {
125      dbus_message_unref (message);
126      BUS_SET_OOM (error);
127      return FALSE;
128    }
129  else
130    {
131      dbus_message_unref (message);
132      return TRUE;
133    }
134}
135
136dbus_bool_t
137bus_driver_send_service_acquired (DBusConnection *connection,
138                                  const char     *service_name,
139                                  BusTransaction *transaction,
140                                  DBusError      *error)
141{
142  DBusMessage *message;
143
144  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
145
146  message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
147                                     DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
148                                     "NameAcquired");
149
150  if (message == NULL)
151    {
152      BUS_SET_OOM (error);
153      return FALSE;
154    }
155
156  if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
157      !dbus_message_append_args (message,
158                                 DBUS_TYPE_STRING, &service_name,
159                                 DBUS_TYPE_INVALID))
160    {
161      dbus_message_unref (message);
162      BUS_SET_OOM (error);
163      return FALSE;
164    }
165
166  if (!bus_transaction_send_from_driver (transaction, connection, message))
167    {
168      dbus_message_unref (message);
169      BUS_SET_OOM (error);
170      return FALSE;
171    }
172  else
173    {
174      dbus_message_unref (message);
175      return TRUE;
176    }
177}
178
179static dbus_bool_t
180create_unique_client_name (BusRegistry *registry,
181                           DBusString  *str)
182{
183  /* We never want to use the same unique client name twice, because
184   * we want to guarantee that if you send a message to a given unique
185   * name, you always get the same application. So we use two numbers
186   * for INT_MAX * INT_MAX combinations, should be pretty safe against
187   * wraparound.
188   */
189  /* FIXME these should be in BusRegistry rather than static vars */
190  static int next_major_number = 0;
191  static int next_minor_number = 0;
192  int len;
193
194  len = _dbus_string_get_length (str);
195
196  while (TRUE)
197    {
198      /* start out with 1-0, go to 1-1, 1-2, 1-3,
199       * up to 1-MAXINT, then 2-0, 2-1, etc.
200       */
201      if (next_minor_number <= 0)
202        {
203          next_major_number += 1;
204          next_minor_number = 0;
205          if (next_major_number <= 0)
206            _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added");
207        }
208
209      _dbus_assert (next_major_number > 0);
210      _dbus_assert (next_minor_number >= 0);
211
212      /* appname:MAJOR-MINOR */
213
214      if (!_dbus_string_append (str, ":"))
215        return FALSE;
216
217      if (!_dbus_string_append_int (str, next_major_number))
218        return FALSE;
219
220      if (!_dbus_string_append (str, "."))
221        return FALSE;
222
223      if (!_dbus_string_append_int (str, next_minor_number))
224        return FALSE;
225
226      next_minor_number += 1;
227
228      /* Check if a client with the name exists */
229      if (bus_registry_lookup (registry, str) == NULL)
230	break;
231
232      /* drop the number again, try the next one. */
233      _dbus_string_set_length (str, len);
234    }
235
236  return TRUE;
237}
238
239static dbus_bool_t
240bus_driver_handle_hello (DBusConnection *connection,
241                         BusTransaction *transaction,
242                         DBusMessage    *message,
243                         DBusError      *error)
244{
245  DBusString unique_name;
246  BusService *service;
247  dbus_bool_t retval;
248  BusRegistry *registry;
249  BusConnections *connections;
250
251  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
252
253  if (bus_connection_is_active (connection))
254    {
255      /* We already handled an Hello message for this connection. */
256      dbus_set_error (error, DBUS_ERROR_FAILED,
257                      "Already handled an Hello message");
258      return FALSE;
259    }
260
261  /* Note that when these limits are exceeded we don't disconnect the
262   * connection; we just sort of leave it hanging there until it times
263   * out or disconnects itself or is dropped due to the max number of
264   * incomplete connections. It's even OK if the connection wants to
265   * retry the hello message, we support that.
266   */
267  connections = bus_connection_get_connections (connection);
268  if (!bus_connections_check_limits (connections, connection,
269                                     error))
270    {
271      _DBUS_ASSERT_ERROR_IS_SET (error);
272      return FALSE;
273    }
274
275  if (!_dbus_string_init (&unique_name))
276    {
277      BUS_SET_OOM (error);
278      return FALSE;
279    }
280
281  retval = FALSE;
282
283  registry = bus_connection_get_registry (connection);
284
285  if (!create_unique_client_name (registry, &unique_name))
286    {
287      BUS_SET_OOM (error);
288      goto out_0;
289    }
290
291  if (!bus_connection_complete (connection, &unique_name, error))
292    {
293      _DBUS_ASSERT_ERROR_IS_SET (error);
294      goto out_0;
295    }
296
297  if (!dbus_message_set_sender (message,
298                                bus_connection_get_name (connection)))
299    {
300      BUS_SET_OOM (error);
301      goto out_0;
302    }
303
304  if (!bus_driver_send_welcome_message (connection, message, transaction, error))
305    goto out_0;
306
307  /* Create the service */
308  service = bus_registry_ensure (registry,
309                                 &unique_name, connection, transaction, error);
310  if (service == NULL)
311    goto out_0;
312
313  bus_service_set_prohibit_replacement (service, TRUE);
314
315  _dbus_assert (bus_connection_is_active (connection));
316  retval = TRUE;
317
318 out_0:
319  _dbus_string_free (&unique_name);
320  return retval;
321}
322
323static dbus_bool_t
324bus_driver_send_welcome_message (DBusConnection *connection,
325                                 DBusMessage    *hello_message,
326                                 BusTransaction *transaction,
327                                 DBusError      *error)
328{
329  DBusMessage *welcome;
330  const char *name;
331
332  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
333
334  name = bus_connection_get_name (connection);
335  _dbus_assert (name != NULL);
336
337  welcome = dbus_message_new_method_return (hello_message);
338  if (welcome == NULL)
339    {
340      BUS_SET_OOM (error);
341      return FALSE;
342    }
343
344  if (!dbus_message_append_args (welcome,
345                                 DBUS_TYPE_STRING, &name,
346                                 DBUS_TYPE_INVALID))
347    {
348      dbus_message_unref (welcome);
349      BUS_SET_OOM (error);
350      return FALSE;
351    }
352
353  _dbus_assert (dbus_message_has_signature (welcome, "s"));
354
355  if (!bus_transaction_send_from_driver (transaction, connection, welcome))
356    {
357      dbus_message_unref (welcome);
358      BUS_SET_OOM (error);
359      return FALSE;
360    }
361  else
362    {
363      dbus_message_unref (welcome);
364      return TRUE;
365    }
366}
367
368static dbus_bool_t
369bus_driver_handle_list_services (DBusConnection *connection,
370                                 BusTransaction *transaction,
371                                 DBusMessage    *message,
372                                 DBusError      *error)
373{
374  DBusMessage *reply;
375  int len;
376  char **services;
377  BusRegistry *registry;
378  int i;
379  DBusMessageIter iter;
380  DBusMessageIter sub;
381
382  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
383
384  registry = bus_connection_get_registry (connection);
385
386  reply = dbus_message_new_method_return (message);
387  if (reply == NULL)
388    {
389      BUS_SET_OOM (error);
390      return FALSE;
391    }
392
393  if (!bus_registry_list_services (registry, &services, &len))
394    {
395      dbus_message_unref (reply);
396      BUS_SET_OOM (error);
397      return FALSE;
398    }
399
400  dbus_message_iter_init_append (reply, &iter);
401
402  if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
403                                         DBUS_TYPE_STRING_AS_STRING,
404                                         &sub))
405    {
406      dbus_free_string_array (services);
407      dbus_message_unref (reply);
408      BUS_SET_OOM (error);
409      return FALSE;
410    }
411
412  i = 0;
413  while (i < len)
414    {
415      if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING,
416                                           &services[i]))
417        {
418          dbus_free_string_array (services);
419          dbus_message_unref (reply);
420          BUS_SET_OOM (error);
421          return FALSE;
422        }
423      ++i;
424    }
425
426  if (!dbus_message_iter_close_container (&iter, &sub))
427    {
428      dbus_free_string_array (services);
429      dbus_message_unref (reply);
430      BUS_SET_OOM (error);
431      return FALSE;
432    }
433
434  dbus_free_string_array (services);
435
436  if (!bus_transaction_send_from_driver (transaction, connection, reply))
437    {
438      dbus_message_unref (reply);
439      BUS_SET_OOM (error);
440      return FALSE;
441    }
442  else
443    {
444      dbus_message_unref (reply);
445      return TRUE;
446    }
447}
448
449static dbus_bool_t
450bus_driver_handle_acquire_service (DBusConnection *connection,
451                                   BusTransaction *transaction,
452                                   DBusMessage    *message,
453                                   DBusError      *error)
454{
455  DBusMessage *reply;
456  DBusString service_name;
457  const char *name;
458  int service_reply;
459  dbus_uint32_t flags;
460  dbus_bool_t retval;
461  BusRegistry *registry;
462
463  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
464
465  registry = bus_connection_get_registry (connection);
466
467  if (!dbus_message_get_args (message, error,
468                              DBUS_TYPE_STRING, &name,
469                              DBUS_TYPE_UINT32, &flags,
470                              DBUS_TYPE_INVALID))
471    return FALSE;
472
473  _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags);
474
475  retval = FALSE;
476  reply = NULL;
477
478  _dbus_string_init_const (&service_name, name);
479
480  if (!bus_registry_acquire_service (registry, connection,
481                                     &service_name, flags,
482                                     &service_reply, transaction,
483                                     error))
484    goto out;
485
486  reply = dbus_message_new_method_return (message);
487  if (reply == NULL)
488    {
489      BUS_SET_OOM (error);
490      goto out;
491    }
492
493  if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID))
494    {
495      BUS_SET_OOM (error);
496      goto out;
497    }
498
499  if (!bus_transaction_send_from_driver (transaction, connection, reply))
500    {
501      BUS_SET_OOM (error);
502      goto out;
503    }
504
505  retval = TRUE;
506
507 out:
508  if (reply)
509    dbus_message_unref (reply);
510  return retval;
511}
512
513static dbus_bool_t
514bus_driver_handle_service_exists (DBusConnection *connection,
515                                  BusTransaction *transaction,
516                                  DBusMessage    *message,
517                                  DBusError      *error)
518{
519  DBusMessage *reply;
520  DBusString service_name;
521  BusService *service;
522  dbus_bool_t service_exists;
523  const char *name;
524  dbus_bool_t retval;
525  BusRegistry *registry;
526
527  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
528
529  registry = bus_connection_get_registry (connection);
530
531  if (!dbus_message_get_args (message, error,
532                              DBUS_TYPE_STRING, &name,
533                              DBUS_TYPE_INVALID))
534    return FALSE;
535
536  retval = FALSE;
537
538  if (strcmp (name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0)
539    {
540      service_exists = TRUE;
541    }
542  else
543    {
544      _dbus_string_init_const (&service_name, name);
545      service = bus_registry_lookup (registry, &service_name);
546      service_exists = service != NULL;
547    }
548
549  reply = dbus_message_new_method_return (message);
550  if (reply == NULL)
551    {
552      BUS_SET_OOM (error);
553      goto out;
554    }
555
556  if (!dbus_message_append_args (reply,
557                                 DBUS_TYPE_BOOLEAN, &service_exists,
558                                 0))
559    {
560      BUS_SET_OOM (error);
561      goto out;
562    }
563
564  if (!bus_transaction_send_from_driver (transaction, connection, reply))
565    {
566      BUS_SET_OOM (error);
567      goto out;
568    }
569
570  retval = TRUE;
571
572 out:
573  if (reply)
574    dbus_message_unref (reply);
575
576  return retval;
577}
578
579static dbus_bool_t
580bus_driver_handle_activate_service (DBusConnection *connection,
581                                    BusTransaction *transaction,
582                                    DBusMessage    *message,
583                                    DBusError      *error)
584{
585  dbus_uint32_t flags;
586  const char *name;
587  dbus_bool_t retval;
588  BusActivation *activation;
589
590  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
591
592  activation = bus_connection_get_activation (connection);
593
594  if (!dbus_message_get_args (message, error,
595                              DBUS_TYPE_STRING, &name,
596                              DBUS_TYPE_UINT32, &flags,
597                              DBUS_TYPE_INVALID))
598    {
599      _DBUS_ASSERT_ERROR_IS_SET (error);
600      _dbus_verbose ("No memory to get arguments to StartServiceByName\n");
601      return FALSE;
602    }
603
604  retval = FALSE;
605
606  if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
607                                        message, name, error))
608    {
609      _DBUS_ASSERT_ERROR_IS_SET (error);
610      _dbus_verbose ("bus_activation_activate_service() failed\n");
611      goto out;
612    }
613
614  retval = TRUE;
615
616 out:
617  return retval;
618}
619
620static dbus_bool_t
621send_ack_reply (DBusConnection *connection,
622                BusTransaction *transaction,
623                DBusMessage    *message,
624                DBusError      *error)
625{
626  DBusMessage *reply;
627
628  reply = dbus_message_new_method_return (message);
629  if (reply == NULL)
630    {
631      BUS_SET_OOM (error);
632      return FALSE;
633    }
634
635  if (!bus_transaction_send_from_driver (transaction, connection, reply))
636    {
637      BUS_SET_OOM (error);
638      dbus_message_unref (reply);
639      return FALSE;
640    }
641
642  dbus_message_unref (reply);
643
644  return TRUE;
645}
646
647static dbus_bool_t
648bus_driver_handle_add_match (DBusConnection *connection,
649                             BusTransaction *transaction,
650                             DBusMessage    *message,
651                             DBusError      *error)
652{
653  BusMatchRule *rule;
654  const char *text;
655  DBusString str;
656  BusMatchmaker *matchmaker;
657
658  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
659
660  text = NULL;
661  rule = NULL;
662
663  if (bus_connection_get_n_match_rules (connection) >=
664      bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
665    {
666      dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
667                      "Connection \"%s\" is not allowed to add more match rules "
668                      "(increase limits in configuration file if required)",
669                      bus_connection_is_active (connection) ?
670                      bus_connection_get_name (connection) :
671                      "(inactive)");
672      goto failed;
673    }
674
675  if (!dbus_message_get_args (message, error,
676                              DBUS_TYPE_STRING, &text,
677                              DBUS_TYPE_INVALID))
678    {
679      _dbus_verbose ("No memory to get arguments to AddMatch\n");
680      goto failed;
681    }
682
683  _dbus_string_init_const (&str, text);
684
685  rule = bus_match_rule_parse (connection, &str, error);
686  if (rule == NULL)
687    goto failed;
688
689  matchmaker = bus_connection_get_matchmaker (connection);
690
691  if (!bus_matchmaker_add_rule (matchmaker, rule))
692    {
693      BUS_SET_OOM (error);
694      goto failed;
695    }
696
697  if (!send_ack_reply (connection, transaction,
698                       message, error))
699    {
700      bus_matchmaker_remove_rule (matchmaker, rule);
701      goto failed;
702    }
703
704  bus_match_rule_unref (rule);
705
706  return TRUE;
707
708 failed:
709  _DBUS_ASSERT_ERROR_IS_SET (error);
710  if (rule)
711    bus_match_rule_unref (rule);
712  return FALSE;
713}
714
715static dbus_bool_t
716bus_driver_handle_remove_match (DBusConnection *connection,
717                                BusTransaction *transaction,
718                                DBusMessage    *message,
719                                DBusError      *error)
720{
721  BusMatchRule *rule;
722  const char *text;
723  DBusString str;
724  BusMatchmaker *matchmaker;
725
726  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
727
728  text = NULL;
729  rule = NULL;
730
731  if (!dbus_message_get_args (message, error,
732                              DBUS_TYPE_STRING, &text,
733                              DBUS_TYPE_INVALID))
734    {
735      _dbus_verbose ("No memory to get arguments to RemoveMatch\n");
736      goto failed;
737    }
738
739  _dbus_string_init_const (&str, text);
740
741  rule = bus_match_rule_parse (connection, &str, error);
742  if (rule == NULL)
743    goto failed;
744
745  /* Send the ack before we remove the rule, since the ack is undone
746   * on transaction cancel, but rule removal isn't.
747   */
748  if (!send_ack_reply (connection, transaction,
749                       message, error))
750    goto failed;
751
752  matchmaker = bus_connection_get_matchmaker (connection);
753
754  if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
755    goto failed;
756
757  bus_match_rule_unref (rule);
758
759  return TRUE;
760
761 failed:
762  _DBUS_ASSERT_ERROR_IS_SET (error);
763  if (rule)
764    bus_match_rule_unref (rule);
765  return FALSE;
766}
767
768static dbus_bool_t
769bus_driver_handle_get_service_owner (DBusConnection *connection,
770				     BusTransaction *transaction,
771				     DBusMessage    *message,
772				     DBusError      *error)
773{
774  const char *text;
775  const char *base_name;
776  DBusString str;
777  BusRegistry *registry;
778  BusService *service;
779  DBusMessage *reply;
780
781  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
782
783  registry = bus_connection_get_registry (connection);
784
785  text = NULL;
786  reply = NULL;
787
788  if (! dbus_message_get_args (message, error,
789			       DBUS_TYPE_STRING, &text,
790			       DBUS_TYPE_INVALID))
791      goto failed;
792
793  _dbus_string_init_const (&str, text);
794  service = bus_registry_lookup (registry, &str);
795  if (service == NULL)
796    {
797      dbus_set_error (error,
798		      DBUS_ERROR_NAME_HAS_NO_OWNER,
799		      "Could not get owner of name '%s': no such name", text);
800      goto failed;
801    }
802
803  base_name = bus_connection_get_name (bus_service_get_primary_owner (service));
804  if (base_name == NULL)
805    {
806      /* FIXME - how is this error possible? */
807      dbus_set_error (error,
808		      DBUS_ERROR_FAILED,
809		      "Could not determine unique name for '%s'", text);
810      goto failed;
811    }
812  _dbus_assert (*base_name == ':');
813
814  reply = dbus_message_new_method_return (message);
815  if (reply == NULL)
816    goto oom;
817
818  if (! dbus_message_append_args (reply,
819				  DBUS_TYPE_STRING, &base_name,
820				  DBUS_TYPE_INVALID))
821    goto oom;
822
823  if (! bus_transaction_send_from_driver (transaction, connection, reply))
824    goto oom;
825
826  dbus_message_unref (reply);
827
828  return TRUE;
829
830 oom:
831  BUS_SET_OOM (error);
832
833 failed:
834  _DBUS_ASSERT_ERROR_IS_SET (error);
835  if (reply)
836    dbus_message_unref (reply);
837  return FALSE;
838}
839
840static dbus_bool_t
841bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
842                                            BusTransaction *transaction,
843                                            DBusMessage    *message,
844                                            DBusError      *error)
845{
846  const char *service;
847  DBusString str;
848  BusRegistry *registry;
849  BusService *serv;
850  DBusConnection *conn;
851  DBusMessage *reply;
852  unsigned long uid;
853  dbus_uint32_t uid32;
854
855  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
856
857  registry = bus_connection_get_registry (connection);
858
859  service = NULL;
860  reply = NULL;
861
862  if (! dbus_message_get_args (message, error,
863			       DBUS_TYPE_STRING, &service,
864			       DBUS_TYPE_INVALID))
865      goto failed;
866
867  _dbus_verbose ("asked for UID of connection %s\n", service);
868
869  _dbus_string_init_const (&str, service);
870  serv = bus_registry_lookup (registry, &str);
871  if (serv == NULL)
872    {
873      dbus_set_error (error,
874		      DBUS_ERROR_NAME_HAS_NO_OWNER,
875		      "Could not get UID of name '%s': no such name", service);
876      goto failed;
877    }
878
879  conn = bus_service_get_primary_owner (serv);
880
881  reply = dbus_message_new_method_return (message);
882  if (reply == NULL)
883    goto oom;
884
885  if (!dbus_connection_get_unix_user (conn, &uid))
886    {
887      dbus_set_error (error,
888                      DBUS_ERROR_FAILED,
889                      "Could not determine UID for '%s'", service);
890      goto failed;
891    }
892
893  uid32 = uid;
894  if (! dbus_message_append_args (reply,
895                                  DBUS_TYPE_UINT32, &uid32,
896                                  DBUS_TYPE_INVALID))
897    goto oom;
898
899  if (! bus_transaction_send_from_driver (transaction, connection, reply))
900    goto oom;
901
902  dbus_message_unref (reply);
903
904  return TRUE;
905
906 oom:
907  BUS_SET_OOM (error);
908
909 failed:
910  _DBUS_ASSERT_ERROR_IS_SET (error);
911  if (reply)
912    dbus_message_unref (reply);
913  return FALSE;
914}
915
916static dbus_bool_t
917bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
918						  BusTransaction *transaction,
919						  DBusMessage    *message,
920						  DBusError      *error)
921{
922  const char *service;
923  DBusString str;
924  BusRegistry *registry;
925  BusService *serv;
926  DBusConnection *conn;
927  DBusMessage *reply;
928  unsigned long pid;
929  dbus_uint32_t pid32;
930
931  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
932
933  registry = bus_connection_get_registry (connection);
934
935  service = NULL;
936  reply = NULL;
937
938  if (! dbus_message_get_args (message, error,
939			       DBUS_TYPE_STRING, &service,
940			       DBUS_TYPE_INVALID))
941      goto failed;
942
943  _dbus_verbose ("asked for PID of connection %s\n", service);
944
945  _dbus_string_init_const (&str, service);
946  serv = bus_registry_lookup (registry, &str);
947  if (serv == NULL)
948    {
949      dbus_set_error (error,
950		      DBUS_ERROR_NAME_HAS_NO_OWNER,
951		      "Could not get PID of name '%s': no such name", service);
952      goto failed;
953    }
954
955  conn = bus_service_get_primary_owner (serv);
956
957  reply = dbus_message_new_method_return (message);
958  if (reply == NULL)
959    goto oom;
960
961  if (!dbus_connection_get_unix_process_id (conn, &pid))
962    {
963      dbus_set_error (error,
964                      DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,
965                      "Could not determine PID for '%s'", service);
966      goto failed;
967    }
968
969  pid32 = pid;
970  if (! dbus_message_append_args (reply,
971                                  DBUS_TYPE_UINT32, &pid32,
972                                  DBUS_TYPE_INVALID))
973    goto oom;
974
975  if (! bus_transaction_send_from_driver (transaction, connection, reply))
976    goto oom;
977
978  dbus_message_unref (reply);
979
980  return TRUE;
981
982 oom:
983  BUS_SET_OOM (error);
984
985 failed:
986  _DBUS_ASSERT_ERROR_IS_SET (error);
987  if (reply)
988    dbus_message_unref (reply);
989  return FALSE;
990}
991
992static dbus_bool_t
993bus_driver_handle_reload_config (DBusConnection *connection,
994				 BusTransaction *transaction,
995				 DBusMessage    *message,
996				 DBusError      *error)
997{
998  BusContext *context;
999  dbus_bool_t retval;
1000
1001  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1002
1003  retval = FALSE;
1004
1005  context = bus_connection_get_context (connection);
1006  if (!bus_context_reload_config (context, error))
1007    {
1008      _DBUS_ASSERT_ERROR_IS_SET (error);
1009      goto out;
1010    }
1011
1012  retval = TRUE;
1013
1014 out:
1015  return retval;
1016}
1017
1018/* For speed it might be useful to sort this in order of
1019 * frequency of use (but doesn't matter with only a few items
1020 * anyhow)
1021 */
1022struct
1023{
1024  const char *name;
1025  dbus_bool_t (* handler) (DBusConnection *connection,
1026                           BusTransaction *transaction,
1027                           DBusMessage    *message,
1028                           DBusError      *error);
1029} message_handlers[] = {
1030  { "RequestName", bus_driver_handle_acquire_service },
1031  { "StartServiceByName", bus_driver_handle_activate_service },
1032  { "Hello", bus_driver_handle_hello },
1033  { "NameHasOwner", bus_driver_handle_service_exists },
1034  { "ListNames", bus_driver_handle_list_services },
1035  { "AddMatch", bus_driver_handle_add_match },
1036  { "RemoveMatch", bus_driver_handle_remove_match },
1037  { "GetNameOwner", bus_driver_handle_get_service_owner },
1038  { "GetConnectionUnixUser", bus_driver_handle_get_connection_unix_user },
1039  { "GetConnectionUnixProcessID", bus_driver_handle_get_connection_unix_process_id },
1040  { "ReloadConfig", bus_driver_handle_reload_config }
1041};
1042
1043dbus_bool_t
1044bus_driver_handle_message (DBusConnection *connection,
1045                           BusTransaction *transaction,
1046			   DBusMessage    *message,
1047                           DBusError      *error)
1048{
1049  const char *name, *sender;
1050  int i;
1051
1052  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1053
1054  if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
1055    {
1056      _dbus_verbose ("Driver got a non-method-call message, ignoring\n");
1057      return TRUE; /* we just ignore this */
1058    }
1059
1060  _dbus_assert (dbus_message_get_interface (message) != NULL);
1061  _dbus_assert (dbus_message_get_member (message) != NULL);
1062
1063  name = dbus_message_get_member (message);
1064  sender = dbus_message_get_sender (message);
1065
1066  if (strcmp (dbus_message_get_interface (message),
1067              DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) != 0)
1068    {
1069      _dbus_verbose ("Driver got message to unknown interface \"%s\"\n",
1070                     dbus_message_get_interface (message));
1071      goto unknown;
1072    }
1073
1074  _dbus_verbose ("Driver got a method call: %s\n",
1075		 dbus_message_get_member (message));
1076
1077  /* security checks should have kept this from getting here */
1078  _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
1079
1080  if (dbus_message_get_reply_serial (message) != 0)
1081    {
1082      _dbus_verbose ("Client sent a reply to the bus driver, ignoring it\n");
1083      return TRUE;
1084    }
1085
1086  i = 0;
1087  while (i < _DBUS_N_ELEMENTS (message_handlers))
1088    {
1089      if (strcmp (message_handlers[i].name, name) == 0)
1090        {
1091          _dbus_verbose ("Running driver handler for %s\n", name);
1092          if ((* message_handlers[i].handler) (connection, transaction, message, error))
1093            {
1094              _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1095              _dbus_verbose ("Driver handler succeeded\n");
1096              return TRUE;
1097            }
1098          else
1099            {
1100              _DBUS_ASSERT_ERROR_IS_SET (error);
1101              _dbus_verbose ("Driver handler returned failure\n");
1102              return FALSE;
1103            }
1104        }
1105
1106      ++i;
1107    }
1108
1109 unknown:
1110  _dbus_verbose ("No driver handler for message \"%s\"\n",
1111                 name);
1112
1113  dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD,
1114                  "%s does not understand message %s",
1115                  DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, name);
1116
1117  return FALSE;
1118}
1119
1120void
1121bus_driver_remove_connection (DBusConnection *connection)
1122{
1123  /* FIXME Does nothing for now, should unregister the connection
1124   * with the bus driver.
1125   */
1126}
1127