Example #1
0
static dbus_bool_t
handle_reload_watch (DBusWatch    *watch,
		     unsigned int  flags,
		     void         *data)
{
  DBusError error;
  DBusString str;
  char *action_str;
  char action = '\0';

  while (!_dbus_string_init (&str))
    _dbus_wait_for_memory ();

  if ((reload_pipe[RELOAD_READ_END].fd > 0) &&
      _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
    {
      _dbus_warn ("Couldn't read from reload pipe.\n");
      close_reload_pipe (&watch);
      return TRUE;
    }

  action_str = _dbus_string_get_data (&str);
  if (action_str != NULL)
    {
      action = action_str[0];
    }
  _dbus_string_free (&str);

  /* this can only fail if we don't understand the config file
   * or OOM.  Either way we should just stick with the currently
   * loaded config.
   */
  dbus_error_init (&error);

  switch (action)
    {
    case ACTION_RELOAD:
      if (! bus_context_reload_config (context, &error))
        {
          _DBUS_ASSERT_ERROR_IS_SET (&error);
          _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) ||
                        dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY));
          _dbus_warn ("Unable to reload configuration: %s\n",
                      error.message);
          dbus_error_free (&error);
        }
      break;

    case ACTION_QUIT:
      {
        DBusLoop *loop;
        /*
         * On OSs without abstract sockets, we want to quit
         * gracefully rather than being killed by SIGTERM,
         * so that DBusServer gets a chance to clean up the
         * sockets from the filesystem. fd.o #38656
         */
        loop = bus_context_get_loop (context);
        if (loop != NULL)
          {
            _dbus_loop_quit (loop);
          }
      }
      break;

    default:
      break;
    }

  return TRUE;
}
/**
 * @ingroup DBusListInternals
 * Unit test for DBusList
 * @returns #TRUE on success.
 */
dbus_bool_t
_dbus_list_test (void)
{
  DBusList *list1;
  DBusList *list2;
  DBusList *link1;
  DBusList *link2;
  DBusList *copy1;
  DBusList *copy2;
  int i;
  
  list1 = NULL;
  list2 = NULL;

  /* Test append and prepend */
  
  i = 0;
  while (i < 10)
    {
      if (!_dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)))
        _dbus_assert_not_reached ("could not allocate for append");
      
      if (!_dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)))
        _dbus_assert_not_reached ("count not allocate for prepend");
      ++i;

      verify_list (&list1);
      verify_list (&list2);
      
      _dbus_assert (_dbus_list_get_length (&list1) == i);
      _dbus_assert (_dbus_list_get_length (&list2) == i);
    }

  _dbus_assert (is_ascending_sequence (&list1));
  _dbus_assert (is_descending_sequence (&list2));

  /* Test list clear */
  _dbus_list_clear (&list1);
  _dbus_list_clear (&list2);

  verify_list (&list1);
  verify_list (&list2);

  /* Test get_first, get_last, pop_first, pop_last */
  
  i = 0;
  while (i < 10)
    {
      _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
      _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
      ++i;
    }

  --i;
  while (i >= 0)
    {
      void *got_data1;
      void *got_data2;
      
      void *data1;
      void *data2;

      got_data1 = _dbus_list_get_last (&list1);
      got_data2 = _dbus_list_get_first (&list2);
      
      data1 = _dbus_list_pop_last (&list1);
      data2 = _dbus_list_pop_first (&list2);

      _dbus_assert (got_data1 == data1);
      _dbus_assert (got_data2 == data2);
      
      _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i);
      _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i);

      verify_list (&list1);
      verify_list (&list2);

      _dbus_assert (is_ascending_sequence (&list1));
      _dbus_assert (is_descending_sequence (&list2));
      
      --i;
    }

  _dbus_assert (list1 == NULL);
  _dbus_assert (list2 == NULL);

  /* Test get_first_link, get_last_link, pop_first_link, pop_last_link */
  
  i = 0;
  while (i < 10)
    {
      _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
      _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
      ++i;
    }

  --i;
  while (i >= 0)
    {
      DBusList *got_link1;
      DBusList *got_link2;

      DBusList *link1;
      DBusList *link2;
      
      void *data1;
      void *data2;
      
      got_link1 = _dbus_list_get_last_link (&list1);
      got_link2 = _dbus_list_get_first_link (&list2);
      
      link1 = _dbus_list_pop_last_link (&list1);
      link2 = _dbus_list_pop_first_link (&list2);

      _dbus_assert (got_link1 == link1);
      _dbus_assert (got_link2 == link2);

      data1 = link1->data;
      data2 = link2->data;

      _dbus_list_free_link (link1);
      _dbus_list_free_link (link2);
      
      _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i);
      _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i);

      verify_list (&list1);
      verify_list (&list2);

      _dbus_assert (is_ascending_sequence (&list1));
      _dbus_assert (is_descending_sequence (&list2));
      
      --i;
    }

  _dbus_assert (list1 == NULL);
  _dbus_assert (list2 == NULL);
  
  /* Test iteration */
  
  i = 0;
  while (i < 10)
    {
      _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
      _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
      ++i;

      verify_list (&list1);
      verify_list (&list2);
      
      _dbus_assert (_dbus_list_get_length (&list1) == i);
      _dbus_assert (_dbus_list_get_length (&list2) == i);
    }

  _dbus_assert (is_ascending_sequence (&list1));
  _dbus_assert (is_descending_sequence (&list2));

  --i;
  link2 = _dbus_list_get_first_link (&list2);
  while (link2 != NULL)
    {
      verify_list (&link2); /* pretend this link is the head */
      
      _dbus_assert (_DBUS_POINTER_TO_INT (link2->data) == i);
      
      link2 = _dbus_list_get_next_link (&list2, link2);
      --i;
    }

  i = 0;
  link1 = _dbus_list_get_first_link (&list1);
  while (link1 != NULL)
    {
      verify_list (&link1); /* pretend this link is the head */
      
      _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i);
      
      link1 = _dbus_list_get_next_link (&list1, link1);
      ++i;
    }

  --i;
  link1 = _dbus_list_get_last_link (&list1);
  while (link1 != NULL)
    {
      verify_list (&link1); /* pretend this link is the head */

      _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i);
      
      link1 = _dbus_list_get_prev_link (&list1, link1);
      --i;
    }

  _dbus_list_clear (&list1);
  _dbus_list_clear (&list2);

  /* Test remove */
  
  i = 0;
  while (i < 10)
    {
      _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
      _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
      ++i;
    }

  --i;
  while (i >= 0)
    {
      if ((i % 2) == 0)
        {
          if (!_dbus_list_remove (&list1, _DBUS_INT_TO_POINTER (i)))
            _dbus_assert_not_reached ("element should have been in list");
          if (!_dbus_list_remove (&list2, _DBUS_INT_TO_POINTER (i)))
            _dbus_assert_not_reached ("element should have been in list");

          verify_list (&list1);
          verify_list (&list2);
        }
      --i;
    }

  _dbus_assert (all_odd_values (&list1));
  _dbus_assert (all_odd_values (&list2));

  _dbus_list_clear (&list1);
  _dbus_list_clear (&list2);

  /* test removing the other half of the elements */
  
  i = 0;
  while (i < 10)
    {
      _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
      _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
      ++i;
    }

  --i;
  while (i >= 0)
    {
      if ((i % 2) != 0)
        {
          if (!_dbus_list_remove (&list1, _DBUS_INT_TO_POINTER (i)))
            _dbus_assert_not_reached ("element should have been in list");
          if (!_dbus_list_remove (&list2, _DBUS_INT_TO_POINTER (i)))
            _dbus_assert_not_reached ("element should have been in list");

          verify_list (&list1);
          verify_list (&list2);
        }
      --i;
    }

  _dbus_assert (all_even_values (&list1));
  _dbus_assert (all_even_values (&list2));

  /* clear list using remove_link */
  while (list1 != NULL)
    {
      _dbus_list_remove_link (&list1, list1);
      verify_list (&list1);
    }
  while (list2 != NULL)
    {
      _dbus_list_remove_link (&list2, list2);
      verify_list (&list2);
    }

  /* Test remove link more generally */
  i = 0;
  while (i < 10)
    {
      _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
      _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
      ++i;
    }

  --i;
  link2 = _dbus_list_get_first_link (&list2);
  while (link2 != NULL)
    {
      DBusList *next = _dbus_list_get_next_link (&list2, link2);
      
      _dbus_assert (_DBUS_POINTER_TO_INT (link2->data) == i);

      if ((i % 2) == 0)
        _dbus_list_remove_link (&list2, link2);

      verify_list (&list2);
      
      link2 = next;
      --i;
    }

  _dbus_assert (all_odd_values (&list2));  
  _dbus_list_clear (&list2);
  
  i = 0;
  link1 = _dbus_list_get_first_link (&list1);
  while (link1 != NULL)
    {
      DBusList *next = _dbus_list_get_next_link (&list1, link1);

      _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i);

      if ((i % 2) != 0)
        _dbus_list_remove_link (&list1, link1);

      verify_list (&list1);
      
      link1 = next;
      ++i;
    }

  _dbus_assert (all_even_values (&list1));
  _dbus_list_clear (&list1);

  /* Test copying a list */
  i = 0;
  while (i < 10)
    {
      _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i));
      _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i));
      ++i;
    }

  /* bad pointers, because they are allowed in the copy dest */
  copy1 = _DBUS_INT_TO_POINTER (0x342234);
  copy2 = _DBUS_INT_TO_POINTER (23);
  
  _dbus_list_copy (&list1, &copy1);
  verify_list (&list1);
  verify_list (&copy1);
  _dbus_assert (lists_equal (&list1, &copy1));
  
  _dbus_list_copy (&list2, &copy2);
  verify_list (&list2);
  verify_list (&copy2);
  _dbus_assert (lists_equal (&list2, &copy2));

  /* Now test copying empty lists */
  _dbus_list_clear (&list1);
  _dbus_list_clear (&list2);
  _dbus_list_clear (&copy1);
  _dbus_list_clear (&copy2);
  
  /* bad pointers, because they are allowed in the copy dest */
  copy1 = _DBUS_INT_TO_POINTER (0x342234);
  copy2 = _DBUS_INT_TO_POINTER (23);
  
  _dbus_list_copy (&list1, &copy1);
  verify_list (&list1);
  verify_list (&copy1);
  _dbus_assert (lists_equal (&list1, &copy1));
  
  _dbus_list_copy (&list2, &copy2);
  verify_list (&list2);
  verify_list (&copy2);
  _dbus_assert (lists_equal (&list2, &copy2));

  _dbus_list_clear (&list1);
  _dbus_list_clear (&list2);
  
  /* insert_before on empty list */
  _dbus_list_insert_before (&list1, NULL,
                            _DBUS_INT_TO_POINTER (0));
  verify_list (&list1);

  /* inserting before first element */
  _dbus_list_insert_before (&list1, list1,
                            _DBUS_INT_TO_POINTER (2));
  verify_list (&list1);
  _dbus_assert (is_descending_sequence (&list1));

  /* inserting in the middle */
  _dbus_list_insert_before (&list1, list1->next,
                            _DBUS_INT_TO_POINTER (1));
  verify_list (&list1);
  _dbus_assert (is_descending_sequence (&list1));  

  /* using insert_before to append */
  _dbus_list_insert_before (&list1, NULL,
                            _DBUS_INT_TO_POINTER (-1));
  verify_list (&list1);
  _dbus_assert (is_descending_sequence (&list1));
  
  _dbus_list_clear (&list1);

  /* insert_after on empty list */
  _dbus_list_insert_after (&list1, NULL,
                           _DBUS_INT_TO_POINTER (0));
  verify_list (&list1);

  /* inserting after first element */
  _dbus_list_insert_after (&list1, list1,
                           _DBUS_INT_TO_POINTER (1));
  verify_list (&list1);
  _dbus_assert (is_ascending_sequence (&list1));

  /* inserting at the end */
  _dbus_list_insert_after (&list1, list1->next,
                           _DBUS_INT_TO_POINTER (2));
  verify_list (&list1);
  _dbus_assert (is_ascending_sequence (&list1));

  /* using insert_after to prepend */
  _dbus_list_insert_after (&list1, NULL,
                           _DBUS_INT_TO_POINTER (-1));
  verify_list (&list1);
  _dbus_assert (is_ascending_sequence (&list1));
  
  _dbus_list_clear (&list1);

  /* using remove_last */
  _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (2));
  _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (1));
  _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (3));

  _dbus_list_remove_last (&list1, _DBUS_INT_TO_POINTER (2));
  
  verify_list (&list1);
  _dbus_assert (is_ascending_sequence (&list1));
  
  _dbus_list_clear (&list1);
  
  return TRUE;
}
/**
 * Wrapper for setenv(). If the value is #NULL, unsets
 * the environment variable.
 *
 * There is an unfixable memleak in that it is unsafe to
 * free memory malloced for use with setenv. This is because
 * we can not rely on internal implementation details of
 * the underlying libc library.
 *
 * @param varname name of environment variable
 * @param value value of environment variable
 * @returns #TRUE on success.
 */
