Ejemplo n.º 1
0
static void
live_messages_notify (DBusCounter *counter,
                           void        *user_data)
{
  DBusTransport *transport = user_data;

  _dbus_transport_ref (transport);

#if 0
  _dbus_verbose ("Size counter value is now %d\n",
                 (int) _dbus_counter_get_size_value (counter));
  _dbus_verbose ("Unix FD counter value is now %d\n",
                 (int) _dbus_counter_get_unix_fd_value (counter));
#endif

  /* disable or re-enable the read watch for the transport if
   * required.
   */
  if (transport->vtable->live_messages_changed)
    {
      _dbus_connection_lock (transport->connection);
      (* transport->vtable->live_messages_changed) (transport);
      _dbus_connection_unlock (transport->connection);
    }

  _dbus_transport_unref (transport);
}
Ejemplo n.º 2
0
static dbus_bool_t
match_acquired_or_lost_signal (DBusConnection *conn, const char *member, const char *name)
{
  int tries;
  DBusMessage *msg;
  const char *interface = "org.freedesktop.DBus";

  for (tries = 0; tries < NUM_TRIES_TIL_FAIL; tries++)
    {
      _dbus_connection_lock (conn);
      _dbus_connection_do_iteration_unlocked (conn,
                                              DBUS_ITERATION_DO_READING |
                                              DBUS_ITERATION_DO_WRITING |
                                              DBUS_ITERATION_BLOCK,
                                              0);
      _dbus_connection_unlock (conn);
      msg = dbus_connection_pop_message (conn);
      if (msg != NULL)
        {
          if (dbus_message_is_signal (msg, 
              interface,
              member))
            {
              const char *n;
              DBusError error;
              dbus_error_init (&error);

              dbus_message_get_args (msg, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID);

              if (dbus_error_is_set (&error))
                {
                  fprintf (stderr, "Error getting args: %s\n", error.message);
                  dbus_error_free (&error);
                  dbus_message_unref (msg);
                  return FALSE;
                }

              if (strcmp (n, name) == 0)
                {
                  dbus_message_unref (msg); 
                  break;
                }
            }
          dbus_message_unref (msg);
        }
    }

  if (tries == NUM_TRIES_TIL_FAIL)
    {
      fprintf (stderr, "Did not recive the expected %s.%s signal!!!\n", interface, member);
      return FALSE;
    }
  
  return TRUE;
}
Ejemplo n.º 3
0
static dbus_bool_t
auth_via_windows_user_function (DBusTransport *transport)
{
  DBusCredentials *auth_identity;  
  dbus_bool_t allow;
  DBusConnection *connection;
  DBusAllowWindowsUserFunction windows_user_function;
  void *windows_user_data;
  char *windows_sid;

  /* Dropping the lock here probably isn't that safe. */
  
  auth_identity = _dbus_auth_get_identity (transport->auth);
  _dbus_assert (auth_identity != NULL);

  connection = transport->connection;
  windows_user_function = transport->windows_user_function;
  windows_user_data = transport->unix_user_data;
  windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));

  if (windows_sid == NULL)
    {
      /* OOM */
      return FALSE;
    }
                
  _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
  _dbus_connection_unlock (connection);

  allow = (* windows_user_function) (connection,
                                     windows_sid,
                                     windows_user_data);
              
  _dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME);
  _dbus_connection_lock (connection);

  if (allow)
    {
      _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
    }
  else
    {
      _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
                     _dbus_credentials_get_windows_sid (auth_identity));
      _dbus_transport_disconnect (transport);
    }

  return allow;
}
Ejemplo n.º 4
0
static dbus_bool_t
auth_via_unix_user_function (DBusTransport *transport)
{
  DBusCredentials *auth_identity;
  dbus_bool_t allow;
  DBusConnection *connection;
  DBusAllowUnixUserFunction unix_user_function;
  void *unix_user_data;
  dbus_uid_t uid;

  /* Dropping the lock here probably isn't that safe. */
  
  auth_identity = _dbus_auth_get_identity (transport->auth);
  _dbus_assert (auth_identity != NULL);

  connection = transport->connection;
  unix_user_function = transport->unix_user_function;
  unix_user_data = transport->unix_user_data;
  uid = _dbus_credentials_get_unix_uid (auth_identity);
              
  _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
  _dbus_connection_unlock (connection);

  allow = (* unix_user_function) (connection,
                                  uid,
                                  unix_user_data);
              
  _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
  _dbus_connection_lock (connection);

  if (allow)
    {
      _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
    }
  else
    {
      _dbus_verbose ("Client UID "DBUS_UID_FORMAT
                     " was rejected, disconnecting\n",
                     _dbus_credentials_get_unix_uid (auth_identity));
      _dbus_transport_disconnect (transport);
    }

  return allow;
}
Ejemplo n.º 5
0
/**
 * @todo We need to have a way to wake up the select sleep if
 * a new iteration request comes in with a flag (read/write) that
 * we're not currently serving. Otherwise a call that just reads
 * could block a write call forever (if there are no incoming
 * messages).
 */
