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