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