dbus_bool_t
_dbus_setenv (const char *varname,
              const char *value)
{
  _dbus_assert (varname != NULL);
  
  if (value == NULL)
    {
#ifdef HAVE_UNSETENV
      unsetenv (varname);
      return TRUE;
#else
      char *putenv_value;
      size_t len;

      len = strlen (varname);

      /* Use system malloc to avoid memleaks that dbus_malloc
       * will get upset about.
       */
      
      putenv_value = malloc (len + 2);
      if (putenv_value == NULL)
        return FALSE;

      strcpy (putenv_value, varname);
#if defined(DBUS_WIN)
      strcat (putenv_value, "=");
#endif
      
      return (putenv (putenv_value) == 0);
#endif
    }
  else
    {
#ifdef HAVE_SETENV
      return (setenv (varname, value, TRUE) == 0);
#else
      char *putenv_value;
      size_t len;
      size_t varname_len;
      size_t value_len;

      varname_len = strlen (varname);
      value_len = strlen (value);
      
      len = varname_len + value_len + 1 /* '=' */ ;

      /* Use system malloc to avoid memleaks that dbus_malloc
       * will get upset about.
       */
      
      putenv_value = malloc (len + 1);
      if (putenv_value == NULL)
        return FALSE;

      strcpy (putenv_value, varname);
      strcpy (putenv_value + varname_len, "=");
      strcpy (putenv_value + varname_len + 1, value);
      
      return (putenv (putenv_value) == 0);
#endif
    }
}
Example #4
0
static dbus_bool_t
init_uninitialized_locks (void)
{
    DBusList *link;

    _dbus_assert (thread_init_generation != _dbus_current_generation);

    link = uninitialized_mutex_list;
    while (link != NULL)
    {
        DBusMutex **mp;

        mp = (DBusMutex **)link->data;
        _dbus_assert (*mp == _DBUS_DUMMY_MUTEX);

        *mp = _dbus_mutex_new ();
        if (*mp == NULL)
            goto fail_mutex;

        link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
    }

    link = uninitialized_condvar_list;
    while (link != NULL)
    {
        DBusCondVar **cp;

        cp = (DBusCondVar **)link->data;
        _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);

        *cp = _dbus_condvar_new ();
        if (*cp == NULL)
            goto fail_condvar;

        link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
    }

    _dbus_list_clear (&uninitialized_mutex_list);
    _dbus_list_clear (&uninitialized_condvar_list);

    if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
                                       NULL))
        goto fail_condvar;

    return TRUE;

fail_condvar:
    link = uninitialized_condvar_list;
    while (link != NULL)
    {
        DBusCondVar **cp;

        cp = (DBusCondVar **)link->data;

        if (*cp != _DBUS_DUMMY_CONDVAR)
            _dbus_condvar_free (*cp);
        else
            break;

        *cp = _DBUS_DUMMY_CONDVAR;

        link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
    }

fail_mutex:
    link = uninitialized_mutex_list;
    while (link != NULL)
    {
        DBusMutex **mp;

        mp = (DBusMutex **)link->data;

        if (*mp != _DBUS_DUMMY_MUTEX)
            _dbus_mutex_free (*mp);
        else
            break;

        *mp = _DBUS_DUMMY_MUTEX;

        link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
    }

    return FALSE;
}
static dbus_bool_t
socket_handle_watch (DBusWatch    *watch,
                   unsigned int  flags,
                   void         *data)
{
  DBusServer *server = data;
  DBusServerSocket *socket_server = data;

#ifndef DBUS_DISABLE_ASSERT
  int i;
  dbus_bool_t found = FALSE;
#endif

  SERVER_LOCK (server);

#ifndef DBUS_DISABLE_ASSERT
  for (i = 0 ; i < socket_server->n_fds ; i++)
    {
      if (socket_server->watch[i] == watch)
        found = TRUE;
    }
  _dbus_assert (found);
#endif

  _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);

  if (flags & DBUS_WATCH_READABLE)
    {
      int client_fd;
      int listen_fd;

      listen_fd = dbus_watch_get_socket (watch);

      if (socket_server->noncefile)
          client_fd = _dbus_accept_with_noncefile (listen_fd, socket_server->noncefile);
      else 
          client_fd = _dbus_accept (listen_fd);

      if (client_fd < 0)
        {
          /* EINTR handled for us */

          if (_dbus_get_is_errno_eagain_or_ewouldblock ())
            _dbus_verbose ("No client available to accept after all\n");
          else
            _dbus_verbose ("Failed to accept a client connection: %s\n",
                           _dbus_strerror_from_errno ());

          SERVER_UNLOCK (server);
        }
      else
        {
          if (!handle_new_client_fd_and_unlock (server, client_fd))
            _dbus_verbose ("Rejected client connection due to lack of memory\n");
        }
    }

  if (flags & DBUS_WATCH_ERROR)
    _dbus_verbose ("Error on server listening socket\n");

  if (flags & DBUS_WATCH_HANGUP)
    _dbus_verbose ("Hangup on server listening socket\n");

  return TRUE;
}
Example #6
0
/**
 * Spawns a new process. The child_setup
 * function is passed the given user_data and is run in the child
 * just before calling exec().
 *
 * Also creates a "babysitter" which tracks the status of the
 * child process, advising the parent if the child exits.
 * If the spawn fails, no babysitter is created.
 * If sitter_p is #NULL, no babysitter is kept.
 *
 * @param sitter_p return location for babysitter or #NULL
 * @param log_name the name under which to log messages about this process being spawned
 * @param argv the executable and arguments
 * @param env the environment, or #NULL to copy the parent's
 * @param child_setup function to call in child pre-exec()
 * @param user_data user data for setup function
 * @param error error object to be filled in if function fails
 * @returns #TRUE on success, #FALSE if error is filled in
 */
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
                                   const char               *log_name,
                                   char                    **argv,
                                   char                    **env,
                                   DBusSpawnChildSetupFunc   child_setup,
                                   void                     *user_data,
                                   DBusError                *error)
{
  DBusBabysitter *sitter;
  int child_err_report_pipe[2] = { -1, -1 };
  DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT };
  pid_t pid;
#ifdef HAVE_SYSTEMD
  int fd_out = -1;
  int fd_err = -1;
#endif
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  _dbus_assert (argv[0] != NULL);

  if (sitter_p != NULL)
    *sitter_p = NULL;

  sitter = NULL;

  sitter = _dbus_babysitter_new ();
  if (sitter == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return FALSE;
    }

  sitter->log_name = _dbus_strdup (log_name);
  if (sitter->log_name == NULL && log_name != NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  if (sitter->log_name == NULL)
    sitter->log_name = _dbus_strdup (argv[0]);

  if (sitter->log_name == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
  
  if (!make_pipe (child_err_report_pipe, error))
    goto cleanup_and_fail;

  if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
    goto cleanup_and_fail;

  /* Setting up the babysitter is only useful in the parent,
   * but we don't want to run out of memory and fail
   * after we've already forked, since then we'd leak
   * child processes everywhere.
   */
  sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
                                         DBUS_WATCH_READABLE,
                                         TRUE, handle_watch, sitter, NULL);
  if (sitter->error_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
        
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
    {
      /* we need to free it early so the destructor won't try to remove it
       * without it having been added, which DBusLoop doesn't allow */
      _dbus_watch_invalidate (sitter->error_watch);
      _dbus_watch_unref (sitter->error_watch);
      sitter->error_watch = NULL;

      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd,
                                          DBUS_WATCH_READABLE,
                                          TRUE, handle_watch, sitter, NULL);
  if (sitter->sitter_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
      /* we need to free it early so the destructor won't try to remove it
       * without it having been added, which DBusLoop doesn't allow */
      _dbus_watch_invalidate (sitter->sitter_watch);
      _dbus_watch_unref (sitter->sitter_watch);
      sitter->sitter_watch = NULL;

      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

#ifdef HAVE_SYSTEMD
  /* This may fail, but it's not critical.
   * In particular, if we were compiled with journald support but are now
   * running on a non-systemd system, this is going to fail, so we
   * have to cope gracefully. */
  fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE);
  fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE);
#endif

  pid = fork ();
  
  if (pid < 0)
    {
      dbus_set_error (error,
		      DBUS_ERROR_SPAWN_FORK_FAILED,
		      "Failed to fork (%s)",
		      _dbus_strerror (errno));
      goto cleanup_and_fail;
    }
  else if (pid == 0)
    {
      /* Immediate child, this is the babysitter process. */
      int grandchild_pid;
      
      /* Be sure we crash if the parent exits
       * and we write to the err_report_pipe
       */
      signal (SIGPIPE, SIG_DFL);

      /* Close the parent's end of the pipes. */
      close_and_invalidate (&child_err_report_pipe[READ_END]);
      close_and_invalidate (&babysitter_pipe[0].fd);
      
      /* Create the child that will exec () */
      grandchild_pid = fork ();
      
      if (grandchild_pid < 0)
	{
	  write_err_and_exit (babysitter_pipe[1].fd,
			      CHILD_FORK_FAILED);
          _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
	}
      else if (grandchild_pid == 0)
      {
          /* Go back to ignoring SIGPIPE, since it's evil
           */
          signal (SIGPIPE, SIG_IGN);

          close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
	  /* log to systemd journal if possible */
	  if (fd_out >= 0)
            dup2 (fd_out, STDOUT_FILENO);
	  if (fd_err >= 0)
            dup2 (fd_err, STDERR_FILENO);
          close_and_invalidate (&fd_out);
          close_and_invalidate (&fd_err);
#endif
	  do_exec (child_err_report_pipe[WRITE_END],
		   argv,
		   env,
		   child_setup, user_data);
          _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
	}
      else
	{
          close_and_invalidate (&child_err_report_pipe[WRITE_END]);
#ifdef HAVE_SYSTEMD
          close_and_invalidate (&fd_out);
          close_and_invalidate (&fd_err);
#endif
          babysit (grandchild_pid, babysitter_pipe[1].fd);
          _dbus_assert_not_reached ("Got to code after babysit()");
	}
    }
  else
    {      
      /* Close the uncared-about ends of the pipes */
      close_and_invalidate (&child_err_report_pipe[WRITE_END]);
      close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
      close_and_invalidate (&fd_out);
      close_and_invalidate (&fd_err);
#endif

      sitter->socket_to_babysitter = babysitter_pipe[0];
      babysitter_pipe[0].fd = -1;
      
      sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
      child_err_report_pipe[READ_END] = -1;

      sitter->sitter_pid = pid;

      if (sitter_p != NULL)
        *sitter_p = sitter;
      else
        _dbus_babysitter_unref (sitter);

      dbus_free_string_array (env);

      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      
      return TRUE;
    }

 cleanup_and_fail:

  _DBUS_ASSERT_ERROR_IS_SET (error);
  
  close_and_invalidate (&child_err_report_pipe[READ_END]);
  close_and_invalidate (&child_err_report_pipe[WRITE_END]);
  close_and_invalidate (&babysitter_pipe[0].fd);
  close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
  close_and_invalidate (&fd_out);
  close_and_invalidate (&fd_err);
#endif

  if (sitter != NULL)
    _dbus_babysitter_unref (sitter);
  
  return FALSE;
}
static dbus_bool_t
fill_group_info (DBusGroupInfo    *info,
                 dbus_gid_t        gid,
                 const DBusString *groupname,
                 DBusError        *error)
{
  const char *group_c_str;

  _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
  _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);

  if (groupname)
    group_c_str = _dbus_string_get_const_data (groupname);
  else
    group_c_str = NULL;
  
  /* For now assuming that the getgrnam() and getgrgid() flavors
   * always correspond to the pwnam flavors, if not we have
   * to add more configure checks.
   */
  
#if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
  {
    struct group *g;
    int result;
    size_t buflen;
    char *buf;
    struct group g_str;
    dbus_bool_t b;

    /* retrieve maximum needed size for buf */
    buflen = sysconf (_SC_GETGR_R_SIZE_MAX);

    /* sysconf actually returns a long, but everything else expects size_t,
     * so just recast here.
     * https://bugs.freedesktop.org/show_bug.cgi?id=17061
     */
    if ((long) buflen <= 0)
      buflen = 1024;

    result = -1;
    while (1)
      {
        buf = dbus_malloc (buflen);
        if (buf == NULL)
          {
            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
            return FALSE;
          }

        g = NULL;
#ifdef HAVE_POSIX_GETPWNAM_R
        if (group_c_str)
          result = getgrnam_r (group_c_str, &g_str, buf, buflen,
                               &g);
        else
          result = getgrgid_r (gid, &g_str, buf, buflen,
                               &g);
#else
        g = getgrnam_r (group_c_str, &g_str, buf, buflen);
        result = 0;
#endif /* !HAVE_POSIX_GETPWNAM_R */
        /* Try a bigger buffer if ERANGE was returned:
           https://bugs.freedesktop.org/show_bug.cgi?id=16727
        */
        if (result == ERANGE && buflen < 512 * 1024)
          {
            dbus_free (buf);
            buflen *= 2;
          }
        else
          {
            break;
          }
      }

    if (result == 0 && g == &g_str)
      {
        b = fill_user_info_from_group (g, info, error);
        dbus_free (buf);
        return b;
      }
    else
      {
        dbus_set_error (error, _dbus_error_from_errno (errno),
                        "Group %s unknown or failed to look it up\n",
                        group_c_str ? group_c_str : "???");
        dbus_free (buf);
        return FALSE;
      }
  }
#else /* ! HAVE_GETPWNAM_R */
  {
    /* I guess we're screwed on thread safety here */
    struct group *g;

    g = getgrnam (group_c_str);

    if (g != NULL)
      {
        return fill_user_info_from_group (g, info, error);
      }
    else
      {
        dbus_set_error (error, _dbus_error_from_errno (errno),
                        "Group %s unknown or failed to look it up\n",
                        group_c_str ? group_c_str : "???");
        return FALSE;
      }
  }
