2003-05-13 James Willcox <jwillcox@gnome.org>
[platform/upstream/dbus.git] / bus / connection.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* connection.c  Client connections
3  *
4  * Copyright (C) 2003  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "connection.h"
24 #include "dispatch.h"
25 #include "policy.h"
26 #include "services.h"
27 #include "utils.h"
28 #include <dbus/dbus-list.h>
29 #include <dbus/dbus-hash.h>
30 #include <dbus/dbus-timeout.h>
31
32 static void bus_connection_remove_transactions (DBusConnection *connection);
33
34 struct BusConnections
35 {
36   int refcount;
37   DBusList *completed;  /**< List of all completed connections */
38   int n_completed;      /**< Length of completed list */
39   DBusList *incomplete; /**< List of all not-yet-active connections */
40   int n_incomplete;     /**< Length of incomplete list */
41   BusContext *context;
42   DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */
43   DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */
44 };
45
46 static int connection_data_slot = -1;
47 static int connection_data_slot_refcount = 0;
48
49 typedef struct
50 {
51   BusConnections *connections;
52   DBusList *link_in_connection_list;
53   DBusConnection *connection;
54   DBusList *services_owned;
55   int n_services_owned;
56   char *name;
57   DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
58   DBusMessage *oom_message;
59   DBusPreallocatedSend *oom_preallocated;
60   BusClientPolicy *policy;
61
62   long connection_tv_sec;  /**< Time when we connected (seconds component) */
63   long connection_tv_usec; /**< Time when we connected (microsec component) */
64 } BusConnectionData;
65
66 static dbus_bool_t expire_incomplete_timeout (void *data);
67
68 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
69
70 static dbus_bool_t
71 connection_data_slot_ref (void)
72 {
73   if (connection_data_slot < 0)
74     {
75       connection_data_slot = dbus_connection_allocate_data_slot ();
76       
77       if (connection_data_slot < 0)
78         return FALSE;
79
80       _dbus_assert (connection_data_slot_refcount == 0);
81     }  
82
83   connection_data_slot_refcount += 1;
84
85   return TRUE;
86
87 }
88
89 static void
90 connection_data_slot_unref (void)
91 {
92   _dbus_assert (connection_data_slot_refcount > 0);
93
94   connection_data_slot_refcount -= 1;
95   
96   if (connection_data_slot_refcount == 0)
97     {
98       dbus_connection_free_data_slot (connection_data_slot);
99       connection_data_slot = -1;
100     }
101 }
102
103 static DBusLoop*
104 connection_get_loop (DBusConnection *connection)
105 {
106   BusConnectionData *d;
107
108   d = BUS_CONNECTION_DATA (connection);
109
110   return bus_context_get_loop (d->connections->context);
111 }
112
113
114 static int
115 get_connections_for_uid (BusConnections *connections,
116                          dbus_uid_t      uid)
117 {
118   void *val;
119   int current_count;
120
121   /* val is NULL is 0 when it isn't in the hash yet */
122   
123   val = _dbus_hash_table_lookup_ulong (connections->completed_by_user,
124                                        uid);
125
126   current_count = _DBUS_POINTER_TO_INT (val);
127
128   return current_count;
129 }
130
131 static dbus_bool_t
132 adjust_connections_for_uid (BusConnections *connections,
133                             dbus_uid_t      uid,
134                             int             adjustment)
135 {
136   int current_count;
137
138   current_count = get_connections_for_uid (connections, uid);
139
140   _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT
141                  ": was %d adjustment %d making %d\n",
142                  uid, current_count, adjustment, current_count + adjustment);
143   
144   _dbus_assert (current_count >= 0);
145   
146   current_count += adjustment;
147
148   _dbus_assert (current_count >= 0);
149
150   if (current_count == 0)
151     {
152       _dbus_hash_table_remove_ulong (connections->completed_by_user, uid);
153       return TRUE;
154     }
155   else
156     {
157       dbus_bool_t retval;
158       
159       retval = _dbus_hash_table_insert_ulong (connections->completed_by_user,
160                                               uid, _DBUS_INT_TO_POINTER (current_count));
161
162       /* only positive adjustment can fail as otherwise
163        * a hash entry should already exist
164        */
165       _dbus_assert (adjustment > 0 ||
166                     (adjustment <= 0 && retval));
167
168       return retval;
169     }
170 }
171
172 void
173 bus_connection_disconnected (DBusConnection *connection)
174 {
175   BusConnectionData *d;
176   BusService *service;
177
178   d = BUS_CONNECTION_DATA (connection);
179   _dbus_assert (d != NULL);
180
181   _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
182                  d->name ? d->name : "(inactive)");
183   
184   /* Drop any service ownership. FIXME Unfortunately, this requires
185    * memory allocation and there doesn't seem to be a good way to
186    * handle it other than sleeping; we can't "fail" the operation of
187    * disconnecting a client, and preallocating a broadcast "service is
188    * now gone" message for every client-service pair seems kind of
189    * involved. Probably we need to do that though.
190    */
191   while ((service = _dbus_list_get_last (&d->services_owned)))
192     {
193       BusTransaction *transaction;
194       DBusError error;
195
196     retry:
197       
198       dbus_error_init (&error);
199         
200       transaction = NULL;
201       while (transaction == NULL)
202         {
203           transaction = bus_transaction_new (d->connections->context);
204           _dbus_wait_for_memory ();
205         }
206         
207       if (!bus_service_remove_owner (service, connection,
208                                      transaction, &error))
209         {
210           _DBUS_ASSERT_ERROR_IS_SET (&error);
211           
212           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
213             {
214               dbus_error_free (&error);
215               bus_transaction_cancel_and_free (transaction);
216               _dbus_wait_for_memory ();
217               goto retry;
218             }
219           else
220             {
221               _dbus_verbose ("Failed to remove service owner: %s %s\n",
222                              error.name, error.message);
223               _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
224             }
225         }
226         
227       bus_transaction_execute_and_free (transaction);
228     }
229
230   bus_dispatch_remove_connection (connection);
231   
232   /* no more watching */
233   if (!dbus_connection_set_watch_functions (connection,
234                                             NULL, NULL, NULL,
235                                             connection,
236                                             NULL))
237     _dbus_assert_not_reached ("setting watch functions to NULL failed");
238
239   if (!dbus_connection_set_timeout_functions (connection,
240                                               NULL, NULL, NULL,
241                                               connection,
242                                               NULL))
243     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
244   
245   dbus_connection_set_unix_user_function (connection,
246                                           NULL, NULL, NULL);
247
248   dbus_connection_set_dispatch_status_function (connection,
249                                                 NULL, NULL, NULL);
250   
251   bus_connection_remove_transactions (connection);
252
253   if (d->link_in_connection_list != NULL)
254     {
255       if (d->name != NULL)
256         {
257           unsigned long uid;
258           
259           _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list);
260           d->link_in_connection_list = NULL;
261           d->connections->n_completed -= 1;
262
263           if (dbus_connection_get_unix_user (connection, &uid))
264             {
265               if (!adjust_connections_for_uid (d->connections,
266                                                uid, -1))
267                 _dbus_assert_not_reached ("adjusting downward should never fail");
268             }
269         }
270       else
271         {
272           _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list);
273           d->link_in_connection_list = NULL;
274           d->connections->n_incomplete -= 1;
275         }
276       
277       _dbus_assert (d->connections->n_incomplete >= 0);
278       _dbus_assert (d->connections->n_completed >= 0);
279     }
280   
281   /* frees "d" as side effect */
282   dbus_connection_set_data (connection,
283                             connection_data_slot,
284                             NULL, NULL);
285
286   dbus_connection_unref (connection);
287 }
288
289 static dbus_bool_t
290 connection_watch_callback (DBusWatch     *watch,
291                            unsigned int   condition,
292                            void          *data)
293 {
294  /* FIXME this can be done in dbus-mainloop.c
295   * if the code in activation.c for the babysitter
296   * watch handler is fixed.
297   */
298   
299 #if 0
300   _dbus_verbose ("Calling handle_watch\n");
301 #endif
302   return dbus_watch_handle (watch, condition);
303 }
304
305 static dbus_bool_t
306 add_connection_watch (DBusWatch      *watch,
307                       void           *data)
308 {
309   DBusConnection *connection = data;
310
311   return _dbus_loop_add_watch (connection_get_loop (connection),
312                                watch, connection_watch_callback, connection,
313                                NULL);
314 }
315
316 static void
317 remove_connection_watch (DBusWatch      *watch,
318                          void           *data)
319 {
320   DBusConnection *connection = data;
321   
322   _dbus_loop_remove_watch (connection_get_loop (connection),
323                            watch, connection_watch_callback, connection);
324 }
325
326 static void
327 connection_timeout_callback (DBusTimeout   *timeout,
328                              void          *data)
329 {
330   /* DBusConnection *connection = data; */
331
332   /* can return FALSE on OOM but we just let it fire again later */
333   dbus_timeout_handle (timeout);
334 }
335
336 static dbus_bool_t
337 add_connection_timeout (DBusTimeout    *timeout,
338                         void           *data)
339 {
340   DBusConnection *connection = data;
341   
342   return _dbus_loop_add_timeout (connection_get_loop (connection),
343                                  timeout, connection_timeout_callback, connection, NULL);
344 }
345
346 static void
347 remove_connection_timeout (DBusTimeout    *timeout,
348                            void           *data)
349 {
350   DBusConnection *connection = data;
351   
352   _dbus_loop_remove_timeout (connection_get_loop (connection),
353                              timeout, connection_timeout_callback, connection);
354 }
355
356 static void
357 dispatch_status_function (DBusConnection    *connection,
358                           DBusDispatchStatus new_status,
359                           void              *data)
360 {
361   DBusLoop *loop = data;
362   
363   if (new_status != DBUS_DISPATCH_COMPLETE)
364     {
365       while (!_dbus_loop_queue_dispatch (loop, connection))
366         _dbus_wait_for_memory ();
367     }
368 }
369
370 static dbus_bool_t
371 allow_user_function (DBusConnection *connection,
372                      unsigned long   uid,
373                      void           *data)
374 {
375   BusConnectionData *d;
376     
377   d = BUS_CONNECTION_DATA (connection);
378
379   _dbus_assert (d != NULL);
380   
381   return bus_context_allow_user (d->connections->context, uid);
382 }
383
384 static void
385 free_connection_data (void *data)
386 {
387   BusConnectionData *d = data;
388
389   /* services_owned should be NULL since we should be disconnected */
390   _dbus_assert (d->services_owned == NULL);
391   _dbus_assert (d->n_services_owned == 0);
392   /* similarly */
393   _dbus_assert (d->transaction_messages == NULL);
394
395   if (d->oom_preallocated)
396     dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
397
398   if (d->oom_message)
399     dbus_message_unref (d->oom_message);
400
401   if (d->policy)
402     bus_client_policy_unref (d->policy);
403   
404   dbus_free (d->name);
405   
406   dbus_free (d);
407 }
408
409 static void
410 call_timeout_callback (DBusTimeout   *timeout,
411                        void          *data)
412 {
413   /* can return FALSE on OOM but we just let it fire again later */
414   dbus_timeout_handle (timeout);
415 }
416
417 BusConnections*
418 bus_connections_new (BusContext *context)
419 {
420   BusConnections *connections;
421
422   if (!connection_data_slot_ref ())
423     goto failed_0;
424
425   connections = dbus_new0 (BusConnections, 1);
426   if (connections == NULL)
427     goto failed_1;
428
429   connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_ULONG,
430                                                          NULL, NULL);
431   if (connections->completed_by_user == NULL)
432     goto failed_2;
433
434   connections->expire_timeout = _dbus_timeout_new (100, /* irrelevant */
435                                                    expire_incomplete_timeout,
436                                                    connections, NULL);
437   if (connections->expire_timeout == NULL)
438     goto failed_3;
439
440   _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
441
442   if (!_dbus_loop_add_timeout (bus_context_get_loop (context),
443                                connections->expire_timeout,
444                                call_timeout_callback, NULL, NULL))
445     goto failed_4;
446   
447   connections->refcount = 1;
448   connections->context = context;
449   
450   return connections;
451
452  failed_4:
453   _dbus_timeout_unref (connections->expire_timeout);
454  failed_3:
455   _dbus_hash_table_unref (connections->completed_by_user);
456  failed_2:
457   dbus_free (connections);
458  failed_1:
459   connection_data_slot_unref ();
460  failed_0:
461   return NULL;
462 }
463
464 void
465 bus_connections_ref (BusConnections *connections)
466 {
467   _dbus_assert (connections->refcount > 0);
468   connections->refcount += 1;
469 }
470
471 void
472 bus_connections_unref (BusConnections *connections)
473 {
474   _dbus_assert (connections->refcount > 0);
475   connections->refcount -= 1;
476   if (connections->refcount == 0)
477     {
478       /* drop all incomplete */
479       while (connections->incomplete != NULL)
480         {
481           DBusConnection *connection;
482
483           connection = connections->incomplete->data;
484
485           dbus_connection_ref (connection);
486           dbus_connection_disconnect (connection);
487           bus_connection_disconnected (connection);
488           dbus_connection_unref (connection);
489         }
490
491       _dbus_assert (connections->n_incomplete == 0);
492       
493       /* drop all real connections */
494       while (connections->completed != NULL)
495         {
496           DBusConnection *connection;
497
498           connection = connections->completed->data;
499
500           dbus_connection_ref (connection);
501           dbus_connection_disconnect (connection);
502           bus_connection_disconnected (connection);
503           dbus_connection_unref (connection);          
504         }
505
506       _dbus_assert (connections->n_completed == 0);
507
508       _dbus_loop_remove_timeout (bus_context_get_loop (connections->context),
509                                  connections->expire_timeout,
510                                  call_timeout_callback, NULL);
511       
512       _dbus_timeout_unref (connections->expire_timeout);
513       
514       _dbus_hash_table_unref (connections->completed_by_user);
515       
516       dbus_free (connections);
517
518       connection_data_slot_unref ();
519     }
520 }
521
522 dbus_bool_t
523 bus_connections_setup_connection (BusConnections *connections,
524                                   DBusConnection *connection)
525 {
526   BusConnectionData *d;
527   dbus_bool_t retval;
528   
529   d = dbus_new0 (BusConnectionData, 1);
530   
531   if (d == NULL)
532     return FALSE;
533
534   d->connections = connections;
535   d->connection = connection;
536   
537   _dbus_get_current_time (&d->connection_tv_sec,
538                           &d->connection_tv_usec);
539   
540   _dbus_assert (connection_data_slot >= 0);
541   
542   if (!dbus_connection_set_data (connection,
543                                  connection_data_slot,
544                                  d, free_connection_data))
545     {
546       dbus_free (d);
547       return FALSE;
548     }
549
550   retval = FALSE;
551   
552   if (!dbus_connection_set_watch_functions (connection,
553                                             add_connection_watch,
554                                             remove_connection_watch,
555                                             NULL,
556                                             connection,
557                                             NULL))
558     goto out;
559   
560   if (!dbus_connection_set_timeout_functions (connection,
561                                               add_connection_timeout,
562                                               remove_connection_timeout,
563                                               NULL,
564                                               connection, NULL))
565     goto out;
566   
567   dbus_connection_set_unix_user_function (connection,
568                                           allow_user_function,
569                                           NULL, NULL);
570
571   dbus_connection_set_dispatch_status_function (connection,
572                                                 dispatch_status_function,
573                                                 bus_context_get_loop (connections->context),
574                                                 NULL);
575
576   d->link_in_connection_list = _dbus_list_alloc_link (connection);
577   if (d->link_in_connection_list == NULL)
578     goto out;
579   
580   /* Setup the connection with the dispatcher */
581   if (!bus_dispatch_add_connection (connection))
582     goto out;
583
584   if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
585     {
586       if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
587         {
588           bus_dispatch_remove_connection (connection);
589           goto out;
590         }
591     }
592
593   _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list);
594   connections->n_incomplete += 1;
595   
596   dbus_connection_ref (connection);
597
598   /* Note that we might disconnect ourselves here, but it only takes
599    * effect on return to the main loop. We call this to free up
600    * expired connections if possible, and to queue the timeout for our
601    * own expiration.
602    */
603   bus_connections_expire_incomplete (connections);
604   
605   /* And we might also disconnect ourselves here, but again it
606    * only takes effect on return to main loop.
607    */
608   if (connections->n_incomplete >
609       bus_context_get_max_incomplete_connections (connections->context))
610     {
611       _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n");
612       
613       _dbus_assert (connections->incomplete != NULL);
614       /* Disconnect the oldest unauthenticated connection.  FIXME
615        * would it be more secure to drop a *random* connection?  This
616        * algorithm seems to mean that if someone can create new
617        * connections quickly enough, they can keep anyone else from
618        * completing authentication. But random may or may not really
619        * help with that, a more elaborate solution might be required.
620        */
621       dbus_connection_disconnect (connections->incomplete->data);
622     }
623   
624   retval = TRUE;
625
626  out:
627   if (!retval)
628     {      
629       if (!dbus_connection_set_watch_functions (connection,
630                                                 NULL, NULL, NULL,
631                                                 connection,
632                                                 NULL))
633         _dbus_assert_not_reached ("setting watch functions to NULL failed");
634       
635       if (!dbus_connection_set_timeout_functions (connection,
636                                                   NULL, NULL, NULL,
637                                                   connection,
638                                                   NULL))
639         _dbus_assert_not_reached ("setting timeout functions to NULL failed");
640
641       dbus_connection_set_unix_user_function (connection,
642                                               NULL, NULL, NULL);
643
644       dbus_connection_set_dispatch_status_function (connection,
645                                                     NULL, NULL, NULL);
646
647       if (d->link_in_connection_list != NULL)
648         {
649           _dbus_assert (d->link_in_connection_list->next == NULL);
650           _dbus_assert (d->link_in_connection_list->prev == NULL);
651           _dbus_list_free_link (d->link_in_connection_list);
652           d->link_in_connection_list = NULL;
653         }
654       
655       if (!dbus_connection_set_data (connection,
656                                      connection_data_slot,
657                                      NULL, NULL))
658         _dbus_assert_not_reached ("failed to set connection data to null");
659
660       /* "d" has now been freed */
661     }
662   
663   return retval;
664 }
665
666 void
667 bus_connections_expire_incomplete (BusConnections *connections)
668 {    
669   int next_interval;
670
671   next_interval = -1;
672   
673   if (connections->incomplete != NULL)
674     {
675       long tv_sec, tv_usec;
676       DBusList *link;
677       int auth_timeout;
678       
679       _dbus_get_current_time (&tv_sec, &tv_usec);
680       auth_timeout = bus_context_get_auth_timeout (connections->context);
681   
682       link = _dbus_list_get_first_link (&connections->incomplete);
683       while (link != NULL)
684         {
685           DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
686           DBusConnection *connection;
687           BusConnectionData *d;
688           double elapsed;
689       
690           connection = link->data;
691       
692           d = BUS_CONNECTION_DATA (connection);
693       
694           _dbus_assert (d != NULL);
695       
696           elapsed = ((double) tv_sec - (double) d->connection_tv_sec) * 1000.0 +
697             ((double) tv_usec - (double) d->connection_tv_usec) / 1000.0;
698
699           if (elapsed >= (double) auth_timeout)
700             {
701               _dbus_verbose ("Timing out authentication for connection %p\n", connection);
702               dbus_connection_disconnect (connection);
703             }
704           else
705             {
706               /* We can end the loop, since the connections are in oldest-first order */
707               next_interval = ((double)auth_timeout) - elapsed;
708               _dbus_verbose ("Connection %p authentication expires in %d milliseconds\n",
709                              connection, next_interval);
710           
711               break;
712             }
713       
714           link = next;
715         }
716     }
717   
718   if (next_interval >= 0)
719     {
720       _dbus_timeout_set_interval (connections->expire_timeout,
721                                   next_interval);
722       _dbus_timeout_set_enabled (connections->expire_timeout, TRUE);
723
724       _dbus_verbose ("Enabled incomplete connections timeout with interval %d, %d incomplete connections\n",
725                      next_interval, connections->n_incomplete);
726     }
727   else if (dbus_timeout_get_enabled (connections->expire_timeout))
728     {
729       _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
730
731       _dbus_verbose ("Disabled incomplete connections timeout, %d incomplete connections\n",
732                      connections->n_incomplete);
733     }
734   else
735     _dbus_verbose ("No need to disable incomplete connections timeout\n");
736 }
737
738 static dbus_bool_t
739 expire_incomplete_timeout (void *data)
740 {
741   BusConnections *connections = data;
742
743   _dbus_verbose ("Running %s\n", _DBUS_FUNCTION_NAME);
744   
745   /* note that this may remove the timeout */
746   bus_connections_expire_incomplete (connections);
747
748   return TRUE;
749 }
750
751 dbus_bool_t
752 bus_connection_get_groups  (DBusConnection   *connection,
753                             unsigned long   **groups,
754                             int              *n_groups,
755                             DBusError        *error)
756 {
757   BusConnectionData *d;
758   unsigned long uid;
759   DBusUserDatabase *user_database;
760   
761   d = BUS_CONNECTION_DATA (connection);
762
763   _dbus_assert (d != NULL);
764
765   user_database = bus_context_get_user_database (d->connections->context);
766   
767   *groups = NULL;
768   *n_groups = 0;
769
770   if (dbus_connection_get_unix_user (connection, &uid))
771     {
772       if (!_dbus_user_database_get_groups (user_database,
773                                            uid, groups, n_groups,
774                                            error))
775         {
776           _DBUS_ASSERT_ERROR_IS_SET (error);
777           _dbus_verbose ("Did not get any groups for UID %lu\n",
778                          uid);
779           return FALSE;
780         }
781       else
782         {
783           _dbus_verbose ("Got %d groups for UID %lu\n",
784                          *n_groups, uid);
785           return TRUE;
786         }
787     }
788   else
789     return TRUE; /* successfully got 0 groups */
790 }
791
792 dbus_bool_t
793 bus_connection_is_in_group (DBusConnection *connection,
794                             unsigned long   gid)
795 {
796   int i;
797   unsigned long *group_ids;
798   int n_group_ids;
799
800   if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids,
801                                   NULL))
802     return FALSE;
803
804   i = 0;
805   while (i < n_group_ids)
806     {
807       if (group_ids[i] == gid)
808         {
809           dbus_free (group_ids);
810           return TRUE;
811         }
812       ++i;
813     }
814
815   dbus_free (group_ids);
816   return FALSE;
817 }
818
819 BusClientPolicy*
820 bus_connection_get_policy (DBusConnection *connection)
821 {
822   BusConnectionData *d;
823     
824   d = BUS_CONNECTION_DATA (connection);
825
826   _dbus_assert (d != NULL);
827   _dbus_assert (d->policy != NULL);
828   
829   return d->policy;
830 }
831
832 static dbus_bool_t
833 foreach_active (BusConnections               *connections,
834                 BusConnectionForeachFunction  function,
835                 void                         *data)
836 {
837   DBusList *link;
838   
839   link = _dbus_list_get_first_link (&connections->completed);
840   while (link != NULL)
841     {
842       DBusConnection *connection = link->data;
843       DBusList *next = _dbus_list_get_next_link (&connections->completed, link);
844
845       if (!(* function) (connection, data))
846         return FALSE;
847       
848       link = next;
849     }
850
851   return TRUE;
852 }
853
854 static dbus_bool_t
855 foreach_inactive (BusConnections               *connections,
856                   BusConnectionForeachFunction  function,
857                   void                         *data)
858 {
859   DBusList *link;
860   
861   link = _dbus_list_get_first_link (&connections->incomplete);
862   while (link != NULL)
863     {
864       DBusConnection *connection = link->data;
865       DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
866
867       if (!(* function) (connection, data))
868         return FALSE;
869       
870       link = next;
871     }
872
873   return TRUE;
874 }
875
876 /**
877  * Calls function on each active connection; if the function returns
878  * #FALSE, stops iterating. Active connections are authenticated
879  * and have sent a Hello message.
880  *
881  * @param connections the connections object
882  * @param function the function
883  * @param data data to pass to it as a second arg
884  */
885 void
886 bus_connections_foreach_active (BusConnections               *connections,
887                                 BusConnectionForeachFunction  function,
888                                 void                         *data)
889 {
890   foreach_active (connections, function, data);
891 }
892
893 /**
894  * Calls function on each connection; if the function returns
895  * #FALSE, stops iterating.
896  *
897  * @param connections the connections object
898  * @param function the function
899  * @param data data to pass to it as a second arg
900  */
901 void
902 bus_connections_foreach (BusConnections               *connections,
903                          BusConnectionForeachFunction  function,
904                          void                         *data)
905 {
906   if (!foreach_active (connections, function, data))
907     return;
908
909   foreach_inactive (connections, function, data);
910 }
911
912 BusContext*
913 bus_connections_get_context (BusConnections *connections)
914 {
915   return connections->context;
916 }
917
918 BusContext*
919 bus_connection_get_context (DBusConnection *connection)
920 {
921   BusConnectionData *d;
922
923   d = BUS_CONNECTION_DATA (connection);
924
925   _dbus_assert (d != NULL);
926
927   return d->connections->context;
928 }
929
930 BusConnections*
931 bus_connection_get_connections (DBusConnection *connection)
932 {
933   BusConnectionData *d;
934     
935   d = BUS_CONNECTION_DATA (connection);
936
937   _dbus_assert (d != NULL);
938
939   return d->connections;
940 }
941
942 BusRegistry*
943 bus_connection_get_registry (DBusConnection *connection)
944 {
945   BusConnectionData *d;
946
947   d = BUS_CONNECTION_DATA (connection);
948
949   _dbus_assert (d != NULL);
950
951   return bus_context_get_registry (d->connections->context);
952 }
953
954 BusActivation*
955 bus_connection_get_activation (DBusConnection *connection)
956 {
957   BusConnectionData *d;
958
959   d = BUS_CONNECTION_DATA (connection);
960
961   _dbus_assert (d != NULL);
962
963   return bus_context_get_activation (d->connections->context);
964 }
965
966 /**
967  * Checks whether the connection is registered with the message bus.
968  *
969  * @param connection the connection
970  * @returns #TRUE if we're an active message bus participant
971  */
972 dbus_bool_t
973 bus_connection_is_active (DBusConnection *connection)
974 {
975   BusConnectionData *d;
976
977   d = BUS_CONNECTION_DATA (connection);
978   
979   return d != NULL && d->name != NULL;
980 }
981
982 dbus_bool_t
983 bus_connection_preallocate_oom_error (DBusConnection *connection)
984 {
985   DBusMessage *message;
986   DBusPreallocatedSend *preallocated;
987   BusConnectionData *d;
988
989   d = BUS_CONNECTION_DATA (connection);  
990
991   _dbus_assert (d != NULL);
992
993   if (d->oom_preallocated != NULL)
994     return TRUE;
995   
996   preallocated = dbus_connection_preallocate_send (connection);
997   if (preallocated == NULL)
998     return FALSE;
999
1000   /* d->name may be NULL, but that is OK */
1001   message = dbus_message_new (DBUS_ERROR_NO_MEMORY,
1002                               d->name);
1003   if (message == NULL)
1004     {
1005       dbus_connection_free_preallocated_send (connection, preallocated);
1006       return FALSE;
1007     }
1008
1009   dbus_message_set_is_error (message, TRUE);
1010
1011   if (!dbus_message_set_sender (message,
1012                                 DBUS_SERVICE_DBUS))
1013     {
1014       dbus_connection_free_preallocated_send (connection, preallocated);
1015       dbus_message_unref (message);
1016       return FALSE;
1017     }
1018   
1019   /* set reply serial to placeholder value just so space is already allocated
1020    * for it.
1021    */
1022   if (!dbus_message_set_reply_serial (message, 14))
1023     {
1024       dbus_connection_free_preallocated_send (connection, preallocated);
1025       dbus_message_unref (message);
1026       return FALSE;
1027     }
1028
1029   d->oom_message = message;
1030   d->oom_preallocated = preallocated;
1031   
1032   return TRUE;
1033 }
1034
1035 void
1036 bus_connection_send_oom_error (DBusConnection *connection,
1037                                DBusMessage    *in_reply_to)
1038 {
1039   BusConnectionData *d;
1040
1041   d = BUS_CONNECTION_DATA (connection);  
1042
1043   _dbus_assert (d != NULL);  
1044   _dbus_assert (d->oom_message != NULL);
1045
1046   /* should always succeed since we set it to a placeholder earlier */
1047   if (!dbus_message_set_reply_serial (d->oom_message,
1048                                       dbus_message_get_serial (in_reply_to)))
1049     _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
1050
1051   _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL);
1052   
1053   dbus_connection_send_preallocated (connection, d->oom_preallocated,
1054                                      d->oom_message, NULL);
1055
1056   dbus_message_unref (d->oom_message);
1057   d->oom_message = NULL;
1058   d->oom_preallocated = NULL;
1059 }
1060
1061 void
1062 bus_connection_add_owned_service_link (DBusConnection *connection,
1063                                        DBusList       *link)
1064 {
1065   BusConnectionData *d;
1066
1067   d = BUS_CONNECTION_DATA (connection);
1068   _dbus_assert (d != NULL);
1069
1070   _dbus_list_append_link (&d->services_owned, link);
1071
1072   d->n_services_owned += 1;
1073 }
1074
1075 dbus_bool_t
1076 bus_connection_add_owned_service (DBusConnection *connection,
1077                                   BusService     *service)
1078 {
1079   DBusList *link;
1080
1081   link = _dbus_list_alloc_link (service);
1082
1083   if (link == NULL)
1084     return FALSE;
1085
1086   bus_connection_add_owned_service_link (connection, link);
1087
1088   return TRUE;
1089 }
1090
1091 void
1092 bus_connection_remove_owned_service (DBusConnection *connection,
1093                                      BusService     *service)
1094 {
1095   BusConnectionData *d;
1096
1097   d = BUS_CONNECTION_DATA (connection);
1098   _dbus_assert (d != NULL);
1099
1100   _dbus_list_remove_last (&d->services_owned, service);
1101
1102   d->n_services_owned -= 1;
1103   _dbus_assert (d->n_services_owned >= 0);
1104 }
1105
1106 int
1107 bus_connection_get_n_services_owned (DBusConnection *connection)
1108 {
1109   BusConnectionData *d;
1110
1111   d = BUS_CONNECTION_DATA (connection);
1112   _dbus_assert (d != NULL);
1113   
1114   return d->n_services_owned;
1115 }
1116
1117 dbus_bool_t
1118 bus_connection_complete (DBusConnection   *connection,
1119                          const DBusString *name,
1120                          DBusError        *error)
1121 {
1122   BusConnectionData *d;
1123   unsigned long uid;
1124   
1125   d = BUS_CONNECTION_DATA (connection);
1126   _dbus_assert (d != NULL);
1127   _dbus_assert (d->name == NULL);
1128   _dbus_assert (d->policy == NULL);
1129   
1130   if (!_dbus_string_copy_data (name, &d->name))
1131     {
1132       BUS_SET_OOM (error);
1133       return FALSE;
1134     }
1135
1136   _dbus_assert (d->name != NULL);
1137   
1138   _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
1139
1140   d->policy = bus_context_create_client_policy (d->connections->context,
1141                                                 connection,
1142                                                 error);
1143
1144   /* we may have a NULL policy on OOM or error getting list of
1145    * groups for a user. In the latter case we don't handle it so
1146    * well currently, as it will just keep failing over and over.
1147    */
1148
1149   if (d->policy == NULL)
1150     {
1151       _dbus_verbose ("Failed to create security policy for connection %p\n",
1152                      connection);
1153       _DBUS_ASSERT_ERROR_IS_SET (error);
1154       dbus_free (d->name);
1155       d->name = NULL;
1156       return FALSE;
1157     }
1158   
1159   if (dbus_connection_get_unix_user (connection, &uid))
1160     {
1161       if (!adjust_connections_for_uid (d->connections,
1162                                        uid, 1))
1163         {
1164           BUS_SET_OOM (error);
1165           dbus_free (d->name);
1166           d->name = NULL;
1167           return FALSE;
1168         }
1169     }
1170   
1171   /* Now the connection is active, move it between lists */
1172   _dbus_list_unlink (&d->connections->incomplete,
1173                      d->link_in_connection_list);
1174   d->connections->n_incomplete -= 1;
1175   _dbus_list_append_link (&d->connections->completed,
1176                           d->link_in_connection_list);
1177   d->connections->n_completed += 1;
1178
1179   _dbus_assert (d->connections->n_incomplete >= 0);
1180   _dbus_assert (d->connections->n_completed > 0);
1181
1182   /* See if we can remove the timeout */
1183   bus_connections_expire_incomplete (d->connections);
1184   
1185   return TRUE;
1186 }
1187
1188 const char *
1189 bus_connection_get_name (DBusConnection *connection)
1190 {
1191   BusConnectionData *d;
1192   
1193   d = BUS_CONNECTION_DATA (connection);
1194   _dbus_assert (d != NULL);
1195   
1196   return d->name;
1197 }
1198
1199 /**
1200  * Check whether completing the passed-in connection would
1201  * exceed limits, and if so set error and return #FALSE
1202  */
1203 dbus_bool_t
1204 bus_connections_check_limits (BusConnections  *connections,
1205                               DBusConnection  *requesting_completion,
1206                               DBusError       *error)
1207 {
1208   BusConnectionData *d;
1209   unsigned long uid;
1210   
1211   d = BUS_CONNECTION_DATA (requesting_completion);
1212   _dbus_assert (d != NULL);
1213
1214   _dbus_assert (d->name == NULL);
1215
1216   if (connections->n_completed >=
1217       bus_context_get_max_completed_connections (connections->context))
1218     {
1219       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1220                       "The maximum number of active connections has been reached");
1221       return FALSE;
1222     }
1223   
1224   if (dbus_connection_get_unix_user (requesting_completion, &uid))
1225     {
1226       if (get_connections_for_uid (connections, uid) >=
1227           bus_context_get_max_connections_per_user (connections->context))
1228         {
1229           dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1230                           "The maximum number of active connections for UID %lu has been reached",
1231                           uid);
1232           return FALSE;
1233         }
1234     }
1235   
1236   return TRUE;
1237 }
1238
1239
1240 /*
1241  * Transactions
1242  *
1243  * Note that this is fairly fragile; in particular, don't try to use
1244  * one transaction across any main loop iterations.
1245  */
1246
1247 typedef struct
1248 {
1249   BusTransaction *transaction;
1250   DBusMessage    *message;
1251   DBusPreallocatedSend *preallocated;
1252 } MessageToSend;
1253
1254 typedef struct
1255 {
1256   BusTransactionCancelFunction cancel_function;
1257   DBusFreeFunction free_data_function;
1258   void *data;
1259 } CancelHook;
1260
1261 struct BusTransaction
1262 {
1263   DBusList *connections;
1264   BusContext *context;
1265   DBusList *cancel_hooks;
1266 };
1267
1268 static void
1269 message_to_send_free (DBusConnection *connection,
1270                       MessageToSend  *to_send)
1271 {
1272   if (to_send->message)
1273     dbus_message_unref (to_send->message);
1274
1275   if (to_send->preallocated)
1276     dbus_connection_free_preallocated_send (connection, to_send->preallocated);
1277
1278   dbus_free (to_send);
1279 }
1280
1281 static void
1282 cancel_hook_cancel (void *element,
1283                     void *data)
1284 {
1285   CancelHook *ch = element;
1286
1287   _dbus_verbose ("Running transaction cancel hook\n");
1288   
1289   if (ch->cancel_function)
1290     (* ch->cancel_function) (ch->data);  
1291 }
1292
1293 static void
1294 cancel_hook_free (void *element,
1295                   void *data)
1296 {
1297   CancelHook *ch = element;
1298
1299   if (ch->free_data_function)
1300     (* ch->free_data_function) (ch->data);
1301
1302   dbus_free (ch);
1303 }
1304
1305 static void
1306 free_cancel_hooks (BusTransaction *transaction)
1307 {
1308   _dbus_list_foreach (&transaction->cancel_hooks,
1309                       cancel_hook_free, NULL);
1310   
1311   _dbus_list_clear (&transaction->cancel_hooks);
1312 }
1313
1314 BusTransaction*
1315 bus_transaction_new (BusContext *context)
1316 {
1317   BusTransaction *transaction;
1318
1319   transaction = dbus_new0 (BusTransaction, 1);
1320   if (transaction == NULL)
1321     return NULL;
1322
1323   transaction->context = context;
1324   
1325   return transaction;
1326 }
1327
1328 BusContext*
1329 bus_transaction_get_context (BusTransaction  *transaction)
1330 {
1331   return transaction->context;
1332 }
1333
1334 BusConnections*
1335 bus_transaction_get_connections (BusTransaction  *transaction)
1336 {
1337   return bus_context_get_connections (transaction->context);
1338 }
1339
1340 dbus_bool_t
1341 bus_transaction_send_from_driver (BusTransaction *transaction,
1342                                   DBusConnection *connection,
1343                                   DBusMessage    *message)
1344 {
1345   /* We have to set the sender to the driver, and have
1346    * to check security policy since it was not done in
1347    * dispatch.c
1348    */
1349   _dbus_verbose ("Sending %s from driver\n",
1350                  dbus_message_get_name (message));
1351   
1352   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
1353     return FALSE;
1354
1355   /* If security policy doesn't allow the message, we silently
1356    * eat it; the driver doesn't care about getting a reply.
1357    */
1358   if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
1359                                           NULL, connection, message, NULL))
1360     return TRUE;
1361
1362   return bus_transaction_send (transaction, connection, message);
1363 }
1364
1365 dbus_bool_t
1366 bus_transaction_send (BusTransaction *transaction,
1367                       DBusConnection *connection,
1368                       DBusMessage    *message)
1369 {
1370   MessageToSend *to_send;
1371   BusConnectionData *d;
1372   DBusList *link;
1373
1374   _dbus_verbose ("  trying to add %s %s to transaction%s\n",
1375                  dbus_message_get_is_error (message) ? "error" :
1376                  dbus_message_get_reply_serial (message) != 0 ? "reply" :
1377                  "message",
1378                  dbus_message_get_name (message),
1379                  dbus_connection_get_is_connected (connection) ?
1380                  "" : " (disconnected)");
1381
1382   _dbus_assert (dbus_message_get_sender (message) != NULL);
1383   
1384   if (!dbus_connection_get_is_connected (connection))
1385     return TRUE; /* silently ignore disconnected connections */
1386   
1387   d = BUS_CONNECTION_DATA (connection);
1388   _dbus_assert (d != NULL);
1389   
1390   to_send = dbus_new (MessageToSend, 1);
1391   if (to_send == NULL)
1392     {
1393       return FALSE;
1394     }
1395
1396   to_send->preallocated = dbus_connection_preallocate_send (connection);
1397   if (to_send->preallocated == NULL)
1398     {
1399       dbus_free (to_send);
1400       return FALSE;
1401     }  
1402   
1403   dbus_message_ref (message);
1404   to_send->message = message;
1405   to_send->transaction = transaction;
1406
1407   _dbus_verbose ("about to prepend message\n");
1408   
1409   if (!_dbus_list_prepend (&d->transaction_messages, to_send))
1410     {
1411       message_to_send_free (connection, to_send);
1412       return FALSE;
1413     }
1414
1415   _dbus_verbose ("prepended message\n");
1416   
1417   /* See if we already had this connection in the list
1418    * for this transaction. If we have a pending message,
1419    * then we should already be in transaction->connections
1420    */
1421   link = _dbus_list_get_first_link (&d->transaction_messages);
1422   _dbus_assert (link->data == to_send);
1423   link = _dbus_list_get_next_link (&d->transaction_messages, link);
1424   while (link != NULL)
1425     {
1426       MessageToSend *m = link->data;
1427       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
1428       
1429       if (m->transaction == transaction)
1430         break;
1431         
1432       link = next;
1433     }
1434
1435   if (link == NULL)
1436     {
1437       if (!_dbus_list_prepend (&transaction->connections, connection))
1438         {
1439           _dbus_list_remove (&d->transaction_messages, to_send);
1440           message_to_send_free (connection, to_send);
1441           return FALSE;
1442         }
1443     }
1444
1445   return TRUE;
1446 }
1447
1448 static void
1449 connection_cancel_transaction (DBusConnection *connection,
1450                                BusTransaction *transaction)
1451 {
1452   DBusList *link;
1453   BusConnectionData *d;
1454   
1455   d = BUS_CONNECTION_DATA (connection);
1456   _dbus_assert (d != NULL);
1457   
1458   link = _dbus_list_get_first_link (&d->transaction_messages);
1459   while (link != NULL)
1460     {
1461       MessageToSend *m = link->data;
1462       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
1463       
1464       if (m->transaction == transaction)
1465         {
1466           _dbus_list_remove_link (&d->transaction_messages,
1467                                   link);
1468           
1469           message_to_send_free (connection, m);
1470         }
1471         
1472       link = next;
1473     }
1474 }
1475
1476 void
1477 bus_transaction_cancel_and_free (BusTransaction *transaction)
1478 {
1479   DBusConnection *connection;
1480
1481   _dbus_verbose ("TRANSACTION: cancelled\n");
1482   
1483   while ((connection = _dbus_list_pop_first (&transaction->connections)))
1484     connection_cancel_transaction (connection, transaction);
1485
1486   _dbus_assert (transaction->connections == NULL);
1487
1488   _dbus_list_foreach (&transaction->cancel_hooks,
1489                       cancel_hook_cancel, NULL);
1490
1491   free_cancel_hooks (transaction);
1492   
1493   dbus_free (transaction);
1494 }
1495
1496 static void
1497 connection_execute_transaction (DBusConnection *connection,
1498                                 BusTransaction *transaction)
1499 {
1500   DBusList *link;
1501   BusConnectionData *d;
1502   
1503   d = BUS_CONNECTION_DATA (connection);
1504   _dbus_assert (d != NULL);
1505
1506   /* Send the queue in order (FIFO) */
1507   link = _dbus_list_get_last_link (&d->transaction_messages);
1508   while (link != NULL)
1509     {
1510       MessageToSend *m = link->data;
1511       DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
1512       
1513       if (m->transaction == transaction)
1514         {
1515           _dbus_list_remove_link (&d->transaction_messages,
1516                                   link);
1517
1518           _dbus_assert (dbus_message_get_sender (m->message) != NULL);
1519           
1520           dbus_connection_send_preallocated (connection,
1521                                              m->preallocated,
1522                                              m->message,
1523                                              NULL);
1524
1525           m->preallocated = NULL; /* so we don't double-free it */
1526           
1527           message_to_send_free (connection, m);
1528         }
1529         
1530       link = prev;
1531     }
1532 }
1533
1534 void
1535 bus_transaction_execute_and_free (BusTransaction *transaction)
1536 {
1537   /* For each connection in transaction->connections
1538    * send the messages
1539    */
1540   DBusConnection *connection;
1541
1542   _dbus_verbose ("TRANSACTION: executing\n");
1543   
1544   while ((connection = _dbus_list_pop_first (&transaction->connections)))
1545     connection_execute_transaction (connection, transaction);
1546
1547   _dbus_assert (transaction->connections == NULL);
1548
1549   free_cancel_hooks (transaction);
1550   
1551   dbus_free (transaction);
1552 }
1553
1554 static void
1555 bus_connection_remove_transactions (DBusConnection *connection)
1556 {
1557   MessageToSend *to_send;
1558   BusConnectionData *d;
1559   
1560   d = BUS_CONNECTION_DATA (connection);
1561   _dbus_assert (d != NULL);
1562   
1563   while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
1564     {
1565       /* only has an effect for the first MessageToSend listing this transaction */
1566       _dbus_list_remove (&to_send->transaction->connections,
1567                          connection);
1568
1569       _dbus_list_remove (&d->transaction_messages, to_send);
1570       message_to_send_free (connection, to_send);
1571     }
1572 }
1573
1574 /**
1575  * Converts the DBusError to a message reply
1576  */
1577 dbus_bool_t
1578 bus_transaction_send_error_reply (BusTransaction  *transaction,
1579                                   DBusConnection  *connection,
1580                                   const DBusError *error,
1581                                   DBusMessage     *in_reply_to)
1582 {
1583   DBusMessage *reply;
1584   
1585   _dbus_assert (error != NULL);
1586   _DBUS_ASSERT_ERROR_IS_SET (error);
1587
1588   _dbus_verbose ("Sending error reply %s \"%s\"\n",
1589                  error->name, error->message);
1590
1591   reply = dbus_message_new_error_reply (in_reply_to,
1592                                         error->name,
1593                                         error->message);
1594   if (reply == NULL)
1595     return FALSE;
1596
1597   if (!bus_transaction_send_from_driver (transaction, connection, reply))
1598     {
1599       dbus_message_unref (reply);
1600       return FALSE;
1601     }
1602
1603   dbus_message_unref (reply);
1604   
1605   return TRUE;
1606 }
1607
1608 dbus_bool_t
1609 bus_transaction_add_cancel_hook (BusTransaction               *transaction,
1610                                  BusTransactionCancelFunction  cancel_function,
1611                                  void                         *data,
1612                                  DBusFreeFunction              free_data_function)
1613 {
1614   CancelHook *ch;
1615
1616   ch = dbus_new (CancelHook, 1);
1617   if (ch == NULL)
1618     return FALSE;
1619   
1620   ch->cancel_function = cancel_function;
1621   ch->data = data;
1622   ch->free_data_function = free_data_function;
1623
1624   /* It's important that the hooks get run in reverse order that they
1625    * were added
1626    */
1627   if (!_dbus_list_prepend (&transaction->cancel_hooks, ch))
1628     {
1629       dbus_free (ch);
1630       return FALSE;
1631     }
1632
1633   return TRUE;
1634 }