D-Bus  1.5.10
dbus-transport.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-transport.c DBusTransport object (internal to D-Bus implementation)
00003  *
00004  * Copyright (C) 2002, 2003  Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-transport-protected.h"
00026 #include "dbus-transport-unix.h"
00027 #include "dbus-transport-socket.h"
00028 #include "dbus-connection-internal.h"
00029 #include "dbus-watch.h"
00030 #include "dbus-auth.h"
00031 #include "dbus-address.h"
00032 #include "dbus-credentials.h"
00033 #include "dbus-mainloop.h"
00034 #include "dbus-message.h"
00035 #ifdef DBUS_BUILD_TESTS
00036 #include "dbus-server-debug-pipe.h"
00037 #endif
00038 
00060 static void
00061 live_messages_notify (DBusCounter *counter,
00062                            void        *user_data)
00063 {
00064   DBusTransport *transport = user_data;
00065 
00066   _dbus_transport_ref (transport);
00067 
00068 #if 0
00069   _dbus_verbose ("Size counter value is now %d\n",
00070                  (int) _dbus_counter_get_size_value (counter));
00071   _dbus_verbose ("Unix FD counter value is now %d\n",
00072                  (int) _dbus_counter_get_unix_fd_value (counter));
00073 #endif
00074 
00075   /* disable or re-enable the read watch for the transport if
00076    * required.
00077    */
00078   if (transport->vtable->live_messages_changed)
00079     {
00080       _dbus_connection_lock (transport->connection);
00081       (* transport->vtable->live_messages_changed) (transport);
00082       _dbus_connection_unlock (transport->connection);
00083     }
00084 
00085   _dbus_transport_unref (transport);
00086 }
00087 
00101 dbus_bool_t
00102 _dbus_transport_init_base (DBusTransport             *transport,
00103                            const DBusTransportVTable *vtable,
00104                            const DBusString          *server_guid,
00105                            const DBusString          *address)
00106 {
00107   DBusMessageLoader *loader;
00108   DBusAuth *auth;
00109   DBusCounter *counter;
00110   char *address_copy;
00111   DBusCredentials *creds;
00112   
00113   loader = _dbus_message_loader_new ();
00114   if (loader == NULL)
00115     return FALSE;
00116   
00117   if (server_guid)
00118     auth = _dbus_auth_server_new (server_guid);
00119   else
00120     auth = _dbus_auth_client_new ();
00121   if (auth == NULL)
00122     {
00123       _dbus_message_loader_unref (loader);
00124       return FALSE;
00125     }
00126 
00127   counter = _dbus_counter_new ();
00128   if (counter == NULL)
00129     {
00130       _dbus_auth_unref (auth);
00131       _dbus_message_loader_unref (loader);
00132       return FALSE;
00133     }  
00134 
00135   creds = _dbus_credentials_new ();
00136   if (creds == NULL)
00137     {
00138       _dbus_counter_unref (counter);
00139       _dbus_auth_unref (auth);
00140       _dbus_message_loader_unref (loader);
00141       return FALSE;
00142     }
00143   
00144   if (server_guid)
00145     {
00146       _dbus_assert (address == NULL);
00147       address_copy = NULL;
00148     }
00149   else
00150     {
00151       _dbus_assert (address != NULL);
00152 
00153       if (!_dbus_string_copy_data (address, &address_copy))
00154         {
00155           _dbus_credentials_unref (creds);
00156           _dbus_counter_unref (counter);
00157           _dbus_auth_unref (auth);
00158           _dbus_message_loader_unref (loader);
00159           return FALSE;
00160         }
00161     }
00162   
00163   transport->refcount = 1;
00164   transport->vtable = vtable;
00165   transport->loader = loader;
00166   transport->auth = auth;
00167   transport->live_messages = counter;
00168   transport->authenticated = FALSE;
00169   transport->disconnected = FALSE;
00170   transport->is_server = (server_guid != NULL);
00171   transport->send_credentials_pending = !transport->is_server;
00172   transport->receive_credentials_pending = transport->is_server;
00173   transport->address = address_copy;
00174   
00175   transport->unix_user_function = NULL;
00176   transport->unix_user_data = NULL;
00177   transport->free_unix_user_data = NULL;
00178 
00179   transport->windows_user_function = NULL;
00180   transport->windows_user_data = NULL;
00181   transport->free_windows_user_data = NULL;
00182   
00183   transport->expected_guid = NULL;
00184   
00185   /* Try to default to something that won't totally hose the system,
00186    * but doesn't impose too much of a limitation.
00187    */
00188   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
00189 
00190   /* On Linux RLIMIT_NOFILE defaults to 1024, so allowing 4096 fds live
00191      should be more than enough */
00192   transport->max_live_messages_unix_fds = 4096;
00193 
00194   /* credentials read from socket if any */
00195   transport->credentials = creds;
00196 
00197   _dbus_counter_set_notify (transport->live_messages,
00198                             transport->max_live_messages_size,
00199                             transport->max_live_messages_unix_fds,
00200                             live_messages_notify,
00201                             transport);
00202 
00203   if (transport->address)
00204     _dbus_verbose ("Initialized transport on address %s\n", transport->address);
00205 
00206   return TRUE;
00207 }
00208 
00215 void
00216 _dbus_transport_finalize_base (DBusTransport *transport)
00217 {
00218   if (!transport->disconnected)
00219     _dbus_transport_disconnect (transport);
00220 
00221   if (transport->free_unix_user_data != NULL)
00222     (* transport->free_unix_user_data) (transport->unix_user_data);
00223 
00224   if (transport->free_windows_user_data != NULL)
00225     (* transport->free_windows_user_data) (transport->windows_user_data);
00226   
00227   _dbus_message_loader_unref (transport->loader);
00228   _dbus_auth_unref (transport->auth);
00229   _dbus_counter_set_notify (transport->live_messages,
00230                             0, 0, NULL, NULL);
00231   _dbus_counter_unref (transport->live_messages);
00232   dbus_free (transport->address);
00233   dbus_free (transport->expected_guid);
00234   if (transport->credentials)
00235     _dbus_credentials_unref (transport->credentials);
00236 }
00237 
00238 
00248 static DBusTransport*
00249 check_address (const char *address, DBusError *error)
00250 {
00251   DBusAddressEntry **entries;
00252   DBusTransport *transport = NULL;
00253   int len, i;
00254 
00255   _dbus_assert (address != NULL);
00256   _dbus_assert (*address != '\0');
00257 
00258   if (!dbus_parse_address (address, &entries, &len, error))
00259     return NULL;              /* not a valid address */
00260 
00261   for (i = 0; i < len; i++)
00262     {
00263       transport = _dbus_transport_open (entries[i], error);
00264       if (transport != NULL)
00265         break;
00266     }
00267 
00268   dbus_address_entries_free (entries);
00269   return transport;
00270 }
00271 
00279 static DBusTransport*
00280 _dbus_transport_new_for_autolaunch (const char *scope, DBusError *error)
00281 {
00282   DBusString address;
00283   DBusTransport *result = NULL;
00284 
00285   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00286 
00287   if (!_dbus_string_init (&address))
00288     {
00289       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00290       return NULL;
00291     }
00292 
00293   if (!_dbus_get_autolaunch_address (scope, &address, error))
00294     {
00295       _DBUS_ASSERT_ERROR_IS_SET (error);
00296       goto out;
00297     }
00298 
00299   result = check_address (_dbus_string_get_const_data (&address), error);
00300   if (result == NULL)
00301     _DBUS_ASSERT_ERROR_IS_SET (error);
00302   else
00303     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00304 
00305  out:
00306   _dbus_string_free (&address);
00307   return result;
00308 }
00309 
00310 static DBusTransportOpenResult
00311 _dbus_transport_open_autolaunch (DBusAddressEntry  *entry,
00312                                  DBusTransport    **transport_p,
00313                                  DBusError         *error)
00314 {
00315   const char *method;
00316   
00317   method = dbus_address_entry_get_method (entry);
00318   _dbus_assert (method != NULL);
00319 
00320   if (strcmp (method, "autolaunch") == 0)
00321     {
00322       const char *scope = dbus_address_entry_get_value (entry, "scope");
00323 
00324       *transport_p = _dbus_transport_new_for_autolaunch (scope, error);
00325 
00326       if (*transport_p == NULL)
00327         {
00328           _DBUS_ASSERT_ERROR_IS_SET (error);
00329           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00330         }
00331       else
00332         {
00333           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00334           return DBUS_TRANSPORT_OPEN_OK;
00335         }      
00336     }
00337   else
00338     {
00339       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00340       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
00341     }
00342 }
00343 
00344 static const struct {
00345   DBusTransportOpenResult (* func) (DBusAddressEntry *entry,
00346                                     DBusTransport   **transport_p,
00347                                     DBusError        *error);
00348 } open_funcs[] = {
00349   { _dbus_transport_open_socket },
00350   { _dbus_transport_open_platform_specific },
00351   { _dbus_transport_open_autolaunch }
00352 #ifdef DBUS_BUILD_TESTS
00353   , { _dbus_transport_open_debug_pipe }
00354 #endif
00355 };
00356 
00365 DBusTransport*
00366 _dbus_transport_open (DBusAddressEntry *entry,
00367                       DBusError        *error)
00368 {
00369   DBusTransport *transport;
00370   const char *expected_guid_orig;
00371   char *expected_guid;
00372   int i;
00373   DBusError tmp_error = DBUS_ERROR_INIT;
00374 
00375   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00376   
00377   transport = NULL;
00378   expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
00379   expected_guid = _dbus_strdup (expected_guid_orig);
00380 
00381   if (expected_guid_orig != NULL && expected_guid == NULL)
00382     {
00383       _DBUS_SET_OOM (error);
00384       return NULL;
00385     }
00386 
00387   for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
00388     {
00389       DBusTransportOpenResult result;
00390 
00391       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00392       result = (* open_funcs[i].func) (entry, &transport, &tmp_error);
00393 
00394       switch (result)
00395         {
00396         case DBUS_TRANSPORT_OPEN_OK:
00397           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00398           goto out;
00399           break;
00400         case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
00401           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00402           /* keep going through the loop of open funcs */
00403           break;
00404         case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
00405           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00406           goto out;
00407           break;
00408         case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
00409           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00410           goto out;
00411           break;
00412         }
00413     }
00414 
00415  out:
00416   
00417   if (transport == NULL)
00418     {
00419       if (!dbus_error_is_set (&tmp_error))
00420         _dbus_set_bad_address (&tmp_error,
00421                                NULL, NULL,
00422                                "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
00423       
00424       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00425       dbus_move_error(&tmp_error, error);
00426       dbus_free (expected_guid);
00427     }
00428   else
00429     {
00430       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00431 
00432       /* In the case of autostart the initial guid is NULL
00433        * and the autostart transport recursively calls
00434        * _dbus_open_transport wich returns a transport
00435        * with a guid.  That guid is the definitive one.
00436        *
00437        * FIXME: if more transports are added they may have
00438        * an effect on the expected_guid semantics (i.e. 
00439        * expected_guid and transport->expected_guid may
00440        * both have values).  This is very unlikely though
00441        * we should either throw asserts here for those 
00442        * corner cases or refactor the code so it is 
00443        * clearer on what is expected and what is not
00444        */
00445       if(expected_guid)
00446         transport->expected_guid = expected_guid;
00447     }
00448 
00449   return transport;
00450 }
00451 
00458 DBusTransport *
00459 _dbus_transport_ref (DBusTransport *transport)
00460 {
00461   _dbus_assert (transport->refcount > 0);
00462   
00463   transport->refcount += 1;
00464 
00465   return transport;
00466 }
00467 
00475 void
00476 _dbus_transport_unref (DBusTransport *transport)
00477 {
00478   _dbus_assert (transport != NULL);
00479   _dbus_assert (transport->refcount > 0);
00480   
00481   transport->refcount -= 1;
00482   if (transport->refcount == 0)
00483     {
00484       _dbus_verbose ("finalizing\n");
00485       
00486       _dbus_assert (transport->vtable->finalize != NULL);
00487       
00488       (* transport->vtable->finalize) (transport);
00489     }
00490 }
00491 
00500 void
00501 _dbus_transport_disconnect (DBusTransport *transport)
00502 {
00503   _dbus_verbose ("start\n");
00504   
00505   _dbus_assert (transport->vtable->disconnect != NULL);
00506   
00507   if (transport->disconnected)
00508     return;
00509 
00510   (* transport->vtable->disconnect) (transport);
00511   
00512   transport->disconnected = TRUE;
00513 
00514   _dbus_verbose ("end\n");
00515 }
00516 
00525 dbus_bool_t
00526 _dbus_transport_get_is_connected (DBusTransport *transport)
00527 {
00528   return !transport->disconnected;
00529 }
00530 
00531 static dbus_bool_t
00532 auth_via_unix_user_function (DBusTransport *transport)
00533 {
00534   DBusCredentials *auth_identity;
00535   dbus_bool_t allow;
00536   DBusConnection *connection;
00537   DBusAllowUnixUserFunction unix_user_function;
00538   void *unix_user_data;
00539   dbus_uid_t uid;
00540 
00541   /* Dropping the lock here probably isn't that safe. */
00542   
00543   auth_identity = _dbus_auth_get_identity (transport->auth);
00544   _dbus_assert (auth_identity != NULL);
00545 
00546   connection = transport->connection;
00547   unix_user_function = transport->unix_user_function;
00548   unix_user_data = transport->unix_user_data;
00549   uid = _dbus_credentials_get_unix_uid (auth_identity);
00550               
00551   _dbus_verbose ("unlock\n");
00552   _dbus_connection_unlock (connection);
00553 
00554   allow = (* unix_user_function) (connection,
00555                                   uid,
00556                                   unix_user_data);
00557               
00558   _dbus_verbose ("lock post unix user function\n");
00559   _dbus_connection_lock (connection);
00560 
00561   if (allow)
00562     {
00563       _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
00564     }
00565   else
00566     {
00567       _dbus_verbose ("Client UID "DBUS_UID_FORMAT
00568                      " was rejected, disconnecting\n",
00569                      _dbus_credentials_get_unix_uid (auth_identity));
00570       _dbus_transport_disconnect (transport);
00571     }
00572 
00573   return allow;
00574 }
00575 
00576 static dbus_bool_t
00577 auth_via_windows_user_function (DBusTransport *transport)
00578 {
00579   DBusCredentials *auth_identity;  
00580   dbus_bool_t allow;
00581   DBusConnection *connection;
00582   DBusAllowWindowsUserFunction windows_user_function;
00583   void *windows_user_data;
00584   char *windows_sid;
00585 
00586   /* Dropping the lock here probably isn't that safe. */
00587   
00588   auth_identity = _dbus_auth_get_identity (transport->auth);
00589   _dbus_assert (auth_identity != NULL);
00590 
00591   connection = transport->connection;
00592   windows_user_function = transport->windows_user_function;
00593   windows_user_data = transport->unix_user_data;
00594   windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
00595 
00596   if (windows_sid == NULL)
00597     {
00598       /* OOM */
00599       return FALSE;
00600     }
00601                 
00602   _dbus_verbose ("unlock\n");
00603   _dbus_connection_unlock (connection);
00604 
00605   allow = (* windows_user_function) (connection,
00606                                      windows_sid,
00607                                      windows_user_data);
00608               
00609   _dbus_verbose ("lock post windows user function\n");
00610   _dbus_connection_lock (connection);
00611 
00612   if (allow)
00613     {
00614       _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
00615     }
00616   else
00617     {
00618       _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
00619                      _dbus_credentials_get_windows_sid (auth_identity));
00620       _dbus_transport_disconnect (transport);
00621     }
00622 
00623   return allow;
00624 }
00625 
00626 static dbus_bool_t
00627 auth_via_default_rules (DBusTransport *transport)
00628 {
00629   DBusCredentials *auth_identity;
00630   DBusCredentials *our_identity;
00631   dbus_bool_t allow;
00632   
00633   auth_identity = _dbus_auth_get_identity (transport->auth);
00634   _dbus_assert (auth_identity != NULL);
00635 
00636   /* By default, connection is allowed if the client is 1) root or 2)
00637    * has the same UID as us or 3) anonymous is allowed.
00638    */
00639   
00640   our_identity = _dbus_credentials_new_from_current_process ();
00641   if (our_identity == NULL)
00642     {
00643       /* OOM */
00644       return FALSE;
00645     }
00646               
00647   if (transport->allow_anonymous ||
00648       _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
00649       _dbus_credentials_same_user (our_identity,
00650                                    auth_identity))
00651     {
00652       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
00653           _dbus_verbose ("Client authorized as SID '%s'"
00654                          "matching our SID '%s'\n",
00655                          _dbus_credentials_get_windows_sid(auth_identity),
00656                          _dbus_credentials_get_windows_sid(our_identity));
00657       else
00658           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
00659                          " matching our UID "DBUS_UID_FORMAT"\n",
00660                          _dbus_credentials_get_unix_uid(auth_identity),
00661                          _dbus_credentials_get_unix_uid(our_identity));
00662       /* We have authenticated! */
00663       allow = TRUE;
00664     }
00665   else
00666     {
00667       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
00668           _dbus_verbose ("Client authorized as SID '%s'"
00669                          " but our SID is '%s', disconnecting\n",
00670                          (_dbus_credentials_get_windows_sid(auth_identity) ?
00671                           _dbus_credentials_get_windows_sid(auth_identity) : "<null>"),
00672                          (_dbus_credentials_get_windows_sid(our_identity) ?
00673                           _dbus_credentials_get_windows_sid(our_identity) : "<null>"));
00674       else
00675           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
00676                          " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
00677                          _dbus_credentials_get_unix_uid(auth_identity),
00678                          _dbus_credentials_get_unix_uid(our_identity));
00679       _dbus_transport_disconnect (transport);
00680       allow = FALSE;
00681     }  
00682 
00683   _dbus_credentials_unref (our_identity);
00684   
00685   return allow;
00686 }
00687 
00688 
00699 dbus_bool_t
00700 _dbus_transport_get_is_authenticated (DBusTransport *transport)
00701 {  
00702   if (transport->authenticated)
00703     return TRUE;
00704   else
00705     {
00706       dbus_bool_t maybe_authenticated;
00707       
00708       if (transport->disconnected)
00709         return FALSE;
00710 
00711       /* paranoia ref since we call user callbacks sometimes */
00712       _dbus_connection_ref_unlocked (transport->connection);
00713       
00714       maybe_authenticated =
00715         (!(transport->send_credentials_pending ||
00716            transport->receive_credentials_pending));
00717 
00718       if (maybe_authenticated)
00719         {
00720           switch (_dbus_auth_do_work (transport->auth))
00721             {
00722             case DBUS_AUTH_STATE_AUTHENTICATED:
00723               /* leave as maybe_authenticated */
00724               break;
00725             default:
00726               maybe_authenticated = FALSE;
00727             }
00728         }
00729 
00730       /* If we're the client, verify the GUID
00731        */
00732       if (maybe_authenticated && !transport->is_server)
00733         {
00734           const char *server_guid;
00735 
00736           server_guid = _dbus_auth_get_guid_from_server (transport->auth);
00737           _dbus_assert (server_guid != NULL);
00738 
00739           if (transport->expected_guid &&
00740               strcmp (transport->expected_guid, server_guid) != 0)
00741             {
00742               _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
00743                              transport->expected_guid, server_guid);
00744               _dbus_transport_disconnect (transport);
00745               _dbus_connection_unref_unlocked (transport->connection);
00746               return FALSE;
00747             }
00748         }
00749 
00750       /* If we're the server, see if we want to allow this identity to proceed.
00751        */
00752       if (maybe_authenticated && transport->is_server)
00753         {
00754           dbus_bool_t allow;
00755           DBusCredentials *auth_identity;
00756           
00757           auth_identity = _dbus_auth_get_identity (transport->auth);
00758           _dbus_assert (auth_identity != NULL);
00759           
00760           /* If we have an auth'd user and a user function, delegate
00761            * deciding whether auth credentials are good enough to the
00762            * app; otherwise, use our default decision process.
00763            */
00764           if (transport->unix_user_function != NULL &&
00765               _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
00766             {
00767               allow = auth_via_unix_user_function (transport);
00768             }
00769           else if (transport->windows_user_function != NULL &&
00770                    _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
00771             {
00772               allow = auth_via_windows_user_function (transport);
00773             }      
00774           else
00775             {
00776               allow = auth_via_default_rules (transport);
00777             }
00778           
00779           if (!allow)
00780             maybe_authenticated = FALSE;
00781         }
00782 
00783       transport->authenticated = maybe_authenticated;
00784 
00785       _dbus_connection_unref_unlocked (transport->connection);
00786       return maybe_authenticated;
00787     }
00788 }
00789 
00796 dbus_bool_t
00797 _dbus_transport_get_is_anonymous (DBusTransport *transport)
00798 {
00799   DBusCredentials *auth_identity;
00800   
00801   if (!transport->authenticated)
00802     return TRUE;
00803   
00804   auth_identity = _dbus_auth_get_identity (transport->auth);
00805 
00806   if (_dbus_credentials_are_anonymous (auth_identity))
00807     return TRUE;
00808   else
00809     return FALSE;
00810 }
00811 
00818 dbus_bool_t
00819 _dbus_transport_can_pass_unix_fd(DBusTransport *transport)
00820 {
00821   return DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport);
00822 }
00823 
00831 const char*
00832 _dbus_transport_get_address (DBusTransport *transport)
00833 {
00834   return transport->address;
00835 }
00836 
00844 const char*
00845 _dbus_transport_get_server_id (DBusTransport *transport)
00846 {
00847   if (transport->is_server)
00848     return NULL;
00849   else if (transport->authenticated)
00850     return _dbus_auth_get_guid_from_server (transport->auth);
00851   else
00852     return transport->expected_guid;
00853 }
00854 
00864 dbus_bool_t
00865 _dbus_transport_handle_watch (DBusTransport           *transport,
00866                               DBusWatch               *watch,
00867                               unsigned int             condition)
00868 {
00869   dbus_bool_t retval;
00870   
00871   _dbus_assert (transport->vtable->handle_watch != NULL);
00872 
00873   if (transport->disconnected)
00874     return TRUE;
00875 
00876   if (dbus_watch_get_socket (watch) < 0)
00877     {
00878       _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
00879       return TRUE;
00880     }
00881   
00882   _dbus_watch_sanitize_condition (watch, &condition);
00883 
00884   _dbus_transport_ref (transport);
00885   _dbus_watch_ref (watch);
00886   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
00887   _dbus_watch_unref (watch);
00888   _dbus_transport_unref (transport);
00889 
00890   return retval;
00891 }
00892 
00902 dbus_bool_t
00903 _dbus_transport_set_connection (DBusTransport  *transport,
00904                                 DBusConnection *connection)
00905 {
00906   _dbus_assert (transport->vtable->connection_set != NULL);
00907   _dbus_assert (transport->connection == NULL);
00908   
00909   transport->connection = connection;
00910 
00911   _dbus_transport_ref (transport);
00912   if (!(* transport->vtable->connection_set) (transport))
00913     transport->connection = NULL;
00914   _dbus_transport_unref (transport);
00915 
00916   return transport->connection != NULL;
00917 }
00918 
00926 dbus_bool_t
00927 _dbus_transport_get_socket_fd (DBusTransport *transport,
00928                                int           *fd_p)
00929 {
00930   dbus_bool_t retval;
00931   
00932   if (transport->vtable->get_socket_fd == NULL)
00933     return FALSE;
00934 
00935   if (transport->disconnected)
00936     return FALSE;
00937 
00938   _dbus_transport_ref (transport);
00939 
00940   retval = (* transport->vtable->get_socket_fd) (transport,
00941                                                  fd_p);
00942   
00943   _dbus_transport_unref (transport);
00944 
00945   return retval;
00946 }
00947 
00959 void
00960 _dbus_transport_do_iteration (DBusTransport  *transport,
00961                               unsigned int    flags,
00962                               int             timeout_milliseconds)
00963 {
00964   _dbus_assert (transport->vtable->do_iteration != NULL);
00965 
00966   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
00967                  flags, timeout_milliseconds, !transport->disconnected);
00968   
00969   if ((flags & (DBUS_ITERATION_DO_WRITING |
00970                 DBUS_ITERATION_DO_READING)) == 0)
00971     return; /* Nothing to do */
00972 
00973   if (transport->disconnected)
00974     return;
00975 
00976   _dbus_transport_ref (transport);
00977   (* transport->vtable->do_iteration) (transport, flags,
00978                                        timeout_milliseconds);
00979   _dbus_transport_unref (transport);
00980 
00981   _dbus_verbose ("end\n");
00982 }
00983 
00984 static dbus_bool_t
00985 recover_unused_bytes (DBusTransport *transport)
00986 {
00987   if (_dbus_auth_needs_decoding (transport->auth))
00988     {
00989       DBusString plaintext;
00990       const DBusString *encoded;
00991       DBusString *buffer;
00992       int orig_len;
00993       
00994       if (!_dbus_string_init (&plaintext))
00995         goto nomem;
00996       
00997       _dbus_auth_get_unused_bytes (transport->auth,
00998                                    &encoded);
00999 
01000       if (!_dbus_auth_decode_data (transport->auth,
01001                                    encoded, &plaintext))
01002         {
01003           _dbus_string_free (&plaintext);
01004           goto nomem;
01005         }
01006       
01007       _dbus_message_loader_get_buffer (transport->loader,
01008                                        &buffer);
01009       
01010       orig_len = _dbus_string_get_length (buffer);
01011       
01012       if (!_dbus_string_move (&plaintext, 0, buffer,
01013                               orig_len))
01014         {
01015           _dbus_string_free (&plaintext);
01016           goto nomem;
01017         }
01018       
01019       _dbus_verbose (" %d unused bytes sent to message loader\n", 
01020                      _dbus_string_get_length (buffer) -
01021                      orig_len);
01022       
01023       _dbus_message_loader_return_buffer (transport->loader,
01024                                           buffer,
01025                                           _dbus_string_get_length (buffer) -
01026                                           orig_len);
01027 
01028       _dbus_auth_delete_unused_bytes (transport->auth);
01029       
01030       _dbus_string_free (&plaintext);
01031     }
01032   else
01033     {
01034       const DBusString *bytes;
01035       DBusString *buffer;
01036       int orig_len;
01037       dbus_bool_t succeeded;
01038 
01039       _dbus_message_loader_get_buffer (transport->loader,
01040                                        &buffer);
01041                 
01042       orig_len = _dbus_string_get_length (buffer);
01043                 
01044       _dbus_auth_get_unused_bytes (transport->auth,
01045                                    &bytes);
01046 
01047       succeeded = TRUE;
01048       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
01049         succeeded = FALSE;
01050       
01051       _dbus_verbose (" %d unused bytes sent to message loader\n", 
01052                      _dbus_string_get_length (buffer) -
01053                      orig_len);
01054       
01055       _dbus_message_loader_return_buffer (transport->loader,
01056                                           buffer,
01057                                           _dbus_string_get_length (buffer) -
01058                                           orig_len);
01059 
01060       if (succeeded)
01061         _dbus_auth_delete_unused_bytes (transport->auth);
01062       else
01063         goto nomem;
01064     }
01065 
01066   return TRUE;
01067 
01068  nomem:
01069   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
01070   return FALSE;
01071 }
01072 
01080 DBusDispatchStatus
01081 _dbus_transport_get_dispatch_status (DBusTransport *transport)
01082 {
01083   if (_dbus_counter_get_size_value (transport->live_messages) >= transport->max_live_messages_size ||
01084       _dbus_counter_get_unix_fd_value (transport->live_messages) >= transport->max_live_messages_unix_fds)
01085     return DBUS_DISPATCH_COMPLETE; /* complete for now */
01086 
01087   if (!_dbus_transport_get_is_authenticated (transport))
01088     {
01089       if (_dbus_auth_do_work (transport->auth) ==
01090           DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
01091         return DBUS_DISPATCH_NEED_MEMORY;
01092       else if (!_dbus_transport_get_is_authenticated (transport))
01093         return DBUS_DISPATCH_COMPLETE;
01094     }
01095 
01096   if (!transport->unused_bytes_recovered &&
01097       !recover_unused_bytes (transport))
01098     return DBUS_DISPATCH_NEED_MEMORY;
01099 
01100   transport->unused_bytes_recovered = TRUE;
01101   
01102   if (!_dbus_message_loader_queue_messages (transport->loader))
01103     return DBUS_DISPATCH_NEED_MEMORY;
01104 
01105   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
01106     return DBUS_DISPATCH_DATA_REMAINS;
01107   else
01108     return DBUS_DISPATCH_COMPLETE;
01109 }
01110 
01119 dbus_bool_t
01120 _dbus_transport_queue_messages (DBusTransport *transport)
01121 {
01122   DBusDispatchStatus status;
01123 
01124 #if 0
01125   _dbus_verbose ("_dbus_transport_queue_messages()\n");
01126 #endif
01127   
01128   /* Queue any messages */
01129   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
01130     {
01131       DBusMessage *message;
01132       DBusList *link;
01133 
01134       link = _dbus_message_loader_pop_message_link (transport->loader);
01135       _dbus_assert (link != NULL);
01136       
01137       message = link->data;
01138       
01139       _dbus_verbose ("queueing received message %p\n", message);
01140 
01141       if (!_dbus_message_add_counter (message, transport->live_messages))
01142         {
01143           _dbus_message_loader_putback_message_link (transport->loader,
01144                                                      link);
01145           status = DBUS_DISPATCH_NEED_MEMORY;
01146           break;
01147         }
01148       else
01149         {
01150           /* We didn't call the notify function when we added the counter, so
01151            * catch up now. Since we have the connection's lock, it's desirable
01152            * that we bypass the notify function and call this virtual method
01153            * directly. */
01154           if (transport->vtable->live_messages_changed)
01155             (* transport->vtable->live_messages_changed) (transport);
01156 
01157           /* pass ownership of link and message ref to connection */
01158           _dbus_connection_queue_received_message_link (transport->connection,
01159                                                         link);
01160         }
01161     }
01162 
01163   if (_dbus_message_loader_get_is_corrupted (transport->loader))
01164     {
01165       _dbus_verbose ("Corrupted message stream, disconnecting\n");
01166       _dbus_transport_disconnect (transport);
01167     }
01168 
01169   return status != DBUS_DISPATCH_NEED_MEMORY;
01170 }
01171 
01178 void
01179 _dbus_transport_set_max_message_size (DBusTransport  *transport,
01180                                       long            size)
01181 {
01182   _dbus_message_loader_set_max_message_size (transport->loader, size);
01183 }
01184 
01191 void
01192 _dbus_transport_set_max_message_unix_fds (DBusTransport  *transport,
01193                                           long            n)
01194 {
01195   _dbus_message_loader_set_max_message_unix_fds (transport->loader, n);
01196 }
01197 
01204 long
01205 _dbus_transport_get_max_message_size (DBusTransport  *transport)
01206 {
01207   return _dbus_message_loader_get_max_message_size (transport->loader);
01208 }
01209 
01216 long
01217 _dbus_transport_get_max_message_unix_fds (DBusTransport  *transport)
01218 {
01219   return _dbus_message_loader_get_max_message_unix_fds (transport->loader);
01220 }
01221 
01228 void
01229 _dbus_transport_set_max_received_size (DBusTransport  *transport,
01230                                        long            size)
01231 {
01232   transport->max_live_messages_size = size;
01233   _dbus_counter_set_notify (transport->live_messages,
01234                             transport->max_live_messages_size,
01235                             transport->max_live_messages_unix_fds,
01236                             live_messages_notify,
01237                             transport);
01238 }
01239 
01246 void
01247 _dbus_transport_set_max_received_unix_fds (DBusTransport  *transport,
01248                                            long            n)
01249 {
01250   transport->max_live_messages_unix_fds = n;
01251   _dbus_counter_set_notify (transport->live_messages,
01252                             transport->max_live_messages_size,
01253                             transport->max_live_messages_unix_fds,
01254                             live_messages_notify,
01255                             transport);
01256 }
01257 
01264 long
01265 _dbus_transport_get_max_received_size (DBusTransport  *transport)
01266 {
01267   return transport->max_live_messages_size;
01268 }
01269 
01276 long
01277 _dbus_transport_get_max_received_unix_fds (DBusTransport  *transport)
01278 {
01279   return transport->max_live_messages_unix_fds;
01280 }
01281 
01289 dbus_bool_t
01290 _dbus_transport_get_unix_user (DBusTransport *transport,
01291                                unsigned long *uid)
01292 {
01293   DBusCredentials *auth_identity;
01294 
01295   *uid = _DBUS_INT32_MAX; /* better than some root or system user in
01296                            * case of bugs in the caller. Caller should
01297                            * never use this value on purpose, however.
01298                            */
01299   
01300   if (!transport->authenticated)
01301     return FALSE;
01302   
01303   auth_identity = _dbus_auth_get_identity (transport->auth);
01304 
01305   if (_dbus_credentials_include (auth_identity,
01306                                  DBUS_CREDENTIAL_UNIX_USER_ID))
01307     {
01308       *uid = _dbus_credentials_get_unix_uid (auth_identity);
01309       return TRUE;
01310     }
01311   else
01312     return FALSE;
01313 }
01314 
01322 dbus_bool_t
01323 _dbus_transport_get_unix_process_id (DBusTransport *transport,
01324                                      unsigned long *pid)
01325 {
01326   DBusCredentials *auth_identity;
01327 
01328   *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,
01329                           * but we set it to a safe number, INT_MAX,
01330                           * just to root out possible bugs in bad callers.
01331                           */
01332   
01333   if (!transport->authenticated)
01334     return FALSE;
01335   
01336   auth_identity = _dbus_auth_get_identity (transport->auth);
01337 
01338   if (_dbus_credentials_include (auth_identity,
01339                                  DBUS_CREDENTIAL_UNIX_PROCESS_ID))
01340     {
01341       *pid = _dbus_credentials_get_unix_pid (auth_identity);
01342       return TRUE;
01343     }
01344   else
01345     return FALSE;
01346 }
01347 
01356 dbus_bool_t
01357 _dbus_transport_get_adt_audit_session_data (DBusTransport      *transport,
01358                                             void              **data,
01359                                             int                *data_size)
01360 {
01361   DBusCredentials *auth_identity;
01362 
01363   *data = NULL;
01364   *data_size = 0;
01365   
01366   if (!transport->authenticated)
01367     return FALSE;
01368   
01369   auth_identity = _dbus_auth_get_identity (transport->auth);
01370 
01371   if (_dbus_credentials_include (auth_identity,
01372                                  DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID))
01373     {
01374       *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity);
01375       *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity);
01376       return TRUE;
01377     }
01378   else
01379     return FALSE;
01380 }
01381 
01392 void
01393 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
01394                                         DBusAllowUnixUserFunction  function,
01395                                         void                      *data,
01396                                         DBusFreeFunction           free_data_function,
01397                                         void                     **old_data,
01398                                         DBusFreeFunction          *old_free_data_function)
01399 {  
01400   *old_data = transport->unix_user_data;
01401   *old_free_data_function = transport->free_unix_user_data;
01402 
01403   transport->unix_user_function = function;
01404   transport->unix_user_data = data;
01405   transport->free_unix_user_data = free_data_function;
01406 }
01407 
01415 dbus_bool_t
01416 _dbus_transport_get_windows_user (DBusTransport              *transport,
01417                                   char                      **windows_sid_p)
01418 {
01419   DBusCredentials *auth_identity;
01420 
01421   *windows_sid_p = NULL;
01422   
01423   if (!transport->authenticated)
01424     return FALSE;
01425   
01426   auth_identity = _dbus_auth_get_identity (transport->auth);
01427 
01428   if (_dbus_credentials_include (auth_identity,
01429                                  DBUS_CREDENTIAL_WINDOWS_SID))
01430     {
01431       /* If no memory, we are supposed to return TRUE and set NULL */
01432       *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
01433 
01434       return TRUE;
01435     }
01436   else
01437     return FALSE;
01438 }
01439 
01451 void
01452 _dbus_transport_set_windows_user_function (DBusTransport              *transport,
01453                                            DBusAllowWindowsUserFunction   function,
01454                                            void                       *data,
01455                                            DBusFreeFunction            free_data_function,
01456                                            void                      **old_data,
01457                                            DBusFreeFunction           *old_free_data_function)
01458 {
01459   *old_data = transport->windows_user_data;
01460   *old_free_data_function = transport->free_windows_user_data;
01461 
01462   transport->windows_user_function = function;
01463   transport->windows_user_data = data;
01464   transport->free_windows_user_data = free_data_function;
01465 }
01466 
01475 dbus_bool_t
01476 _dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
01477                                      const char    **mechanisms)
01478 {
01479   return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
01480 }
01481 
01488 void
01489 _dbus_transport_set_allow_anonymous (DBusTransport              *transport,
01490                                      dbus_bool_t                 value)
01491 {
01492   transport->allow_anonymous = value != FALSE;
01493 }
01494 
01495 #ifdef DBUS_ENABLE_STATS
01496 void
01497 _dbus_transport_get_stats (DBusTransport  *transport,
01498                            dbus_uint32_t  *queue_bytes,
01499                            dbus_uint32_t  *queue_fds,
01500                            dbus_uint32_t  *peak_queue_bytes,
01501                            dbus_uint32_t  *peak_queue_fds)
01502 {
01503   if (queue_bytes != NULL)
01504     *queue_bytes = _dbus_counter_get_size_value (transport->live_messages);
01505 
01506   if (queue_fds != NULL)
01507     *queue_fds = _dbus_counter_get_unix_fd_value (transport->live_messages);
01508 
01509   if (peak_queue_bytes != NULL)
01510     *peak_queue_bytes = _dbus_counter_get_peak_size_value (transport->live_messages);
01511 
01512   if (peak_queue_fds != NULL)
01513     *peak_queue_fds = _dbus_counter_get_peak_unix_fd_value (transport->live_messages);
01514 }
01515 #endif /* DBUS_ENABLE_STATS */
01516