#endif  /* ! HAVE_GETPWNAM_R */
}
static void
byteswap_body_helper (DBusTypeReader       *reader,
                      dbus_bool_t           walk_reader_to_end,
                      int                   old_byte_order,
                      int                   new_byte_order,
                      unsigned char        *p,
                      unsigned char       **new_p)
{
    int current_type;

    while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
    {
        switch (current_type)
        {
        case DBUS_TYPE_BYTE:
            ++p;
            break;

        case DBUS_TYPE_INT16:
        case DBUS_TYPE_UINT16:
        {
            p = _DBUS_ALIGN_ADDRESS (p, 2);
            *((dbus_uint16_t*)p) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)p));
            p += 2;
        }
        break;

        case DBUS_TYPE_BOOLEAN:
        case DBUS_TYPE_INT32:
        case DBUS_TYPE_UINT32:
        {
            p = _DBUS_ALIGN_ADDRESS (p, 4);
            *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p));
            p += 4;
        }
        break;

        case DBUS_TYPE_INT64:
        case DBUS_TYPE_UINT64:
        case DBUS_TYPE_DOUBLE:
        {
            p = _DBUS_ALIGN_ADDRESS (p, 8);
#ifdef DBUS_HAVE_INT64
            *((dbus_uint64_t*)p) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)p));
#else
            _dbus_swap_array (p, 1, 8);
#endif
            p += 8;
        }
        break;

        case DBUS_TYPE_ARRAY:
        case DBUS_TYPE_STRING:
        case DBUS_TYPE_OBJECT_PATH:
        {
            dbus_uint32_t array_len;

            p = _DBUS_ALIGN_ADDRESS (p, 4);

            array_len = _dbus_unpack_uint32 (old_byte_order, p);

            *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p));
            p += 4;

            if (current_type == DBUS_TYPE_ARRAY)
            {
                int elem_type;
                int alignment;

                elem_type = _dbus_type_reader_get_element_type (reader);
                alignment = _dbus_type_get_alignment (elem_type);

                _dbus_assert ((array_len / alignment) < DBUS_MAXIMUM_ARRAY_LENGTH);

                p = _DBUS_ALIGN_ADDRESS (p, alignment);

                if (dbus_type_is_fixed (elem_type))
                {
                    if (alignment > 1)
                        _dbus_swap_array (p, array_len / alignment, alignment);
                    p += array_len;
                }
                else
                {
                    DBusTypeReader sub;
                    const unsigned char *array_end;

                    array_end = p + array_len;

                    _dbus_type_reader_recurse (reader, &sub);

                    while (p < array_end)
                    {
                        byteswap_body_helper (&sub,
                                              FALSE,
                                              old_byte_order,
                                              new_byte_order,
                                              p, &p);
                    }
                }
            }
            else
            {
                _dbus_assert (current_type == DBUS_TYPE_STRING ||
                              current_type == DBUS_TYPE_OBJECT_PATH);

                p += (array_len + 1); /* + 1 for nul */
            }
        }
        break;

        case DBUS_TYPE_SIGNATURE:
        {
            dbus_uint32_t sig_len;

            sig_len = *p;

            p += (sig_len + 2); /* +2 for len and nul */
        }
        break;

        case DBUS_TYPE_VARIANT:
        {
            /* 1 byte sig len, sig typecodes, align to
             * contained-type-boundary, values.
             */
            dbus_uint32_t sig_len;
            DBusString sig;
            DBusTypeReader sub;
            int contained_alignment;

            sig_len = *p;
            ++p;

            _dbus_string_init_const_len (&sig, p, sig_len);

            p += (sig_len + 1); /* 1 for nul */

            contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0));

            p = _DBUS_ALIGN_ADDRESS (p, contained_alignment);

            _dbus_type_reader_init_types_only (&sub, &sig, 0);

            byteswap_body_helper (&sub, FALSE, old_byte_order, new_byte_order, p, &p);
        }
        break;

        case DBUS_TYPE_STRUCT:
        case DBUS_TYPE_DICT_ENTRY:
        {
            DBusTypeReader sub;

            p = _DBUS_ALIGN_ADDRESS (p, 8);

            _dbus_type_reader_recurse (reader, &sub);

            byteswap_body_helper (&sub, TRUE, old_byte_order, new_byte_order, p, &p);
        }
        break;

        default:
            _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature");
            break;
        }

        if (walk_reader_to_end)
            _dbus_type_reader_next (reader);
        else
            break;
    }

    if (new_p)
        *new_p = p;
}
static void
time_for_size (int size)
{
  int i;
  int j;
  clock_t start;
  clock_t end;
#define FREE_ARRAY_SIZE 512
#define N_ITERATIONS FREE_ARRAY_SIZE * 512
  void *to_free[FREE_ARRAY_SIZE];
  DBusMemPool *pool;

  _dbus_verbose ("Timings for size %d\n", size);
  
  _dbus_verbose (" malloc\n");
  
  start = clock ();
  
  i = 0;
  j = 0;
  while (i < N_ITERATIONS)
    {
      to_free[j] = dbus_malloc (size);
      _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */

      ++j;

      if (j == FREE_ARRAY_SIZE)
        {
          j = 0;
          while (j < FREE_ARRAY_SIZE)
            {
              dbus_free (to_free[j]);
              ++j;
            }

          j = 0;
        }
      
      ++i;
    }

  end = clock ();

  _dbus_verbose ("  created/destroyed %d elements in %g seconds\n",
                 N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC);



  _dbus_verbose (" mempools\n");
  
  start = clock ();

  pool = _dbus_mem_pool_new (size, FALSE);
  
  i = 0;
  j = 0;
  while (i < N_ITERATIONS)
    {
      to_free[j] = _dbus_mem_pool_alloc (pool); 
      _dbus_assert (to_free[j] != NULL);  /* in a real app of course this is wrong */

      ++j;

      if (j == FREE_ARRAY_SIZE)
        {
          j = 0;
          while (j < FREE_ARRAY_SIZE)
            {
              _dbus_mem_pool_dealloc (pool, to_free[j]);
              ++j;
            }

          j = 0;
        }
      
      ++i;
    }

  _dbus_mem_pool_free (pool);
  
  end = clock ();

  _dbus_verbose ("  created/destroyed %d elements in %g seconds\n",
                 N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC);

  _dbus_verbose (" zeroed malloc\n");
    
  start = clock ();
  
  i = 0;
  j = 0;
  while (i < N_ITERATIONS)
    {
      to_free[j] = dbus_malloc0 (size);
      _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */

      ++j;

      if (j == FREE_ARRAY_SIZE)
        {
          j = 0;
          while (j < FREE_ARRAY_SIZE)
            {
              dbus_free (to_free[j]);
              ++j;
            }

          j = 0;
        }
      
      ++i;
    }

  end = clock ();

  _dbus_verbose ("  created/destroyed %d elements in %g seconds\n",
                 N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC);
  
  _dbus_verbose (" zeroed mempools\n");
  
  start = clock ();

  pool = _dbus_mem_pool_new (size, TRUE);
  
  i = 0;
  j = 0;
  while (i < N_ITERATIONS)
    {
      to_free[j] = _dbus_mem_pool_alloc (pool); 
      _dbus_assert (to_free[j] != NULL);  /* in a real app of course this is wrong */

      ++j;

      if (j == FREE_ARRAY_SIZE)
        {
          j = 0;
          while (j < FREE_ARRAY_SIZE)
            {
              _dbus_mem_pool_dealloc (pool, to_free[j]);
              ++j;
            }

          j = 0;
        }
      
      ++i;
    }

  _dbus_mem_pool_free (pool);
  
  end = clock ();

  _dbus_verbose ("  created/destroyed %d elements in %g seconds\n",
                 N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC);
}
dbus_bool_t
_dbus_message_test (const char *test_data_dir)
{
  DBusMessage *message;
  DBusMessageLoader *loader;
  int i;
  const char *data;
  DBusMessage *copy;
  const char *name1;
  const char *name2;
  const dbus_uint32_t our_uint32_array[] =
    { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
  const dbus_int32_t our_int32_array[] =
    { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
  const dbus_uint32_t *v_ARRAY_UINT32 = our_uint32_array;
  const dbus_int32_t *v_ARRAY_INT32 = our_int32_array;
#ifdef DBUS_HAVE_INT64
  const dbus_uint64_t our_uint64_array[] =
    { 0x12345678, 0x23456781, 0x34567812, 0x45678123 };
  const dbus_int64_t our_int64_array[] =
    { 0x12345678, -0x23456781, 0x34567812, -0x45678123 };
  const dbus_uint64_t *v_ARRAY_UINT64 = our_uint64_array;
  const dbus_int64_t *v_ARRAY_INT64 = our_int64_array;
#endif
  const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" };
  const char **v_ARRAY_STRING = our_string_array;
  const double our_double_array[] = { 0.1234, 9876.54321, -300.0 };
  const double *v_ARRAY_DOUBLE = our_double_array;
  const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 };
  const unsigned char *v_ARRAY_BYTE = our_byte_array;
  const dbus_bool_t our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE };
  const dbus_bool_t *v_ARRAY_BOOLEAN = our_boolean_array;
  char sig[64];
  const char *s;
  const char *v_STRING;
  double v_DOUBLE;
  dbus_int16_t v_INT16;
  dbus_uint16_t v_UINT16;
  dbus_int32_t v_INT32;
  dbus_uint32_t v_UINT32;
#ifdef DBUS_HAVE_INT64
  dbus_int64_t v_INT64;
  dbus_uint64_t v_UINT64;
#endif
  unsigned char v_BYTE;
  unsigned char v2_BYTE;
  dbus_bool_t v_BOOLEAN;

  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
                                          "/org/freedesktop/TestPath",
                                          "Foo.TestInterface",
                                          "TestMethod");
  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
  _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface",
                                             "TestMethod"));
  _dbus_assert (strcmp (dbus_message_get_path (message),
                        "/org/freedesktop/TestPath") == 0);
  _dbus_message_set_serial (message, 1234);

  /* string length including nul byte not a multiple of 4 */
  if (!dbus_message_set_sender (message, "org.foo.bar1"))
    _dbus_assert_not_reached ("out of memory");

  _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1"));
  dbus_message_set_reply_serial (message, 5678);

  _dbus_verbose_bytes_of_string (&message->header.data, 0,
                                 _dbus_string_get_length (&message->header.data));
  _dbus_verbose_bytes_of_string (&message->body, 0,
                                 _dbus_string_get_length (&message->body));

  if (!dbus_message_set_sender (message, NULL))
    _dbus_assert_not_reached ("out of memory");


  _dbus_verbose_bytes_of_string (&message->header.data, 0,
                                 _dbus_string_get_length (&message->header.data));
  _dbus_verbose_bytes_of_string (&message->body, 0,
                                 _dbus_string_get_length (&message->body));


  _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1"));
  _dbus_assert (dbus_message_get_serial (message) == 1234);
  _dbus_assert (dbus_message_get_reply_serial (message) == 5678);
  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));

  _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
  dbus_message_set_no_reply (message, TRUE);
  _dbus_assert (dbus_message_get_no_reply (message) == TRUE);
  dbus_message_set_no_reply (message, FALSE);
  _dbus_assert (dbus_message_get_no_reply (message) == FALSE);

  /* Set/get some header fields */

  if (!dbus_message_set_path (message, "/foo"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_path (message),
                        "/foo") == 0);

  if (!dbus_message_set_interface (message, "org.Foo"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_interface (message),
                        "org.Foo") == 0);

  if (!dbus_message_set_member (message, "Bar"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_member (message),
                        "Bar") == 0);

  /* Set/get them with longer values */
  if (!dbus_message_set_path (message, "/foo/bar"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_path (message),
                        "/foo/bar") == 0);

  if (!dbus_message_set_interface (message, "org.Foo.Bar"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_interface (message),
                        "org.Foo.Bar") == 0);

  if (!dbus_message_set_member (message, "BarFoo"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_member (message),
                        "BarFoo") == 0);

  /* Realloc shorter again */

  if (!dbus_message_set_path (message, "/foo"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_path (message),
                        "/foo") == 0);

  if (!dbus_message_set_interface (message, "org.Foo"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_interface (message),
                        "org.Foo") == 0);

  if (!dbus_message_set_member (message, "Bar"))
    _dbus_assert_not_reached ("out of memory");
  _dbus_assert (strcmp (dbus_message_get_member (message),
                        "Bar") == 0);

  dbus_message_unref (message);

  /* Test the vararg functions */
  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
                                          "/org/freedesktop/TestPath",
                                          "Foo.TestInterface",
                                          "TestMethod");
  _dbus_message_set_serial (message, 1);
  dbus_message_set_reply_serial (message, 5678);

  v_INT16 = -0x123;
  v_UINT16 = 0x123;
  v_INT32 = -0x12345678;
  v_UINT32 = 0x12300042;
#ifdef DBUS_HAVE_INT64
  v_INT64 = DBUS_INT64_CONSTANT (-0x123456789abcd);
  v_UINT64 = DBUS_UINT64_CONSTANT (0x123456789abcd);
