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