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