#endif
  v_STRING = "Test string";
  v_DOUBLE = 3.14159;
  v_BOOLEAN = TRUE;
  v_BYTE = 42;
  v2_BYTE = 24;

  dbus_message_append_args (message,
                            DBUS_TYPE_INT16, &v_INT16,
                            DBUS_TYPE_UINT16, &v_UINT16,
			    DBUS_TYPE_INT32, &v_INT32,
                            DBUS_TYPE_UINT32, &v_UINT32,
#ifdef DBUS_HAVE_INT64
                            DBUS_TYPE_INT64, &v_INT64,
                            DBUS_TYPE_UINT64, &v_UINT64,
#endif
			    DBUS_TYPE_STRING, &v_STRING,
			    DBUS_TYPE_DOUBLE, &v_DOUBLE,
			    DBUS_TYPE_BOOLEAN, &v_BOOLEAN,
			    DBUS_TYPE_BYTE, &v_BYTE,
			    DBUS_TYPE_BYTE, &v2_BYTE,
			    DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &v_ARRAY_UINT32,
                            _DBUS_N_ELEMENTS (our_uint32_array),
                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY_INT32,
                            _DBUS_N_ELEMENTS (our_int32_array),
#ifdef DBUS_HAVE_INT64
                            DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &v_ARRAY_UINT64,
                            _DBUS_N_ELEMENTS (our_uint64_array),
                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &v_ARRAY_INT64,
                            _DBUS_N_ELEMENTS (our_int64_array),
#endif
                            DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &v_ARRAY_DOUBLE,
                            _DBUS_N_ELEMENTS (our_double_array),
                            DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &v_ARRAY_BYTE,
                            _DBUS_N_ELEMENTS (our_byte_array),
                            DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN,
                            _DBUS_N_ELEMENTS (our_boolean_array),
                            DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &v_ARRAY_STRING,
                            _DBUS_N_ELEMENTS (our_string_array),
			    DBUS_TYPE_INVALID);

  i = 0;
  sig[i++] = DBUS_TYPE_INT16;
  sig[i++] = DBUS_TYPE_UINT16;
  sig[i++] = DBUS_TYPE_INT32;
  sig[i++] = DBUS_TYPE_UINT32;
#ifdef DBUS_HAVE_INT64
  sig[i++] = DBUS_TYPE_INT64;
  sig[i++] = DBUS_TYPE_UINT64;
#endif
  sig[i++] = DBUS_TYPE_STRING;
  sig[i++] = DBUS_TYPE_DOUBLE;
  sig[i++] = DBUS_TYPE_BOOLEAN;
  sig[i++] = DBUS_TYPE_BYTE;
  sig[i++] = DBUS_TYPE_BYTE;
  sig[i++] = DBUS_TYPE_ARRAY;
  sig[i++] = DBUS_TYPE_UINT32;
  sig[i++] = DBUS_TYPE_ARRAY;
  sig[i++] = DBUS_TYPE_INT32;
#ifdef DBUS_HAVE_INT64
  sig[i++] = DBUS_TYPE_ARRAY;
  sig[i++] = DBUS_TYPE_UINT64;
  sig[i++] = DBUS_TYPE_ARRAY;
  sig[i++] = DBUS_TYPE_INT64;
#endif
  sig[i++] = DBUS_TYPE_ARRAY;
  sig[i++] = DBUS_TYPE_DOUBLE;
  sig[i++] = DBUS_TYPE_ARRAY;
  sig[i++] = DBUS_TYPE_BYTE;
  sig[i++] = DBUS_TYPE_ARRAY;
  sig[i++] = DBUS_TYPE_BOOLEAN;
  sig[i++] = DBUS_TYPE_ARRAY;
  sig[i++] = DBUS_TYPE_STRING;
  sig[i++] = DBUS_TYPE_INVALID;  

  _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig));

  _dbus_verbose ("HEADER\n");
  _dbus_verbose_bytes_of_string (&message->header.data, 0,
                                 _dbus_string_get_length (&message->header.data));
  _dbus_verbose ("BODY\n");
  _dbus_verbose_bytes_of_string (&message->body, 0,
                                 _dbus_string_get_length (&message->body));

  _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n",
                 sig, dbus_message_get_signature (message));

  s = dbus_message_get_signature (message);

  _dbus_assert (dbus_message_has_signature (message, sig));
  _dbus_assert (strcmp (s, sig) == 0);

  verify_test_message (message);

  copy = dbus_message_copy (message);

  _dbus_assert (dbus_message_get_reply_serial (message) ==
                dbus_message_get_reply_serial (copy));
  _dbus_assert (message->header.padding == copy->header.padding);

  _dbus_assert (_dbus_string_get_length (&message->header.data) ==
                _dbus_string_get_length (&copy->header.data));

  _dbus_assert (_dbus_string_get_length (&message->body) ==
                _dbus_string_get_length (&copy->body));

  verify_test_message (copy);

  name1 = dbus_message_get_interface (message);
  name2 = dbus_message_get_interface (copy);

  _dbus_assert (strcmp (name1, name2) == 0);

  name1 = dbus_message_get_member (message);
  name2 = dbus_message_get_member (copy);

  _dbus_assert (strcmp (name1, name2) == 0);

  dbus_message_unref (copy);

  /* Message loader test */
  _dbus_message_lock (message);
  loader = _dbus_message_loader_new ();
  
  /* check ref/unref */
  _dbus_message_loader_ref (loader);
  _dbus_message_loader_unref (loader);

  /* Write the header data one byte at a time */
  data = _dbus_string_get_const_data (&message->header.data);
  for (i = 0; i < _dbus_string_get_length (&message->header.data); i++)
    {
      DBusString *buffer;

      _dbus_message_loader_get_buffer (loader, &buffer);
      _dbus_string_append_byte (buffer, data[i]);
      _dbus_message_loader_return_buffer (loader, buffer, 1);
    }

  /* Write the body data one byte at a time */
  data = _dbus_string_get_const_data (&message->body);
  for (i = 0; i < _dbus_string_get_length (&message->body); i++)
    {
      DBusString *buffer;

      _dbus_message_loader_get_buffer (loader, &buffer);
      _dbus_string_append_byte (buffer, data[i]);
      _dbus_message_loader_return_buffer (loader, buffer, 1);
    }

  dbus_message_unref (message);

  /* Now pop back the message */
  if (!_dbus_message_loader_queue_messages (loader))
    _dbus_assert_not_reached ("no memory to queue messages");

  if (_dbus_message_loader_get_is_corrupted (loader))
    _dbus_assert_not_reached ("message loader corrupted");

  message = _dbus_message_loader_pop_message (loader);
  if (!message)
    _dbus_assert_not_reached ("received a NULL message");

  if (dbus_message_get_reply_serial (message) != 5678)
    _dbus_assert_not_reached ("reply serial fields differ");

  verify_test_message (message);

  dbus_message_unref (message);
  _dbus_message_loader_unref (loader);

  check_memleaks ();

  /* Load all the sample messages from the message factory */
  {
    DBusMessageDataIter diter;
    DBusMessageData mdata;
    int count;

    reset_validities_seen ();
    
    count = 0;
    _dbus_message_data_iter_init (&diter);
    
    while (_dbus_message_data_iter_get_and_next (&diter,
                                                 &mdata))
      {
        if (!dbus_internal_do_not_use_try_message_data (&mdata.data,
                                                        mdata.expected_validity))
          {
            _dbus_warn ("expected validity %d and did not get it\n",
                        mdata.expected_validity);
            _dbus_assert_not_reached ("message data failed");
          }

        _dbus_message_data_free (&mdata);

        count += 1;
      }

    printf ("%d sample messages tested\n", count);

    print_validities_seen (FALSE);
    print_validities_seen (TRUE);
  }
  
  check_memleaks ();
  
  /* Now load every message in test_data_dir if we have one */
  if (test_data_dir == NULL)
    return TRUE;

  return dbus_internal_do_not_use_foreach_message_file (test_data_dir,
                                                        (DBusForeachMessageFileFunc)
                                                        dbus_internal_do_not_use_try_message_file,
                                                        NULL);  
}
/**
 * Allocates an object from the memory pool.
 * The object must be freed with _dbus_mem_pool_dealloc().
 *
 * @param pool the memory pool
 * @returns the allocated object or #NULL if no memory.
 */
void*
_dbus_mem_pool_alloc (DBusMemPool *pool)
{
#ifdef DBUS_BUILD_TESTS
  if (_dbus_disable_mem_pools ())
    {
      DBusMemBlock *block;
      int alloc_size;
      
      /* This is obviously really silly, but it's
       * debug-mode-only code that is compiled out
       * when tests are disabled (_dbus_disable_mem_pools()
       * is a constant expression FALSE so this block
       * should vanish)
       */
      
      alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING +
        pool->element_size;
      
      if (pool->zero_elements)
        block = dbus_malloc0 (alloc_size);
      else
        block = dbus_malloc (alloc_size);

      if (block != NULL)
        {
          block->next = pool->blocks;
          pool->blocks = block;
          pool->allocated_elements += 1;

          return (void*) &block->elements[0];
        }
      else
        return NULL;
    }
  else
#endif
    {
      if (_dbus_decrement_fail_alloc_counter ())
        {
          _dbus_verbose (" FAILING mempool alloc\n");
          return NULL;
        }
      else if (pool->free_elements)
        {
          DBusFreedElement *element = pool->free_elements;

          pool->free_elements = pool->free_elements->next;

          if (pool->zero_elements)
            memset (element, '\0', pool->element_size);

          pool->allocated_elements += 1;
          
          return element;
        }
      else
        {
          void *element;
      
          if (pool->blocks == NULL ||
              pool->blocks->used_so_far == pool->block_size)
            {
              /* Need a new block */
              DBusMemBlock *block;
              int alloc_size;
#ifdef DBUS_BUILD_TESTS
              int saved_counter;
#endif
          
              if (pool->block_size <= _DBUS_INT_MAX / 4) /* avoid overflow */
                {
                  /* use a larger block size for our next block */
                  pool->block_size *= 2;
                  _dbus_assert ((pool->block_size %
                                 pool->element_size) == 0);
                }

              alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING + pool->block_size;

#ifdef DBUS_BUILD_TESTS
              /* We save/restore the counter, so that memory pools won't
               * cause a given function to have different number of
               * allocations on different invocations. i.e.  when testing
               * we want consistent alloc patterns. So we skip our
               * malloc here for purposes of failed alloc simulation.
               */
              saved_counter = _dbus_get_fail_alloc_counter ();
              _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
#endif
          
              if (pool->zero_elements)
                block = dbus_malloc0 (alloc_size);
              else
                block = dbus_malloc (alloc_size);

#ifdef DBUS_BUILD_TESTS
              _dbus_set_fail_alloc_counter (saved_counter);
              _dbus_assert (saved_counter == _dbus_get_fail_alloc_counter ());
#endif
          
              if (block == NULL)
                return NULL;

              block->used_so_far = 0;
              block->next = pool->blocks;
              pool->blocks = block;          
            }
      
          element = &pool->blocks->elements[pool->blocks->used_so_far];
          
          pool->blocks->used_so_far += pool->element_size;

          pool->allocated_elements += 1;
          
          return element;
        }
    }
}
Example #12
0
EXPORT_C
#endif
dbus_bool_t
dbus_threads_init (const DBusThreadFunctions *functions)
{
    dbus_bool_t mutex_set;
    dbus_bool_t recursive_mutex_set;

    _dbus_assert (functions != NULL);

    /* these base functions are required. Future additions to
     * DBusThreadFunctions may be optional.
     */
    _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
    _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
    _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
    _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
    _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
    _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
    _dbus_assert (functions->condvar_new != NULL);
    _dbus_assert (functions->condvar_free != NULL);
    _dbus_assert (functions->condvar_wait != NULL);
    _dbus_assert (functions->condvar_wait_timeout != NULL);
    _dbus_assert (functions->condvar_wake_one != NULL);
    _dbus_assert (functions->condvar_wake_all != NULL);

    /* Either the mutex function set or recursive mutex set needs
     * to be available but not both
     */
    mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&
                (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) &&
                (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
                (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
                functions->mutex_new &&
                functions->mutex_free &&
                functions->mutex_lock &&
                functions->mutex_unlock;

    recursive_mutex_set =
        (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) &&
        (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) &&
        (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) &&
        (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
        functions->recursive_mutex_new &&
        functions->recursive_mutex_free &&
        functions->recursive_mutex_lock &&
        functions->recursive_mutex_unlock;

    if (!(mutex_set || recursive_mutex_set))
        _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
                                  "functions sets should be passed into "
                                  "dbus_threads_init. Neither sets were passed.");

    if (mutex_set && recursive_mutex_set)
        _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
                                  "functions sets should be passed into "
                                  "dbus_threads_init. Both sets were passed. "
                                  "You most likely just want to set the recursive "
                                  "mutex functions to avoid deadlocks in D-Bus.");

    /* Check that all bits in the mask actually are valid mask bits.
     * ensures people won't write code that breaks when we add
     * new bits.
     */
    _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);

    if (thread_init_generation != _dbus_current_generation)
        thread_functions.mask = 0; /* allow re-init in new generation */

    /* Silently allow multiple init
     * First init wins and D-Bus will always use its threading system
     */
    if (thread_functions.mask != 0)
        return TRUE;

    thread_functions.mutex_new = functions->mutex_new;
    thread_functions.mutex_free = functions->mutex_free;
    thread_functions.mutex_lock = functions->mutex_lock;
    thread_functions.mutex_unlock = functions->mutex_unlock;

    thread_functions.condvar_new = functions->condvar_new;
    thread_functions.condvar_free = functions->condvar_free;
    thread_functions.condvar_wait = functions->condvar_wait;
    thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
    thread_functions.condvar_wake_one = functions->condvar_wake_one;
    thread_functions.condvar_wake_all = functions->condvar_wake_all;

    if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
        thread_functions.recursive_mutex_new = functions->recursive_mutex_new;

    if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
        thread_functions.recursive_mutex_free = functions->recursive_mutex_free;

    if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
        thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;

    if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
        thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;

    thread_functions.mask = functions->mask;

    if (!init_locks ())
        return FALSE;

    thread_init_generation = _dbus_current_generation;

    return TRUE;
}
Example #13
0
static dbus_bool_t
init_locks (void)
{
    int i;
    DBusMutex ***dynamic_global_locks;
#ifndef EMULATOR
    DBusMutex **global_locks[] = {
#define LOCK_ADDR(name) (& _dbus_lock_##name)
        LOCK_ADDR (win_fds),
        LOCK_ADDR (sid_atom_cache),
        LOCK_ADDR (list),
        LOCK_ADDR (connection_slots),
        LOCK_ADDR (pending_call_slots),
        LOCK_ADDR (server_slots),
        LOCK_ADDR (message_slots),
        LOCK_ADDR (atomic),
        LOCK_ADDR (bus),
        LOCK_ADDR (bus_datas),
        LOCK_ADDR (shutdown_funcs),
        LOCK_ADDR (system_users),
        LOCK_ADDR (message_cache),
        LOCK_ADDR (shared_connections),
        LOCK_ADDR (machine_uuid)
#undef LOCK_ADDR
    };
#else
    DBusMutex **global_locks[15];

#define LOCK_ADDR(name) ((DBusMutex **)& _dbus_lock_##name)
    global_locks[0]=LOCK_ADDR (win_fds);
    global_locks[1]=LOCK_ADDR (sid_atom_cache);
    global_locks[2]=LOCK_ADDR (list);
    global_locks[3]=LOCK_ADDR (connection_slots);
    global_locks[4]=LOCK_ADDR (pending_call_slots);
    global_locks[5]=LOCK_ADDR (server_slots);
    global_locks[6]=LOCK_ADDR (message_slots);
    global_locks[7]=LOCK_ADDR (atomic);
    global_locks[8]=LOCK_ADDR (bus);
    global_locks[9]=LOCK_ADDR (bus_datas);
    global_locks[10]=LOCK_ADDR (shutdown_funcs);
    global_locks[11]=LOCK_ADDR (system_users);
    global_locks[12]=LOCK_ADDR (message_cache);
    global_locks[13]=LOCK_ADDR (shared_connections);
    global_locks[14]=LOCK_ADDR (machine_uuid);

#undef LOCK_ADDR


#endif
    _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
                  _DBUS_N_GLOBAL_LOCKS);

    i = 0;

    dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
    if (dynamic_global_locks == NULL)
        goto failed;

    while (i < _DBUS_N_ELEMENTS (global_locks))
    {
        *global_locks[i] = _dbus_mutex_new ();

        if (*global_locks[i] == NULL)
            goto failed;

        dynamic_global_locks[i] = global_locks[i];

        ++i;
    }

    if (!_dbus_register_shutdown_func (shutdown_global_locks,
                                       dynamic_global_locks))
        goto failed;

    if (!init_uninitialized_locks ())
        goto failed;

    return TRUE;