static  void
socket_do_iteration (DBusTransport *transport,
                   unsigned int   flags,
                   int            timeout_milliseconds)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
  DBusPollFD poll_fd;
  int poll_res;
  int poll_timeout;

  _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %" DBUS_SOCKET_FORMAT "\n",
                 flags & DBUS_ITERATION_DO_READING ? "read" : "",
                 flags & DBUS_ITERATION_DO_WRITING ? "write" : "",
                 timeout_milliseconds,
                 socket_transport->read_watch,
                 socket_transport->write_watch,
                 _dbus_socket_printable (socket_transport->fd));
  
  /* the passed in DO_READING/DO_WRITING flags indicate whether to
   * read/write messages, but regardless of those we may need to block
   * for reading/writing to do auth.  But if we do reading for auth,
   * we don't want to read any messages yet if not given DO_READING.
   */

  poll_fd.fd = _dbus_socket_get_pollable (socket_transport->fd);
  poll_fd.events = 0;
  
  if (_dbus_transport_try_to_authenticate (transport))
    {
      /* This is kind of a hack; if we have stuff to write, then try
       * to avoid the poll. This is probably about a 5% speedup on an
       * echo client/server.
       *
       * If both reading and writing were requested, we want to avoid this
       * since it could have funky effects:
       *   - both ends spinning waiting for the other one to read
       *     data so they can finish writing
       *   - prioritizing all writing ahead of reading
       */
      if ((flags & DBUS_ITERATION_DO_WRITING) &&
          !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) &&
          !transport->disconnected &&
          _dbus_connection_has_messages_to_send_unlocked (transport->connection))
        {
          do_writing (transport);

          if (transport->disconnected ||
              !_dbus_connection_has_messages_to_send_unlocked (transport->connection))
            goto out;
        }

      /* If we get here, we decided to do the poll() after all */
      _dbus_assert (socket_transport->read_watch);
      if (flags & DBUS_ITERATION_DO_READING)
	poll_fd.events |= _DBUS_POLLIN;

      _dbus_assert (socket_transport->write_watch);
      if (flags & DBUS_ITERATION_DO_WRITING)
        poll_fd.events |= _DBUS_POLLOUT;
    }
  else
    {
      DBusAuthState auth_state;
      
      auth_state = _dbus_auth_do_work (transport->auth);

      if (transport->receive_credentials_pending ||
          auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
	poll_fd.events |= _DBUS_POLLIN;

      if (transport->send_credentials_pending ||
          auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
	poll_fd.events |= _DBUS_POLLOUT;
    }

  if (poll_fd.events)
    {
      int saved_errno;

      if (flags & DBUS_ITERATION_BLOCK)
	poll_timeout = timeout_milliseconds;
      else
	poll_timeout = 0;

      /* For blocking selects we drop the connection lock here
       * to avoid blocking out connection access during a potentially
       * indefinite blocking call. The io path is still protected
       * by the io_path_cond condvar, so we won't reenter this.
       */
      if (flags & DBUS_ITERATION_BLOCK)
        {
          _dbus_verbose ("unlock pre poll\n");
          _dbus_connection_unlock (transport->connection);
        }
      
    again:
      poll_res = _dbus_poll (&poll_fd, 1, poll_timeout);
      saved_errno = _dbus_save_socket_errno ();

      if (poll_res < 0 && _dbus_get_is_errno_eintr (saved_errno))
	goto again;

      if (flags & DBUS_ITERATION_BLOCK)
        {
          _dbus_verbose ("lock post poll\n");
          _dbus_connection_lock (transport->connection);
        }
      
      if (poll_res >= 0)
        {
          if (poll_res == 0)
            poll_fd.revents = 0; /* some concern that posix does not guarantee this;
                                  * valgrind flags it as an error. though it probably
                                  * is guaranteed on linux at least.
                                  */
          
          if (poll_fd.revents & _DBUS_POLLERR)
            do_io_error (transport);
          else
            {
              dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0;
              dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0;
	      dbus_bool_t authentication_completed;

              _dbus_verbose ("in iteration, need_read=%d need_write=%d\n",
                             need_read, need_write);
              do_authentication (transport, need_read, need_write,
				 &authentication_completed);

	      /* See comment in socket_handle_watch. */
	      if (authentication_completed)
                goto out;
                                 
              if (need_read && (flags & DBUS_ITERATION_DO_READING))
                do_reading (transport);
              if (need_write && (flags & DBUS_ITERATION_DO_WRITING))
                do_writing (transport);
            }
        }
      else
        {
          _dbus_verbose ("Error from _dbus_poll(): %s\n",
                         _dbus_strerror (saved_errno));
        }
    }


 out:
  /* We need to install the write watch only if we did not
   * successfully write everything. Note we need to be careful that we
   * don't call check_write_watch *before* do_writing, since it's
   * inefficient to add the write watch, and we can avoid it most of
   * the time since we can write immediately.
   * 
   * However, we MUST always call check_write_watch(); DBusConnection code
   * relies on the fact that running an iteration will notice that
   * messages are pending.
   */
  check_write_watch (transport);

  _dbus_verbose (" ... leaving do_iteration()\n");
}
Ejemplo n.º 6
0
static dbus_bool_t
match_name_owner_changed_signal (DBusConnection *conn, const char *bus_name, const char *lost_name, const char *acquired_name)
{
  int tries;
  DBusMessage *msg;
 
  for (tries = 0; tries < NUM_TRIES_TIL_FAIL; tries++)
    {
      _dbus_connection_lock (conn);
      _dbus_connection_do_iteration_unlocked (conn,
                                              DBUS_ITERATION_DO_READING |
                                              DBUS_ITERATION_DO_WRITING |
                                              DBUS_ITERATION_BLOCK,
                                              0);
      _dbus_connection_unlock (conn);
      msg = dbus_connection_pop_message (conn);
    
      if (msg != NULL)
        {
          if (dbus_message_is_signal (msg, 
              "org.freedesktop.DBus",
              "NameOwnerChanged"))
            {
              const char *n;
              const char *ln;
              const char *an;
              DBusError error;
              dbus_error_init (&error);

              dbus_message_get_args (msg, &error, DBUS_TYPE_STRING, &n, DBUS_TYPE_STRING, &ln, DBUS_TYPE_STRING, &an, DBUS_TYPE_INVALID);

              if (dbus_error_is_set (&error))
                {
                  fprintf (stderr, "Error getting args: %s\n", error.message);
                  dbus_error_free (&error);
                  dbus_message_unref (msg);
                  return FALSE;
                }

              if (strcmp (n, bus_name) == 0)
                {
                  if ((lost_name == NULL && strcmp (ln, "") == 0)
                        || strcmp (lost_name, ln) == 0)
                    {
                      if ((acquired_name == NULL && strcmp (an, "") == 0)
                            || strcmp (acquired_name, an) == 0)
                        {
                          dbus_message_unref (msg); 
                          break;
                        }
                      else
                        {
                          fprintf (stderr, "Error: name %s was expected to be acquired but we got %s instead\n", acquired_name, an);
                          dbus_message_unref (msg);
                          return FALSE;
                        }
                    }
                  else
                    {
                      fprintf (stderr, "Error: name %s was expected to be lost but we got %s instead\n", lost_name, ln);
                      dbus_message_unref (msg);
                      return FALSE;
                    }
                }
            }
          dbus_message_unref (msg);
        }
    }

  if (tries == NUM_TRIES_TIL_FAIL)
    {
      fprintf (stderr, "Did not recive the expected NameOwnerChanged signal!!!\n");
      return FALSE;
    }
  
  return TRUE;
}
/**
 * Returns #TRUE if we have been authenticated.  Will return #TRUE
 * even if the transport is disconnected.
 *
 * @todo we drop connection->mutex when calling the unix_user_function,
 * which may not be safe really.
 *
 * @param transport the transport
 * @returns whether we're authenticated
 */
dbus_bool_t
_dbus_transport_get_is_authenticated (DBusTransport *transport)
{  
  if (transport->authenticated)
    return TRUE;
  else
    {
      dbus_bool_t maybe_authenticated;
      
      if (transport->disconnected)
        return FALSE;

      /* paranoia ref since we call user callbacks sometimes */
      _dbus_connection_ref_unlocked (transport->connection);
      
      maybe_authenticated =
        (!(transport->send_credentials_pending ||
           transport->receive_credentials_pending));

      if (maybe_authenticated)
        {
          switch (_dbus_auth_do_work (transport->auth))
            {
            case DBUS_AUTH_STATE_AUTHENTICATED:
              /* leave as maybe_authenticated */
              break;
            default:
              maybe_authenticated = FALSE;
            }
        }

      if (maybe_authenticated && !transport->is_server)
        {
          const char *server_guid;

          server_guid = _dbus_auth_get_guid_from_server (transport->auth);
          _dbus_assert (server_guid != NULL);

          if (transport->expected_guid &&
              strcmp (transport->expected_guid, server_guid) != 0)
            {
              _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
                             transport->expected_guid, server_guid);
              _dbus_transport_disconnect (transport);
              _dbus_connection_unref_unlocked (transport->connection);
              return FALSE;
            }

          if (transport->expected_guid == NULL)
            {
              transport->expected_guid = _dbus_strdup (server_guid);

              if (transport->expected_guid == NULL)
                {
                  _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME);
                  return FALSE;
                }
            }
        }
      
      /* If we've authenticated as some identity, check that the auth
       * identity is the same as our own identity.  In the future, we
       * may have API allowing applications to specify how this is
       * done, for example they may allow connection as any identity,
       * but then impose restrictions on certain identities.
       * Or they may give certain identities extra privileges.
       */
      
      if (maybe_authenticated && transport->is_server)
        {
          DBusCredentials auth_identity;

          _dbus_auth_get_identity (transport->auth, &auth_identity);

          if (transport->unix_user_function != NULL)
            {
              dbus_bool_t allow;
              DBusConnection *connection;
              DBusAllowUnixUserFunction unix_user_function;
              void *unix_user_data;
              
              /* Dropping the lock here probably isn't that safe. */

              connection = transport->connection;
              unix_user_function = transport->unix_user_function;
              unix_user_data = transport->unix_user_data;

              _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
              _dbus_connection_unlock (connection);
              
              allow = (* unix_user_function) (connection,
                                              auth_identity.uid,
                                              unix_user_data);

              _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
              _dbus_connection_lock (connection);

              if (allow)
                {
                  _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid);
                }
              else
                {
                  _dbus_verbose ("Client UID "DBUS_UID_FORMAT
                                 " was rejected, disconnecting\n",
                                 auth_identity.uid);
                  _dbus_transport_disconnect (transport);
                  _dbus_connection_unref_unlocked (connection);
                  return FALSE;
                }
            }
          else
            {
              DBusCredentials our_identity;
              
              _dbus_credentials_from_current_process (&our_identity);
              
              if (!_dbus_credentials_match (&our_identity,
                                            &auth_identity))
                {
                  _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
                                 " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
                                 auth_identity.uid, our_identity.uid);
                  _dbus_transport_disconnect (transport);
                  _dbus_connection_unref_unlocked (transport->connection);
                  return FALSE;
                }
              else
                {
                  _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
                                 " matching our UID "DBUS_UID_FORMAT"\n",
                                 auth_identity.uid, our_identity.uid);
                }
            }
        }
      
      transport->authenticated = maybe_authenticated;

      _dbus_connection_unref_unlocked (transport->connection);
      return maybe_authenticated;
    }
}
Ejemplo n.º 8
0
static void
test_pending_call (Fixture *f,
    gconstpointer data)
{
  Thread public_api = {
    f,
    NULL,
    (RefFunc) dbus_pending_call_ref,
    NULL,
    (VoidFunc) dbus_pending_call_unref,
    NULL,
    NULL,
    NULL };
  Thread internal_api = {
    f,
    NULL,
    (RefFunc) _dbus_pending_call_ref_unlocked,
    NULL,
    (VoidFunc) dbus_pending_call_unref,
    f->connection,
    (VoidFunc) _dbus_connection_lock,
    (VoidFunc) _dbus_connection_unlock };
  /* This one can't be used to ref, only to cycle or unref. */
  Thread unref_and_unlock_api = {
    f,
    NULL,
    (RefFunc) _dbus_pending_call_ref_unlocked,
    NULL,
    (VoidFunc) _dbus_pending_call_unref_and_unlock,
    f->connection,
    (VoidFunc) _dbus_connection_lock,
    NULL };
  unsigned i;
  DBusPendingCall *pending_call;

  _dbus_connection_lock (f->connection);
  pending_call = _dbus_pending_call_new_unlocked (f->connection,
      DBUS_TIMEOUT_INFINITE, NULL);
  g_assert (pending_call != NULL);
  _dbus_connection_unlock (f->connection);

  public_api.thing = pending_call;
  internal_api.thing = pending_call;
  unref_and_unlock_api.thing = pending_call;

  if (!dbus_pending_call_set_data (pending_call, pending_call_slot, f,
        last_unref))
    g_error ("OOM");

  for (i = 0; i < f->n_threads; i++)
    {
      if ((i % 2) == 0)
        f->threads[i] = g_thread_new (NULL, ref_thread, &public_api);
      else
        f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api);

      g_assert (f->threads[i] != NULL);
    }

  wait_for_all_threads (f);

  for (i = 0; i < f->n_threads; i++)
    {
      switch (i % 3)
        {
          case 0:
            f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api);
            break;
          case 1:
            f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api);
            break;
          default:
            f->threads[i] = g_thread_new (NULL, cycle_thread,
                &unref_and_unlock_api);
        }

      g_assert (f->threads[i] != NULL);
    }

  wait_for_all_threads (f);

  for (i = 0; i < f->n_threads; i++)
    {
      switch (i % 3)
        {
          case 0:
            f->threads[i] = g_thread_new (NULL, unref_thread, &public_api);
            break;
          case 1:
            f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api);
            break;
          default:
            f->threads[i] = g_thread_new (NULL, unref_thread,
                &unref_and_unlock_api);
        }

      g_assert (f->threads[i] != NULL);
    }

  wait_for_all_threads (f);

  /* Destroy the pending call. This should be the last-unref. */
  g_assert (!f->last_unref);
  dbus_pending_call_unref (pending_call);
  g_assert (f->last_unref);
}