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