failed:
    dbus_free (dynamic_global_locks);

    for (i = i - 1; i >= 0; i--)
    {
        _dbus_mutex_free (*global_locks[i]);
        *global_locks[i] = NULL;
    }
    return FALSE;
}
/**
 * Looks up a uid or username in the user database.  Only one of name
 * or UID can be provided. There are wrapper functions for this that
 * are better to use, this one does no locking or anything on the
 * database and otherwise sort of sucks.
 *
 * @param db the database
 * @param uid the user ID or #DBUS_UID_UNSET
 * @param username username or #NULL 
 * @param error error to fill in
 * @returns the entry in the database
 */
DBusUserInfo*
_dbus_user_database_lookup (DBusUserDatabase *db,
                            dbus_uid_t        uid,
                            const DBusString *username,
                            DBusError        *error)
{
  DBusUserInfo *info;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);

  /* See if the username is really a number */
  if (uid == DBUS_UID_UNSET)
    {
      unsigned long n;

      if (_dbus_is_a_number (username, &n))
        uid = n;
    }

#ifdef DBUS_ENABLE_USERDB_CACHE  
  if (uid != DBUS_UID_UNSET)
    info = _dbus_hash_table_lookup_ulong (db->users, uid);
  else
    info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));

  if (info)
    {
      _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
                     info->uid);
      return info;
    }
  else
#else 
  if (1)
#endif
    {
      if (uid != DBUS_UID_UNSET)
	_dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
		       uid);
      else
	_dbus_verbose ("No cache for user \"%s\"\n",
		       _dbus_string_get_const_data (username));
      
      info = dbus_new0 (DBusUserInfo, 1);
      if (info == NULL)
        {
          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
          return NULL;
        }

      if (uid != DBUS_UID_UNSET)
        {
          if (!_dbus_user_info_fill_uid (info, uid, error))
            {
              _DBUS_ASSERT_ERROR_IS_SET (error);
              _dbus_user_info_free_allocated (info);
              return NULL;
            }
        }
      else
        {
          if (!_dbus_user_info_fill (info, username, error))
            {
              _DBUS_ASSERT_ERROR_IS_SET (error);
              _dbus_user_info_free_allocated (info);
              return NULL;
            }
        }

      /* be sure we don't use these after here */
      uid = DBUS_UID_UNSET;
      username = NULL;

      /* insert into hash */
      if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info))
        {
          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
          _dbus_user_info_free_allocated (info);
          return NULL;
        }

      if (!_dbus_hash_table_insert_string (db->users_by_name,
                                           info->username,
                                           info))
        {
          _dbus_hash_table_remove_ulong (db->users, info->uid);
          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
          return NULL;
        }
      
      return info;
    }
}
Example #15
0
/**
 * Returns true if the given connection can acquire a service,
 * using the tasks security context
 *
 * @param connection connection that wants to own the service
 * @param bustype name of the bus
 * @param service_name the name of the service to acquire
 * @param error the reason for failure when FALSE is returned
 * @returns TRUE if acquire is permitted
 */
dbus_bool_t
bus_apparmor_allows_acquire_service (DBusConnection     *connection,
                                     const char         *bustype,
                                     const char         *service_name,
                                     DBusError          *error)
{

#ifdef HAVE_APPARMOR
  BusAppArmorConfinement *con = NULL;
  DBusString qstr, auxdata;
  dbus_bool_t free_auxdata = FALSE;
  /* the AppArmor API uses pointers to int for pointers to boolean, and
   * int is not strictly guaranteed to be the same as dbus_bool_t */
  int allow = FALSE, audit = TRUE;
  unsigned long pid;
  int res, serrno = 0;

  if (!apparmor_enabled)
    return TRUE;

  _dbus_assert (connection != NULL);

  con = bus_connection_dup_apparmor_confinement (connection);

  if (is_unconfined (con->label, con->mode))
    {
      allow = TRUE;
      audit = FALSE;
      goto out;
    }

  if (!_dbus_string_init (&qstr))
    goto oom;

  if (!build_service_query (&qstr, con->label, bustype, service_name))
    {
      _dbus_string_free (&qstr);
      goto oom;
    }

  res = aa_query_label (AA_DBUS_BIND,
                        _dbus_string_get_data (&qstr),
                        _dbus_string_get_length (&qstr),
                        &allow, &audit);
  _dbus_string_free (&qstr);
  if (res == -1)
    {
      serrno = errno;
      set_error_from_query_errno (error, serrno);
      goto audit;
    }

  /* Don't fail operations on profiles in complain mode */
  if (modestr_is_complain (con->mode))
      allow = TRUE;

  if (!allow)
    dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
                    "Connection \"%s\" is not allowed to own the service "
                    "\"%s\" due to AppArmor policy",
                    bus_connection_is_active (connection) ?
                     bus_connection_get_name (connection) : "(inactive)",
                    service_name);

  if (!audit)
    goto out;

 audit:
  if (!_dbus_string_init (&auxdata))
    goto oom;
  free_auxdata = TRUE;

  if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
    goto oom;

  if (!_dbus_append_pair_str (&auxdata, "name", service_name))
    goto oom;

  if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
    goto oom;

  if (!_dbus_append_mask (&auxdata, AA_DBUS_BIND))
    goto oom;

  if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
      !_dbus_append_pair_uint (&auxdata, "pid", pid))
    goto oom;

  if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
    goto oom;

  log_message (allow, "bind", &auxdata);

 out:
  if (con != NULL)
    bus_apparmor_confinement_unref (con);
  if (free_auxdata)
    _dbus_string_free (&auxdata);
  return allow;

 oom:
  if (error != NULL && !dbus_error_is_set (error))
    BUS_SET_OOM (error);
  allow = FALSE;
  goto out;

#else
  return TRUE;
#endif /* HAVE_APPARMOR */
}
static dbus_bool_t
init_system_db (void)
{
  _dbus_assert (database_locked);
    
  if (system_db == NULL)
    {
      DBusError error = DBUS_ERROR_INIT;
      const DBusUserInfo *info;
      
      system_db = _dbus_user_database_new ();
      if (system_db == NULL)
        return FALSE;

      if (!_dbus_user_database_get_uid (system_db,
                                        _dbus_getuid (),
                                        &info,
                                        &error))
        {
          _dbus_user_database_unref (system_db);
          system_db = NULL;
          
          if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
            {
              dbus_error_free (&error);
              return FALSE;
            }
          else
            {
              /* This really should not happen. */
              _dbus_warn ("Could not get password database information for UID of current process: %s\n",
                          error.message);
              dbus_error_free (&error);
              return FALSE;
            }
        }

      if (!_dbus_string_init (&process_username))
        {
          _dbus_user_database_unref (system_db);
          system_db = NULL;
          return FALSE;
        }

      if (!_dbus_string_init (&process_homedir))
        {
          _dbus_string_free (&process_username);
          _dbus_user_database_unref (system_db);
          system_db = NULL;
          return FALSE;
        }

      if (!_dbus_string_append (&process_username,
                                info->username) ||
          !_dbus_string_append (&process_homedir,
                                info->homedir) ||
          !_dbus_register_shutdown_func (shutdown_system_db, NULL))
        {
          _dbus_string_free (&process_username);
          _dbus_string_free (&process_homedir);
          _dbus_user_database_unref (system_db);
          system_db = NULL;
          return FALSE;
        }
    }

  return TRUE;
}
Example #17
0
/**
 * Check if Apparmor security controls allow the message to be sent to a
 * particular connection based on the security context of the sender and
 * that of the receiver. The destination connection need not be the
 * addressed recipient, it could be an "eavesdropper"
 *
 * @param sender the sender of the message.
 * @param proposed_recipient the connection the message is to be sent to.
 * @param requested_reply TRUE if the message is a reply requested by
 *                        proposed_recipient
 * @param bustype name of the bus
 * @param msgtype message type (DBUS_MESSAGE_TYPE_METHOD_CALL, etc.)
 * @param path object path the message should be sent to
 * @param interface the type of the object instance
 * @param member the member of the object
 * @param error_name the name of the error if the message type is error
 * @param destination name that the message should be sent to
 * @param source name that the message should be sent from
 * @param error the reason for failure when FALSE is returned
 * @returns TRUE if the message is permitted
 */
