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