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