dbus_bool_t
bus_apparmor_allows_send (DBusConnection     *sender,
                          DBusConnection     *proposed_recipient,
                          dbus_bool_t         requested_reply,
                          const char         *bustype,
                          int                 msgtype,
                          const char         *path,
                          const char         *interface,
                          const char         *member,
                          const char         *error_name,
                          const char         *destination,
                          const char         *source,
                          BusActivationEntry *activation_entry,
                          DBusError          *error)
{
#ifdef HAVE_APPARMOR
  BusAppArmorConfinement *src_con = NULL, *dst_con = NULL;
  DBusString qstr, auxdata;
  int src_allow = FALSE, dst_allow = FALSE;
  int src_audit = TRUE, dst_audit = TRUE;
  dbus_bool_t free_auxdata = FALSE;
  unsigned long pid;
  int len, res, src_errno = 0, dst_errno = 0;
  uint32_t src_perm = AA_DBUS_SEND, dst_perm = AA_DBUS_RECEIVE;
  const char *msgtypestr = dbus_message_type_to_string(msgtype);
  const char *dst_label = NULL;
  const char *dst_mode = NULL;

  if (!apparmor_enabled)
    return TRUE;

  _dbus_assert (sender != NULL);

  src_con = bus_connection_dup_apparmor_confinement (sender);

  if (proposed_recipient)
    {
      dst_con = bus_connection_dup_apparmor_confinement (proposed_recipient);
    }
  else if (activation_entry != NULL)
    {
      dst_label = bus_activation_entry_get_assumed_apparmor_label (activation_entry);
    }
  else
    {
      dst_con = bus_con;
      bus_apparmor_confinement_ref (dst_con);
    }

  if (dst_con != NULL)
    {
      dst_label = dst_con->label;
      dst_mode = dst_con->mode;
    }

  /* map reply messages to initial send and receive permission. That is
   * permission to receive a message from X grants permission to reply to X.
   * And permission to send a message to Y grants permission to receive a reply
   * from Y. Note that this only applies to requested replies. Unrequested
   * replies still require a policy query.
   */
  if (requested_reply)
    {
      /* ignore requested reply messages and let dbus reply mapping handle them
       * as the send was already allowed
       */
      src_allow = TRUE;
      dst_allow = TRUE;
      goto out;
    }

  if (is_unconfined (src_con->label, src_con->mode))
    {
      src_allow = TRUE;
      src_audit = FALSE;
    }
  else
    {
      if (!_dbus_string_init (&qstr))
        goto oom;

      if (!build_message_query (&qstr, src_con->label, bustype, destination,
                                dst_label, path, interface, member))
        {
          _dbus_string_free (&qstr);
          goto oom;
        }

      res = aa_query_label (src_perm,
                            _dbus_string_get_data (&qstr),
                            _dbus_string_get_length (&qstr),
                            &src_allow, &src_audit);
      _dbus_string_free (&qstr);
      if (res == -1)
        {
          src_errno = errno;
          set_error_from_query_errno (error, src_errno);
          goto audit;
        }
    }

  /* When deciding whether we can activate a service, we only check that
   * we are allowed to send a message to it, not that it is allowed to
   * receive that message from us.
   */
  if (activation_entry != NULL || is_unconfined (dst_label, dst_mode))
    {
      dst_allow = TRUE;
      dst_audit = FALSE;
    }
  else
    {
      if (!_dbus_string_init (&qstr))
        goto oom;

      if (!build_message_query (&qstr, dst_label, bustype, source,
                                src_con->label, path, interface, member))
        {
          _dbus_string_free (&qstr);
          goto oom;
        }

      res = aa_query_label (dst_perm,
                            _dbus_string_get_data (&qstr),
                            _dbus_string_get_length (&qstr),
                            &dst_allow, &dst_audit);
      _dbus_string_free (&qstr);
      if (res == -1)
        {
          dst_errno = errno;
          set_error_from_query_errno (error, dst_errno);
          goto audit;
        }
    }

  /* Don't fail operations on profiles in complain mode */
  if (modestr_is_complain (src_con->mode))
    src_allow = TRUE;
  if (modestr_is_complain (dst_mode))
    dst_allow = TRUE;

  if (!src_allow || !dst_allow)
    set_error_from_denied_message (error,
                                   sender,
                                   proposed_recipient,
                                   requested_reply,
                                   msgtypestr,
                                   path,
                                   interface,
                                   member,
                                   error_name,
                                   destination);

  /* Don't audit the message if one of the following conditions is true:
   *   1) The AppArmor query indicates that auditing should not happen.
   *   2) The message is a reply type. Reply message are not audited because
   *      the AppArmor policy language does not have the notion of a reply
   *      message. Unrequested replies will be silently discarded if the sender
   *      does not have permission to send to the receiver or if the receiver
   *      does not have permission to receive from the sender.
   */
  if ((!src_audit && !dst_audit) ||
      (msgtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
       msgtype == DBUS_MESSAGE_TYPE_ERROR))
    goto out;

 audit:
  if (!_dbus_string_init (&auxdata))
    goto oom;
  free_auxdata = TRUE;

  if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
    goto oom;

  if (path && !_dbus_append_pair_str (&auxdata, "path", path))
    goto oom;

  if (interface && !_dbus_append_pair_str (&auxdata, "interface", interface))
    goto oom;

  if (member && !_dbus_append_pair_str (&auxdata, "member", member))
    goto oom;

  if (error_name && !_dbus_append_pair_str (&auxdata, "error_name", error_name))
    goto oom;

  len = _dbus_string_get_length (&auxdata);

  if (src_audit)
    {
      if (!_dbus_append_mask (&auxdata, src_perm))
        goto oom;

      if (destination && !_dbus_append_pair_str (&auxdata, "name", destination))
        goto oom;

      if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
          !_dbus_append_pair_uint (&auxdata, "pid", pid))
        goto oom;

      if (src_con->label &&
          !_dbus_append_pair_str (&auxdata, "label", src_con->label))
        goto oom;

      if (proposed_recipient &&
          dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
          !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
        goto oom;

      if (dst_label &&
          !_dbus_append_pair_str (&auxdata, "peer_label", dst_label))
        goto oom;

      if (src_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (src_errno)))
        goto oom;

      if (dst_errno &&
          !_dbus_append_pair_str (&auxdata, "peer_info", strerror (dst_errno)))
        goto oom;

      log_message (src_allow, msgtypestr, &auxdata);
    }
  if (dst_audit)
    {
      _dbus_string_set_length (&auxdata, len);

      if (source && !_dbus_append_pair_str (&auxdata, "name", source))
        goto oom;

      if (!_dbus_append_mask (&auxdata, dst_perm))
        goto oom;

      if (proposed_recipient &&
          dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
          !_dbus_append_pair_uint (&auxdata, "pid", pid))
        goto oom;

      if (dst_label &&
          !_dbus_append_pair_str (&auxdata, "label", dst_label))
        goto oom;

      if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
          !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
        goto oom;

      if (src_con->label &&
          !_dbus_append_pair_str (&auxdata, "peer_label", src_con->label))
        goto oom;

      if (dst_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (dst_errno)))
        goto oom;

      if (src_errno &&
          !_dbus_append_pair_str (&auxdata, "peer_info", strerror (src_errno)))
        goto oom;

      log_message (dst_allow, msgtypestr, &auxdata);
    }

 out:
  if (src_con != NULL)
    bus_apparmor_confinement_unref (src_con);
  if (dst_con != NULL)
    bus_apparmor_confinement_unref (dst_con);
  if (free_auxdata)
    _dbus_string_free (&auxdata);

  return src_allow && dst_allow;

 oom:
  if (error != NULL && !dbus_error_is_set (error))
    BUS_SET_OOM (error);
  src_allow = FALSE;
  dst_allow = FALSE;
  goto out;

#else
  return TRUE;
#endif /* HAVE_APPARMOR */
}
static inline DBusSocketSetPoll *
socket_set_poll_cast (DBusSocketSet *set)
{
  _dbus_assert (set->cls == &_dbus_socket_set_poll_class);
  return (DBusSocketSetPoll *) set;
}
/**
 * Opens platform specific transport types.
 * 
 * @param entry the address entry to try opening
 * @param transport_p return location for the opened transport
 * @param error error to be set
 * @returns result of the attempt
 */
DBusTransportOpenResult
_dbus_transport_open_platform_specific (DBusAddressEntry  *entry,
                                        DBusTransport    **transport_p,
                                        DBusError         *error)
{
  const char *method;
  
  method = dbus_address_entry_get_method (entry);
  _dbus_assert (method != NULL);

  if (strcmp (method, "unix") == 0)
    {
      const char *path = dbus_address_entry_get_value (entry, "path");
      const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
      const char *abstract = dbus_address_entry_get_value (entry, "abstract");
          
      if (tmpdir != NULL)
        {
          _dbus_set_bad_address (error, NULL, NULL,
                                 "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on");
          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
        }
          
      if (path == NULL && abstract == NULL)
        {
          _dbus_set_bad_address (error, "unix",
                                 "path or abstract",
                                 NULL);
          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
        }

      if (path != NULL && abstract != NULL)
        {
          _dbus_set_bad_address (error, NULL, NULL,
                                 "can't specify both \"path\" and \"abstract\" options in an address");
          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
        }

      if (path)
        *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE,
                                                           error);
      else
        *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE,
                                                           error);
      if (*transport_p == NULL)
        {
          _DBUS_ASSERT_ERROR_IS_SET (error);
          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
        }
      else
        {
          _DBUS_ASSERT_ERROR_IS_CLEAR (error);
          return DBUS_TRANSPORT_OPEN_OK;
        }      
    }
  else
    {
      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
    }
}
Example #20
0
dbus_bool_t
bus_expire_list_test (const DBusString *test_data_dir)
{
  DBusLoop *loop;
  BusExpireList *list;
  long tv_sec, tv_usec;
  long tv_sec_not_expired, tv_usec_not_expired;
  long tv_sec_expired, tv_usec_expired;
  long tv_sec_past, tv_usec_past;
  TestExpireItem *item;
  int next_interval;
  dbus_bool_t result = FALSE;


  loop = _dbus_loop_new ();
  _dbus_assert (loop != NULL);

#define EXPIRE_AFTER 100
  
  list = bus_expire_list_new (loop, EXPIRE_AFTER,
                              test_expire_func, NULL);
  _dbus_assert (list != NULL);

  _dbus_get_monotonic_time (&tv_sec, &tv_usec);

  tv_sec_not_expired = tv_sec;
  tv_usec_not_expired = tv_usec;
  time_add_milliseconds (&tv_sec_not_expired,
                         &tv_usec_not_expired, EXPIRE_AFTER - 1);

  tv_sec_expired = tv_sec;
  tv_usec_expired = tv_usec;
  time_add_milliseconds (&tv_sec_expired,
                         &tv_usec_expired, EXPIRE_AFTER);
  

  tv_sec_past = tv_sec - 1;
  tv_usec_past = tv_usec;

  item = dbus_new0 (TestExpireItem, 1);

  if (item == NULL)
    goto oom;

  item->item.added_tv_sec = tv_sec;
  item->item.added_tv_usec = tv_usec;
  if (!bus_expire_list_add (list, &item->item))
    _dbus_test_fatal ("out of memory");

  next_interval =
    do_expiration_with_monotonic_time (list, tv_sec_not_expired,
                                       tv_usec_not_expired);
  _dbus_assert (item->expire_count == 0);
  _dbus_verbose ("next_interval = %d\n", next_interval);
  _dbus_assert (next_interval == 1);
  
  next_interval =
    do_expiration_with_monotonic_time (list, tv_sec_expired,
                                       tv_usec_expired);
  _dbus_assert (item->expire_count == 1);
  _dbus_verbose ("next_interval = %d\n", next_interval);
  _dbus_assert (next_interval == -1);

  next_interval =
    do_expiration_with_monotonic_time (list, tv_sec_past,
                                       tv_usec_past);
  _dbus_assert (item->expire_count == 1);
  _dbus_verbose ("next_interval = %d\n", next_interval);
  _dbus_assert (next_interval == 1000 + EXPIRE_AFTER);

  bus_expire_list_remove (list, &item->item);
  dbus_free (item);
  
  bus_expire_list_free (list);
  _dbus_loop_unref (loop);
  
  result = TRUE;

 oom:
  return result;
}
Example #21
0
/**
 * @ingroup DBusStringInternals
 * Unit test for DBusString.
 *
 * @todo Need to write tests for _dbus_string_copy() and
 * _dbus_string_move() moving to/from each of start/middle/end of a
 * string. Also need tests for _dbus_string_move_len ()
 * 
 * @returns #TRUE on success.
 */
