Use DBUS_ERROR_INIT instead of dbus_error_init wherever it's clearly equivalent
[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., 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 = DBUS_ERROR_INIT;
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   for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
372     {
373       DBusTransportOpenResult result;
374
375       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
376       result = (* open_funcs[i].func) (entry, &transport, &tmp_error);
377
378       switch (result)
379         {
380         case DBUS_TRANSPORT_OPEN_OK:
381           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
382           goto out;
383           break;
384         case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
385           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
386           /* keep going through the loop of open funcs */
387           break;
388         case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
389           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
390           goto out;
391           break;
392         case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
393           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
394           goto out;
395           break;
396         }
397     }
398
399  out:
400   
401   if (transport == NULL)
402     {
403       if (!dbus_error_is_set (&tmp_error))
404         _dbus_set_bad_address (&tmp_error,
405                                NULL, NULL,
406                                "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
407       
408       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
409       dbus_move_error(&tmp_error, error);
410       dbus_free (expected_guid);
411     }
412   else
413     {
414       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
415       transport->expected_guid = expected_guid;
416     }
417
418   return transport;
419 }
420
421 /**
422  * Increments the reference count for the transport.
423  *
424  * @param transport the transport.
425  * @returns the transport.
426  */
427 DBusTransport *
428 _dbus_transport_ref (DBusTransport *transport)
429 {
430   _dbus_assert (transport->refcount > 0);
431   
432   transport->refcount += 1;
433
434   return transport;
435 }
436
437 /**
438  * Decrements the reference count for the transport.
439  * Disconnects and finalizes the transport if
440  * the reference count reaches zero.
441  *
442  * @param transport the transport.
443  */
444 void
445 _dbus_transport_unref (DBusTransport *transport)
446 {
447   _dbus_assert (transport != NULL);
448   _dbus_assert (transport->refcount > 0);
449   
450   transport->refcount -= 1;
451   if (transport->refcount == 0)
452     {
453       _dbus_verbose ("%s: finalizing\n", _DBUS_FUNCTION_NAME);
454       
455       _dbus_assert (transport->vtable->finalize != NULL);
456       
457       (* transport->vtable->finalize) (transport);
458     }
459 }
460
461 /**
462  * Closes our end of the connection to a remote application. Further
463  * attempts to use this transport will fail. Only the first call to
464  * _dbus_transport_disconnect() will have an effect.
465  *
466  * @param transport the transport.
467  * 
468  */
469 void
470 _dbus_transport_disconnect (DBusTransport *transport)
471 {
472   _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME);
473   
474   _dbus_assert (transport->vtable->disconnect != NULL);
475   
476   if (transport->disconnected)
477     return;
478
479   (* transport->vtable->disconnect) (transport);
480   
481   transport->disconnected = TRUE;
482
483   _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
484 }
485
486 /**
487  * Returns #TRUE if the transport has not been disconnected.
488  * Disconnection can result from _dbus_transport_disconnect()
489  * or because the server drops its end of the connection.
490  *
491  * @param transport the transport.
492  * @returns whether we're connected
493  */
494 dbus_bool_t
495 _dbus_transport_get_is_connected (DBusTransport *transport)
496 {
497   return !transport->disconnected;
498 }
499
500 static dbus_bool_t
501 auth_via_unix_user_function (DBusTransport *transport)
502 {
503   DBusCredentials *auth_identity;
504   dbus_bool_t allow;
505   DBusConnection *connection;
506   DBusAllowUnixUserFunction unix_user_function;
507   void *unix_user_data;
508   dbus_uid_t uid;
509
510   /* Dropping the lock here probably isn't that safe. */
511   
512   auth_identity = _dbus_auth_get_identity (transport->auth);
513   _dbus_assert (auth_identity != NULL);
514
515   connection = transport->connection;
516   unix_user_function = transport->unix_user_function;
517   unix_user_data = transport->unix_user_data;
518   uid = _dbus_credentials_get_unix_uid (auth_identity);
519               
520   _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
521   _dbus_connection_unlock (connection);
522
523   allow = (* unix_user_function) (connection,
524                                   uid,
525                                   unix_user_data);
526               
527   _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
528   _dbus_connection_lock (connection);
529
530   if (allow)
531     {
532       _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
533     }
534   else
535     {
536       _dbus_verbose ("Client UID "DBUS_UID_FORMAT
537                      " was rejected, disconnecting\n",
538                      _dbus_credentials_get_unix_uid (auth_identity));
539       _dbus_transport_disconnect (transport);
540     }
541
542   return allow;
543 }
544
545 static dbus_bool_t
546 auth_via_windows_user_function (DBusTransport *transport)
547 {
548   DBusCredentials *auth_identity;  
549   dbus_bool_t allow;
550   DBusConnection *connection;
551   DBusAllowWindowsUserFunction windows_user_function;
552   void *windows_user_data;
553   char *windows_sid;
554
555   /* Dropping the lock here probably isn't that safe. */
556   
557   auth_identity = _dbus_auth_get_identity (transport->auth);
558   _dbus_assert (auth_identity != NULL);
559
560   connection = transport->connection;
561   windows_user_function = transport->windows_user_function;
562   windows_user_data = transport->unix_user_data;
563   windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
564
565   if (windows_sid == NULL)
566     {
567       /* OOM */
568       return FALSE;
569     }
570                 
571   _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
572   _dbus_connection_unlock (connection);
573
574   allow = (* windows_user_function) (connection,
575                                      windows_sid,
576                                      windows_user_data);
577               
578   _dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME);
579   _dbus_connection_lock (connection);
580
581   if (allow)
582     {
583       _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
584     }
585   else
586     {
587       _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
588                      _dbus_credentials_get_windows_sid (auth_identity));
589       _dbus_transport_disconnect (transport);
590     }
591
592   return allow;
593 }
594
595 static dbus_bool_t
596 auth_via_default_rules (DBusTransport *transport)
597 {
598   DBusCredentials *auth_identity;
599   DBusCredentials *our_identity;
600   dbus_bool_t allow;
601   
602   auth_identity = _dbus_auth_get_identity (transport->auth);
603   _dbus_assert (auth_identity != NULL);
604
605   /* By default, connection is allowed if the client is 1) root or 2)
606    * has the same UID as us or 3) anonymous is allowed.
607    */
608   
609   our_identity = _dbus_credentials_new_from_current_process ();
610   if (our_identity == NULL)
611     {
612       /* OOM */
613       return FALSE;
614     }
615               
616   if (transport->allow_anonymous ||
617       _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
618       _dbus_credentials_same_user (our_identity,
619                                    auth_identity))
620     {
621       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
622           _dbus_verbose ("Client authorized as SID '%s'"
623                          "matching our SID '%s'\n",
624                          _dbus_credentials_get_windows_sid(auth_identity),
625                          _dbus_credentials_get_windows_sid(our_identity));
626       else
627           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
628                          " matching our UID "DBUS_UID_FORMAT"\n",
629                          _dbus_credentials_get_unix_uid(auth_identity),
630                          _dbus_credentials_get_unix_uid(our_identity));
631       /* We have authenticated! */
632       allow = TRUE;
633     }
634   else
635     {
636       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
637           _dbus_verbose ("Client authorized as SID '%s'"
638                          " but our SID is '%s', disconnecting\n",
639                          _dbus_credentials_get_windows_sid(our_identity),
640                          _dbus_credentials_get_windows_sid(our_identity));
641       else
642           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
643                          " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
644                          _dbus_credentials_get_unix_uid(our_identity),
645                          _dbus_credentials_get_unix_uid(our_identity));
646       _dbus_transport_disconnect (transport);
647       allow = FALSE;
648     }  
649
650   _dbus_credentials_unref (our_identity);
651   
652   return allow;
653 }
654
655
656 /**
657  * Returns #TRUE if we have been authenticated.  Will return #TRUE
658  * even if the transport is disconnected.
659  *
660  * @todo we drop connection->mutex when calling the unix_user_function,
661  * and windows_user_function, which may not be safe really.
662  *
663  * @param transport the transport
664  * @returns whether we're authenticated
665  */
666 dbus_bool_t
667 _dbus_transport_get_is_authenticated (DBusTransport *transport)
668 {  
669   if (transport->authenticated)
670     return TRUE;
671   else
672     {
673       dbus_bool_t maybe_authenticated;
674       
675       if (transport->disconnected)
676         return FALSE;
677
678       /* paranoia ref since we call user callbacks sometimes */
679       _dbus_connection_ref_unlocked (transport->connection);
680       
681       maybe_authenticated =
682         (!(transport->send_credentials_pending ||
683            transport->receive_credentials_pending));
684
685       if (maybe_authenticated)
686         {
687           switch (_dbus_auth_do_work (transport->auth))
688             {
689             case DBUS_AUTH_STATE_AUTHENTICATED:
690               /* leave as maybe_authenticated */
691               break;
692             default:
693               maybe_authenticated = FALSE;
694             }
695         }
696
697       /* If we're the client, verify the GUID
698        */
699       if (maybe_authenticated && !transport->is_server)
700         {
701           const char *server_guid;
702
703           server_guid = _dbus_auth_get_guid_from_server (transport->auth);
704           _dbus_assert (server_guid != NULL);
705
706           if (transport->expected_guid &&
707               strcmp (transport->expected_guid, server_guid) != 0)
708             {
709               _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
710                              transport->expected_guid, server_guid);
711               _dbus_transport_disconnect (transport);
712               _dbus_connection_unref_unlocked (transport->connection);
713               return FALSE;
714             }
715
716           if (transport->expected_guid == NULL)
717             {
718               transport->expected_guid = _dbus_strdup (server_guid);
719
720               if (transport->expected_guid == NULL)
721                 {
722                   _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME);
723                   return FALSE;
724                 }
725             }
726         }
727
728       /* If we're the server, see if we want to allow this identity to proceed.
729        */
730       if (maybe_authenticated && transport->is_server)
731         {
732           dbus_bool_t allow;
733           DBusCredentials *auth_identity;
734           
735           auth_identity = _dbus_auth_get_identity (transport->auth);
736           _dbus_assert (auth_identity != NULL);
737           
738           /* If we have an auth'd user and a user function, delegate
739            * deciding whether auth credentials are good enough to the
740            * app; otherwise, use our default decision process.
741            */
742           if (transport->unix_user_function != NULL &&
743               _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
744             {
745               allow = auth_via_unix_user_function (transport);
746             }
747           else if (transport->windows_user_function != NULL &&
748                    _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
749             {
750               allow = auth_via_windows_user_function (transport);
751             }      
752           else
753             {
754               allow = auth_via_default_rules (transport);
755             }
756           
757           if (!allow)
758             maybe_authenticated = FALSE;
759         }
760
761       transport->authenticated = maybe_authenticated;
762
763       _dbus_connection_unref_unlocked (transport->connection);
764       return maybe_authenticated;
765     }
766 }
767
768 /**
769  * See dbus_connection_get_is_anonymous().
770  *
771  * @param transport the transport
772  * @returns #TRUE if not authenticated or authenticated as anonymous
773  */
774 dbus_bool_t
775 _dbus_transport_get_is_anonymous (DBusTransport *transport)
776 {
777   DBusCredentials *auth_identity;
778   
779   if (!transport->authenticated)
780     return TRUE;
781   
782   auth_identity = _dbus_auth_get_identity (transport->auth);
783
784   if (_dbus_credentials_are_anonymous (auth_identity))
785     return TRUE;
786   else
787     return FALSE;
788 }
789
790 /**
791  * Gets the address of a transport. It will be
792  * #NULL for a server-side transport.
793  *
794  * @param transport the transport
795  * @returns transport's address
796  */
797 const char*
798 _dbus_transport_get_address (DBusTransport *transport)
799 {
800   return transport->address;
801 }
802
803 /**
804  * Gets the id of the server we are connected to (see
805  * dbus_server_get_id()). Only works on client side.
806  *
807  * @param transport the transport
808  * @returns transport's server's id or #NULL if we are the server side
809  */
810 const char*
811 _dbus_transport_get_server_id (DBusTransport *transport)
812 {
813   if (transport->is_server)
814     return NULL;
815   else
816     return transport->expected_guid;
817 }
818
819 /**
820  * Handles a watch by reading data, writing data, or disconnecting
821  * the transport, as appropriate for the given condition.
822  *
823  * @param transport the transport.
824  * @param watch the watch.
825  * @param condition the current state of the watched file descriptor.
826  * @returns #FALSE if not enough memory to fully handle the watch
827  */
828 dbus_bool_t
829 _dbus_transport_handle_watch (DBusTransport           *transport,
830                               DBusWatch               *watch,
831                               unsigned int             condition)
832 {
833   dbus_bool_t retval;
834   
835   _dbus_assert (transport->vtable->handle_watch != NULL);
836
837   if (transport->disconnected)
838     return TRUE;
839
840   if (dbus_watch_get_socket (watch) < 0)
841     {
842       _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
843       return TRUE;
844     }
845   
846   _dbus_watch_sanitize_condition (watch, &condition);
847
848   _dbus_transport_ref (transport);
849   _dbus_watch_ref (watch);
850   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
851   _dbus_watch_unref (watch);
852   _dbus_transport_unref (transport);
853
854   return retval;
855 }
856
857 /**
858  * Sets the connection using this transport. Allows the transport
859  * to add watches to the connection, queue incoming messages,
860  * and pull outgoing messages.
861  *
862  * @param transport the transport.
863  * @param connection the connection.
864  * @returns #FALSE if not enough memory
865  */
866 dbus_bool_t
867 _dbus_transport_set_connection (DBusTransport  *transport,
868                                 DBusConnection *connection)
869 {
870   _dbus_assert (transport->vtable->connection_set != NULL);
871   _dbus_assert (transport->connection == NULL);
872   
873   transport->connection = connection;
874
875   _dbus_transport_ref (transport);
876   if (!(* transport->vtable->connection_set) (transport))
877     transport->connection = NULL;
878   _dbus_transport_unref (transport);
879
880   return transport->connection != NULL;
881 }
882
883 /**
884  * Get the socket file descriptor, if any.
885  *
886  * @param transport the transport
887  * @param fd_p pointer to fill in with the descriptor
888  * @returns #TRUE if a descriptor was available
889  */
890 dbus_bool_t
891 _dbus_transport_get_socket_fd (DBusTransport *transport,
892                                int           *fd_p)
893 {
894   dbus_bool_t retval;
895   
896   if (transport->vtable->get_socket_fd == NULL)
897     return FALSE;
898
899   if (transport->disconnected)
900     return FALSE;
901
902   _dbus_transport_ref (transport);
903
904   retval = (* transport->vtable->get_socket_fd) (transport,
905                                                  fd_p);
906   
907   _dbus_transport_unref (transport);
908
909   return retval;
910 }
911
912 /**
913  * Performs a single poll()/select() on the transport's file
914  * descriptors and then reads/writes data as appropriate,
915  * queueing incoming messages and sending outgoing messages.
916  * This is the backend for _dbus_connection_do_iteration().
917  * See _dbus_connection_do_iteration() for full details.
918  *
919  * @param transport the transport.
920  * @param flags indicates whether to read or write, and whether to block.
921  * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
922  */
923 void
924 _dbus_transport_do_iteration (DBusTransport  *transport,
925                               unsigned int    flags,
926                               int             timeout_milliseconds)
927 {
928   _dbus_assert (transport->vtable->do_iteration != NULL);
929
930   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
931                  flags, timeout_milliseconds, !transport->disconnected);
932   
933   if ((flags & (DBUS_ITERATION_DO_WRITING |
934                 DBUS_ITERATION_DO_READING)) == 0)
935     return; /* Nothing to do */
936
937   if (transport->disconnected)
938     return;
939
940   _dbus_transport_ref (transport);
941   (* transport->vtable->do_iteration) (transport, flags,
942                                        timeout_milliseconds);
943   _dbus_transport_unref (transport);
944
945   _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
946 }
947
948 static dbus_bool_t
949 recover_unused_bytes (DBusTransport *transport)
950 {
951   if (_dbus_auth_needs_decoding (transport->auth))
952     {
953       DBusString plaintext;
954       const DBusString *encoded;
955       DBusString *buffer;
956       int orig_len;
957       
958       if (!_dbus_string_init (&plaintext))
959         goto nomem;
960       
961       _dbus_auth_get_unused_bytes (transport->auth,
962                                    &encoded);
963
964       if (!_dbus_auth_decode_data (transport->auth,
965                                    encoded, &plaintext))
966         {
967           _dbus_string_free (&plaintext);
968           goto nomem;
969         }
970       
971       _dbus_message_loader_get_buffer (transport->loader,
972                                        &buffer);
973       
974       orig_len = _dbus_string_get_length (buffer);
975       
976       if (!_dbus_string_move (&plaintext, 0, buffer,
977                               orig_len))
978         {
979           _dbus_string_free (&plaintext);
980           goto nomem;
981         }
982       
983       _dbus_verbose (" %d unused bytes sent to message loader\n", 
984                      _dbus_string_get_length (buffer) -
985                      orig_len);
986       
987       _dbus_message_loader_return_buffer (transport->loader,
988                                           buffer,
989                                           _dbus_string_get_length (buffer) -
990                                           orig_len);
991
992       _dbus_auth_delete_unused_bytes (transport->auth);
993       
994       _dbus_string_free (&plaintext);
995     }
996   else
997     {
998       const DBusString *bytes;
999       DBusString *buffer;
1000       int orig_len;
1001       dbus_bool_t succeeded;
1002
1003       _dbus_message_loader_get_buffer (transport->loader,
1004                                        &buffer);
1005                 
1006       orig_len = _dbus_string_get_length (buffer);
1007                 
1008       _dbus_auth_get_unused_bytes (transport->auth,
1009                                    &bytes);
1010
1011       succeeded = TRUE;
1012       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
1013         succeeded = FALSE;
1014       
1015       _dbus_verbose (" %d unused bytes sent to message loader\n", 
1016                      _dbus_string_get_length (buffer) -
1017                      orig_len);
1018       
1019       _dbus_message_loader_return_buffer (transport->loader,
1020                                           buffer,
1021                                           _dbus_string_get_length (buffer) -
1022                                           orig_len);
1023
1024       if (succeeded)
1025         _dbus_auth_delete_unused_bytes (transport->auth);
1026       else
1027         goto nomem;
1028     }
1029
1030   return TRUE;
1031
1032  nomem:
1033   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
1034   return FALSE;
1035 }
1036
1037 /**
1038  * Reports our current dispatch status (whether there's buffered
1039  * data to be queued as messages, or not, or we need memory).
1040  *
1041  * @param transport the transport
1042  * @returns current status
1043  */
1044 DBusDispatchStatus
1045 _dbus_transport_get_dispatch_status (DBusTransport *transport)
1046 {
1047   if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
1048     return DBUS_DISPATCH_COMPLETE; /* complete for now */
1049
1050   if (!_dbus_transport_get_is_authenticated (transport))
1051     {
1052       if (_dbus_auth_do_work (transport->auth) ==
1053           DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
1054         return DBUS_DISPATCH_NEED_MEMORY;
1055       else if (!_dbus_transport_get_is_authenticated (transport))
1056         return DBUS_DISPATCH_COMPLETE;
1057     }
1058
1059   if (!transport->unused_bytes_recovered &&
1060       !recover_unused_bytes (transport))
1061     return DBUS_DISPATCH_NEED_MEMORY;
1062
1063   transport->unused_bytes_recovered = TRUE;
1064   
1065   if (!_dbus_message_loader_queue_messages (transport->loader))
1066     return DBUS_DISPATCH_NEED_MEMORY;
1067
1068   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
1069     return DBUS_DISPATCH_DATA_REMAINS;
1070   else
1071     return DBUS_DISPATCH_COMPLETE;
1072 }
1073
1074 /**
1075  * Processes data we've read while handling a watch, potentially
1076  * converting some of it to messages and queueing those messages on
1077  * the connection.
1078  *
1079  * @param transport the transport
1080  * @returns #TRUE if we had enough memory to queue all messages
1081  */
1082 dbus_bool_t
1083 _dbus_transport_queue_messages (DBusTransport *transport)
1084 {
1085   DBusDispatchStatus status;
1086
1087 #if 0
1088   _dbus_verbose ("_dbus_transport_queue_messages()\n");
1089 #endif
1090   
1091   /* Queue any messages */
1092   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
1093     {
1094       DBusMessage *message;
1095       DBusList *link;
1096
1097       link = _dbus_message_loader_pop_message_link (transport->loader);
1098       _dbus_assert (link != NULL);
1099       
1100       message = link->data;
1101       
1102       _dbus_verbose ("queueing received message %p\n", message);
1103
1104       if (!_dbus_message_add_size_counter (message, transport->live_messages_size))
1105         {
1106           _dbus_message_loader_putback_message_link (transport->loader,
1107                                                      link);
1108           status = DBUS_DISPATCH_NEED_MEMORY;
1109           break;
1110         }
1111       else
1112         {
1113           /* pass ownership of link and message ref to connection */
1114           _dbus_connection_queue_received_message_link (transport->connection,
1115                                                         link);
1116         }
1117     }
1118
1119   if (_dbus_message_loader_get_is_corrupted (transport->loader))
1120     {
1121       _dbus_verbose ("Corrupted message stream, disconnecting\n");
1122       _dbus_transport_disconnect (transport);
1123     }
1124
1125   return status != DBUS_DISPATCH_NEED_MEMORY;
1126 }
1127
1128 /**
1129  * See dbus_connection_set_max_message_size().
1130  *
1131  * @param transport the transport
1132  * @param size the max size of a single message
1133  */
1134 void
1135 _dbus_transport_set_max_message_size (DBusTransport  *transport,
1136                                       long            size)
1137 {
1138   _dbus_message_loader_set_max_message_size (transport->loader, size);
1139 }
1140
1141 /**
1142  * See dbus_connection_get_max_message_size().
1143  *
1144  * @param transport the transport
1145  * @returns max message size
1146  */
1147 long
1148 _dbus_transport_get_max_message_size (DBusTransport  *transport)
1149 {
1150   return _dbus_message_loader_get_max_message_size (transport->loader);
1151 }
1152
1153 /**
1154  * See dbus_connection_set_max_received_size().
1155  *
1156  * @param transport the transport
1157  * @param size the max size of all incoming messages
1158  */
1159 void
1160 _dbus_transport_set_max_received_size (DBusTransport  *transport,
1161                                        long            size)
1162 {
1163   transport->max_live_messages_size = size;
1164   _dbus_counter_set_notify (transport->live_messages_size,
1165                             transport->max_live_messages_size,
1166                             live_messages_size_notify,
1167                             transport);
1168 }
1169
1170
1171 /**
1172  * See dbus_connection_get_max_received_size().
1173  *
1174  * @param transport the transport
1175  * @returns max bytes for all live messages
1176  */
1177 long
1178 _dbus_transport_get_max_received_size (DBusTransport  *transport)
1179 {
1180   return transport->max_live_messages_size;
1181 }
1182
1183 /**
1184  * See dbus_connection_get_unix_user().
1185  *
1186  * @param transport the transport
1187  * @param uid return location for the user ID
1188  * @returns #TRUE if uid is filled in with a valid user ID
1189  */
1190 dbus_bool_t
1191 _dbus_transport_get_unix_user (DBusTransport *transport,
1192                                unsigned long *uid)
1193 {
1194   DBusCredentials *auth_identity;
1195
1196   *uid = _DBUS_INT32_MAX; /* better than some root or system user in
1197                            * case of bugs in the caller. Caller should
1198                            * never use this value on purpose, however.
1199                            */
1200   
1201   if (!transport->authenticated)
1202     return FALSE;
1203   
1204   auth_identity = _dbus_auth_get_identity (transport->auth);
1205
1206   if (_dbus_credentials_include (auth_identity,
1207                                  DBUS_CREDENTIAL_UNIX_USER_ID))
1208     {
1209       *uid = _dbus_credentials_get_unix_uid (auth_identity);
1210       return TRUE;
1211     }
1212   else
1213     return FALSE;
1214 }
1215
1216 /**
1217  * See dbus_connection_get_unix_process_id().
1218  *
1219  * @param transport the transport
1220  * @param pid return location for the process ID
1221  * @returns #TRUE if uid is filled in with a valid process ID
1222  */
1223 dbus_bool_t
1224 _dbus_transport_get_unix_process_id (DBusTransport *transport,
1225                                      unsigned long *pid)
1226 {
1227   DBusCredentials *auth_identity;
1228
1229   *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,
1230                           * but we set it to a safe number, INT_MAX,
1231                           * just to root out possible bugs in bad callers.
1232                           */
1233   
1234   if (!transport->authenticated)
1235     return FALSE;
1236   
1237   auth_identity = _dbus_auth_get_identity (transport->auth);
1238
1239   if (_dbus_credentials_include (auth_identity,
1240                                  DBUS_CREDENTIAL_UNIX_PROCESS_ID))
1241     {
1242       *pid = _dbus_credentials_get_unix_pid (auth_identity);
1243       return TRUE;
1244     }
1245   else
1246     return FALSE;
1247 }
1248
1249 /**
1250  * See dbus_connection_set_unix_user_function().
1251  *
1252  * @param transport the transport
1253  * @param function the predicate
1254  * @param data data to pass to the predicate
1255  * @param free_data_function function to free the data
1256  * @param old_data the old user data to be freed
1257  * @param old_free_data_function old free data function to free it with
1258  */
1259 void
1260 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
1261                                         DBusAllowUnixUserFunction  function,
1262                                         void                      *data,
1263                                         DBusFreeFunction           free_data_function,
1264                                         void                     **old_data,
1265                                         DBusFreeFunction          *old_free_data_function)
1266 {  
1267   *old_data = transport->unix_user_data;
1268   *old_free_data_function = transport->free_unix_user_data;
1269
1270   transport->unix_user_function = function;
1271   transport->unix_user_data = data;
1272   transport->free_unix_user_data = free_data_function;
1273 }
1274
1275 /**
1276  * See dbus_connection_get_windows_user().
1277  *
1278  * @param transport the transport
1279  * @param windows_sid_p return location for the user ID
1280  * @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it
1281  */
1282 dbus_bool_t
1283 _dbus_transport_get_windows_user (DBusTransport              *transport,
1284                                   char                      **windows_sid_p)
1285 {
1286   DBusCredentials *auth_identity;
1287
1288   *windows_sid_p = NULL;
1289   
1290   if (!transport->authenticated)
1291     return FALSE;
1292   
1293   auth_identity = _dbus_auth_get_identity (transport->auth);
1294
1295   if (_dbus_credentials_include (auth_identity,
1296                                  DBUS_CREDENTIAL_WINDOWS_SID))
1297     {
1298       /* If no memory, we are supposed to return TRUE and set NULL */
1299       *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
1300
1301       return TRUE;
1302     }
1303   else
1304     return FALSE;
1305 }
1306
1307 /**
1308  * See dbus_connection_set_windows_user_function().
1309  *
1310  * @param transport the transport
1311  * @param function the predicate
1312  * @param data data to pass to the predicate
1313  * @param free_data_function function to free the data
1314  * @param old_data the old user data to be freed
1315  * @param old_free_data_function old free data function to free it with
1316  */
1317
1318 void
1319 _dbus_transport_set_windows_user_function (DBusTransport              *transport,
1320                                            DBusAllowWindowsUserFunction   function,
1321                                            void                       *data,
1322                                            DBusFreeFunction            free_data_function,
1323                                            void                      **old_data,
1324                                            DBusFreeFunction           *old_free_data_function)
1325 {
1326   *old_data = transport->windows_user_data;
1327   *old_free_data_function = transport->free_windows_user_data;
1328
1329   transport->windows_user_function = function;
1330   transport->windows_user_data = data;
1331   transport->free_windows_user_data = free_data_function;
1332 }
1333
1334 /**
1335  * Sets the SASL authentication mechanisms supported by this transport.
1336  *
1337  * @param transport the transport
1338  * @param mechanisms the #NULL-terminated array of mechanisms
1339  *
1340  * @returns #FALSE if no memory
1341  */
1342 dbus_bool_t
1343 _dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
1344                                      const char    **mechanisms)
1345 {
1346   return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
1347 }
1348
1349 /**
1350  * See dbus_connection_set_allow_anonymous()
1351  *
1352  * @param transport the transport
1353  * @param value #TRUE to allow anonymous connection
1354  */
1355 void
1356 _dbus_transport_set_allow_anonymous (DBusTransport              *transport,
1357                                      dbus_bool_t                 value)
1358 {
1359   transport->allow_anonymous = value != FALSE;
1360 }
1361
1362 /** @} */