1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2/* connection.c  Client connections
3 *
4 * Copyright (C) 2003  Red Hat, Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#include <config.h>
25#include "connection.h"
26#include "dispatch.h"
27#include "policy.h"
28#include "services.h"
29#include "utils.h"
30#include "signals.h"
31#include "expirelist.h"
32#include "selinux.h"
33#include <dbus/dbus-list.h>
34#include <dbus/dbus-hash.h>
35#include <dbus/dbus-timeout.h>
36
37/* Trim executed commands to this length; we want to keep logs readable */
38#define MAX_LOG_COMMAND_LEN 50
39
40static void bus_connection_remove_transactions (DBusConnection *connection);
41
42typedef struct
43{
44  BusExpireItem expire_item;
45
46  DBusConnection *will_get_reply;
47  DBusConnection *will_send_reply;
48
49  dbus_uint32_t reply_serial;
50
51} BusPendingReply;
52
53struct BusConnections
54{
55  int refcount;
56  DBusList *completed;  /**< List of all completed connections */
57  int n_completed;      /**< Length of completed list */
58  DBusList *incomplete; /**< List of all not-yet-active connections */
59  int n_incomplete;     /**< Length of incomplete list */
60  BusContext *context;
61  DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */
62  DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */
63  int stamp;                   /**< Incrementing number */
64  BusExpireList *pending_replies; /**< List of pending replies */
65
66#ifdef DBUS_ENABLE_STATS
67  int total_match_rules;
68  int peak_match_rules;
69  int peak_match_rules_per_conn;
70
71  int total_bus_names;
72  int peak_bus_names;
73  int peak_bus_names_per_conn;
74#endif
75};
76
77static dbus_int32_t connection_data_slot = -1;
78
79typedef struct
80{
81  BusConnections *connections;
82  DBusList *link_in_connection_list;
83  DBusConnection *connection;
84  DBusList *services_owned;
85  int n_services_owned;
86  DBusList *match_rules;
87  int n_match_rules;
88  char *name;
89  DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
90  DBusMessage *oom_message;
91  DBusPreallocatedSend *oom_preallocated;
92  BusClientPolicy *policy;
93
94  char *cached_loginfo_string;
95  BusSELinuxID *selinux_id;
96
97  long connection_tv_sec;  /**< Time when we connected (seconds component) */
98  long connection_tv_usec; /**< Time when we connected (microsec component) */
99  int stamp;               /**< connections->stamp last time we were traversed */
100
101#ifdef DBUS_ENABLE_STATS
102  int peak_match_rules;
103  int peak_bus_names;
104#endif
105} BusConnectionData;
106
107static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
108                                              DBusList      *link,
109                                              void          *data);
110
111static void bus_connection_drop_pending_replies (BusConnections  *connections,
112                                                 DBusConnection  *connection);
113
114static dbus_bool_t expire_incomplete_timeout (void *data);
115
116#define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
117
118static DBusLoop*
119connection_get_loop (DBusConnection *connection)
120{
121  BusConnectionData *d;
122
123  d = BUS_CONNECTION_DATA (connection);
124
125  return bus_context_get_loop (d->connections->context);
126}
127
128
129static int
130get_connections_for_uid (BusConnections *connections,
131                         dbus_uid_t      uid)
132{
133  void *val;
134  int current_count;
135
136  /* val is NULL is 0 when it isn't in the hash yet */
137
138  val = _dbus_hash_table_lookup_uintptr (connections->completed_by_user,
139                                       uid);
140
141  current_count = _DBUS_POINTER_TO_INT (val);
142
143  return current_count;
144}
145
146static dbus_bool_t
147adjust_connections_for_uid (BusConnections *connections,
148                            dbus_uid_t      uid,
149                            int             adjustment)
150{
151  int current_count;
152
153  current_count = get_connections_for_uid (connections, uid);
154
155  _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT
156                 ": was %d adjustment %d making %d\n",
157                 uid, current_count, adjustment, current_count + adjustment);
158
159  _dbus_assert (current_count >= 0);
160
161  current_count += adjustment;
162
163  _dbus_assert (current_count >= 0);
164
165  if (current_count == 0)
166    {
167      _dbus_hash_table_remove_uintptr (connections->completed_by_user, uid);
168      return TRUE;
169    }
170  else
171    {
172      dbus_bool_t retval;
173
174      retval = _dbus_hash_table_insert_uintptr (connections->completed_by_user,
175                                              uid, _DBUS_INT_TO_POINTER (current_count));
176
177      /* only positive adjustment can fail as otherwise
178       * a hash entry should already exist
179       */
180      _dbus_assert (adjustment > 0 ||
181                    (adjustment <= 0 && retval));
182
183      return retval;
184    }
185}
186
187void
188bus_connection_disconnected (DBusConnection *connection)
189{
190  BusConnectionData *d;
191  BusService *service;
192  BusMatchmaker *matchmaker;
193
194  d = BUS_CONNECTION_DATA (connection);
195  _dbus_assert (d != NULL);
196
197  _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
198                 d->name ? d->name : "(inactive)");
199
200  /* Delete our match rules */
201  if (d->n_match_rules > 0)
202    {
203      matchmaker = bus_context_get_matchmaker (d->connections->context);
204      bus_matchmaker_disconnected (matchmaker, connection);
205    }
206
207  /* Drop any service ownership. Unfortunately, this requires
208   * memory allocation and there doesn't seem to be a good way to
209   * handle it other than sleeping; we can't "fail" the operation of
210   * disconnecting a client, and preallocating a broadcast "service is
211   * now gone" message for every client-service pair seems kind of
212   * involved.
213   */
214  while ((service = _dbus_list_get_last (&d->services_owned)))
215    {
216      BusTransaction *transaction;
217      DBusError error;
218
219    retry:
220
221      dbus_error_init (&error);
222
223      while ((transaction = bus_transaction_new (d->connections->context)) == NULL)
224        _dbus_wait_for_memory ();
225
226      if (!bus_service_remove_owner (service, connection,
227                                     transaction, &error))
228        {
229          _DBUS_ASSERT_ERROR_IS_SET (&error);
230
231          if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
232            {
233              dbus_error_free (&error);
234              bus_transaction_cancel_and_free (transaction);
235              _dbus_wait_for_memory ();
236              goto retry;
237            }
238          else
239            {
240              _dbus_verbose ("Failed to remove service owner: %s %s\n",
241                             error.name, error.message);
242              _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
243            }
244        }
245
246      bus_transaction_execute_and_free (transaction);
247    }
248
249  bus_dispatch_remove_connection (connection);
250
251  /* no more watching */
252  if (!dbus_connection_set_watch_functions (connection,
253                                            NULL, NULL, NULL,
254                                            connection,
255                                            NULL))
256    _dbus_assert_not_reached ("setting watch functions to NULL failed");
257
258  if (!dbus_connection_set_timeout_functions (connection,
259                                              NULL, NULL, NULL,
260                                              connection,
261                                              NULL))
262    _dbus_assert_not_reached ("setting timeout functions to NULL failed");
263
264  dbus_connection_set_unix_user_function (connection,
265                                          NULL, NULL, NULL);
266  dbus_connection_set_windows_user_function (connection,
267                                             NULL, NULL, NULL);
268
269  dbus_connection_set_dispatch_status_function (connection,
270                                                NULL, NULL, NULL);
271
272  bus_connection_remove_transactions (connection);
273
274  if (d->link_in_connection_list != NULL)
275    {
276      if (d->name != NULL)
277        {
278          unsigned long uid;
279
280          _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list);
281          d->link_in_connection_list = NULL;
282          d->connections->n_completed -= 1;
283
284          if (dbus_connection_get_unix_user (connection, &uid))
285            {
286              if (!adjust_connections_for_uid (d->connections,
287                                               uid, -1))
288                _dbus_assert_not_reached ("adjusting downward should never fail");
289            }
290        }
291      else
292        {
293          _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list);
294          d->link_in_connection_list = NULL;
295          d->connections->n_incomplete -= 1;
296        }
297
298      _dbus_assert (d->connections->n_incomplete >= 0);
299      _dbus_assert (d->connections->n_completed >= 0);
300    }
301
302  bus_connection_drop_pending_replies (d->connections, connection);
303
304  /* frees "d" as side effect */
305  dbus_connection_set_data (connection,
306                            connection_data_slot,
307                            NULL, NULL);
308
309  dbus_connection_unref (connection);
310}
311
312static dbus_bool_t
313add_connection_watch (DBusWatch      *watch,
314                      void           *data)
315{
316  DBusConnection *connection = data;
317
318  return _dbus_loop_add_watch (connection_get_loop (connection), watch);
319}
320
321static void
322remove_connection_watch (DBusWatch      *watch,
323                         void           *data)
324{
325  DBusConnection *connection = data;
326
327  _dbus_loop_remove_watch (connection_get_loop (connection), watch);
328}
329
330static void
331toggle_connection_watch (DBusWatch      *watch,
332                         void           *data)
333{
334  DBusConnection *connection = data;
335
336  _dbus_loop_toggle_watch (connection_get_loop (connection), watch);
337}
338
339static dbus_bool_t
340add_connection_timeout (DBusTimeout    *timeout,
341                        void           *data)
342{
343  DBusConnection *connection = data;
344
345  return _dbus_loop_add_timeout (connection_get_loop (connection), timeout);
346}
347
348static void
349remove_connection_timeout (DBusTimeout    *timeout,
350                           void           *data)
351{
352  DBusConnection *connection = data;
353
354  _dbus_loop_remove_timeout (connection_get_loop (connection), timeout);
355}
356
357static void
358dispatch_status_function (DBusConnection    *connection,
359                          DBusDispatchStatus new_status,
360                          void              *data)
361{
362  DBusLoop *loop = data;
363
364  if (new_status != DBUS_DISPATCH_COMPLETE)
365    {
366      while (!_dbus_loop_queue_dispatch (loop, connection))
367        _dbus_wait_for_memory ();
368    }
369}
370
371static dbus_bool_t
372allow_unix_user_function (DBusConnection *connection,
373                          unsigned long   uid,
374                          void           *data)
375{
376  BusConnectionData *d;
377
378  d = BUS_CONNECTION_DATA (connection);
379
380  _dbus_assert (d != NULL);
381
382  return bus_context_allow_unix_user (d->connections->context, uid);
383}
384
385static void
386free_connection_data (void *data)
387{
388  BusConnectionData *d = data;
389
390  /* services_owned should be NULL since we should be disconnected */
391  _dbus_assert (d->services_owned == NULL);
392  _dbus_assert (d->n_services_owned == 0);
393  /* similarly */
394  _dbus_assert (d->transaction_messages == NULL);
395
396  if (d->oom_preallocated)
397    dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
398
399  if (d->oom_message)
400    dbus_message_unref (d->oom_message);
401
402  if (d->policy)
403    bus_client_policy_unref (d->policy);
404
405  if (d->selinux_id)
406    bus_selinux_id_unref (d->selinux_id);
407
408  dbus_free (d->cached_loginfo_string);
409
410  dbus_free (d->name);
411
412  dbus_free (d);
413}
414
415BusConnections*
416bus_connections_new (BusContext *context)
417{
418  BusConnections *connections;
419
420  if (!dbus_connection_allocate_data_slot (&connection_data_slot))
421    goto failed_0;
422
423  connections = dbus_new0 (BusConnections, 1);
424  if (connections == NULL)
425    goto failed_1;
426
427  connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_UINTPTR,
428                                                         NULL, NULL);
429  if (connections->completed_by_user == NULL)
430    goto failed_2;
431
432  connections->expire_timeout = _dbus_timeout_new (100, /* irrelevant */
433                                                   expire_incomplete_timeout,
434                                                   connections, NULL);
435  if (connections->expire_timeout == NULL)
436    goto failed_3;
437
438  _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
439
440  connections->pending_replies = bus_expire_list_new (bus_context_get_loop (context),
441                                                      bus_context_get_reply_timeout (context),
442                                                      bus_pending_reply_expired,
443                                                      connections);
444  if (connections->pending_replies == NULL)
445    goto failed_4;
446
447  if (!_dbus_loop_add_timeout (bus_context_get_loop (context),
448                               connections->expire_timeout))
449    goto failed_5;
450
451  connections->refcount = 1;
452  connections->context = context;
453
454  return connections;
455
456 failed_5:
457  bus_expire_list_free (connections->pending_replies);
458 failed_4:
459  _dbus_timeout_unref (connections->expire_timeout);
460 failed_3:
461  _dbus_hash_table_unref (connections->completed_by_user);
462 failed_2:
463  dbus_free (connections);
464 failed_1:
465  dbus_connection_free_data_slot (&connection_data_slot);
466 failed_0:
467  return NULL;
468}
469
470BusConnections *
471bus_connections_ref (BusConnections *connections)
472{
473  _dbus_assert (connections->refcount > 0);
474  connections->refcount += 1;
475
476  return connections;
477}
478
479void
480bus_connections_unref (BusConnections *connections)
481{
482  _dbus_assert (connections->refcount > 0);
483  connections->refcount -= 1;
484  if (connections->refcount == 0)
485    {
486      /* drop all incomplete */
487      while (connections->incomplete != NULL)
488        {
489          DBusConnection *connection;
490
491          connection = connections->incomplete->data;
492
493          dbus_connection_ref (connection);
494          dbus_connection_close (connection);
495          bus_connection_disconnected (connection);
496          dbus_connection_unref (connection);
497        }
498
499      _dbus_assert (connections->n_incomplete == 0);
500
501      /* drop all real connections */
502      while (connections->completed != NULL)
503        {
504          DBusConnection *connection;
505
506          connection = connections->completed->data;
507
508          dbus_connection_ref (connection);
509          dbus_connection_close (connection);
510          bus_connection_disconnected (connection);
511          dbus_connection_unref (connection);
512        }
513
514      _dbus_assert (connections->n_completed == 0);
515
516      bus_expire_list_free (connections->pending_replies);
517
518      _dbus_loop_remove_timeout (bus_context_get_loop (connections->context),
519                                 connections->expire_timeout);
520
521      _dbus_timeout_unref (connections->expire_timeout);
522
523      _dbus_hash_table_unref (connections->completed_by_user);
524
525      dbus_free (connections);
526
527      dbus_connection_free_data_slot (&connection_data_slot);
528    }
529}
530
531/* Used for logging */
532static dbus_bool_t
533cache_peer_loginfo_string (BusConnectionData *d,
534                           DBusConnection    *connection)
535{
536  DBusString loginfo_buf;
537  unsigned long uid;
538  unsigned long pid;
539  char *windows_sid;
540  dbus_bool_t prev_added;
541
542  if (!_dbus_string_init (&loginfo_buf))
543    return FALSE;
544
545  prev_added = FALSE;
546  if (dbus_connection_get_unix_user (connection, &uid))
547    {
548      if (!_dbus_string_append_printf (&loginfo_buf, "uid=%ld", uid))
549        goto oom;
550      else
551        prev_added = TRUE;
552    }
553
554  if (dbus_connection_get_unix_process_id (connection, &pid))
555    {
556      if (prev_added)
557        {
558          if (!_dbus_string_append_byte (&loginfo_buf, ' '))
559            goto oom;
560        }
561      if (!_dbus_string_append_printf (&loginfo_buf, "pid=%ld comm=\"", pid))
562        goto oom;
563      /* Ignore errors here; we may not have permissions to read the
564       * proc file. */
565      _dbus_command_for_pid (pid, &loginfo_buf, MAX_LOG_COMMAND_LEN, NULL);
566      if (!_dbus_string_append_byte (&loginfo_buf, '"'))
567        goto oom;
568    }
569
570  if (dbus_connection_get_windows_user (connection, &windows_sid))
571    {
572      dbus_bool_t did_append;
573      did_append = _dbus_string_append_printf (&loginfo_buf,
574                                               "sid=\"%s\" ", windows_sid);
575      dbus_free (windows_sid);
576      if (!did_append)
577        goto oom;
578    }
579
580  if (!_dbus_string_steal_data (&loginfo_buf, &(d->cached_loginfo_string)))
581    goto oom;
582
583  _dbus_string_free (&loginfo_buf);
584
585  return TRUE;
586oom:
587   _dbus_string_free (&loginfo_buf);
588   return FALSE;
589}
590
591dbus_bool_t
592bus_connections_setup_connection (BusConnections *connections,
593                                  DBusConnection *connection)
594{
595
596  BusConnectionData *d;
597  dbus_bool_t retval;
598  DBusError error;
599
600
601  d = dbus_new0 (BusConnectionData, 1);
602
603  if (d == NULL)
604    return FALSE;
605
606  d->connections = connections;
607  d->connection = connection;
608
609  _dbus_get_monotonic_time (&d->connection_tv_sec,
610                            &d->connection_tv_usec);
611
612  _dbus_assert (connection_data_slot >= 0);
613
614  if (!dbus_connection_set_data (connection,
615                                 connection_data_slot,
616                                 d, free_connection_data))
617    {
618      dbus_free (d);
619      return FALSE;
620    }
621
622  dbus_connection_set_route_peer_messages (connection, TRUE);
623
624  retval = FALSE;
625
626  dbus_error_init (&error);
627  d->selinux_id = bus_selinux_init_connection_id (connection,
628                                                  &error);
629  if (dbus_error_is_set (&error))
630    {
631      /* This is a bit bogus because we pretend all errors
632       * are OOM; this is done because we know that in bus.c
633       * an OOM error disconnects the connection, which is
634       * the same thing we want on any other error.
635       */
636      dbus_error_free (&error);
637      goto out;
638    }
639
640  if (!dbus_connection_set_watch_functions (connection,
641                                            add_connection_watch,
642                                            remove_connection_watch,
643                                            toggle_connection_watch,
644                                            connection,
645                                            NULL))
646    goto out;
647
648  if (!dbus_connection_set_timeout_functions (connection,
649                                              add_connection_timeout,
650                                              remove_connection_timeout,
651                                              NULL,
652                                              connection, NULL))
653    goto out;
654
655  /* For now we don't need to set a Windows user function because
656   * there are no policies in the config file controlling what
657   * Windows users can connect. The default 'same user that owns the
658   * bus can connect' behavior of DBusConnection is fine on Windows.
659   */
660  dbus_connection_set_unix_user_function (connection,
661                                          allow_unix_user_function,
662                                          NULL, NULL);
663
664  dbus_connection_set_dispatch_status_function (connection,
665                                                dispatch_status_function,
666                                                bus_context_get_loop (connections->context),
667                                                NULL);
668
669  d->link_in_connection_list = _dbus_list_alloc_link (connection);
670  if (d->link_in_connection_list == NULL)
671    goto out;
672
673  /* Setup the connection with the dispatcher */
674  if (!bus_dispatch_add_connection (connection))
675    goto out;
676
677  if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
678    {
679      if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
680        {
681          bus_dispatch_remove_connection (connection);
682          goto out;
683        }
684    }
685
686  _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list);
687  connections->n_incomplete += 1;
688
689  dbus_connection_ref (connection);
690
691  /* Note that we might disconnect ourselves here, but it only takes
692   * effect on return to the main loop. We call this to free up
693   * expired connections if possible, and to queue the timeout for our
694   * own expiration.
695   */
696  bus_connections_expire_incomplete (connections);
697
698  /* And we might also disconnect ourselves here, but again it
699   * only takes effect on return to main loop.
700   */
701  if (connections->n_incomplete >
702      bus_context_get_max_incomplete_connections (connections->context))
703    {
704      _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n");
705
706      _dbus_assert (connections->incomplete != NULL);
707      /* Disconnect the oldest unauthenticated connection.  FIXME
708       * would it be more secure to drop a *random* connection?  This
709       * algorithm seems to mean that if someone can create new
710       * connections quickly enough, they can keep anyone else from
711       * completing authentication. But random may or may not really
712       * help with that, a more elaborate solution might be required.
713       */
714      dbus_connection_close (connections->incomplete->data);
715    }
716
717  retval = TRUE;
718
719 out:
720  if (!retval)
721    {
722      if (d->selinux_id)
723        bus_selinux_id_unref (d->selinux_id);
724      d->selinux_id = NULL;
725
726      if (!dbus_connection_set_watch_functions (connection,
727                                                NULL, NULL, NULL,
728                                                connection,
729                                                NULL))
730        _dbus_assert_not_reached ("setting watch functions to NULL failed");
731
732      if (!dbus_connection_set_timeout_functions (connection,
733                                                  NULL, NULL, NULL,
734                                                  connection,
735                                                  NULL))
736        _dbus_assert_not_reached ("setting timeout functions to NULL failed");
737
738      dbus_connection_set_unix_user_function (connection,
739                                              NULL, NULL, NULL);
740
741      dbus_connection_set_windows_user_function (connection,
742                                                 NULL, NULL, NULL);
743
744      dbus_connection_set_dispatch_status_function (connection,
745                                                    NULL, NULL, NULL);
746
747      if (d->link_in_connection_list != NULL)
748        {
749          _dbus_assert (d->link_in_connection_list->next == NULL);
750          _dbus_assert (d->link_in_connection_list->prev == NULL);
751          _dbus_list_free_link (d->link_in_connection_list);
752          d->link_in_connection_list = NULL;
753        }
754
755      if (!dbus_connection_set_data (connection,
756                                     connection_data_slot,
757                                     NULL, NULL))
758        _dbus_assert_not_reached ("failed to set connection data to null");
759
760      /* "d" has now been freed */
761    }
762
763  return retval;
764}
765
766void
767bus_connections_expire_incomplete (BusConnections *connections)
768{
769  int next_interval;
770
771  next_interval = -1;
772
773  if (connections->incomplete != NULL)
774    {
775      long tv_sec, tv_usec;
776      DBusList *link;
777      int auth_timeout;
778
779      _dbus_get_monotonic_time (&tv_sec, &tv_usec);
780      auth_timeout = bus_context_get_auth_timeout (connections->context);
781
782      link = _dbus_list_get_first_link (&connections->incomplete);
783      while (link != NULL)
784        {
785          DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
786          DBusConnection *connection;
787          BusConnectionData *d;
788          double elapsed;
789
790          connection = link->data;
791
792          d = BUS_CONNECTION_DATA (connection);
793
794          _dbus_assert (d != NULL);
795
796          elapsed = ELAPSED_MILLISECONDS_SINCE (d->connection_tv_sec,
797                                                d->connection_tv_usec,
798                                                tv_sec, tv_usec);
799
800          if (elapsed >= (double) auth_timeout)
801            {
802              _dbus_verbose ("Timing out authentication for connection %p\n", connection);
803              dbus_connection_close (connection);
804            }
805          else
806            {
807              /* We can end the loop, since the connections are in oldest-first order */
808              next_interval = ((double)auth_timeout) - elapsed;
809              _dbus_verbose ("Connection %p authentication expires in %d milliseconds\n",
810                             connection, next_interval);
811
812              break;
813            }
814
815          link = next;
816        }
817    }
818
819  bus_expire_timeout_set_interval (connections->expire_timeout,
820                                   next_interval);
821}
822
823static dbus_bool_t
824expire_incomplete_timeout (void *data)
825{
826  BusConnections *connections = data;
827
828  _dbus_verbose ("Running\n");
829
830  /* note that this may remove the timeout */
831  bus_connections_expire_incomplete (connections);
832
833  return TRUE;
834}
835
836dbus_bool_t
837bus_connection_get_unix_groups  (DBusConnection   *connection,
838                                 unsigned long   **groups,
839                                 int              *n_groups,
840                                 DBusError        *error)
841{
842  unsigned long uid;
843
844  *groups = NULL;
845  *n_groups = 0;
846
847  if (dbus_connection_get_unix_user (connection, &uid))
848    {
849      if (!_dbus_unix_groups_from_uid (uid, groups, n_groups))
850        {
851          _dbus_verbose ("Did not get any groups for UID %lu\n",
852                         uid);
853          return FALSE;
854        }
855      else
856        {
857          _dbus_verbose ("Got %d groups for UID %lu\n",
858                         *n_groups, uid);
859          return TRUE;
860        }
861    }
862  else
863    return TRUE; /* successfully got 0 groups */
864}
865
866dbus_bool_t
867bus_connection_is_in_unix_group (DBusConnection *connection,
868                                 unsigned long   gid)
869{
870  int i;
871  unsigned long *group_ids;
872  int n_group_ids;
873
874  if (!bus_connection_get_unix_groups (connection, &group_ids, &n_group_ids,
875                                       NULL))
876    return FALSE;
877
878  i = 0;
879  while (i < n_group_ids)
880    {
881      if (group_ids[i] == gid)
882        {
883          dbus_free (group_ids);
884          return TRUE;
885        }
886      ++i;
887    }
888
889  dbus_free (group_ids);
890  return FALSE;
891}
892
893const char *
894bus_connection_get_loginfo (DBusConnection        *connection)
895{
896  BusConnectionData *d;
897
898  d = BUS_CONNECTION_DATA (connection);
899
900  if (!bus_connection_is_active (connection))
901    return "inactive";
902  return d->cached_loginfo_string;
903}
904
905BusClientPolicy*
906bus_connection_get_policy (DBusConnection *connection)
907{
908  BusConnectionData *d;
909
910  d = BUS_CONNECTION_DATA (connection);
911
912  _dbus_assert (d != NULL);
913  _dbus_assert (d->policy != NULL);
914
915  return d->policy;
916}
917
918static dbus_bool_t
919foreach_active (BusConnections               *connections,
920                BusConnectionForeachFunction  function,
921                void                         *data)
922{
923  DBusList *link;
924
925  link = _dbus_list_get_first_link (&connections->completed);
926  while (link != NULL)
927    {
928      DBusConnection *connection = link->data;
929      DBusList *next = _dbus_list_get_next_link (&connections->completed, link);
930
931      if (!(* function) (connection, data))
932        return FALSE;
933
934      link = next;
935    }
936
937  return TRUE;
938}
939
940static dbus_bool_t
941foreach_inactive (BusConnections               *connections,
942                  BusConnectionForeachFunction  function,
943                  void                         *data)
944{
945  DBusList *link;
946
947  link = _dbus_list_get_first_link (&connections->incomplete);
948  while (link != NULL)
949    {
950      DBusConnection *connection = link->data;
951      DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
952
953      if (!(* function) (connection, data))
954        return FALSE;
955
956      link = next;
957    }
958
959  return TRUE;
960}
961
962/**
963 * Calls function on each active connection; if the function returns
964 * #FALSE, stops iterating. Active connections are authenticated
965 * and have sent a Hello message.
966 *
967 * @param connections the connections object
968 * @param function the function
969 * @param data data to pass to it as a second arg
970 */
971void
972bus_connections_foreach_active (BusConnections               *connections,
973                                BusConnectionForeachFunction  function,
974                                void                         *data)
975{
976  foreach_active (connections, function, data);
977}
978
979/**
980 * Calls function on each connection; if the function returns
981 * #FALSE, stops iterating.
982 *
983 * @param connections the connections object
984 * @param function the function
985 * @param data data to pass to it as a second arg
986 */
987void
988bus_connections_foreach (BusConnections               *connections,
989                         BusConnectionForeachFunction  function,
990                         void                         *data)
991{
992  if (!foreach_active (connections, function, data))
993    return;
994
995  foreach_inactive (connections, function, data);
996}
997
998BusContext*
999bus_connections_get_context (BusConnections *connections)
1000{
1001  return connections->context;
1002}
1003
1004/*
1005 * This is used to avoid covering the same connection twice when
1006 * traversing connections. Note that it assumes we will
1007 * bus_connection_mark_stamp() each connection at least once per
1008 * INT_MAX increments of the global stamp, or wraparound would break
1009 * things.
1010 */
1011void
1012bus_connections_increment_stamp (BusConnections *connections)
1013{
1014  connections->stamp += 1;
1015}
1016
1017/* Mark connection with current stamp, return TRUE if it
1018 * didn't already have that stamp
1019 */
1020dbus_bool_t
1021bus_connection_mark_stamp (DBusConnection *connection)
1022{
1023  BusConnectionData *d;
1024
1025  d = BUS_CONNECTION_DATA (connection);
1026
1027  _dbus_assert (d != NULL);
1028
1029  if (d->stamp == d->connections->stamp)
1030    return FALSE;
1031  else
1032    {
1033      d->stamp = d->connections->stamp;
1034      return TRUE;
1035    }
1036}
1037
1038BusContext*
1039bus_connection_get_context (DBusConnection *connection)
1040{
1041  BusConnectionData *d;
1042
1043  d = BUS_CONNECTION_DATA (connection);
1044
1045  _dbus_assert (d != NULL);
1046
1047  return d->connections->context;
1048}
1049
1050BusConnections*
1051bus_connection_get_connections (DBusConnection *connection)
1052{
1053  BusConnectionData *d;
1054
1055  d = BUS_CONNECTION_DATA (connection);
1056
1057  _dbus_assert (d != NULL);
1058
1059  return d->connections;
1060}
1061
1062BusRegistry*
1063bus_connection_get_registry (DBusConnection *connection)
1064{
1065  BusConnectionData *d;
1066
1067  d = BUS_CONNECTION_DATA (connection);
1068
1069  _dbus_assert (d != NULL);
1070
1071  return bus_context_get_registry (d->connections->context);
1072}
1073
1074BusActivation*
1075bus_connection_get_activation (DBusConnection *connection)
1076{
1077  BusConnectionData *d;
1078
1079  d = BUS_CONNECTION_DATA (connection);
1080
1081  _dbus_assert (d != NULL);
1082
1083  return bus_context_get_activation (d->connections->context);
1084}
1085
1086BusMatchmaker*
1087bus_connection_get_matchmaker (DBusConnection *connection)
1088{
1089  BusConnectionData *d;
1090
1091  d = BUS_CONNECTION_DATA (connection);
1092
1093  _dbus_assert (d != NULL);
1094
1095  return bus_context_get_matchmaker (d->connections->context);
1096}
1097
1098BusSELinuxID*
1099bus_connection_get_selinux_id (DBusConnection *connection)
1100{
1101  BusConnectionData *d;
1102
1103  d = BUS_CONNECTION_DATA (connection);
1104
1105  _dbus_assert (d != NULL);
1106
1107  return d->selinux_id;
1108}
1109
1110/**
1111 * Checks whether the connection is registered with the message bus.
1112 *
1113 * @param connection the connection
1114 * @returns #TRUE if we're an active message bus participant
1115 */
1116dbus_bool_t
1117bus_connection_is_active (DBusConnection *connection)
1118{
1119  BusConnectionData *d;
1120
1121  d = BUS_CONNECTION_DATA (connection);
1122
1123  return d != NULL && d->name != NULL;
1124}
1125
1126dbus_bool_t
1127bus_connection_preallocate_oom_error (DBusConnection *connection)
1128{
1129  DBusMessage *message;
1130  DBusPreallocatedSend *preallocated;
1131  BusConnectionData *d;
1132
1133  d = BUS_CONNECTION_DATA (connection);
1134
1135  _dbus_assert (d != NULL);
1136
1137  if (d->oom_preallocated != NULL)
1138    return TRUE;
1139
1140  preallocated = dbus_connection_preallocate_send (connection);
1141  if (preallocated == NULL)
1142    return FALSE;
1143
1144  message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
1145
1146  if (message == NULL)
1147    {
1148      dbus_connection_free_preallocated_send (connection, preallocated);
1149      return FALSE;
1150    }
1151
1152  /* d->name may be NULL, but that is OK */
1153  if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) ||
1154      !dbus_message_set_destination (message, d->name) ||
1155      !dbus_message_set_sender (message,
1156                                DBUS_SERVICE_DBUS))
1157    {
1158      dbus_connection_free_preallocated_send (connection, preallocated);
1159      dbus_message_unref (message);
1160      return FALSE;
1161    }
1162
1163  /* set reply serial to placeholder value just so space is already allocated
1164   * for it.
1165   */
1166  if (!dbus_message_set_reply_serial (message, 14))
1167    {
1168      dbus_connection_free_preallocated_send (connection, preallocated);
1169      dbus_message_unref (message);
1170      return FALSE;
1171    }
1172
1173  d->oom_message = message;
1174  d->oom_preallocated = preallocated;
1175
1176  return TRUE;
1177}
1178
1179void
1180bus_connection_send_oom_error (DBusConnection *connection,
1181                               DBusMessage    *in_reply_to)
1182{
1183  BusConnectionData *d;
1184
1185  d = BUS_CONNECTION_DATA (connection);
1186
1187  _dbus_assert (d != NULL);
1188  _dbus_assert (d->oom_message != NULL);
1189
1190  /* should always succeed since we set it to a placeholder earlier */
1191  if (!dbus_message_set_reply_serial (d->oom_message,
1192                                      dbus_message_get_serial (in_reply_to)))
1193    _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
1194
1195  _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL);
1196
1197  dbus_connection_send_preallocated (connection, d->oom_preallocated,
1198                                     d->oom_message, NULL);
1199
1200  dbus_message_unref (d->oom_message);
1201  d->oom_message = NULL;
1202  d->oom_preallocated = NULL;
1203}
1204
1205#ifdef DBUS_ENABLE_STATS
1206static void
1207update_peak (int *peak,
1208             int n)
1209{
1210  if (*peak < n)
1211    *peak = n;
1212}
1213#endif
1214
1215void
1216bus_connection_add_match_rule_link (DBusConnection *connection,
1217                                    DBusList       *link)
1218{
1219  BusConnectionData *d;
1220
1221  d = BUS_CONNECTION_DATA (connection);
1222  _dbus_assert (d != NULL);
1223
1224  _dbus_list_append_link (&d->match_rules, link);
1225
1226  d->n_match_rules += 1;
1227
1228#ifdef DBUS_ENABLE_STATS
1229  update_peak (&d->peak_match_rules, d->n_match_rules);
1230  update_peak (&d->connections->peak_match_rules_per_conn, d->n_match_rules);
1231
1232  d->connections->total_match_rules += 1;
1233  update_peak (&d->connections->peak_match_rules,
1234               d->connections->total_match_rules);
1235#endif
1236}
1237
1238dbus_bool_t
1239bus_connection_add_match_rule (DBusConnection *connection,
1240                               BusMatchRule   *rule)
1241{
1242    DBusList *link;
1243
1244  link = _dbus_list_alloc_link (rule);
1245
1246  if (link == NULL)
1247    return FALSE;
1248
1249  bus_connection_add_match_rule_link (connection, link);
1250
1251  return TRUE;
1252}
1253
1254void
1255bus_connection_remove_match_rule (DBusConnection *connection,
1256                                  BusMatchRule   *rule)
1257{
1258  BusConnectionData *d;
1259
1260  d = BUS_CONNECTION_DATA (connection);
1261  _dbus_assert (d != NULL);
1262
1263  _dbus_list_remove_last (&d->match_rules, rule);
1264
1265  d->n_match_rules -= 1;
1266  _dbus_assert (d->n_match_rules >= 0);
1267
1268#ifdef DBUS_ENABLE_STATS
1269  d->connections->total_match_rules -= 1;
1270#endif
1271}
1272
1273int
1274bus_connection_get_n_match_rules (DBusConnection *connection)
1275{
1276  BusConnectionData *d;
1277
1278  d = BUS_CONNECTION_DATA (connection);
1279  _dbus_assert (d != NULL);
1280
1281  return d->n_match_rules;
1282}
1283
1284void
1285bus_connection_add_owned_service_link (DBusConnection *connection,
1286                                       DBusList       *link)
1287{
1288  BusConnectionData *d;
1289
1290  d = BUS_CONNECTION_DATA (connection);
1291  _dbus_assert (d != NULL);
1292
1293  _dbus_list_append_link (&d->services_owned, link);
1294
1295  d->n_services_owned += 1;
1296
1297#ifdef DBUS_ENABLE_STATS
1298  update_peak (&d->peak_bus_names, d->n_services_owned);
1299  update_peak (&d->connections->peak_bus_names_per_conn,
1300               d->n_services_owned);
1301
1302  d->connections->total_bus_names += 1;
1303  update_peak (&d->connections->peak_bus_names,
1304               d->connections->total_bus_names);
1305#endif
1306}
1307
1308dbus_bool_t
1309bus_connection_add_owned_service (DBusConnection *connection,
1310                                  BusService     *service)
1311{
1312  DBusList *link;
1313
1314  link = _dbus_list_alloc_link (service);
1315
1316  if (link == NULL)
1317    return FALSE;
1318
1319  bus_connection_add_owned_service_link (connection, link);
1320
1321  return TRUE;
1322}
1323
1324void
1325bus_connection_remove_owned_service (DBusConnection *connection,
1326                                     BusService     *service)
1327{
1328  BusConnectionData *d;
1329
1330  d = BUS_CONNECTION_DATA (connection);
1331  _dbus_assert (d != NULL);
1332
1333  _dbus_list_remove_last (&d->services_owned, service);
1334
1335  d->n_services_owned -= 1;
1336  _dbus_assert (d->n_services_owned >= 0);
1337
1338#ifdef DBUS_ENABLE_STATS
1339  d->connections->total_bus_names -= 1;
1340#endif
1341}
1342
1343int
1344bus_connection_get_n_services_owned (DBusConnection *connection)
1345{
1346  BusConnectionData *d;
1347
1348  d = BUS_CONNECTION_DATA (connection);
1349  _dbus_assert (d != NULL);
1350
1351  return d->n_services_owned;
1352}
1353
1354dbus_bool_t
1355bus_connection_complete (DBusConnection   *connection,
1356			 const DBusString *name,
1357                         DBusError        *error)
1358{
1359  BusConnectionData *d;
1360  unsigned long uid;
1361
1362  d = BUS_CONNECTION_DATA (connection);
1363  _dbus_assert (d != NULL);
1364  _dbus_assert (d->name == NULL);
1365  _dbus_assert (d->policy == NULL);
1366
1367  _dbus_assert (!bus_connection_is_active (connection));
1368
1369  if (!_dbus_string_copy_data (name, &d->name))
1370    {
1371      BUS_SET_OOM (error);
1372      return FALSE;
1373    }
1374
1375  _dbus_assert (d->name != NULL);
1376
1377  _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
1378
1379  d->policy = bus_context_create_client_policy (d->connections->context,
1380                                                connection,
1381                                                error);
1382
1383  /* we may have a NULL policy on OOM or error getting list of
1384   * groups for a user. In the latter case we don't handle it so
1385   * well currently, as it will just keep failing over and over.
1386   */
1387
1388  if (d->policy == NULL)
1389    {
1390      _dbus_verbose ("Failed to create security policy for connection %p\n",
1391                     connection);
1392      _DBUS_ASSERT_ERROR_IS_SET (error);
1393      dbus_free (d->name);
1394      d->name = NULL;
1395      return FALSE;
1396    }
1397
1398  if (dbus_connection_get_unix_user (connection, &uid))
1399    {
1400      if (!adjust_connections_for_uid (d->connections,
1401                                       uid, 1))
1402        goto fail;
1403    }
1404
1405  /* Create and cache a string which holds information about the
1406   * peer process; used for logging purposes.
1407   */
1408  if (!cache_peer_loginfo_string (d, connection))
1409    goto fail;
1410
1411  /* Now the connection is active, move it between lists */
1412  _dbus_list_unlink (&d->connections->incomplete,
1413                     d->link_in_connection_list);
1414  d->connections->n_incomplete -= 1;
1415  _dbus_list_append_link (&d->connections->completed,
1416                          d->link_in_connection_list);
1417  d->connections->n_completed += 1;
1418
1419  _dbus_assert (d->connections->n_incomplete >= 0);
1420  _dbus_assert (d->connections->n_completed > 0);
1421
1422  /* See if we can remove the timeout */
1423  bus_connections_expire_incomplete (d->connections);
1424
1425  _dbus_assert (bus_connection_is_active (connection));
1426
1427  return TRUE;
1428fail:
1429  BUS_SET_OOM (error);
1430  dbus_free (d->name);
1431  d->name = NULL;
1432  if (d->policy)
1433    bus_client_policy_unref (d->policy);
1434  d->policy = NULL;
1435  return FALSE;
1436}
1437
1438const char *
1439bus_connection_get_name (DBusConnection *connection)
1440{
1441  BusConnectionData *d;
1442
1443  d = BUS_CONNECTION_DATA (connection);
1444  _dbus_assert (d != NULL);
1445
1446  return d->name;
1447}
1448
1449/**
1450 * Check whether completing the passed-in connection would
1451 * exceed limits, and if so set error and return #FALSE
1452 */
1453dbus_bool_t
1454bus_connections_check_limits (BusConnections  *connections,
1455                              DBusConnection  *requesting_completion,
1456                              DBusError       *error)
1457{
1458  unsigned long uid;
1459
1460  if (connections->n_completed >=
1461      bus_context_get_max_completed_connections (connections->context))
1462    {
1463      dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1464                      "The maximum number of active connections has been reached");
1465      return FALSE;
1466    }
1467
1468  if (dbus_connection_get_unix_user (requesting_completion, &uid))
1469    {
1470      if (get_connections_for_uid (connections, uid) >=
1471          bus_context_get_max_connections_per_user (connections->context))
1472        {
1473          dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1474                          "The maximum number of active connections for UID %lu has been reached",
1475                          uid);
1476          return FALSE;
1477        }
1478    }
1479
1480  return TRUE;
1481}
1482
1483static void
1484bus_pending_reply_free (BusPendingReply *pending)
1485{
1486  _dbus_verbose ("Freeing pending reply %p, replier %p receiver %p serial %u\n",
1487                 pending,
1488                 pending->will_send_reply,
1489                 pending->will_get_reply,
1490                 pending->reply_serial);
1491
1492  dbus_free (pending);
1493}
1494
1495static dbus_bool_t
1496bus_pending_reply_send_no_reply (BusConnections  *connections,
1497                                 BusTransaction  *transaction,
1498                                 BusPendingReply *pending)
1499{
1500  DBusMessage *message;
1501  DBusMessageIter iter;
1502  dbus_bool_t retval;
1503  const char *errmsg;
1504
1505  retval = FALSE;
1506
1507  message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
1508  if (message == NULL)
1509    return FALSE;
1510
1511  dbus_message_set_no_reply (message, TRUE);
1512
1513  if (!dbus_message_set_reply_serial (message,
1514                                      pending->reply_serial))
1515    goto out;
1516
1517  if (!dbus_message_set_error_name (message,
1518                                    DBUS_ERROR_NO_REPLY))
1519    goto out;
1520
1521  errmsg = "Message did not receive a reply (timeout by message bus)";
1522  dbus_message_iter_init_append (message, &iter);
1523  if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &errmsg))
1524    goto out;
1525
1526  if (!bus_transaction_send_from_driver (transaction, pending->will_get_reply,
1527                                         message))
1528    goto out;
1529
1530  retval = TRUE;
1531
1532 out:
1533  dbus_message_unref (message);
1534  return retval;
1535}
1536
1537static dbus_bool_t
1538bus_pending_reply_expired (BusExpireList *list,
1539                           DBusList      *link,
1540                           void          *data)
1541{
1542  BusPendingReply *pending = link->data;
1543  BusConnections *connections = data;
1544  BusTransaction *transaction;
1545
1546  /* No reply is forthcoming. So nuke it if we can. If not,
1547   * leave it in the list to try expiring again later when we
1548   * get more memory.
1549   */
1550
1551  _dbus_verbose ("Expiring pending reply %p, replier %p receiver %p serial %u\n",
1552                 pending,
1553                 pending->will_send_reply,
1554                 pending->will_get_reply,
1555                 pending->reply_serial);
1556
1557  transaction = bus_transaction_new (connections->context);
1558  if (transaction == NULL)
1559    return FALSE;
1560
1561  if (!bus_pending_reply_send_no_reply (connections,
1562                                        transaction,
1563                                        pending))
1564    {
1565      bus_transaction_cancel_and_free (transaction);
1566      return FALSE;
1567    }
1568
1569  bus_expire_list_remove_link (connections->pending_replies, link);
1570
1571  bus_pending_reply_free (pending);
1572  bus_transaction_execute_and_free (transaction);
1573
1574  return TRUE;
1575}
1576
1577static void
1578bus_connection_drop_pending_replies (BusConnections  *connections,
1579                                     DBusConnection  *connection)
1580{
1581  /* The DBusConnection is almost 100% finalized here, so you can't
1582   * do anything with it except check for pointer equality
1583   */
1584  DBusList *link;
1585
1586  _dbus_verbose ("Dropping pending replies that involve connection %p\n",
1587                 connection);
1588
1589  link = bus_expire_list_get_first_link (connections->pending_replies);
1590  while (link != NULL)
1591    {
1592      DBusList *next;
1593      BusPendingReply *pending;
1594
1595      next = bus_expire_list_get_next_link (connections->pending_replies,
1596                                            link);
1597      pending = link->data;
1598
1599      if (pending->will_get_reply == connection)
1600        {
1601          /* We don't need to track this pending reply anymore */
1602
1603          _dbus_verbose ("Dropping pending reply %p, replier %p receiver %p serial %u\n",
1604                         pending,
1605                         pending->will_send_reply,
1606                         pending->will_get_reply,
1607                         pending->reply_serial);
1608
1609          bus_expire_list_remove_link (connections->pending_replies,
1610                                       link);
1611          bus_pending_reply_free (pending);
1612        }
1613      else if (pending->will_send_reply == connection)
1614        {
1615          /* The reply isn't going to be sent, so set things
1616           * up so it will be expired right away
1617           */
1618          _dbus_verbose ("Will expire pending reply %p, replier %p receiver %p serial %u\n",
1619                         pending,
1620                         pending->will_send_reply,
1621                         pending->will_get_reply,
1622                         pending->reply_serial);
1623
1624          pending->will_send_reply = NULL;
1625          pending->expire_item.added_tv_sec = 0;
1626          pending->expire_item.added_tv_usec = 0;
1627
1628          bus_expire_list_recheck_immediately (connections->pending_replies);
1629        }
1630
1631      link = next;
1632    }
1633}
1634
1635
1636typedef struct
1637{
1638  BusPendingReply *pending;
1639  BusConnections  *connections;
1640} CancelPendingReplyData;
1641
1642static void
1643cancel_pending_reply (void *data)
1644{
1645  CancelPendingReplyData *d = data;
1646
1647  _dbus_verbose ("d = %p\n", d);
1648
1649  if (!bus_expire_list_remove (d->connections->pending_replies,
1650                               &d->pending->expire_item))
1651    _dbus_assert_not_reached ("pending reply did not exist to be cancelled");
1652
1653  bus_pending_reply_free (d->pending); /* since it's been cancelled */
1654}
1655
1656static void
1657cancel_pending_reply_data_free (void *data)
1658{
1659  CancelPendingReplyData *d = data;
1660
1661  _dbus_verbose ("d = %p\n", d);
1662
1663  /* d->pending should be either freed or still
1664   * in the list of pending replies (owned by someone
1665   * else)
1666   */
1667
1668  dbus_free (d);
1669}
1670
1671/*
1672 * Record that a reply is allowed; return TRUE on success.
1673 */
1674dbus_bool_t
1675bus_connections_expect_reply (BusConnections  *connections,
1676                              BusTransaction  *transaction,
1677                              DBusConnection  *will_get_reply,
1678                              DBusConnection  *will_send_reply,
1679                              DBusMessage     *reply_to_this,
1680                              DBusError       *error)
1681{
1682  BusPendingReply *pending;
1683  dbus_uint32_t reply_serial;
1684  DBusList *link;
1685  CancelPendingReplyData *cprd;
1686  int count;
1687
1688  _dbus_assert (will_get_reply != NULL);
1689  _dbus_assert (will_send_reply != NULL);
1690  _dbus_assert (reply_to_this != NULL);
1691
1692  if (dbus_message_get_no_reply (reply_to_this))
1693    return TRUE; /* we won't allow a reply, since client doesn't care for one. */
1694
1695  reply_serial = dbus_message_get_serial (reply_to_this);
1696
1697  link = bus_expire_list_get_first_link (connections->pending_replies);
1698  count = 0;
1699  while (link != NULL)
1700    {
1701      pending = link->data;
1702
1703      if (pending->reply_serial == reply_serial &&
1704          pending->will_get_reply == will_get_reply &&
1705          pending->will_send_reply == will_send_reply)
1706        {
1707          dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
1708                          "Message has the same reply serial as a currently-outstanding existing method call");
1709          return FALSE;
1710        }
1711
1712      link = bus_expire_list_get_next_link (connections->pending_replies,
1713                                            link);
1714      if (pending->will_get_reply == will_get_reply)
1715        ++count;
1716    }
1717
1718  if (count >=
1719      bus_context_get_max_replies_per_connection (connections->context))
1720    {
1721      dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1722		      "The maximum number of pending replies per connection has been reached");
1723      return FALSE;
1724    }
1725
1726  pending = dbus_new0 (BusPendingReply, 1);
1727  if (pending == NULL)
1728    {
1729      BUS_SET_OOM (error);
1730      return FALSE;
1731    }
1732
1733#ifdef DBUS_ENABLE_VERBOSE_MODE
1734  /* so we can see a not-yet-added pending reply */
1735  pending->expire_item.added_tv_sec = 1;
1736  pending->expire_item.added_tv_usec = 1;
1737#endif
1738
1739  pending->will_get_reply = will_get_reply;
1740  pending->will_send_reply = will_send_reply;
1741  pending->reply_serial = reply_serial;
1742
1743  cprd = dbus_new0 (CancelPendingReplyData, 1);
1744  if (cprd == NULL)
1745    {
1746      BUS_SET_OOM (error);
1747      bus_pending_reply_free (pending);
1748      return FALSE;
1749    }
1750
1751  if (!bus_expire_list_add (connections->pending_replies,
1752                            &pending->expire_item))
1753    {
1754      BUS_SET_OOM (error);
1755      dbus_free (cprd);
1756      bus_pending_reply_free (pending);
1757      return FALSE;
1758    }
1759
1760  if (!bus_transaction_add_cancel_hook (transaction,
1761                                        cancel_pending_reply,
1762                                        cprd,
1763                                        cancel_pending_reply_data_free))
1764    {
1765      BUS_SET_OOM (error);
1766      bus_expire_list_remove (connections->pending_replies, &pending->expire_item);
1767      dbus_free (cprd);
1768      bus_pending_reply_free (pending);
1769      return FALSE;
1770    }
1771
1772  cprd->pending = pending;
1773  cprd->connections = connections;
1774
1775  _dbus_get_monotonic_time (&pending->expire_item.added_tv_sec,
1776                            &pending->expire_item.added_tv_usec);
1777
1778  _dbus_verbose ("Added pending reply %p, replier %p receiver %p serial %u\n",
1779                 pending,
1780                 pending->will_send_reply,
1781                 pending->will_get_reply,
1782                 pending->reply_serial);
1783
1784  return TRUE;
1785}
1786
1787typedef struct
1788{
1789  DBusList        *link;
1790  BusConnections  *connections;
1791} CheckPendingReplyData;
1792
1793static void
1794cancel_check_pending_reply (void *data)
1795{
1796  CheckPendingReplyData *d = data;
1797
1798  _dbus_verbose ("d = %p\n",d);
1799
1800  bus_expire_list_add_link (d->connections->pending_replies,
1801                            d->link);
1802  d->link = NULL;
1803}
1804
1805static void
1806check_pending_reply_data_free (void *data)
1807{
1808  CheckPendingReplyData *d = data;
1809
1810  _dbus_verbose ("d = %p\n",d);
1811
1812  if (d->link != NULL)
1813    {
1814      BusPendingReply *pending = d->link->data;
1815
1816      _dbus_assert (!bus_expire_list_contains_item (d->connections->pending_replies,
1817                                                    &pending->expire_item));
1818
1819      bus_pending_reply_free (pending);
1820      _dbus_list_free_link (d->link);
1821    }
1822
1823  dbus_free (d);
1824}
1825
1826/*
1827 * Check whether a reply is allowed, remove BusPendingReply
1828 * if so, return TRUE if so.
1829 */
1830dbus_bool_t
1831bus_connections_check_reply (BusConnections *connections,
1832                             BusTransaction *transaction,
1833                             DBusConnection *sending_reply,
1834                             DBusConnection *receiving_reply,
1835                             DBusMessage    *reply,
1836                             DBusError      *error)
1837{
1838  CheckPendingReplyData *cprd;
1839  DBusList *link;
1840  dbus_uint32_t reply_serial;
1841
1842  _dbus_assert (sending_reply != NULL);
1843  _dbus_assert (receiving_reply != NULL);
1844
1845  reply_serial = dbus_message_get_reply_serial (reply);
1846
1847  link = bus_expire_list_get_first_link (connections->pending_replies);
1848  while (link != NULL)
1849    {
1850      BusPendingReply *pending = link->data;
1851
1852      if (pending->reply_serial == reply_serial &&
1853          pending->will_get_reply == receiving_reply &&
1854          pending->will_send_reply == sending_reply)
1855        {
1856          _dbus_verbose ("Found pending reply with serial %u\n", reply_serial);
1857          break;
1858        }
1859
1860      link = bus_expire_list_get_next_link (connections->pending_replies,
1861                                            link);
1862    }
1863
1864  if (link == NULL)
1865    {
1866      _dbus_verbose ("No pending reply expected\n");
1867
1868      return FALSE;
1869    }
1870
1871  cprd = dbus_new0 (CheckPendingReplyData, 1);
1872  if (cprd == NULL)
1873    {
1874      BUS_SET_OOM (error);
1875      return FALSE;
1876    }
1877
1878  if (!bus_transaction_add_cancel_hook (transaction,
1879                                        cancel_check_pending_reply,
1880                                        cprd,
1881                                        check_pending_reply_data_free))
1882    {
1883      BUS_SET_OOM (error);
1884      dbus_free (cprd);
1885      return FALSE;
1886    }
1887
1888  cprd->link = link;
1889  cprd->connections = connections;
1890
1891  bus_expire_list_unlink (connections->pending_replies,
1892                          link);
1893
1894  _dbus_assert (!bus_expire_list_contains_item (connections->pending_replies, link->data));
1895
1896  return TRUE;
1897}
1898
1899/*
1900 * Transactions
1901 *
1902 * Note that this is fairly fragile; in particular, don't try to use
1903 * one transaction across any main loop iterations.
1904 */
1905
1906typedef struct
1907{
1908  BusTransaction *transaction;
1909  DBusMessage    *message;
1910  DBusPreallocatedSend *preallocated;
1911} MessageToSend;
1912
1913typedef struct
1914{
1915  BusTransactionCancelFunction cancel_function;
1916  DBusFreeFunction free_data_function;
1917  void *data;
1918} CancelHook;
1919
1920struct BusTransaction
1921{
1922  DBusList *connections;
1923  BusContext *context;
1924  DBusList *cancel_hooks;
1925};
1926
1927static void
1928message_to_send_free (DBusConnection *connection,
1929                      MessageToSend  *to_send)
1930{
1931  if (to_send->message)
1932    dbus_message_unref (to_send->message);
1933
1934  if (to_send->preallocated)
1935    dbus_connection_free_preallocated_send (connection, to_send->preallocated);
1936
1937  dbus_free (to_send);
1938}
1939
1940static void
1941cancel_hook_cancel (void *element,
1942                    void *data)
1943{
1944  CancelHook *ch = element;
1945
1946  _dbus_verbose ("Running transaction cancel hook\n");
1947
1948  if (ch->cancel_function)
1949    (* ch->cancel_function) (ch->data);
1950}
1951
1952static void
1953cancel_hook_free (void *element,
1954                  void *data)
1955{
1956  CancelHook *ch = element;
1957
1958  if (ch->free_data_function)
1959    (* ch->free_data_function) (ch->data);
1960
1961  dbus_free (ch);
1962}
1963
1964static void
1965free_cancel_hooks (BusTransaction *transaction)
1966{
1967  _dbus_list_foreach (&transaction->cancel_hooks,
1968                      cancel_hook_free, NULL);
1969
1970  _dbus_list_clear (&transaction->cancel_hooks);
1971}
1972
1973BusTransaction*
1974bus_transaction_new (BusContext *context)
1975{
1976  BusTransaction *transaction;
1977
1978  transaction = dbus_new0 (BusTransaction, 1);
1979  if (transaction == NULL)
1980    return NULL;
1981
1982  transaction->context = context;
1983
1984  return transaction;
1985}
1986
1987BusContext*
1988bus_transaction_get_context (BusTransaction  *transaction)
1989{
1990  return transaction->context;
1991}
1992
1993BusConnections*
1994bus_transaction_get_connections (BusTransaction  *transaction)
1995{
1996  return bus_context_get_connections (transaction->context);
1997}
1998
1999dbus_bool_t
2000bus_transaction_send_from_driver (BusTransaction *transaction,
2001                                  DBusConnection *connection,
2002                                  DBusMessage    *message)
2003{
2004  /* We have to set the sender to the driver, and have
2005   * to check security policy since it was not done in
2006   * dispatch.c
2007   */
2008  _dbus_verbose ("Sending %s %s %s from driver\n",
2009                 dbus_message_get_interface (message) ?
2010                 dbus_message_get_interface (message) : "(no interface)",
2011                 dbus_message_get_member (message) ?
2012                 dbus_message_get_member (message) : "(no member)",
2013                 dbus_message_get_error_name (message) ?
2014                 dbus_message_get_error_name (message) : "(no error name)");
2015
2016  if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
2017    return FALSE;
2018
2019  if (bus_connection_is_active (connection))
2020    {
2021      if (!dbus_message_set_destination (message,
2022                                         bus_connection_get_name (connection)))
2023        return FALSE;
2024    }
2025
2026  /* bus driver never wants a reply */
2027  dbus_message_set_no_reply (message, TRUE);
2028
2029  /* If security policy doesn't allow the message, we silently
2030   * eat it; the driver doesn't care about getting a reply.
2031   */
2032  if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
2033                                          transaction,
2034                                          NULL, connection, connection, message, NULL))
2035    return TRUE;
2036
2037  return bus_transaction_send (transaction, connection, message);
2038}
2039
2040dbus_bool_t
2041bus_transaction_send (BusTransaction *transaction,
2042                      DBusConnection *connection,
2043                      DBusMessage    *message)
2044{
2045  MessageToSend *to_send;
2046  BusConnectionData *d;
2047  DBusList *link;
2048
2049  _dbus_verbose ("  trying to add %s interface=%s member=%s error=%s to transaction%s\n",
2050                 dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" :
2051                 dbus_message_get_reply_serial (message) != 0 ? "reply" :
2052                 "message",
2053                 dbus_message_get_interface (message) ?
2054                 dbus_message_get_interface (message) : "(unset)",
2055                 dbus_message_get_member (message) ?
2056                 dbus_message_get_member (message) : "(unset)",
2057                 dbus_message_get_error_name (message) ?
2058                 dbus_message_get_error_name (message) : "(unset)",
2059                 dbus_connection_get_is_connected (connection) ?
2060                 "" : " (disconnected)");
2061
2062  _dbus_assert (dbus_message_get_sender (message) != NULL);
2063
2064  if (!dbus_connection_get_is_connected (connection))
2065    return TRUE; /* silently ignore disconnected connections */
2066
2067  d = BUS_CONNECTION_DATA (connection);
2068  _dbus_assert (d != NULL);
2069
2070  to_send = dbus_new (MessageToSend, 1);
2071  if (to_send == NULL)
2072    {
2073      return FALSE;
2074    }
2075
2076  to_send->preallocated = dbus_connection_preallocate_send (connection);
2077  if (to_send->preallocated == NULL)
2078    {
2079      dbus_free (to_send);
2080      return FALSE;
2081    }
2082
2083  dbus_message_ref (message);
2084  to_send->message = message;
2085  to_send->transaction = transaction;
2086
2087  _dbus_verbose ("about to prepend message\n");
2088
2089  if (!_dbus_list_prepend (&d->transaction_messages, to_send))
2090    {
2091      message_to_send_free (connection, to_send);
2092      return FALSE;
2093    }
2094
2095  _dbus_verbose ("prepended message\n");
2096
2097  /* See if we already had this connection in the list
2098   * for this transaction. If we have a pending message,
2099   * then we should already be in transaction->connections
2100   */
2101  link = _dbus_list_get_first_link (&d->transaction_messages);
2102  _dbus_assert (link->data == to_send);
2103  link = _dbus_list_get_next_link (&d->transaction_messages, link);
2104  while (link != NULL)
2105    {
2106      MessageToSend *m = link->data;
2107      DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
2108
2109      if (m->transaction == transaction)
2110        break;
2111
2112      link = next;
2113    }
2114
2115  if (link == NULL)
2116    {
2117      if (!_dbus_list_prepend (&transaction->connections, connection))
2118        {
2119          _dbus_list_remove (&d->transaction_messages, to_send);
2120          message_to_send_free (connection, to_send);
2121          return FALSE;
2122        }
2123    }
2124
2125  return TRUE;
2126}
2127
2128static void
2129connection_cancel_transaction (DBusConnection *connection,
2130                               BusTransaction *transaction)
2131{
2132  DBusList *link;
2133  BusConnectionData *d;
2134
2135  d = BUS_CONNECTION_DATA (connection);
2136  _dbus_assert (d != NULL);
2137
2138  link = _dbus_list_get_first_link (&d->transaction_messages);
2139  while (link != NULL)
2140    {
2141      MessageToSend *m = link->data;
2142      DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
2143
2144      if (m->transaction == transaction)
2145        {
2146          _dbus_list_remove_link (&d->transaction_messages,
2147                                  link);
2148
2149          message_to_send_free (connection, m);
2150        }
2151
2152      link = next;
2153    }
2154}
2155
2156void
2157bus_transaction_cancel_and_free (BusTransaction *transaction)
2158{
2159  DBusConnection *connection;
2160
2161  _dbus_verbose ("TRANSACTION: cancelled\n");
2162
2163  while ((connection = _dbus_list_pop_first (&transaction->connections)))
2164    connection_cancel_transaction (connection, transaction);
2165
2166  _dbus_assert (transaction->connections == NULL);
2167
2168  _dbus_list_foreach (&transaction->cancel_hooks,
2169                      cancel_hook_cancel, NULL);
2170
2171  free_cancel_hooks (transaction);
2172
2173  dbus_free (transaction);
2174}
2175
2176static void
2177connection_execute_transaction (DBusConnection *connection,
2178                                BusTransaction *transaction)
2179{
2180  DBusList *link;
2181  BusConnectionData *d;
2182
2183  d = BUS_CONNECTION_DATA (connection);
2184  _dbus_assert (d != NULL);
2185
2186  /* Send the queue in order (FIFO) */
2187  link = _dbus_list_get_last_link (&d->transaction_messages);
2188  while (link != NULL)
2189    {
2190      MessageToSend *m = link->data;
2191      DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
2192
2193      if (m->transaction == transaction)
2194        {
2195          _dbus_list_remove_link (&d->transaction_messages,
2196                                  link);
2197
2198          _dbus_assert (dbus_message_get_sender (m->message) != NULL);
2199
2200          dbus_connection_send_preallocated (connection,
2201                                             m->preallocated,
2202                                             m->message,
2203                                             NULL);
2204
2205          m->preallocated = NULL; /* so we don't double-free it */
2206
2207          message_to_send_free (connection, m);
2208        }
2209
2210      link = prev;
2211    }
2212}
2213
2214void
2215bus_transaction_execute_and_free (BusTransaction *transaction)
2216{
2217  /* For each connection in transaction->connections
2218   * send the messages
2219   */
2220  DBusConnection *connection;
2221
2222  _dbus_verbose ("TRANSACTION: executing\n");
2223
2224  while ((connection = _dbus_list_pop_first (&transaction->connections)))
2225    connection_execute_transaction (connection, transaction);
2226
2227  _dbus_assert (transaction->connections == NULL);
2228
2229  free_cancel_hooks (transaction);
2230
2231  dbus_free (transaction);
2232}
2233
2234static void
2235bus_connection_remove_transactions (DBusConnection *connection)
2236{
2237  MessageToSend *to_send;
2238  BusConnectionData *d;
2239
2240  d = BUS_CONNECTION_DATA (connection);
2241  _dbus_assert (d != NULL);
2242
2243  while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
2244    {
2245      /* only has an effect for the first MessageToSend listing this transaction */
2246      _dbus_list_remove (&to_send->transaction->connections,
2247                         connection);
2248
2249      _dbus_list_remove (&d->transaction_messages, to_send);
2250      message_to_send_free (connection, to_send);
2251    }
2252}
2253
2254/**
2255 * Converts the DBusError to a message reply
2256 */
2257dbus_bool_t
2258bus_transaction_send_error_reply (BusTransaction  *transaction,
2259                                  DBusConnection  *connection,
2260                                  const DBusError *error,
2261                                  DBusMessage     *in_reply_to)
2262{
2263  DBusMessage *reply;
2264
2265  _dbus_assert (error != NULL);
2266  _DBUS_ASSERT_ERROR_IS_SET (error);
2267
2268  _dbus_verbose ("Sending error reply %s \"%s\"\n",
2269                 error->name, error->message);
2270
2271  reply = dbus_message_new_error (in_reply_to,
2272                                  error->name,
2273                                  error->message);
2274  if (reply == NULL)
2275    return FALSE;
2276
2277  if (!bus_transaction_send_from_driver (transaction, connection, reply))
2278    {
2279      dbus_message_unref (reply);
2280      return FALSE;
2281    }
2282
2283  dbus_message_unref (reply);
2284
2285  return TRUE;
2286}
2287
2288dbus_bool_t
2289bus_transaction_add_cancel_hook (BusTransaction               *transaction,
2290                                 BusTransactionCancelFunction  cancel_function,
2291                                 void                         *data,
2292                                 DBusFreeFunction              free_data_function)
2293{
2294  CancelHook *ch;
2295
2296  ch = dbus_new (CancelHook, 1);
2297  if (ch == NULL)
2298    return FALSE;
2299
2300  _dbus_verbose ("     adding cancel hook function = %p data = %p\n",
2301                 cancel_function, data);
2302
2303  ch->cancel_function = cancel_function;
2304  ch->data = data;
2305  ch->free_data_function = free_data_function;
2306
2307  /* It's important that the hooks get run in reverse order that they
2308   * were added
2309   */
2310  if (!_dbus_list_prepend (&transaction->cancel_hooks, ch))
2311    {
2312      dbus_free (ch);
2313      return FALSE;
2314    }
2315
2316  return TRUE;
2317}
2318
2319#ifdef DBUS_ENABLE_STATS
2320int
2321bus_connections_get_n_active (BusConnections *connections)
2322{
2323  return connections->n_completed;
2324}
2325
2326int
2327bus_connections_get_n_incomplete (BusConnections *connections)
2328{
2329  return connections->n_incomplete;
2330}
2331
2332int
2333bus_connections_get_total_match_rules (BusConnections *connections)
2334{
2335  return connections->total_match_rules;
2336}
2337
2338int
2339bus_connections_get_peak_match_rules (BusConnections *connections)
2340{
2341  return connections->peak_match_rules;
2342}
2343
2344int
2345bus_connections_get_peak_match_rules_per_conn (BusConnections *connections)
2346{
2347  return connections->peak_match_rules_per_conn;
2348}
2349
2350int
2351bus_connections_get_total_bus_names (BusConnections *connections)
2352{
2353  return connections->total_bus_names;
2354}
2355
2356int
2357bus_connections_get_peak_bus_names (BusConnections *connections)
2358{
2359  return connections->peak_bus_names;
2360}
2361
2362int
2363bus_connections_get_peak_bus_names_per_conn (BusConnections *connections)
2364{
2365  return connections->peak_bus_names_per_conn;
2366}
2367
2368int
2369bus_connection_get_peak_match_rules (DBusConnection *connection)
2370{
2371  BusConnectionData *d;
2372
2373  d = BUS_CONNECTION_DATA (connection);
2374  return d->peak_match_rules;
2375}
2376
2377int
2378bus_connection_get_peak_bus_names (DBusConnection *connection)
2379{
2380  BusConnectionData *d;
2381
2382  d = BUS_CONNECTION_DATA (connection);
2383  return d->peak_bus_names;
2384}
2385#endif /* DBUS_ENABLE_STATS */
2386