dbus_bool_t
_dbus_string_test (void)
{
  DBusString str;
  DBusString other;
  int i, a, end;
  long v;
  int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 };
  char *s;

  /* Test shortening and setting length */
  i = 0;
  while (i < _DBUS_N_ELEMENTS (lens))
    {
      int j;
      
      if (!_dbus_string_init (&str))
        _dbus_assert_not_reached ("failed to init string");

      if (!_dbus_string_set_length (&str, lens[i]))
        _dbus_assert_not_reached ("failed to set string length");

      j = lens[i];
      while (j > 0)
        {
          _dbus_assert (_dbus_string_get_length (&str) == j);
          if (j > 0)
            {
              _dbus_string_shorten (&str, 1);
              _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
            }
          --j;
        }
      
      _dbus_string_free (&str);

      ++i;
    }

  /* Test equality */
  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("oom");

  if (!_dbus_string_append (&str, "Hello World"))
    _dbus_assert_not_reached ("oom");

  _dbus_string_init_const (&other, "H");
  _dbus_assert (_dbus_string_equal_substring (&str, 0, 1, &other, 0));
  _dbus_assert (_dbus_string_equal_substring (&str, 1, 0, &other, 1));
  _dbus_string_init_const (&other, "Hello");
  _dbus_assert (_dbus_string_equal_substring (&str, 0, 5, &other, 0));
  _dbus_assert (_dbus_string_equal_substring (&str, 1, 4, &other, 1));
  _dbus_assert (_dbus_string_equal_substring (&str, 2, 3, &other, 2));
  _dbus_assert (_dbus_string_equal_substring (&str, 3, 2, &other, 3));
  _dbus_assert (_dbus_string_equal_substring (&str, 4, 1, &other, 4));
  _dbus_assert (_dbus_string_equal_substring (&str, 5, 0, &other, 5));

  _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 0));
  _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 1));
  _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 2));
  _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 3));
  _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 4));
  _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 5));

  
  _dbus_string_init_const (&other, "World");
  _dbus_assert (_dbus_string_equal_substring (&str, 6,  5, &other, 0));
  _dbus_assert (_dbus_string_equal_substring (&str, 7,  4, &other, 1));
  _dbus_assert (_dbus_string_equal_substring (&str, 8,  3, &other, 2));
  _dbus_assert (_dbus_string_equal_substring (&str, 9,  2, &other, 3));
  _dbus_assert (_dbus_string_equal_substring (&str, 10, 1, &other, 4));
  _dbus_assert (_dbus_string_equal_substring (&str, 11, 0, &other, 5));

  _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 6));
  _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 7));
  _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 8));
  _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 9));
  _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 10));
  _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 11));
  
  _dbus_string_free (&str);
  
  /* Test appending data */
  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("failed to init string");

  i = 0;
  while (i < 10)
    {
      if (!_dbus_string_append (&str, "a"))
        _dbus_assert_not_reached ("failed to append string to string");

      _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);

      if (!_dbus_string_append_byte (&str, 'b'))
        _dbus_assert_not_reached ("failed to append byte to string");

      _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
                    
      ++i;
    }

  _dbus_string_free (&str);

  /* Check steal_data */
  
  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("failed to init string");

  if (!_dbus_string_append (&str, "Hello World"))
    _dbus_assert_not_reached ("could not append to string");

  i = _dbus_string_get_length (&str);
  
  if (!_dbus_string_steal_data (&str, &s))
    _dbus_assert_not_reached ("failed to steal data");

  _dbus_assert (_dbus_string_get_length (&str) == 0);
  _dbus_assert (((int)strlen (s)) == i);

  dbus_free (s);

  /* Check move */
  
  if (!_dbus_string_append (&str, "Hello World"))
    _dbus_assert_not_reached ("could not append to string");

  i = _dbus_string_get_length (&str);

  if (!_dbus_string_init (&other))
    _dbus_assert_not_reached ("could not init string");
  
  if (!_dbus_string_move (&str, 0, &other, 0))
    _dbus_assert_not_reached ("could not move");

  _dbus_assert (_dbus_string_get_length (&str) == 0);
  _dbus_assert (_dbus_string_get_length (&other) == i);

  if (!_dbus_string_append (&str, "Hello World"))
    _dbus_assert_not_reached ("could not append to string");
  
  if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other)))
    _dbus_assert_not_reached ("could not move");

  _dbus_assert (_dbus_string_get_length (&str) == 0);
  _dbus_assert (_dbus_string_get_length (&other) == i * 2);

    if (!_dbus_string_append (&str, "Hello World"))
    _dbus_assert_not_reached ("could not append to string");
  
  if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2))
    _dbus_assert_not_reached ("could not move");

  _dbus_assert (_dbus_string_get_length (&str) == 0);
  _dbus_assert (_dbus_string_get_length (&other) == i * 3);
  
  _dbus_string_free (&other);

  /* Check copy */
  
  if (!_dbus_string_append (&str, "Hello World"))
    _dbus_assert_not_reached ("could not append to string");

  i = _dbus_string_get_length (&str);
  
  if (!_dbus_string_init (&other))
    _dbus_assert_not_reached ("could not init string");
  
  if (!_dbus_string_copy (&str, 0, &other, 0))
    _dbus_assert_not_reached ("could not copy");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == i);

  if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other)))
    _dbus_assert_not_reached ("could not copy");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == i * 2);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "Hello WorldHello World"));

  if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2))
    _dbus_assert_not_reached ("could not copy");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == i * 3);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "Hello WorldHello WorldHello World"));
  
  _dbus_string_free (&str);
  _dbus_string_free (&other);

  /* Check replace */

  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("failed to init string");
  
  if (!_dbus_string_append (&str, "Hello World"))
    _dbus_assert_not_reached ("could not append to string");

  i = _dbus_string_get_length (&str);
  
  if (!_dbus_string_init (&other))
    _dbus_assert_not_reached ("could not init string");
  
  if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
                                 &other, 0, _dbus_string_get_length (&other)))
    _dbus_assert_not_reached ("could not replace");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == i);
  _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World"));
  
  if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str),
                                 &other, 5, 1))
    _dbus_assert_not_reached ("could not replace center space");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "HelloHello WorldWorld"));

  
  if (!_dbus_string_replace_len (&str, 1, 1,
                                 &other,
                                 _dbus_string_get_length (&other) - 1,
                                 1))
    _dbus_assert_not_reached ("could not replace end character");
  
  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "HelloHello WorldWorle"));

  _dbus_string_free (&str);
  _dbus_string_free (&other);

  /* Different tests are provided because different behaviours are
   * implemented in _dbus_string_replace_len() in function of replacing and
   * replaced lengths
   */

  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("failed to init string");
  
  if (!_dbus_string_append (&str, "Hello World"))
    _dbus_assert_not_reached ("could not append to string");

  i = _dbus_string_get_length (&str);
  
  if (!_dbus_string_init (&other))
    _dbus_assert_not_reached ("could not init string");

  if (!_dbus_string_append (&other, "Foo String"))
    _dbus_assert_not_reached ("could not append to string");

  a = _dbus_string_get_length (&other);

  if (!_dbus_string_replace_len (&str, 0, 6,
                                 &other, 4, 0))
    _dbus_assert_not_reached ("could not replace 0 length");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == a + 6);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "Foo Hello String"));

  if (!_dbus_string_replace_len (&str, 5, 6,
                                 &other,
                                 _dbus_string_get_length (&other),
                                 0))
    _dbus_assert_not_reached ("could not replace at the end");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == a + 6 + 6);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "Foo Hello String World"));

  if (!_dbus_string_replace_len (&str, 0, 5,
                                 &other,
                                 _dbus_string_get_length (&other) - 5,
                                 5))
    _dbus_assert_not_reached ("could not replace same length");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == a + 6 + 6);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "Foo Hello String Hello"));

  if (!_dbus_string_replace_len (&str, 6, 5,
                                 &other, 4, 12))
    _dbus_assert_not_reached ("could not replace with shorter string");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == a + 5);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "Foo World Hello"));

  if (!_dbus_string_replace_len (&str, 0, 1,
                                 &other, 0, 3))
    _dbus_assert_not_reached ("could not replace at the beginning");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == a + 3);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "H World Hello"));

  if (!_dbus_string_replace_len (&str, 6, 5,
                                 &other,
                                 _dbus_string_get_length (&other) - 5,
                                 5))
    _dbus_assert_not_reached ("could not replace same length");

  _dbus_assert (_dbus_string_get_length (&str) == i);
  _dbus_assert (_dbus_string_get_length (&other) == a + 3);
  _dbus_assert (_dbus_string_equal_c_str (&other,
                                          "H World World"));

  _dbus_string_free (&str);
  _dbus_string_free (&other);

  /* Check insert/set/get byte */
  
  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("failed to init string");

  if (!_dbus_string_append (&str, "Hello"))
    _dbus_assert_not_reached ("failed to append Hello");

  _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H');
  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e');
  _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l');
  _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l');
  _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o');

  _dbus_string_set_byte (&str, 1, 'q');
  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');

  if (!_dbus_string_insert_bytes (&str, 0, 1, 255))
    _dbus_assert_not_reached ("can't insert byte");

  if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z'))
    _dbus_assert_not_reached ("can't insert byte");

  if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W'))
    _dbus_assert_not_reached ("can't insert byte");
  
  _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
  _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
  _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
  _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z');
  _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z');
  _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z');
  _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q');
  _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l');
  _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l');
  _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o');
  _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W');

  _dbus_string_free (&str);
  
  /* Check append/parse int/double */
  
  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("failed to init string");

  if (!_dbus_string_append_int (&str, 27))
    _dbus_assert_not_reached ("failed to append int");

  i = _dbus_string_get_length (&str);

  if (!_dbus_string_parse_int (&str, 0, &v, &end))
    _dbus_assert_not_reached ("failed to parse int");

  _dbus_assert (v == 27);
  _dbus_assert (end == i);

  _dbus_string_free (&str);

  /* Test find */
  if (!_dbus_string_init (&str))
    _dbus_assert_not_reached ("failed to init string");

  if (!_dbus_string_append (&str, "Hello"))
    _dbus_assert_not_reached ("couldn't append to string");
  
  if (!_dbus_string_find (&str, 0, "He", &i))
    _dbus_assert_not_reached ("didn't find 'He'");
  _dbus_assert (i == 0);

  if (!_dbus_string_find (&str, 0, "Hello", &i))
    _dbus_assert_not_reached ("didn't find 'Hello'");
  _dbus_assert (i == 0);
  
  if (!_dbus_string_find (&str, 0, "ello", &i))
    _dbus_assert_not_reached ("didn't find 'ello'");
  _dbus_assert (i == 1);

  if (!_dbus_string_find (&str, 0, "lo", &i))
    _dbus_assert_not_reached ("didn't find 'lo'");
  _dbus_assert (i == 3);

  if (!_dbus_string_find (&str, 2, "lo", &i))
    _dbus_assert_not_reached ("didn't find 'lo'");
  _dbus_assert (i == 3);

  if (_dbus_string_find (&str, 4, "lo", &i))
    _dbus_assert_not_reached ("did find 'lo'");
  
  if (!_dbus_string_find (&str, 0, "l", &i))
    _dbus_assert_not_reached ("didn't find 'l'");
  _dbus_assert (i == 2);

  if (!_dbus_string_find (&str, 0, "H", &i))
    _dbus_assert_not_reached ("didn't find 'H'");
  _dbus_assert (i == 0);

  if (!_dbus_string_find (&str, 0, "", &i))
    _dbus_assert_not_reached ("didn't find ''");
  _dbus_assert (i == 0);
  
  if (_dbus_string_find (&str, 0, "Hello!", NULL))
    _dbus_assert_not_reached ("Did find 'Hello!'");

  if (_dbus_string_find (&str, 0, "Oh, Hello", NULL))
    _dbus_assert_not_reached ("Did find 'Oh, Hello'");
  
  if (_dbus_string_find (&str, 0, "ill", NULL))
    _dbus_assert_not_reached ("Did find 'ill'");

  if (_dbus_string_find (&str, 0, "q", NULL))
    _dbus_assert_not_reached ("Did find 'q'");

  if (!_dbus_string_find_to (&str, 0, 2, "He", NULL))
    _dbus_assert_not_reached ("Didn't find 'He'");

  if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL))
    _dbus_assert_not_reached ("Did find 'Hello'");

  if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i))
    _dbus_assert_not_reached ("Did not find 'H'");
  _dbus_assert (i == 0);

  if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i))
    _dbus_assert_not_reached ("Did not find 'o'");
  _dbus_assert (i == _dbus_string_get_length (&str) - 1);

  if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i))
    _dbus_assert_not_reached ("Did find 'o'");
  _dbus_assert (i == -1);

  if (_dbus_string_find_byte_backward (&str, 1, 'e', &i))
    _dbus_assert_not_reached ("Did find 'e'");
  _dbus_assert (i == -1);

  if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i))
    _dbus_assert_not_reached ("Didn't find 'e'");
  _dbus_assert (i == 1);
  
  _dbus_string_free (&str);

  /* Hex encoding */
  _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string");
  if (!_dbus_string_init (&other))
    _dbus_assert_not_reached ("could not init string");

  if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0))
    _dbus_assert_not_reached ("deccoded bogus hex string with no error");

  _dbus_assert (end == 8);

  _dbus_string_free (&other);

  test_roundtrips (test_hex_roundtrip);
  
  _dbus_string_free (&str);

  {                                                                                           
    int found, found_len;  

    _dbus_string_init_const (&str, "012\r\n567\n90");
    
    if (!_dbus_string_find_eol (&str, 0, &found, &found_len) || found != 3 || found_len != 2)
      _dbus_assert_not_reached ("Did not find '\\r\\n'");                                       
    if (found != 3 || found_len != 2)                                                           
      _dbus_assert_not_reached ("invalid return values");                                       
    
    if (!_dbus_string_find_eol (&str, 5, &found, &found_len))                                    
      _dbus_assert_not_reached ("Did not find '\\n'");                                          
    if (found != 8 || found_len != 1)                                                           
      _dbus_assert_not_reached ("invalid return values");                                       
    
    if (_dbus_string_find_eol (&str, 9, &found, &found_len))                                     
      _dbus_assert_not_reached ("Found not expected '\\n'");                                    
    else if (found != 11 || found_len != 0)                                                     
      _dbus_assert_not_reached ("invalid return values '\\n'");                                 

    found = -1;
    found_len = -1;
    _dbus_string_init_const (&str, "");
    if (_dbus_string_find_eol (&str, 0, &found, &found_len))
      _dbus_assert_not_reached ("found an eol in an empty string");
    _dbus_assert (found == 0);
    _dbus_assert (found_len == 0);
    
    found = -1;
    found_len = -1;
    _dbus_string_init_const (&str, "foobar");
    if (_dbus_string_find_eol (&str, 0, &found, &found_len))
      _dbus_assert_not_reached ("found eol in string that lacks one");
    _dbus_assert (found == 6);
    _dbus_assert (found_len == 0);

    found = -1;
    found_len = -1;
    _dbus_string_init_const (&str, "foobar\n");
    if (!_dbus_string_find_eol (&str, 0, &found, &found_len))
      _dbus_assert_not_reached ("did not find eol in string that has one at end");
    _dbus_assert (found == 6);
    _dbus_assert (found_len == 1);
  }

  {
    DBusString line;

#define FIRST_LINE "this is a line"
#define SECOND_LINE "this is a second line"
    /* third line is empty */
#define THIRD_LINE ""
#define FOURTH_LINE "this is a fourth line"
    
    if (!_dbus_string_init (&str))
      _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_append (&str, FIRST_LINE "\n" SECOND_LINE "\r\n" THIRD_LINE "\n" FOURTH_LINE))
      _dbus_assert_not_reached ("no memory");
    
    if (!_dbus_string_init (&line))
      _dbus_assert_not_reached ("no memory");
    
    if (!_dbus_string_pop_line (&str, &line))
      _dbus_assert_not_reached ("failed to pop first line");

    _dbus_assert (_dbus_string_equal_c_str (&line, FIRST_LINE));
    
    if (!_dbus_string_pop_line (&str, &line))
      _dbus_assert_not_reached ("failed to pop second line");

    _dbus_assert (_dbus_string_equal_c_str (&line, SECOND_LINE));
    
    if (!_dbus_string_pop_line (&str, &line))
      _dbus_assert_not_reached ("failed to pop third line");

    _dbus_assert (_dbus_string_equal_c_str (&line, THIRD_LINE));
    
    if (!_dbus_string_pop_line (&str, &line))
      _dbus_assert_not_reached ("failed to pop fourth line");

    _dbus_assert (_dbus_string_equal_c_str (&line, FOURTH_LINE));
    
    _dbus_string_free (&str);
    _dbus_string_free (&line);
  }

  {
    if (!_dbus_string_init (&str))
      _dbus_assert_not_reached ("no memory");

    for (i = 0; i < 10000; i++)
      if (!_dbus_string_append (&str, "abcdefghijklmnopqrstuvwxyz"))
        _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_set_length (&str, 10))
      _dbus_assert_not_reached ("failed to set length");

    /* actually compact */
    if (!_dbus_string_compact (&str, 2048))
      _dbus_assert_not_reached ("failed to compact after set_length");

    /* peek inside to make sure it worked */
    if (((DBusRealString *)&str)->allocated > 30)
      _dbus_assert_not_reached ("compacting string didn't do anything");

    if (!_dbus_string_equal_c_str (&str, "abcdefghij"))
      _dbus_assert_not_reached ("unexpected content after compact");

    /* compact nothing */
    if (!_dbus_string_compact (&str, 2048))
      _dbus_assert_not_reached ("failed to compact 2nd time");

    if (!_dbus_string_equal_c_str (&str, "abcdefghij"))
      _dbus_assert_not_reached ("unexpected content after 2nd compact");

    /* and make sure it still works...*/
    if (!_dbus_string_append (&str, "123456"))
      _dbus_assert_not_reached ("failed to append after compact");

    if (!_dbus_string_equal_c_str (&str, "abcdefghij123456"))
      _dbus_assert_not_reached ("unexpected content after append");

    /* after growing automatically, this should do nothing */
    if (!_dbus_string_compact (&str, 20000))
      _dbus_assert_not_reached ("failed to compact after grow");

    /* but this one will do something */
    if (!_dbus_string_compact (&str, 0))
      _dbus_assert_not_reached ("failed to compact after grow");

    if (!_dbus_string_equal_c_str (&str, "abcdefghij123456"))
      _dbus_assert_not_reached ("unexpected content");

    if (!_dbus_string_append (&str, "!@#$%"))
      _dbus_assert_not_reached ("failed to append after compact");

    if (!_dbus_string_equal_c_str (&str, "abcdefghij123456!@#$%"))
      _dbus_assert_not_reached ("unexpected content");

    _dbus_string_free (&str);
  }

  {
    const char two_strings[] = "one\ttwo";

    if (!_dbus_string_init (&str))
      _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_init (&other))
      _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_append (&str, two_strings))
      _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_split_on_byte (&str, '\t', &other))
      _dbus_assert_not_reached ("no memory or delimiter not found");

    if (strcmp (_dbus_string_get_data (&str), "one") != 0)
      _dbus_assert_not_reached ("left side after split on tab is wrong");

    if (strcmp (_dbus_string_get_data (&other), "two") != 0)
      _dbus_assert_not_reached ("right side after split on tab is wrong");

    _dbus_string_free (&str);
    _dbus_string_free (&other);
  }

  {
    const char upper_string[] = "TOUPPERSTRING";
    const char lower_string[] = "toupperstring";
    const char lower2_string[] = "toupperSTRING";

    if (!_dbus_string_init (&str))
      _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_append (&str, upper_string))
      _dbus_assert_not_reached ("no memory");

    _dbus_string_tolower_ascii (&str, 0, _dbus_string_get_length(&str));

    if (!_dbus_string_equal_c_str (&str, lower_string))
      _dbus_assert_not_reached ("_dbus_string_tolower_ascii failed");

    _dbus_string_free (&str);

    if (!_dbus_string_init (&str))
      _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_append (&str, upper_string))
      _dbus_assert_not_reached ("no memory");

    _dbus_string_tolower_ascii (&str, 0, 7);

    if (!_dbus_string_equal_c_str (&str, lower2_string))
      _dbus_assert_not_reached ("_dbus_string_tolower_ascii failed in partial conversion");

    _dbus_string_free (&str);
  }

  {
    const char lower_string[] = "toupperstring";
    const char upper_string[] = "TOUPPERSTRING";
    const char upper2_string[] = "TOUPPERstring";

    if (!_dbus_string_init (&str))
      _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_append (&str, lower_string))
      _dbus_assert_not_reached ("no memory");

    _dbus_string_toupper_ascii (&str, 0, _dbus_string_get_length(&str));

    if (!_dbus_string_equal_c_str (&str, upper_string))
      _dbus_assert_not_reached ("_dbus_string_toupper_ascii failed");

    _dbus_string_free (&str);

    if (!_dbus_string_init (&str))
      _dbus_assert_not_reached ("no memory");

    if (!_dbus_string_append (&str, lower_string))
      _dbus_assert_not_reached ("no memory");

    _dbus_string_toupper_ascii (&str, 0, 7);

    if (!_dbus_string_equal_c_str (&str, upper2_string))
      _dbus_assert_not_reached ("_dbus_string_toupper_ascii failed in partial conversion");

    _dbus_string_free (&str);
  }

  return TRUE;
}
Example #22
0
/**
 * Decrement the reference count on the babysitter object.
 * When the reference count of the babysitter object reaches
 * zero, the babysitter is killed and the child that was being
 * babysat gets emancipated.
 *
 * @param sitter the babysitter
 */
