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