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