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