void
_dbus_babysitter_unref (DBusBabysitter *sitter)
{
  _dbus_assert (sitter != NULL);
  _dbus_assert (sitter->refcount > 0);
  
  sitter->refcount -= 1;
  if (sitter->refcount == 0)
    {
      /* If we haven't forked other babysitters
       * since this babysitter and socket were
       * created then this close will cause the
       * babysitter to wake up from poll with
       * a hangup and then the babysitter will
       * quit itself.
       */
      close_socket_to_babysitter (sitter);

      close_error_pipe_from_child (sitter);

      if (sitter->sitter_pid > 0)
        {
          int status;
          int ret;

          /* It's possible the babysitter died on its own above 
           * from the close, or was killed randomly
           * by some other process, so first try to reap it
           */
          ret = waitpid (sitter->sitter_pid, &status, WNOHANG);

          /* If we couldn't reap the child then kill it, and
           * try again
           */
          if (ret == 0)
            kill (sitter->sitter_pid, SIGKILL);

          if (ret == 0)
            {
              do
                {
                  ret = waitpid (sitter->sitter_pid, &status, 0);
                }
              while (_DBUS_UNLIKELY (ret < 0 && errno == EINTR));
            }

          if (ret < 0)
            {
              if (errno == ECHILD)
                _dbus_warn ("Babysitter process not available to be reaped; should not happen\n");
              else
                _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n",
                            errno, _dbus_strerror (errno));
            }
          else
            {
              _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n",
                             (long) ret, (long) sitter->sitter_pid);
              
              if (WIFEXITED (sitter->status))
                _dbus_verbose ("Babysitter exited with status %d\n",
                               WEXITSTATUS (sitter->status));
              else if (WIFSIGNALED (sitter->status))
                _dbus_verbose ("Babysitter received signal %d\n",
                               WTERMSIG (sitter->status));
              else
                _dbus_verbose ("Babysitter exited abnormally\n");
            }

          sitter->sitter_pid = -1;
        }

      if (sitter->watches)
        _dbus_watch_list_free (sitter->watches);

      dbus_free (sitter->log_name);
      
      dbus_free (sitter);
    }
}
void
_dbus_trace_ref (const char *obj_name,
                 void       *obj,
                 int         old_refcount,
                 int         new_refcount,
                 const char *why,
                 const char *env_var,
                 int        *enabled)
{
  _dbus_assert (obj_name != NULL);
  _dbus_assert (obj != NULL);
  _dbus_assert (old_refcount >= -1);
  _dbus_assert (new_refcount >= -1);

  if (old_refcount == -1)
    {
      _dbus_assert (new_refcount == -1);
    }
  else
    {
      _dbus_assert (new_refcount >= 0);
      _dbus_assert (old_refcount >= 0);
      _dbus_assert (old_refcount > 0 || new_refcount > 0);
    }

  _dbus_assert (why != NULL);
  _dbus_assert (env_var != NULL);
  _dbus_assert (enabled != NULL);

  if (*enabled < 0)
    {
      const char *s = _dbus_getenv (env_var);

      *enabled = FALSE;

      if (s && *s)
        {
          if (*s == '0')
            *enabled = FALSE;
          else if (*s == '1')
            *enabled = TRUE;
          else
            _dbus_warn ("%s should be 0 or 1 if set, not '%s'", env_var, s);
        }
    }

  if (*enabled)
    {
      if (old_refcount == -1)
        {
          VALGRIND_PRINTF_BACKTRACE ("%s %p ref stolen (%s)",
                                     obj_name, obj, why);
          _dbus_verbose ("%s %p ref stolen (%s)\n",
                         obj_name, obj, why);
        }
      else
        {
          VALGRIND_PRINTF_BACKTRACE ("%s %p %d -> %d refs (%s)",
                                     obj_name, obj,
                                     old_refcount, new_refcount, why);
          _dbus_verbose ("%s %p %d -> %d refs (%s)\n",
                         obj_name, obj, old_refcount, new_refcount, why);
        }
    }
}
/* Calls strtod in a locale-independent fashion, by looking at
 * the locale data and patching the decimal comma to a point.
 *
 * Relicensed from glib.
 */
static double
ascii_strtod (const char *nptr,
	      char      **endptr)
{
  /* FIXME: The Win32 C library's strtod() doesn't handle hex.
   * Presumably many Unixes don't either.
   */

  char *fail_pos;
  double val;
  struct lconv *locale_data;
  const char *decimal_point;
  int decimal_point_len;
  const char *p, *decimal_point_pos;
  const char *end = NULL; /* Silence gcc */

  fail_pos = NULL;

  locale_data = localeconv ();
  decimal_point = locale_data->decimal_point;
  decimal_point_len = strlen (decimal_point);

  _dbus_assert (decimal_point_len != 0);
  
  decimal_point_pos = NULL;
  if (decimal_point[0] != '.' ||
      decimal_point[1] != 0)
    {
      p = nptr;
      /* Skip leading space */
      while (ascii_isspace (*p))
	p++;
      
      /* Skip leading optional sign */
      if (*p == '+' || *p == '-')
	p++;
      
      if (p[0] == '0' &&
	  (p[1] == 'x' || p[1] == 'X'))
	{
	  p += 2;
	  /* HEX - find the (optional) decimal point */
	  
	  while (ascii_isxdigit (*p))
	    p++;
	  
	  if (*p == '.')
	    {
	      decimal_point_pos = p++;
	      
	      while (ascii_isxdigit (*p))
		p++;
	      
	      if (*p == 'p' || *p == 'P')
		p++;
	      if (*p == '+' || *p == '-')
		p++;
	      while (ascii_isdigit (*p))
		p++;
	      end = p;
	    }
	}
      else
	{
	  while (ascii_isdigit (*p))
	    p++;
	  
	  if (*p == '.')
	    {
	      decimal_point_pos = p++;
	      
	      while (ascii_isdigit (*p))
		p++;
	      
	      if (*p == 'e' || *p == 'E')
		p++;
	      if (*p == '+' || *p == '-')
		p++;
	      while (ascii_isdigit (*p))
		p++;
	      end = p;
	    }
	}
      /* For the other cases, we need not convert the decimal point */
    }

  /* Set errno to zero, so that we can distinguish zero results
     and underflows */
  errno = 0;
  
  if (decimal_point_pos)
    {
      char *copy, *c;

      /* We need to convert the '.' to the locale specific decimal point */
      copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
      
      c = copy;
      memcpy (c, nptr, decimal_point_pos - nptr);
      c += decimal_point_pos - nptr;
      memcpy (c, decimal_point, decimal_point_len);
      c += decimal_point_len;
      memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
      c += end - (decimal_point_pos + 1);
      *c = 0;

      val = strtod (copy, &fail_pos);

      if (fail_pos)
	{
	  if (fail_pos > decimal_point_pos)
	    fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
	  else
	    fail_pos = (char *)nptr + (fail_pos - copy);
	}
      
      dbus_free (copy);
	  
    }
  else
    val = strtod (nptr, &fail_pos);

  if (endptr)
    *endptr = fail_pos;
  
  return val;
}
Example #25
0
BusClientPolicy*
bus_policy_create_client_policy (BusPolicy      *policy,
                                 DBusConnection *connection,
                                 DBusError      *error)
{
  BusClientPolicy *client;
  dbus_uid_t uid;
  dbus_bool_t at_console;

  _dbus_assert (dbus_connection_get_is_authenticated (connection));
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  client = bus_client_policy_new ();
  if (client == NULL)
    goto nomem;

  if (!add_list_to_client (&policy->default_rules,
                           client))
    goto nomem;

  /* we avoid the overhead of looking up user's groups
   * if we don't have any group rules anyway
   */
  if (_dbus_hash_table_get_n_entries (policy->rules_by_gid) > 0)
    {
      unsigned long *groups;
      int n_groups;
      int i;
      
      if (!bus_connection_get_groups (connection, &groups, &n_groups, error))
        goto failed;
      
      i = 0;
      while (i < n_groups)
        {
          DBusList **list;
          
          list = _dbus_hash_table_lookup_ulong (policy->rules_by_gid,
                                                groups[i]);
          
          if (list != NULL)
            {
              if (!add_list_to_client (list, client))
                {
                  dbus_free (groups);
                  goto nomem;
                }
            }
          
          ++i;
        }

      dbus_free (groups);
    }

  if (!dbus_connection_get_unix_user (connection, &uid))
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "No user ID known for connection, cannot determine security policy\n");
      goto failed;
    }

  if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
    {
      DBusList **list;
      
      list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
                                            uid);

      if (list != NULL)
        {
          if (!add_list_to_client (list, client))
            goto nomem;
        }
    }

  /* Add console rules */
  at_console = _dbus_is_console_user (uid, error);

  if (at_console)
    {
      if (!add_list_to_client (&policy->at_console_true_rules, client))
        goto nomem;
    }
  else if (dbus_error_is_set (error) == TRUE)
    {
      goto failed;
    }
  else if (!add_list_to_client (&policy->at_console_false_rules, client))
    {
      goto nomem;
    }

  if (!add_list_to_client (&policy->mandatory_rules,
                           client))
    goto nomem;

  bus_client_policy_optimize (client);
  
  return client;

 nomem:
  BUS_SET_OOM (error);
 failed:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  if (client)
    bus_client_policy_unref (client);
  return NULL;
}