Working: - dbus authorization replaced by kdbus policies
[platform/upstream/dbus.git] / dbus / dbus-transport.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-transport.c DBusTransport object (internal to D-Bus implementation)
3  *
4  * Copyright (C) 2002, 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 "dbus-transport-protected.h"
26 #include "dbus-transport-unix.h"
27 #include "dbus-transport-socket.h"
28 #include "dbus-connection-internal.h"
29 #include "dbus-watch.h"
30 #include "dbus-auth.h"
31 #include "dbus-address.h"
32 #include "dbus-credentials.h"
33 #include "dbus-mainloop.h"
34 #include "dbus-message.h"
35
36 #include "dbus-transport-kdbus.h"
37 #ifdef DBUS_BUILD_TESTS
38 #include "dbus-server-debug-pipe.h"
39 #endif
40
41 /**
42  * @defgroup DBusTransport DBusTransport object
43  * @ingroup  DBusInternals
44  * @brief "Backend" for a DBusConnection.
45  *
46  * Types and functions related to DBusTransport.  A transport is an
47  * abstraction that can send and receive data via various kinds of
48  * network connections or other IPC mechanisms.
49  * 
50  * @{
51  */
52
53 /**
54  * @typedef DBusTransport
55  *
56  * Opaque object representing a way message stream.
57  * DBusTransport abstracts various kinds of actual
58  * transport mechanism, such as different network protocols,
59  * or encryption schemes.
60  */
61
62 static void
63 live_messages_notify (DBusCounter *counter,
64                            void        *user_data)
65 {
66   DBusTransport *transport = user_data;
67
68   _dbus_transport_ref (transport);
69
70 #if 0
71   _dbus_verbose ("Size counter value is now %d\n",
72                  (int) _dbus_counter_get_size_value (counter));
73   _dbus_verbose ("Unix FD counter value is now %d\n",
74                  (int) _dbus_counter_get_unix_fd_value (counter));
75 #endif
76
77   /* disable or re-enable the read watch for the transport if
78    * required.
79    */
80   if (transport->vtable->live_messages_changed)
81     {
82       _dbus_connection_lock (transport->connection);
83       (* transport->vtable->live_messages_changed) (transport);
84       _dbus_connection_unlock (transport->connection);
85     }
86
87   _dbus_transport_unref (transport);
88 }
89
90 /**
91  * Initializes the base class members of DBusTransport.  Chained up to
92  * by subclasses in their constructor.  The server GUID is the
93  * globally unique ID for the server creating this connection
94  * and will be #NULL for the client side of a connection. The GUID
95  * is in hex format.
96  *
97  * @param transport the transport being created.
98  * @param vtable the subclass vtable.
99  * @param server_guid non-#NULL if this transport is on the server side of a connection
100  * @param address the address of the transport
101  * @returns #TRUE on success.
102  */
103 dbus_bool_t
104 _dbus_transport_init_base (DBusTransport             *transport,
105                            const DBusTransportVTable *vtable,
106                            const DBusString          *server_guid,
107                            const DBusString          *address)
108 {
109   DBusMessageLoader *loader;
110   DBusAuth *auth;
111   DBusCounter *counter;
112   char *address_copy;
113   DBusCredentials *creds;
114   
115   loader = _dbus_message_loader_new ();
116   if (loader == NULL)
117     return FALSE;
118   
119   if (server_guid)
120     auth = _dbus_auth_server_new (server_guid);
121   else
122   {
123           _dbus_assert (address != NULL);
124           if (!_dbus_string_copy_data (address, &address_copy))
125         {
126           _dbus_message_loader_unref (loader);
127           return FALSE;
128         }
129       if(address_copy == strstr(address_copy, "kdbus:path="))
130           auth = _dbus_auth_client_new_kdbus();
131           else
132                   auth = _dbus_auth_client_new ();
133   }
134
135   if (auth == NULL)
136     {
137       _dbus_message_loader_unref (loader);
138       return FALSE;
139     }
140
141   counter = _dbus_counter_new ();
142   if (counter == NULL)
143     {
144       _dbus_auth_unref (auth);
145       _dbus_message_loader_unref (loader);
146       return FALSE;
147     }  
148
149   creds = _dbus_credentials_new ();
150   if (creds == NULL)
151     {
152       _dbus_counter_unref (counter);
153       _dbus_auth_unref (auth);
154       _dbus_message_loader_unref (loader);
155       return FALSE;
156     }
157   
158   if (server_guid)
159     {
160       _dbus_assert (address == NULL);
161       address_copy = NULL;
162     }
163   else
164     {
165       _dbus_assert (address != NULL);  /*TODO duplicated above in that function because of kdbus
166       maybe to be optimized when final kdbus authorization will be done */
167       if (!_dbus_string_copy_data (address, &address_copy))
168         {
169           _dbus_credentials_unref (creds);
170           _dbus_counter_unref (counter);
171           _dbus_auth_unref (auth);
172           _dbus_message_loader_unref (loader);
173           return FALSE;
174         }
175     }
176   
177   transport->refcount = 1;
178   transport->vtable = vtable;
179   transport->loader = loader;
180   transport->auth = auth;
181   transport->live_messages = counter;
182   transport->authenticated = FALSE;
183   transport->disconnected = FALSE;
184   transport->is_server = (server_guid != NULL);
185   transport->send_credentials_pending = !transport->is_server;
186   transport->receive_credentials_pending = transport->is_server;
187   transport->address = address_copy;
188   
189   transport->unix_user_function = NULL;
190   transport->unix_user_data = NULL;
191   transport->free_unix_user_data = NULL;
192
193   transport->windows_user_function = NULL;
194   transport->windows_user_data = NULL;
195   transport->free_windows_user_data = NULL;
196   
197   transport->expected_guid = NULL;
198   
199   /* Try to default to something that won't totally hose the system,
200    * but doesn't impose too much of a limitation.
201    */
202   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
203
204   /* On Linux RLIMIT_NOFILE defaults to 1024, so allowing 4096 fds live
205      should be more than enough */
206   transport->max_live_messages_unix_fds = 4096;
207
208   /* credentials read from socket if any */
209   transport->credentials = creds;
210
211   _dbus_counter_set_notify (transport->live_messages,
212                             transport->max_live_messages_size,
213                             transport->max_live_messages_unix_fds,
214                             live_messages_notify,
215                             transport);
216
217   if (transport->address)
218     _dbus_verbose ("Initialized transport on address %s\n", transport->address);
219
220   return TRUE;
221 }
222
223 /**
224  * Finalizes base class members of DBusTransport.
225  * Chained up to from subclass finalizers.
226  *
227  * @param transport the transport.
228  */
229 void
230 _dbus_transport_finalize_base (DBusTransport *transport)
231 {
232   if (!transport->disconnected)
233     _dbus_transport_disconnect (transport);
234
235   if (transport->free_unix_user_data != NULL)
236     (* transport->free_unix_user_data) (transport->unix_user_data);
237
238   if (transport->free_windows_user_data != NULL)
239     (* transport->free_windows_user_data) (transport->windows_user_data);
240   
241   _dbus_message_loader_unref (transport->loader);
242   _dbus_auth_unref (transport->auth);
243   _dbus_counter_set_notify (transport->live_messages,
244                             0, 0, NULL, NULL);
245   _dbus_counter_unref (transport->live_messages);
246   dbus_free (transport->address);
247   dbus_free (transport->expected_guid);
248   if (transport->credentials)
249     _dbus_credentials_unref (transport->credentials);
250 }
251
252
253 /**
254  * Verifies if a given D-Bus address is a valid address
255  * by attempting to connect to it. If it is, returns the
256  * opened DBusTransport object. If it isn't, returns #NULL
257  * and sets @p error.
258  *
259  * @param error address where an error can be returned.
260  * @returns a new transport, or #NULL on failure.
261  */
262 static DBusTransport*
263 check_address (const char *address, DBusError *error)
264 {
265   DBusAddressEntry **entries;
266   DBusTransport *transport = NULL;
267   int len, i;
268
269   _dbus_assert (address != NULL);
270
271   if (!dbus_parse_address (address, &entries, &len, error))
272     return NULL;              /* not a valid address */
273
274   for (i = 0; i < len; i++)
275     {
276       transport = _dbus_transport_open (entries[i], error);
277       if (transport != NULL)
278         break;
279     }
280
281   dbus_address_entries_free (entries);
282   return transport;
283 }
284
285 /**
286  * Creates a new transport for the "autostart" method.
287  * This creates a client-side of a transport.
288  *
289  * @param error address where an error can be returned.
290  * @returns a new transport, or #NULL on failure.
291  */
292 static DBusTransport*
293 _dbus_transport_new_for_autolaunch (const char *scope, DBusError *error)
294 {
295   DBusString address;
296   DBusTransport *result = NULL;
297
298   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
299
300   if (!_dbus_string_init (&address))
301     {
302       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
303       return NULL;
304     }
305
306   if (!_dbus_get_autolaunch_address (scope, &address, error))
307     {
308       _DBUS_ASSERT_ERROR_IS_SET (error);
309       goto out;
310     }
311
312   result = check_address (_dbus_string_get_const_data (&address), error);
313   if (result == NULL)
314     _DBUS_ASSERT_ERROR_IS_SET (error);
315   else
316     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
317
318  out:
319   _dbus_string_free (&address);
320   return result;
321 }
322
323 static DBusTransportOpenResult
324 _dbus_transport_open_autolaunch (DBusAddressEntry  *entry,
325                                  DBusTransport    **transport_p,
326                                  DBusError         *error)
327 {
328   const char *method;
329   
330   method = dbus_address_entry_get_method (entry);
331   _dbus_assert (method != NULL);
332
333   if (strcmp (method, "autolaunch") == 0)
334     {
335       const char *scope = dbus_address_entry_get_value (entry, "scope");
336
337       *transport_p = _dbus_transport_new_for_autolaunch (scope, error);
338
339       if (*transport_p == NULL)
340         {
341           _DBUS_ASSERT_ERROR_IS_SET (error);
342           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
343         }
344       else
345         {
346           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
347           return DBUS_TRANSPORT_OPEN_OK;
348         }      
349     }
350   else
351     {
352       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
353       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
354     }
355 }
356
357 static const struct {
358   DBusTransportOpenResult (* func) (DBusAddressEntry *entry,
359                                     DBusTransport   **transport_p,
360                                     DBusError        *error);
361 } open_funcs[] = {
362   { _dbus_transport_open_socket },
363   { _dbus_transport_open_platform_specific },
364   { _dbus_transport_open_kdbus },
365   { _dbus_transport_open_autolaunch }
366 #ifdef DBUS_BUILD_TESTS
367   , { _dbus_transport_open_debug_pipe }
368 #endif
369 };
370
371 /**
372  * Try to open a new transport for the given address entry.  (This
373  * opens a client-side-of-the-connection transport.)
374  * 
375  * @param entry the address entry
376  * @param error location to store reason for failure.
377  * @returns new transport of #NULL on failure.
378  */
379 DBusTransport*
380 _dbus_transport_open (DBusAddressEntry *entry,
381                       DBusError        *error)
382 {
383   DBusTransport *transport;
384   const char *expected_guid_orig;
385   char *expected_guid;
386   int i;
387   DBusError tmp_error = DBUS_ERROR_INIT;
388
389   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
390   
391   transport = NULL;
392   expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
393   expected_guid = _dbus_strdup (expected_guid_orig);
394
395   if (expected_guid_orig != NULL && expected_guid == NULL)
396     {
397       _DBUS_SET_OOM (error);
398       return NULL;
399     }
400
401   for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
402     {
403       DBusTransportOpenResult result;
404
405       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
406       result = (* open_funcs[i].func) (entry, &transport, &tmp_error);
407
408       switch (result)
409         {
410         case DBUS_TRANSPORT_OPEN_OK:
411           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
412           goto out;
413           break;
414         case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
415           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
416           /* keep going through the loop of open funcs */
417           break;
418         case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
419           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
420           goto out;
421           break;
422         case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
423           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
424           goto out;
425           break;
426         }
427     }
428
429  out:
430   
431   if (transport == NULL)
432     {
433       if (!dbus_error_is_set (&tmp_error))
434         _dbus_set_bad_address (&tmp_error,
435                                NULL, NULL,
436                                "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
437       
438       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
439       dbus_move_error(&tmp_error, error);
440       dbus_free (expected_guid);
441     }
442   else
443     {
444       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
445
446       /* In the case of autostart the initial guid is NULL
447        * and the autostart transport recursively calls
448        * _dbus_open_transport wich returns a transport
449        * with a guid.  That guid is the definitive one.
450        *
451        * FIXME: if more transports are added they may have
452        * an effect on the expected_guid semantics (i.e. 
453        * expected_guid and transport->expected_guid may
454        * both have values).  This is very unlikely though
455        * we should either throw asserts here for those 
456        * corner cases or refactor the code so it is 
457        * clearer on what is expected and what is not
458        */
459       if(expected_guid)
460         transport->expected_guid = expected_guid;
461     }
462
463   return transport;
464 }
465
466 /**
467  * Increments the reference count for the transport.
468  *
469  * @param transport the transport.
470  * @returns the transport.
471  */
472 DBusTransport *
473 _dbus_transport_ref (DBusTransport *transport)
474 {
475   _dbus_assert (transport->refcount > 0);
476   
477   transport->refcount += 1;
478
479   return transport;
480 }
481
482 /**
483  * Decrements the reference count for the transport.
484  * Disconnects and finalizes the transport if
485  * the reference count reaches zero.
486  *
487  * @param transport the transport.
488  */
489 void
490 _dbus_transport_unref (DBusTransport *transport)
491 {
492   _dbus_assert (transport != NULL);
493   _dbus_assert (transport->refcount > 0);
494   
495   transport->refcount -= 1;
496   if (transport->refcount == 0)
497     {
498       _dbus_verbose ("finalizing\n");
499       
500       _dbus_assert (transport->vtable->finalize != NULL);
501       
502       (* transport->vtable->finalize) (transport);
503     }
504 }
505
506 /**
507  * Closes our end of the connection to a remote application. Further
508  * attempts to use this transport will fail. Only the first call to
509  * _dbus_transport_disconnect() will have an effect.
510  *
511  * @param transport the transport.
512  * 
513  */
514 void
515 _dbus_transport_disconnect (DBusTransport *transport)
516 {
517   _dbus_verbose ("start\n");
518   
519   _dbus_assert (transport->vtable->disconnect != NULL);
520   
521   if (transport->disconnected)
522     return;
523
524   (* transport->vtable->disconnect) (transport);
525   
526   transport->disconnected = TRUE;
527
528   _dbus_verbose ("end\n");
529 }
530
531 /**
532  * Returns #TRUE if the transport has not been disconnected.
533  * Disconnection can result from _dbus_transport_disconnect()
534  * or because the server drops its end of the connection.
535  *
536  * @param transport the transport.
537  * @returns whether we're connected
538  */
539 dbus_bool_t
540 _dbus_transport_get_is_connected (DBusTransport *transport)
541 {
542   return !transport->disconnected;
543 }
544
545 static dbus_bool_t
546 auth_via_unix_user_function (DBusTransport *transport)
547 {
548   DBusCredentials *auth_identity;
549   dbus_bool_t allow;
550   DBusConnection *connection;
551   DBusAllowUnixUserFunction unix_user_function;
552   void *unix_user_data;
553   dbus_uid_t uid;
554
555   /* Dropping the lock here probably isn't that safe. */
556   
557   auth_identity = _dbus_auth_get_identity (transport->auth);
558   _dbus_assert (auth_identity != NULL);
559
560   connection = transport->connection;
561   unix_user_function = transport->unix_user_function;
562   unix_user_data = transport->unix_user_data;
563   uid = _dbus_credentials_get_unix_uid (auth_identity);
564               
565   _dbus_verbose ("unlock\n");
566   _dbus_connection_unlock (connection);
567
568   allow = (* unix_user_function) (connection,
569                                   uid,
570                                   unix_user_data);
571               
572   _dbus_verbose ("lock post unix user function\n");
573   _dbus_connection_lock (connection);
574
575   if (allow)
576     {
577       _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
578     }
579   else
580     {
581       _dbus_verbose ("Client UID "DBUS_UID_FORMAT
582                      " was rejected, disconnecting\n",
583                      _dbus_credentials_get_unix_uid (auth_identity));
584       _dbus_transport_disconnect (transport);
585     }
586
587   return allow;
588 }
589
590 static dbus_bool_t
591 auth_via_windows_user_function (DBusTransport *transport)
592 {
593   DBusCredentials *auth_identity;  
594   dbus_bool_t allow;
595   DBusConnection *connection;
596   DBusAllowWindowsUserFunction windows_user_function;
597   void *windows_user_data;
598   char *windows_sid;
599
600   /* Dropping the lock here probably isn't that safe. */
601   
602   auth_identity = _dbus_auth_get_identity (transport->auth);
603   _dbus_assert (auth_identity != NULL);
604
605   connection = transport->connection;
606   windows_user_function = transport->windows_user_function;
607   windows_user_data = transport->unix_user_data;
608   windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
609
610   if (windows_sid == NULL)
611     {
612       /* OOM */
613       return FALSE;
614     }
615                 
616   _dbus_verbose ("unlock\n");
617   _dbus_connection_unlock (connection);
618
619   allow = (* windows_user_function) (connection,
620                                      windows_sid,
621                                      windows_user_data);
622               
623   _dbus_verbose ("lock post windows user function\n");
624   _dbus_connection_lock (connection);
625
626   if (allow)
627     {
628       _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
629     }
630   else
631     {
632       _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
633                      _dbus_credentials_get_windows_sid (auth_identity));
634       _dbus_transport_disconnect (transport);
635     }
636
637   return allow;
638 }
639
640 static dbus_bool_t
641 auth_via_default_rules (DBusTransport *transport)
642 {
643   DBusCredentials *auth_identity;
644   DBusCredentials *our_identity;
645   dbus_bool_t allow;
646   
647   auth_identity = _dbus_auth_get_identity (transport->auth);
648   _dbus_assert (auth_identity != NULL);
649
650   /* By default, connection is allowed if the client is 1) root or 2)
651    * has the same UID as us or 3) anonymous is allowed.
652    */
653   
654   our_identity = _dbus_credentials_new_from_current_process ();
655   if (our_identity == NULL)
656     {
657       /* OOM */
658       return FALSE;
659     }
660               
661   if (transport->allow_anonymous ||
662       _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
663       _dbus_credentials_same_user (our_identity,
664                                    auth_identity))
665     {
666       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
667           _dbus_verbose ("Client authorized as SID '%s'"
668                          "matching our SID '%s'\n",
669                          _dbus_credentials_get_windows_sid(auth_identity),
670                          _dbus_credentials_get_windows_sid(our_identity));
671       else
672           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
673                          " matching our UID "DBUS_UID_FORMAT"\n",
674                          _dbus_credentials_get_unix_uid(auth_identity),
675                          _dbus_credentials_get_unix_uid(our_identity));
676       /* We have authenticated! */
677       allow = TRUE;
678     }
679   else
680     {
681       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
682           _dbus_verbose ("Client authorized as SID '%s'"
683                          " but our SID is '%s', disconnecting\n",
684                          (_dbus_credentials_get_windows_sid(auth_identity) ?
685                           _dbus_credentials_get_windows_sid(auth_identity) : "<null>"),
686                          (_dbus_credentials_get_windows_sid(our_identity) ?
687                           _dbus_credentials_get_windows_sid(our_identity) : "<null>"));
688       else
689           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
690                          " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
691                          _dbus_credentials_get_unix_uid(auth_identity),
692                          _dbus_credentials_get_unix_uid(our_identity));
693       _dbus_transport_disconnect (transport);
694       allow = FALSE;
695     }  
696
697   _dbus_credentials_unref (our_identity);
698   
699   return allow;
700 }
701
702
703 /**
704  * Returns #TRUE if we have been authenticated.  Will return #TRUE
705  * even if the transport is disconnected.
706  *
707  * @todo we drop connection->mutex when calling the unix_user_function,
708  * and windows_user_function, which may not be safe really.
709  *
710  * @param transport the transport
711  * @returns whether we're authenticated
712  */
713 dbus_bool_t
714 _dbus_transport_get_is_authenticated (DBusTransport *transport)
715 {  
716   if (transport->authenticated)
717     return TRUE;
718   else
719     {
720       dbus_bool_t maybe_authenticated;
721       
722       if (transport->disconnected)
723         return FALSE;
724
725       /* paranoia ref since we call user callbacks sometimes */
726       _dbus_connection_ref_unlocked (transport->connection);
727       
728       maybe_authenticated =
729         (!(transport->send_credentials_pending ||
730            transport->receive_credentials_pending));
731
732       if (maybe_authenticated)
733         {
734           switch (_dbus_auth_do_work (transport->auth))
735             {
736             case DBUS_AUTH_STATE_AUTHENTICATED:
737               /* leave as maybe_authenticated */
738               break;
739             default:
740               maybe_authenticated = FALSE;
741             }
742         }
743
744       /* If we're the client, verify the GUID
745        */
746       if (maybe_authenticated && !transport->is_server)
747         {
748           const char *server_guid;
749
750           server_guid = _dbus_auth_get_guid_from_server (transport->auth);
751           _dbus_assert (server_guid != NULL);
752
753           if (transport->expected_guid &&
754               strcmp (transport->expected_guid, server_guid) != 0)
755             {
756               _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
757                              transport->expected_guid, server_guid);
758               _dbus_transport_disconnect (transport);
759               _dbus_connection_unref_unlocked (transport->connection);
760               return FALSE;
761             }
762         }
763
764       /* If we're the server, see if we want to allow this identity to proceed.
765        */
766       if (maybe_authenticated && transport->is_server)
767         {
768           dbus_bool_t allow;
769           DBusCredentials *auth_identity;
770           
771           auth_identity = _dbus_auth_get_identity (transport->auth);
772           _dbus_assert (auth_identity != NULL);
773           
774           /* If we have an auth'd user and a user function, delegate
775            * deciding whether auth credentials are good enough to the
776            * app; otherwise, use our default decision process.
777            */
778           if (transport->unix_user_function != NULL &&
779               _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
780             {
781               allow = auth_via_unix_user_function (transport);
782             }
783           else if (transport->windows_user_function != NULL &&
784                    _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
785             {
786               allow = auth_via_windows_user_function (transport);
787             }      
788           else
789             {
790               allow = auth_via_default_rules (transport);
791             }
792           
793           if (!allow)
794             maybe_authenticated = FALSE;
795         }
796
797       transport->authenticated = maybe_authenticated;
798
799       _dbus_connection_unref_unlocked (transport->connection);
800       return maybe_authenticated;
801     }
802 }
803
804 /**
805  * See dbus_connection_get_is_anonymous().
806  *
807  * @param transport the transport
808  * @returns #TRUE if not authenticated or authenticated as anonymous
809  */
810 dbus_bool_t
811 _dbus_transport_get_is_anonymous (DBusTransport *transport)
812 {
813   DBusCredentials *auth_identity;
814   
815   if (!transport->authenticated)
816     return TRUE;
817   
818   auth_identity = _dbus_auth_get_identity (transport->auth);
819
820   if (_dbus_credentials_are_anonymous (auth_identity))
821     return TRUE;
822   else
823     return FALSE;
824 }
825
826 /**
827  * Returns TRUE if the transport supports sending unix fds.
828  *
829  * @param transport the transport
830  * @returns #TRUE if TRUE it is possible to send unix fds across the transport.
831  */
832 dbus_bool_t
833 _dbus_transport_can_pass_unix_fd(DBusTransport *transport)
834 {
835   return DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport);
836 }
837
838 /**
839  * Gets the address of a transport. It will be
840  * #NULL for a server-side transport.
841  *
842  * @param transport the transport
843  * @returns transport's address
844  */
845 const char*
846 _dbus_transport_get_address (DBusTransport *transport)
847 {
848   return transport->address;
849 }
850
851 /**
852  * Gets the id of the server we are connected to (see
853  * dbus_server_get_id()). Only works on client side.
854  *
855  * @param transport the transport
856  * @returns transport's server's id or #NULL if we are the server side
857  */
858 const char*
859 _dbus_transport_get_server_id (DBusTransport *transport)
860 {
861   if (transport->is_server)
862     return NULL;
863   else if (transport->authenticated)
864     return _dbus_auth_get_guid_from_server (transport->auth);
865   else
866     return transport->expected_guid;
867 }
868
869 /**
870  * Handles a watch by reading data, writing data, or disconnecting
871  * the transport, as appropriate for the given condition.
872  *
873  * @param transport the transport.
874  * @param watch the watch.
875  * @param condition the current state of the watched file descriptor.
876  * @returns #FALSE if not enough memory to fully handle the watch
877  */
878 dbus_bool_t
879 _dbus_transport_handle_watch (DBusTransport           *transport,
880                               DBusWatch               *watch,
881                               unsigned int             condition)
882 {
883   dbus_bool_t retval;
884   
885   _dbus_assert (transport->vtable->handle_watch != NULL);
886
887   if (transport->disconnected)
888     return TRUE;
889
890   if (dbus_watch_get_socket (watch) < 0)
891     {
892       _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
893       return TRUE;
894     }
895   
896   _dbus_watch_sanitize_condition (watch, &condition);
897
898   _dbus_transport_ref (transport);
899   _dbus_watch_ref (watch);
900   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
901   _dbus_watch_unref (watch);
902   _dbus_transport_unref (transport);
903
904   return retval;
905 }
906
907 /**
908  * Sets the connection using this transport. Allows the transport
909  * to add watches to the connection, queue incoming messages,
910  * and pull outgoing messages.
911  *
912  * @param transport the transport.
913  * @param connection the connection.
914  * @returns #FALSE if not enough memory
915  */
916 dbus_bool_t
917 _dbus_transport_set_connection (DBusTransport  *transport,
918                                 DBusConnection *connection)
919 {
920   _dbus_assert (transport->vtable->connection_set != NULL);
921   _dbus_assert (transport->connection == NULL);
922   
923   transport->connection = connection;
924
925   _dbus_transport_ref (transport);
926   if (!(* transport->vtable->connection_set) (transport))
927     transport->connection = NULL;
928   _dbus_transport_unref (transport);
929
930   return transport->connection != NULL;
931 }
932
933 /**
934  * Get the socket file descriptor, if any.
935  *
936  * @param transport the transport
937  * @param fd_p pointer to fill in with the descriptor
938  * @returns #TRUE if a descriptor was available
939  */
940 dbus_bool_t
941 _dbus_transport_get_socket_fd (DBusTransport *transport,
942                                int           *fd_p)
943 {
944   dbus_bool_t retval;
945   
946   if (transport->vtable->get_socket_fd == NULL)
947     return FALSE;
948
949   if (transport->disconnected)
950     return FALSE;
951
952   _dbus_transport_ref (transport);
953
954   retval = (* transport->vtable->get_socket_fd) (transport,
955                                                  fd_p);
956   
957   _dbus_transport_unref (transport);
958
959   return retval;
960 }
961
962 /**
963  * Performs a single poll()/select() on the transport's file
964  * descriptors and then reads/writes data as appropriate,
965  * queueing incoming messages and sending outgoing messages.
966  * This is the backend for _dbus_connection_do_iteration().
967  * See _dbus_connection_do_iteration() for full details.
968  *
969  * @param transport the transport.
970  * @param flags indicates whether to read or write, and whether to block.
971  * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
972  */
973 void
974 _dbus_transport_do_iteration (DBusTransport  *transport,
975                               unsigned int    flags,
976                               int             timeout_milliseconds)
977 {
978   _dbus_assert (transport->vtable->do_iteration != NULL);
979
980   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
981                  flags, timeout_milliseconds, !transport->disconnected);
982   
983   if ((flags & (DBUS_ITERATION_DO_WRITING |
984                 DBUS_ITERATION_DO_READING)) == 0)
985     return; /* Nothing to do */
986
987   if (transport->disconnected)
988     return;
989
990   _dbus_transport_ref (transport);
991   (* transport->vtable->do_iteration) (transport, flags,
992                                        timeout_milliseconds);
993   _dbus_transport_unref (transport);
994
995   _dbus_verbose ("end\n");
996 }
997
998 static dbus_bool_t
999 recover_unused_bytes (DBusTransport *transport)
1000 {
1001   if (_dbus_auth_needs_decoding (transport->auth))
1002     {
1003       DBusString plaintext;
1004       const DBusString *encoded;
1005       DBusString *buffer;
1006       int orig_len;
1007
1008       if (!_dbus_string_init (&plaintext))
1009         goto nomem;
1010       
1011       _dbus_auth_get_unused_bytes (transport->auth,
1012                                    &encoded);
1013
1014       if (!_dbus_auth_decode_data (transport->auth,
1015                                    encoded, &plaintext))
1016         {
1017           _dbus_string_free (&plaintext);
1018           goto nomem;
1019         }
1020
1021       _dbus_message_loader_get_buffer (transport->loader,
1022                                        &buffer);
1023       
1024       orig_len = _dbus_string_get_length (buffer);
1025
1026       if (!_dbus_string_move (&plaintext, 0, buffer,
1027                               orig_len))
1028         {
1029           _dbus_string_free (&plaintext);
1030           goto nomem;
1031         }
1032       
1033       _dbus_verbose (" %d unused bytes sent to message loader\n", 
1034                      _dbus_string_get_length (buffer) -
1035                      orig_len);
1036       
1037       _dbus_message_loader_return_buffer (transport->loader,
1038                                           buffer,
1039                                           _dbus_string_get_length (buffer) -
1040                                           orig_len);
1041
1042       _dbus_auth_delete_unused_bytes (transport->auth);
1043       
1044       _dbus_string_free (&plaintext);
1045     }
1046   else
1047     {
1048       const DBusString *bytes;
1049       DBusString *buffer;
1050       int orig_len;
1051       dbus_bool_t succeeded;
1052
1053       _dbus_message_loader_get_buffer (transport->loader,
1054                                        &buffer);
1055                 
1056       orig_len = _dbus_string_get_length (buffer);
1057
1058       _dbus_auth_get_unused_bytes (transport->auth,
1059                                    &bytes);
1060
1061       succeeded = TRUE;
1062       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
1063         succeeded = FALSE;
1064       
1065       _dbus_verbose (" %d unused bytes sent to message loader\n", 
1066                      _dbus_string_get_length (buffer) -
1067                      orig_len);
1068       
1069       _dbus_message_loader_return_buffer (transport->loader,
1070                                           buffer,
1071                                           _dbus_string_get_length (buffer) -
1072                                           orig_len);
1073
1074       if (succeeded)
1075         _dbus_auth_delete_unused_bytes (transport->auth);
1076       else
1077         goto nomem;
1078     }
1079
1080   return TRUE;
1081
1082  nomem:
1083   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
1084   return FALSE;
1085 }
1086
1087 /**
1088  * Reports our current dispatch status (whether there's buffered
1089  * data to be queued as messages, or not, or we need memory).
1090  *
1091  * @param transport the transport
1092  * @returns current status
1093  */
1094 DBusDispatchStatus
1095 _dbus_transport_get_dispatch_status (DBusTransport *transport)
1096 {
1097   if (_dbus_counter_get_size_value (transport->live_messages) >= transport->max_live_messages_size ||
1098       _dbus_counter_get_unix_fd_value (transport->live_messages) >= transport->max_live_messages_unix_fds)
1099     return DBUS_DISPATCH_COMPLETE; /* complete for now */
1100
1101   if (!_dbus_transport_get_is_authenticated (transport))
1102     {
1103       if (_dbus_auth_do_work (transport->auth) ==
1104           DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
1105         return DBUS_DISPATCH_NEED_MEMORY;
1106       else if (!_dbus_transport_get_is_authenticated (transport))
1107         return DBUS_DISPATCH_COMPLETE;
1108     }
1109
1110   if (!transport->unused_bytes_recovered &&
1111       !recover_unused_bytes (transport))
1112     return DBUS_DISPATCH_NEED_MEMORY;
1113
1114   transport->unused_bytes_recovered = TRUE;
1115   
1116   if (!_dbus_message_loader_queue_messages (transport->loader))
1117     return DBUS_DISPATCH_NEED_MEMORY;
1118
1119   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
1120     return DBUS_DISPATCH_DATA_REMAINS;
1121   else
1122     return DBUS_DISPATCH_COMPLETE;
1123 }
1124
1125 /**
1126  * Processes data we've read while handling a watch, potentially
1127  * converting some of it to messages and queueing those messages on
1128  * the connection.
1129  *
1130  * @param transport the transport
1131  * @returns #TRUE if we had enough memory to queue all messages
1132  */
1133 dbus_bool_t
1134 _dbus_transport_queue_messages (DBusTransport *transport)
1135 {
1136   DBusDispatchStatus status;
1137
1138 #if 0
1139   _dbus_verbose ("_dbus_transport_queue_messages()\n");
1140 #endif
1141   
1142   /* Queue any messages */
1143   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
1144     {
1145       DBusMessage *message;
1146       DBusList *link;
1147
1148       link = _dbus_message_loader_pop_message_link (transport->loader);
1149       _dbus_assert (link != NULL);
1150       
1151       message = link->data;
1152       
1153       _dbus_verbose ("queueing received message %p\n", message);
1154
1155       if (!_dbus_message_add_counter (message, transport->live_messages))
1156         {
1157           _dbus_message_loader_putback_message_link (transport->loader,
1158                                                      link);
1159           status = DBUS_DISPATCH_NEED_MEMORY;
1160           break;
1161         }
1162       else
1163         {
1164           /* We didn't call the notify function when we added the counter, so
1165            * catch up now. Since we have the connection's lock, it's desirable
1166            * that we bypass the notify function and call this virtual method
1167            * directly. */
1168           if (transport->vtable->live_messages_changed)
1169             (* transport->vtable->live_messages_changed) (transport);
1170
1171           /* pass ownership of link and message ref to connection */
1172           _dbus_connection_queue_received_message_link (transport->connection,
1173                                                         link);
1174         }
1175     }
1176
1177   if (_dbus_message_loader_get_is_corrupted (transport->loader))
1178     {
1179       _dbus_verbose ("Corrupted message stream, disconnecting\n");
1180       _dbus_transport_disconnect (transport);
1181     }
1182
1183   return status != DBUS_DISPATCH_NEED_MEMORY;
1184 }
1185
1186 /**
1187  * See dbus_connection_set_max_message_size().
1188  *
1189  * @param transport the transport
1190  * @param size the max size of a single message
1191  */
1192 void
1193 _dbus_transport_set_max_message_size (DBusTransport  *transport,
1194                                       long            size)
1195 {
1196   _dbus_message_loader_set_max_message_size (transport->loader, size);
1197 }
1198
1199 /**
1200  * See dbus_connection_set_max_message_unix_fds().
1201  *
1202  * @param transport the transport
1203  * @param n the max number of unix fds of a single message
1204  */
1205 void
1206 _dbus_transport_set_max_message_unix_fds (DBusTransport  *transport,
1207                                           long            n)
1208 {
1209   _dbus_message_loader_set_max_message_unix_fds (transport->loader, n);
1210 }
1211
1212 /**
1213  * See dbus_connection_get_max_message_size().
1214  *
1215  * @param transport the transport
1216  * @returns max message size
1217  */
1218 long
1219 _dbus_transport_get_max_message_size (DBusTransport  *transport)
1220 {
1221   return _dbus_message_loader_get_max_message_size (transport->loader);
1222 }
1223
1224 /**
1225  * See dbus_connection_get_max_message_unix_fds().
1226  *
1227  * @param transport the transport
1228  * @returns max message unix fds
1229  */
1230 long
1231 _dbus_transport_get_max_message_unix_fds (DBusTransport  *transport)
1232 {
1233   return _dbus_message_loader_get_max_message_unix_fds (transport->loader);
1234 }
1235
1236 /**
1237  * See dbus_connection_set_max_received_size().
1238  *
1239  * @param transport the transport
1240  * @param size the max size of all incoming messages
1241  */
1242 void
1243 _dbus_transport_set_max_received_size (DBusTransport  *transport,
1244                                        long            size)
1245 {
1246   transport->max_live_messages_size = size;
1247   _dbus_counter_set_notify (transport->live_messages,
1248                             transport->max_live_messages_size,
1249                             transport->max_live_messages_unix_fds,
1250                             live_messages_notify,
1251                             transport);
1252 }
1253
1254 /**
1255  * See dbus_connection_set_max_received_unix_fds().
1256  *
1257  * @param transport the transport
1258  * @param n the max unix fds of all incoming messages
1259  */
1260 void
1261 _dbus_transport_set_max_received_unix_fds (DBusTransport  *transport,
1262                                            long            n)
1263 {
1264   transport->max_live_messages_unix_fds = n;
1265   _dbus_counter_set_notify (transport->live_messages,
1266                             transport->max_live_messages_size,
1267                             transport->max_live_messages_unix_fds,
1268                             live_messages_notify,
1269                             transport);
1270 }
1271
1272 /**
1273  * See dbus_connection_get_max_received_size().
1274  *
1275  * @param transport the transport
1276  * @returns max bytes for all live messages
1277  */
1278 long
1279 _dbus_transport_get_max_received_size (DBusTransport  *transport)
1280 {
1281   return transport->max_live_messages_size;
1282 }
1283
1284 /**
1285  * See dbus_connection_set_max_received_unix_fds().
1286  *
1287  * @param transport the transport
1288  * @returns max unix fds for all live messages
1289  */
1290 long
1291 _dbus_transport_get_max_received_unix_fds (DBusTransport  *transport)
1292 {
1293   return transport->max_live_messages_unix_fds;
1294 }
1295
1296 /**
1297  * See dbus_connection_get_unix_user().
1298  *
1299  * @param transport the transport
1300  * @param uid return location for the user ID
1301  * @returns #TRUE if uid is filled in with a valid user ID
1302  */
1303 dbus_bool_t
1304 _dbus_transport_get_unix_user (DBusTransport *transport,
1305                                unsigned long *uid)
1306 {
1307   DBusCredentials *auth_identity;
1308
1309   *uid = _DBUS_INT32_MAX; /* better than some root or system user in
1310                            * case of bugs in the caller. Caller should
1311                            * never use this value on purpose, however.
1312                            */
1313   
1314   if (!transport->authenticated)
1315     return FALSE;
1316   
1317   auth_identity = _dbus_auth_get_identity (transport->auth);
1318
1319   if (_dbus_credentials_include (auth_identity,
1320                                  DBUS_CREDENTIAL_UNIX_USER_ID))
1321     {
1322       *uid = _dbus_credentials_get_unix_uid (auth_identity);
1323       return TRUE;
1324     }
1325   else
1326     return FALSE;
1327 }
1328
1329 /**
1330  * See dbus_connection_get_unix_process_id().
1331  *
1332  * @param transport the transport
1333  * @param pid return location for the process ID
1334  * @returns #TRUE if uid is filled in with a valid process ID
1335  */
1336 dbus_bool_t
1337 _dbus_transport_get_unix_process_id (DBusTransport *transport,
1338                                      unsigned long *pid)
1339 {
1340   DBusCredentials *auth_identity;
1341
1342   *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,
1343                           * but we set it to a safe number, INT_MAX,
1344                           * just to root out possible bugs in bad callers.
1345                           */
1346   
1347   if (!transport->authenticated)
1348     return FALSE;
1349   
1350   auth_identity = _dbus_auth_get_identity (transport->auth);
1351
1352   if (_dbus_credentials_include (auth_identity,
1353                                  DBUS_CREDENTIAL_UNIX_PROCESS_ID))
1354     {
1355       *pid = _dbus_credentials_get_pid (auth_identity);
1356       return TRUE;
1357     }
1358   else
1359     return FALSE;
1360 }
1361
1362 /**
1363  * See dbus_connection_get_adt_audit_session_data().
1364  *
1365  * @param transport the transport
1366  * @param data return location for the ADT audit data 
1367  * @param data_size return length of audit data
1368  * @returns #TRUE if audit data is filled in with a valid ucred
1369  */
1370 dbus_bool_t
1371 _dbus_transport_get_adt_audit_session_data (DBusTransport      *transport,
1372                                             void              **data,
1373                                             int                *data_size)
1374 {
1375   DBusCredentials *auth_identity;
1376
1377   *data = NULL;
1378   *data_size = 0;
1379   
1380   if (!transport->authenticated)
1381     return FALSE;
1382   
1383   auth_identity = _dbus_auth_get_identity (transport->auth);
1384
1385   if (_dbus_credentials_include (auth_identity,
1386                                  DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID))
1387     {
1388       *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity);
1389       *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity);
1390       return TRUE;
1391     }
1392   else
1393     return FALSE;
1394 }
1395
1396 /**
1397  * See dbus_connection_set_unix_user_function().
1398  *
1399  * @param transport the transport
1400  * @param function the predicate
1401  * @param data data to pass to the predicate
1402  * @param free_data_function function to free the data
1403  * @param old_data the old user data to be freed
1404  * @param old_free_data_function old free data function to free it with
1405  */
1406 void
1407 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
1408                                         DBusAllowUnixUserFunction  function,
1409                                         void                      *data,
1410                                         DBusFreeFunction           free_data_function,
1411                                         void                     **old_data,
1412                                         DBusFreeFunction          *old_free_data_function)
1413 {  
1414   *old_data = transport->unix_user_data;
1415   *old_free_data_function = transport->free_unix_user_data;
1416
1417   transport->unix_user_function = function;
1418   transport->unix_user_data = data;
1419   transport->free_unix_user_data = free_data_function;
1420 }
1421
1422 /**
1423  * See dbus_connection_get_windows_user().
1424  *
1425  * @param transport the transport
1426  * @param windows_sid_p return location for the user ID
1427  * @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it
1428  */
1429 dbus_bool_t
1430 _dbus_transport_get_windows_user (DBusTransport              *transport,
1431                                   char                      **windows_sid_p)
1432 {
1433   DBusCredentials *auth_identity;
1434
1435   *windows_sid_p = NULL;
1436   
1437   if (!transport->authenticated)
1438     return FALSE;
1439   
1440   auth_identity = _dbus_auth_get_identity (transport->auth);
1441
1442   if (_dbus_credentials_include (auth_identity,
1443                                  DBUS_CREDENTIAL_WINDOWS_SID))
1444     {
1445       /* If no memory, we are supposed to return TRUE and set NULL */
1446       *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
1447
1448       return TRUE;
1449     }
1450   else
1451     return FALSE;
1452 }
1453
1454 /**
1455  * See dbus_connection_set_windows_user_function().
1456  *
1457  * @param transport the transport
1458  * @param function the predicate
1459  * @param data data to pass to the predicate
1460  * @param free_data_function function to free the data
1461  * @param old_data the old user data to be freed
1462  * @param old_free_data_function old free data function to free it with
1463  */
1464
1465 void
1466 _dbus_transport_set_windows_user_function (DBusTransport              *transport,
1467                                            DBusAllowWindowsUserFunction   function,
1468                                            void                       *data,
1469                                            DBusFreeFunction            free_data_function,
1470                                            void                      **old_data,
1471                                            DBusFreeFunction           *old_free_data_function)
1472 {
1473   *old_data = transport->windows_user_data;
1474   *old_free_data_function = transport->free_windows_user_data;
1475
1476   transport->windows_user_function = function;
1477   transport->windows_user_data = data;
1478   transport->free_windows_user_data = free_data_function;
1479 }
1480
1481 /**
1482  * Sets the SASL authentication mechanisms supported by this transport.
1483  *
1484  * @param transport the transport
1485  * @param mechanisms the #NULL-terminated array of mechanisms
1486  *
1487  * @returns #FALSE if no memory
1488  */
1489 dbus_bool_t
1490 _dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
1491                                      const char    **mechanisms)
1492 {
1493   return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
1494 }
1495
1496 /**
1497  * See dbus_connection_set_allow_anonymous()
1498  *
1499  * @param transport the transport
1500  * @param value #TRUE to allow anonymous connection
1501  */
1502 void
1503 _dbus_transport_set_allow_anonymous (DBusTransport              *transport,
1504                                      dbus_bool_t                 value)
1505 {
1506   transport->allow_anonymous = value != FALSE;
1507 }
1508
1509 #ifdef DBUS_ENABLE_STATS
1510 void
1511 _dbus_transport_get_stats (DBusTransport  *transport,
1512                            dbus_uint32_t  *queue_bytes,
1513                            dbus_uint32_t  *queue_fds,
1514                            dbus_uint32_t  *peak_queue_bytes,
1515                            dbus_uint32_t  *peak_queue_fds)
1516 {
1517   if (queue_bytes != NULL)
1518     *queue_bytes = _dbus_counter_get_size_value (transport->live_messages);
1519
1520   if (queue_fds != NULL)
1521     *queue_fds = _dbus_counter_get_unix_fd_value (transport->live_messages);
1522
1523   if (peak_queue_bytes != NULL)
1524     *peak_queue_bytes = _dbus_counter_get_peak_size_value (transport->live_messages);
1525
1526   if (peak_queue_fds != NULL)
1527     *peak_queue_fds = _dbus_counter_get_peak_unix_fd_value (transport->live_messages);
1528 }
1529 #endif /* DBUS_ENABLE_STATS */
1530
1531 /** @} */