D-Bus  1.6.8
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 
00257   if (!dbus_parse_address (address, &entries, &len, error))
00258     return NULL;              /* not a valid address */
00259 
00260   for (i = 0; i < len; i++)
00261     {
00262       transport = _dbus_transport_open (entries[i], error);
00263       if (transport != NULL)
00264         break;
00265     }
00266 
00267   dbus_address_entries_free (entries);
00268   return transport;
00269 }
00270 
00278 static DBusTransport*
00279 _dbus_transport_new_for_autolaunch (const char *scope, DBusError *error)
00280 {
00281   DBusString address;
00282   DBusTransport *result = NULL;
00283 
00284   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00285 
00286   if (!_dbus_string_init (&address))
00287     {
00288       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00289       return NULL;
00290     }
00291 
00292   if (!_dbus_get_autolaunch_address (scope, &address, error))
00293     {
00294       _DBUS_ASSERT_ERROR_IS_SET (error);
00295       goto out;
00296     }
00297 
00298   result = check_address (_dbus_string_get_const_data (&address), error);
00299   if (result == NULL)
00300     _DBUS_ASSERT_ERROR_IS_SET (error);
00301   else
00302     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00303 
00304  out:
00305   _dbus_string_free (&address);
00306   return result;
00307 }
00308 
00309 static DBusTransportOpenResult
00310 _dbus_transport_open_autolaunch (DBusAddressEntry  *entry,
00311                                  DBusTransport    **transport_p,
00312                                  DBusError         *error)
00313 {
00314   const char *method;
00315   
00316   method = dbus_address_entry_get_method (entry);
00317   _dbus_assert (method != NULL);
00318 
00319   if (strcmp (method, "autolaunch") == 0)
00320     {
00321       const char *scope = dbus_address_entry_get_value (entry, "scope");
00322 
00323       *transport_p = _dbus_transport_new_for_autolaunch (scope, error);
00324 
00325       if (*transport_p == NULL)
00326         {
00327           _DBUS_ASSERT_ERROR_IS_SET (error);
00328           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00329         }
00330       else
00331         {
00332           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00333           return DBUS_TRANSPORT_OPEN_OK;
00334         }      
00335     }
00336   else
00337     {
00338       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00339       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
00340     }
00341 }
00342 
00343 static const struct {
00344   DBusTransportOpenResult (* func) (DBusAddressEntry *entry,
00345                                     DBusTransport   **transport_p,
00346                                     DBusError        *error);
00347 } open_funcs[] = {
00348   { _dbus_transport_open_socket },
00349   { _dbus_transport_open_platform_specific },
00350   { _dbus_transport_open_autolaunch }
00351 #ifdef DBUS_BUILD_TESTS
00352   , { _dbus_transport_open_debug_pipe }
00353 #endif
00354 };
00355 
00364 DBusTransport*
00365 _dbus_transport_open (DBusAddressEntry *entry,
00366                       DBusError        *error)
00367 {
00368   DBusTransport *transport;
00369   const char *expected_guid_orig;
00370   char *expected_guid;
00371   int i;
00372   DBusError tmp_error = DBUS_ERROR_INIT;
00373 
00374   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00375   
00376   transport = NULL;
00377   expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
00378   expected_guid = _dbus_strdup (expected_guid_orig);
00379 
00380   if (expected_guid_orig != NULL && expected_guid == NULL)
00381     {
00382       _DBUS_SET_OOM (error);
00383       return NULL;
00384     }
00385 
00386   for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
00387     {
00388       DBusTransportOpenResult result;
00389 
00390       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00391       result = (* open_funcs[i].func) (entry, &transport, &tmp_error);
00392 
00393       switch (result)
00394         {
00395         case DBUS_TRANSPORT_OPEN_OK:
00396           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00397           goto out;
00398           break;
00399         case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
00400           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00401           /* keep going through the loop of open funcs */
00402           break;
00403         case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
00404           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00405           goto out;
00406           break;
00407         case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
00408           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00409           goto out;
00410           break;
00411         }
00412     }
00413 
00414  out:
00415   
00416   if (transport == NULL)
00417     {
00418       if (!dbus_error_is_set (&tmp_error))
00419         _dbus_set_bad_address (&tmp_error,
00420                                NULL, NULL,
00421                                "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
00422       
00423       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00424       dbus_move_error(&tmp_error, error);
00425       dbus_free (expected_guid);
00426     }
00427   else
00428     {
00429       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00430 
00431       /* In the case of autostart the initial guid is NULL
00432        * and the autostart transport recursively calls
00433        * _dbus_open_transport wich returns a transport
00434        * with a guid.  That guid is the definitive one.
00435        *
00436        * FIXME: if more transports are added they may have
00437        * an effect on the expected_guid semantics (i.e. 
00438        * expected_guid and transport->expected_guid may
00439        * both have values).  This is very unlikely though
00440        * we should either throw asserts here for those 
00441        * corner cases or refactor the code so it is 
00442        * clearer on what is expected and what is not
00443        */
00444       if(expected_guid)
00445         transport->expected_guid = expected_guid;
00446     }
00447 
00448   return transport;
00449 }
00450 
00457 DBusTransport *
00458 _dbus_transport_ref (DBusTransport *transport)
00459 {
00460   _dbus_assert (transport->refcount > 0);
00461   
00462   transport->refcount += 1;
00463 
00464   return transport;
00465 }
00466 
00474 void
00475 _dbus_transport_unref (DBusTransport *transport)
00476 {
00477   _dbus_assert (transport != NULL);
00478   _dbus_assert (transport->refcount > 0);
00479   
00480   transport->refcount -= 1;
00481   if (transport->refcount == 0)
00482     {
00483       _dbus_verbose ("finalizing\n");
00484       
00485       _dbus_assert (transport->vtable->finalize != NULL);
00486       
00487       (* transport->vtable->finalize) (transport);
00488     }
00489 }
00490 
00499 void
00500 _dbus_transport_disconnect (DBusTransport *transport)
00501 {
00502   _dbus_verbose ("start\n");
00503   
00504   _dbus_assert (transport->vtable->disconnect != NULL);
00505   
00506   if (transport->disconnected)
00507     return;
00508 
00509   (* transport->vtable->disconnect) (transport);
00510   
00511   transport->disconnected = TRUE;
00512 
00513   _dbus_verbose ("end\n");
00514 }
00515 
00524 dbus_bool_t
00525 _dbus_transport_get_is_connected (DBusTransport *transport)
00526 {
00527   return !transport->disconnected;
00528 }
00529 
00530 static dbus_bool_t
00531 auth_via_unix_user_function (DBusTransport *transport)
00532 {
00533   DBusCredentials *auth_identity;
00534   dbus_bool_t allow;
00535   DBusConnection *connection;
00536   DBusAllowUnixUserFunction unix_user_function;
00537   void *unix_user_data;
00538   dbus_uid_t uid;
00539 
00540   /* Dropping the lock here probably isn't that safe. */
00541   
00542   auth_identity = _dbus_auth_get_identity (transport->auth);
00543   _dbus_assert (auth_identity != NULL);
00544 
00545   connection = transport->connection;
00546   unix_user_function = transport->unix_user_function;
00547   unix_user_data = transport->unix_user_data;
00548   uid = _dbus_credentials_get_unix_uid (auth_identity);
00549               
00550   _dbus_verbose ("unlock\n");
00551   _dbus_connection_unlock (connection);
00552 
00553   allow = (* unix_user_function) (connection,
00554                                   uid,
00555                                   unix_user_data);
00556               
00557   _dbus_verbose ("lock post unix user function\n");
00558   _dbus_connection_lock (connection);
00559 
00560   if (allow)
00561     {
00562       _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
00563     }
00564   else
00565     {
00566       _dbus_verbose ("Client UID "DBUS_UID_FORMAT
00567                      " was rejected, disconnecting\n",
00568                      _dbus_credentials_get_unix_uid (auth_identity));
00569       _dbus_transport_disconnect (transport);
00570     }
00571 
00572   return allow;
00573 }
00574 
00575 static dbus_bool_t
00576 auth_via_windows_user_function (DBusTransport *transport)
00577 {
00578   DBusCredentials *auth_identity;  
00579   dbus_bool_t allow;
00580   DBusConnection *connection;
00581   DBusAllowWindowsUserFunction windows_user_function;
00582   void *windows_user_data;
00583   char *windows_sid;
00584 
00585   /* Dropping the lock here probably isn't that safe. */
00586   
00587   auth_identity = _dbus_auth_get_identity (transport->auth);
00588   _dbus_assert (auth_identity != NULL);
00589 
00590   connection = transport->connection;
00591   windows_user_function = transport->windows_user_function;
00592   windows_user_data = transport->unix_user_data;
00593   windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
00594 
00595   if (windows_sid == NULL)
00596     {
00597       /* OOM */
00598       return FALSE;
00599     }
00600                 
00601   _dbus_verbose ("unlock\n");
00602   _dbus_connection_unlock (connection);
00603 
00604   allow = (* windows_user_function) (connection,
00605                                      windows_sid,
00606                                      windows_user_data);
00607               
00608   _dbus_verbose ("lock post windows user function\n");
00609   _dbus_connection_lock (connection);
00610 
00611   if (allow)
00612     {
00613       _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
00614     }
00615   else
00616     {
00617       _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
00618                      _dbus_credentials_get_windows_sid (auth_identity));
00619       _dbus_transport_disconnect (transport);
00620     }
00621 
00622   return allow;
00623 }
00624 
00625 static dbus_bool_t
00626 auth_via_default_rules (DBusTransport *transport)
00627 {
00628   DBusCredentials *auth_identity;
00629   DBusCredentials *our_identity;
00630   dbus_bool_t allow;
00631   
00632   auth_identity = _dbus_auth_get_identity (transport->auth);
00633   _dbus_assert (auth_identity != NULL);
00634 
00635   /* By default, connection is allowed if the client is 1) root or 2)
00636    * has the same UID as us or 3) anonymous is allowed.
00637    */
00638   
00639   our_identity = _dbus_credentials_new_from_current_process ();
00640   if (our_identity == NULL)
00641     {
00642       /* OOM */
00643       return FALSE;
00644     }
00645               
00646   if (transport->allow_anonymous ||
00647       _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
00648       _dbus_credentials_same_user (our_identity,
00649                                    auth_identity))
00650     {
00651       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
00652           _dbus_verbose ("Client authorized as SID '%s'"
00653                          "matching our SID '%s'\n",
00654                          _dbus_credentials_get_windows_sid(auth_identity),
00655                          _dbus_credentials_get_windows_sid(our_identity));
00656       else
00657           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
00658                          " matching our UID "DBUS_UID_FORMAT"\n",
00659                          _dbus_credentials_get_unix_uid(auth_identity),
00660                          _dbus_credentials_get_unix_uid(our_identity));
00661       /* We have authenticated! */
00662       allow = TRUE;
00663     }
00664   else
00665     {
00666       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
00667           _dbus_verbose ("Client authorized as SID '%s'"
00668                          " but our SID is '%s', disconnecting\n",
00669                          (_dbus_credentials_get_windows_sid(auth_identity) ?
00670                           _dbus_credentials_get_windows_sid(auth_identity) : "<null>"),
00671                          (_dbus_credentials_get_windows_sid(our_identity) ?
00672                           _dbus_credentials_get_windows_sid(our_identity) : "<null>"));
00673       else
00674           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
00675                          " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
00676                          _dbus_credentials_get_unix_uid(auth_identity),
00677                          _dbus_credentials_get_unix_uid(our_identity));
00678       _dbus_transport_disconnect (transport);
00679       allow = FALSE;
00680     }  
00681 
00682   _dbus_credentials_unref (our_identity);
00683   
00684   return allow;
00685 }
00686 
00687 
00698 dbus_bool_t
00699 _dbus_transport_get_is_authenticated (DBusTransport *transport)
00700 {  
00701   if (transport->authenticated)
00702     return TRUE;
00703   else
00704     {
00705       dbus_bool_t maybe_authenticated;
00706       
00707       if (transport->disconnected)
00708         return FALSE;
00709 
00710       /* paranoia ref since we call user callbacks sometimes */
00711       _dbus_connection_ref_unlocked (transport->connection);
00712       
00713       maybe_authenticated =
00714         (!(transport->send_credentials_pending ||
00715            transport->receive_credentials_pending));
00716 
00717       if (maybe_authenticated)
00718         {
00719           switch (_dbus_auth_do_work (transport->auth))
00720             {
00721             case DBUS_AUTH_STATE_AUTHENTICATED:
00722               /* leave as maybe_authenticated */
00723               break;
00724             default:
00725               maybe_authenticated = FALSE;
00726             }
00727         }
00728 
00729       /* If we're the client, verify the GUID
00730        */
00731       if (maybe_authenticated && !transport->is_server)
00732         {
00733           const char *server_guid;
00734 
00735           server_guid = _dbus_auth_get_guid_from_server (transport->auth);
00736           _dbus_assert (server_guid != NULL);
00737 
00738           if (transport->expected_guid &&
00739               strcmp (transport->expected_guid, server_guid) != 0)
00740             {
00741               _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
00742                              transport->expected_guid, server_guid);
00743               _dbus_transport_disconnect (transport);
00744               _dbus_connection_unref_unlocked (transport->connection);
00745               return FALSE;
00746             }
00747         }
00748 
00749       /* If we're the server, see if we want to allow this identity to proceed.
00750        */
00751       if (maybe_authenticated && transport->is_server)
00752         {
00753           dbus_bool_t allow;
00754           DBusCredentials *auth_identity;
00755           
00756           auth_identity = _dbus_auth_get_identity (transport->auth);
00757           _dbus_assert (auth_identity != NULL);
00758           
00759           /* If we have an auth'd user and a user function, delegate
00760            * deciding whether auth credentials are good enough to the
00761            * app; otherwise, use our default decision process.
00762            */
00763           if (transport->unix_user_function != NULL &&
00764               _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
00765             {
00766               allow = auth_via_unix_user_function (transport);
00767             }
00768           else if (transport->windows_user_function != NULL &&
00769                    _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
00770             {
00771               allow = auth_via_windows_user_function (transport);
00772             }      
00773           else
00774             {
00775               allow = auth_via_default_rules (transport);
00776             }
00777           
00778           if (!allow)
00779             maybe_authenticated = FALSE;
00780         }
00781 
00782       transport->authenticated = maybe_authenticated;
00783 
00784       _dbus_connection_unref_unlocked (transport->connection);
00785       return maybe_authenticated;
00786     }
00787 }
00788 
00795 dbus_bool_t
00796 _dbus_transport_get_is_anonymous (DBusTransport *transport)
00797 {
00798   DBusCredentials *auth_identity;
00799   
00800   if (!transport->authenticated)
00801     return TRUE;
00802   
00803   auth_identity = _dbus_auth_get_identity (transport->auth);
00804 
00805   if (_dbus_credentials_are_anonymous (auth_identity))
00806     return TRUE;
00807   else
00808     return FALSE;
00809 }
00810 
00817 dbus_bool_t
00818 _dbus_transport_can_pass_unix_fd(DBusTransport *transport)
00819 {
00820   return DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport);
00821 }
00822 
00830 const char*
00831 _dbus_transport_get_address (DBusTransport *transport)
00832 {
00833   return transport->address;
00834 }
00835 
00843 const char*
00844 _dbus_transport_get_server_id (DBusTransport *transport)
00845 {
00846   if (transport->is_server)
00847     return NULL;
00848   else if (transport->authenticated)
00849     return _dbus_auth_get_guid_from_server (transport->auth);
00850   else
00851     return transport->expected_guid;
00852 }
00853 
00863 dbus_bool_t
00864 _dbus_transport_handle_watch (DBusTransport           *transport,
00865                               DBusWatch               *watch,
00866                               unsigned int             condition)
00867 {
00868   dbus_bool_t retval;
00869   
00870   _dbus_assert (transport->vtable->handle_watch != NULL);
00871 
00872   if (transport->disconnected)
00873     return TRUE;
00874 
00875   if (dbus_watch_get_socket (watch) < 0)
00876     {
00877       _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
00878       return TRUE;
00879     }
00880   
00881   _dbus_watch_sanitize_condition (watch, &condition);
00882 
00883   _dbus_transport_ref (transport);
00884   _dbus_watch_ref (watch);
00885   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
00886   _dbus_watch_unref (watch);
00887   _dbus_transport_unref (transport);
00888 
00889   return retval;
00890 }
00891 
00901 dbus_bool_t
00902 _dbus_transport_set_connection (DBusTransport  *transport,
00903                                 DBusConnection *connection)
00904 {
00905   _dbus_assert (transport->vtable->connection_set != NULL);
00906   _dbus_assert (transport->connection == NULL);
00907   
00908   transport->connection = connection;
00909 
00910   _dbus_transport_ref (transport);
00911   if (!(* transport->vtable->connection_set) (transport))
00912     transport->connection = NULL;
00913   _dbus_transport_unref (transport);
00914 
00915   return transport->connection != NULL;
00916 }
00917 
00925 dbus_bool_t
00926 _dbus_transport_get_socket_fd (DBusTransport *transport,
00927                                int           *fd_p)
00928 {
00929   dbus_bool_t retval;
00930   
00931   if (transport->vtable->get_socket_fd == NULL)
00932     return FALSE;
00933 
00934   if (transport->disconnected)
00935     return FALSE;
00936 
00937   _dbus_transport_ref (transport);
00938 
00939   retval = (* transport->vtable->get_socket_fd) (transport,
00940                                                  fd_p);
00941   
00942   _dbus_transport_unref (transport);
00943 
00944   return retval;
00945 }
00946 
00958 void
00959 _dbus_transport_do_iteration (DBusTransport  *transport,
00960                               unsigned int    flags,
00961                               int             timeout_milliseconds)
00962 {
00963   _dbus_assert (transport->vtable->do_iteration != NULL);
00964 
00965   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
00966                  flags, timeout_milliseconds, !transport->disconnected);
00967   
00968   if ((flags & (DBUS_ITERATION_DO_WRITING |
00969                 DBUS_ITERATION_DO_READING)) == 0)
00970     return; /* Nothing to do */
00971 
00972   if (transport->disconnected)
00973     return;
00974 
00975   _dbus_transport_ref (transport);
00976   (* transport->vtable->do_iteration) (transport, flags,
00977                                        timeout_milliseconds);
00978   _dbus_transport_unref (transport);
00979 
00980   _dbus_verbose ("end\n");
00981 }
00982 
00983 static dbus_bool_t
00984 recover_unused_bytes (DBusTransport *transport)
00985 {
00986   if (_dbus_auth_needs_decoding (transport->auth))
00987     {
00988       DBusString plaintext;
00989       const DBusString *encoded;
00990       DBusString *buffer;
00991       int orig_len;
00992       
00993       if (!_dbus_string_init (&plaintext))
00994         goto nomem;
00995       
00996       _dbus_auth_get_unused_bytes (transport->auth,
00997                                    &encoded);
00998 
00999       if (!_dbus_auth_decode_data (transport->auth,
01000                                    encoded, &plaintext))
01001         {
01002           _dbus_string_free (&plaintext);
01003           goto nomem;
01004         }
01005       
01006       _dbus_message_loader_get_buffer (transport->loader,
01007                                        &buffer);
01008       
01009       orig_len = _dbus_string_get_length (buffer);
01010       
01011       if (!_dbus_string_move (&plaintext, 0, buffer,
01012                               orig_len))
01013         {
01014           _dbus_string_free (&plaintext);
01015           goto nomem;
01016         }
01017       
01018       _dbus_verbose (" %d unused bytes sent to message loader\n", 
01019                      _dbus_string_get_length (buffer) -
01020                      orig_len);
01021       
01022       _dbus_message_loader_return_buffer (transport->loader,
01023                                           buffer,
01024                                           _dbus_string_get_length (buffer) -
01025                                           orig_len);
01026 
01027       _dbus_auth_delete_unused_bytes (transport->auth);
01028       
01029       _dbus_string_free (&plaintext);
01030     }
01031   else
01032     {
01033       const DBusString *bytes;
01034       DBusString *buffer;
01035       int orig_len;
01036       dbus_bool_t succeeded;
01037 
01038       _dbus_message_loader_get_buffer (transport->loader,
01039                                        &buffer);
01040                 
01041       orig_len = _dbus_string_get_length (buffer);
01042                 
01043       _dbus_auth_get_unused_bytes (transport->auth,
01044                                    &bytes);
01045 
01046       succeeded = TRUE;
01047       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
01048         succeeded = FALSE;
01049       
01050       _dbus_verbose (" %d unused bytes sent to message loader\n", 
01051                      _dbus_string_get_length (buffer) -
01052                      orig_len);
01053       
01054       _dbus_message_loader_return_buffer (transport->loader,
01055                                           buffer,
01056                                           _dbus_string_get_length (buffer) -
01057                                           orig_len);
01058 
01059       if (succeeded)
01060         _dbus_auth_delete_unused_bytes (transport->auth);
01061       else
01062         goto nomem;
01063     }
01064 
01065   return TRUE;
01066 
01067  nomem:
01068   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
01069   return FALSE;
01070 }
01071 
01079 DBusDispatchStatus
01080 _dbus_transport_get_dispatch_status (DBusTransport *transport)
01081 {
01082   if (_dbus_counter_get_size_value (transport->live_messages) >= transport->max_live_messages_size ||
01083       _dbus_counter_get_unix_fd_value (transport->live_messages) >= transport->max_live_messages_unix_fds)
01084     return DBUS_DISPATCH_COMPLETE; /* complete for now */
01085 
01086   if (!_dbus_transport_get_is_authenticated (transport))
01087     {
01088       if (_dbus_auth_do_work (transport->auth) ==
01089           DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
01090         return DBUS_DISPATCH_NEED_MEMORY;
01091       else if (!_dbus_transport_get_is_authenticated (transport))
01092         return DBUS_DISPATCH_COMPLETE;
01093     }
01094 
01095   if (!transport->unused_bytes_recovered &&
01096       !recover_unused_bytes (transport))
01097     return DBUS_DISPATCH_NEED_MEMORY;
01098 
01099   transport->unused_bytes_recovered = TRUE;
01100   
01101   if (!_dbus_message_loader_queue_messages (transport->loader))
01102     return DBUS_DISPATCH_NEED_MEMORY;
01103 
01104   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
01105     return DBUS_DISPATCH_DATA_REMAINS;
01106   else
01107     return DBUS_DISPATCH_COMPLETE;
01108 }
01109 
01118 dbus_bool_t
01119 _dbus_transport_queue_messages (DBusTransport *transport)
01120 {
01121   DBusDispatchStatus status;
01122 
01123 #if 0
01124   _dbus_verbose ("_dbus_transport_queue_messages()\n");
01125 #endif
01126   
01127   /* Queue any messages */
01128   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
01129     {
01130       DBusMessage *message;
01131       DBusList *link;
01132 
01133       link = _dbus_message_loader_pop_message_link (transport->loader);
01134       _dbus_assert (link != NULL);
01135       
01136       message = link->data;
01137       
01138       _dbus_verbose ("queueing received message %p\n", message);
01139 
01140       if (!_dbus_message_add_counter (message, transport->live_messages))
01141         {
01142           _dbus_message_loader_putback_message_link (transport->loader,
01143                                                      link);
01144           status = DBUS_DISPATCH_NEED_MEMORY;
01145           break;
01146         }
01147       else
01148         {
01149           /* We didn't call the notify function when we added the counter, so
01150            * catch up now. Since we have the connection's lock, it's desirable
01151            * that we bypass the notify function and call this virtual method
01152            * directly. */
01153           if (transport->vtable->live_messages_changed)
01154             (* transport->vtable->live_messages_changed) (transport);
01155 
01156           /* pass ownership of link and message ref to connection */
01157           _dbus_connection_queue_received_message_link (transport->connection,
01158                                                         link);
01159         }
01160     }
01161 
01162   if (_dbus_message_loader_get_is_corrupted (transport->loader))
01163     {
01164       _dbus_verbose ("Corrupted message stream, disconnecting\n");
01165       _dbus_transport_disconnect (transport);
01166     }
01167 
01168   return status != DBUS_DISPATCH_NEED_MEMORY;
01169 }
01170 
01177 void
01178 _dbus_transport_set_max_message_size (DBusTransport  *transport,
01179                                       long            size)
01180 {
01181   _dbus_message_loader_set_max_message_size (transport->loader, size);
01182 }
01183 
01190 void
01191 _dbus_transport_set_max_message_unix_fds (DBusTransport  *transport,
01192                                           long            n)
01193 {
01194   _dbus_message_loader_set_max_message_unix_fds (transport->loader, n);
01195 }
01196 
01203 long
01204 _dbus_transport_get_max_message_size (DBusTransport  *transport)
01205 {
01206   return _dbus_message_loader_get_max_message_size (transport->loader);
01207 }
01208 
01215 long
01216 _dbus_transport_get_max_message_unix_fds (DBusTransport  *transport)
01217 {
01218   return _dbus_message_loader_get_max_message_unix_fds (transport->loader);
01219 }
01220 
01227 void
01228 _dbus_transport_set_max_received_size (DBusTransport  *transport,
01229                                        long            size)
01230 {
01231   transport->max_live_messages_size = size;
01232   _dbus_counter_set_notify (transport->live_messages,
01233                             transport->max_live_messages_size,
01234                             transport->max_live_messages_unix_fds,
01235                             live_messages_notify,
01236                             transport);
01237 }
01238 
01245 void
01246 _dbus_transport_set_max_received_unix_fds (DBusTransport  *transport,
01247                                            long            n)
01248 {
01249   transport->max_live_messages_unix_fds = n;
01250   _dbus_counter_set_notify (transport->live_messages,
01251                             transport->max_live_messages_size,
01252                             transport->max_live_messages_unix_fds,
01253                             live_messages_notify,
01254                             transport);
01255 }
01256 
01263 long
01264 _dbus_transport_get_max_received_size (DBusTransport  *transport)
01265 {
01266   return transport->max_live_messages_size;
01267 }
01268 
01275 long
01276 _dbus_transport_get_max_received_unix_fds (DBusTransport  *transport)
01277 {
01278   return transport->max_live_messages_unix_fds;
01279 }
01280 
01288 dbus_bool_t
01289 _dbus_transport_get_unix_user (DBusTransport *transport,
01290                                unsigned long *uid)
01291 {
01292   DBusCredentials *auth_identity;
01293 
01294   *uid = _DBUS_INT32_MAX; /* better than some root or system user in
01295                            * case of bugs in the caller. Caller should
01296                            * never use this value on purpose, however.
01297                            */
01298   
01299   if (!transport->authenticated)
01300     return FALSE;
01301   
01302   auth_identity = _dbus_auth_get_identity (transport->auth);
01303 
01304   if (_dbus_credentials_include (auth_identity,
01305                                  DBUS_CREDENTIAL_UNIX_USER_ID))
01306     {
01307       *uid = _dbus_credentials_get_unix_uid (auth_identity);
01308       return TRUE;
01309     }
01310   else
01311     return FALSE;
01312 }
01313 
01321 dbus_bool_t
01322 _dbus_transport_get_unix_process_id (DBusTransport *transport,
01323                                      unsigned long *pid)
01324 {
01325   DBusCredentials *auth_identity;
01326 
01327   *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,
01328                           * but we set it to a safe number, INT_MAX,
01329                           * just to root out possible bugs in bad callers.
01330                           */
01331   
01332   if (!transport->authenticated)
01333     return FALSE;
01334   
01335   auth_identity = _dbus_auth_get_identity (transport->auth);
01336 
01337   if (_dbus_credentials_include (auth_identity,
01338                                  DBUS_CREDENTIAL_UNIX_PROCESS_ID))
01339     {
01340       *pid = _dbus_credentials_get_unix_pid (auth_identity);
01341       return TRUE;
01342     }
01343   else
01344     return FALSE;
01345 }
01346 
01355 dbus_bool_t
01356 _dbus_transport_get_adt_audit_session_data (DBusTransport      *transport,
01357                                             void              **data,
01358                                             int                *data_size)
01359 {
01360   DBusCredentials *auth_identity;
01361 
01362   *data = NULL;
01363   *data_size = 0;
01364   
01365   if (!transport->authenticated)
01366     return FALSE;
01367   
01368   auth_identity = _dbus_auth_get_identity (transport->auth);
01369 
01370   if (_dbus_credentials_include (auth_identity,
01371                                  DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID))
01372     {
01373       *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity);
01374       *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity);
01375       return TRUE;
01376     }
01377   else
01378     return FALSE;
01379 }
01380 
01391 void
01392 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
01393                                         DBusAllowUnixUserFunction  function,
01394                                         void                      *data,
01395                                         DBusFreeFunction           free_data_function,
01396                                         void                     **old_data,
01397                                         DBusFreeFunction          *old_free_data_function)
01398 {  
01399   *old_data = transport->unix_user_data;
01400   *old_free_data_function = transport->free_unix_user_data;
01401 
01402   transport->unix_user_function = function;
01403   transport->unix_user_data = data;
01404   transport->free_unix_user_data = free_data_function;
01405 }
01406 
01414 dbus_bool_t
01415 _dbus_transport_get_windows_user (DBusTransport              *transport,
01416                                   char                      **windows_sid_p)
01417 {
01418   DBusCredentials *auth_identity;
01419 
01420   *windows_sid_p = NULL;
01421   
01422   if (!transport->authenticated)
01423     return FALSE;
01424   
01425   auth_identity = _dbus_auth_get_identity (transport->auth);
01426 
01427   if (_dbus_credentials_include (auth_identity,
01428                                  DBUS_CREDENTIAL_WINDOWS_SID))
01429     {
01430       /* If no memory, we are supposed to return TRUE and set NULL */
01431       *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
01432 
01433       return TRUE;
01434     }
01435   else
01436     return FALSE;
01437 }
01438 
01450 void
01451 _dbus_transport_set_windows_user_function (DBusTransport              *transport,
01452                                            DBusAllowWindowsUserFunction   function,
01453                                            void                       *data,
01454                                            DBusFreeFunction            free_data_function,
01455                                            void                      **old_data,
01456                                            DBusFreeFunction           *old_free_data_function)
01457 {
01458   *old_data = transport->windows_user_data;
01459   *old_free_data_function = transport->free_windows_user_data;
01460 
01461   transport->windows_user_function = function;
01462   transport->windows_user_data = data;
01463   transport->free_windows_user_data = free_data_function;
01464 }
01465 
01474 dbus_bool_t
01475 _dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
01476                                      const char    **mechanisms)
01477 {
01478   return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
01479 }
01480 
01487 void
01488 _dbus_transport_set_allow_anonymous (DBusTransport              *transport,
01489                                      dbus_bool_t                 value)
01490 {
01491   transport->allow_anonymous = value != FALSE;
01492 }
01493 
01494 #ifdef DBUS_ENABLE_STATS
01495 void
01496 _dbus_transport_get_stats (DBusTransport  *transport,
01497                            dbus_uint32_t  *queue_bytes,
01498                            dbus_uint32_t  *queue_fds,
01499                            dbus_uint32_t  *peak_queue_bytes,
01500                            dbus_uint32_t  *peak_queue_fds)
01501 {
01502   if (queue_bytes != NULL)
01503     *queue_bytes = _dbus_counter_get_size_value (transport->live_messages);
01504 
01505   if (queue_fds != NULL)
01506     *queue_fds = _dbus_counter_get_unix_fd_value (transport->live_messages);
01507 
01508   if (peak_queue_bytes != NULL)
01509     *peak_queue_bytes = _dbus_counter_get_peak_size_value (transport->live_messages);
01510 
01511   if (peak_queue_fds != NULL)
01512     *peak_queue_fds = _dbus_counter_get_peak_unix_fd_value (transport->live_messages);
01513 }
01514 #endif /* DBUS_ENABLE_STATS */
01515