/** Checks if user is at the console
*
* @param username user to check
* @param error return location for errors
* @returns #TRUE is the user is at the consolei and there are no errors
*/
dbus_bool_t 
_dbus_user_at_console (const char *username,
                       DBusError  *error)
{

  DBusString f;
  dbus_bool_t result;

  result = FALSE;
  if (!_dbus_string_init (&f))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
    {
      _DBUS_SET_OOM (error);
      goto out;
    }


  if (!_dbus_string_append (&f, username))
    {
      _DBUS_SET_OOM (error);
      goto out;
    }

  result = _dbus_file_exists (_dbus_string_get_const_data (&f));

 out:
  _dbus_string_free (&f);

  return result;
}
Beispiel #2
0
static dbus_bool_t
_dbus_create_uuid_file_exclusively (const DBusString *filename,
                                    DBusGUID         *uuid,
                                    DBusError        *error)
{
  DBusString encoded;

  if (!_dbus_string_init (&encoded))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  _dbus_generate_uuid (uuid);
  
  if (!_dbus_uuid_encode (uuid, &encoded))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }
  
  /* FIXME this is racy; we need a save_file_exclusively
   * function. But in practice this should be fine for now.
   *
   * - first be sure we can create the file and it
   *   doesn't exist by creating it empty with O_EXCL
   * - then create it by creating a temporary file and
   *   overwriting atomically with rename()
   */
  if (!_dbus_create_file_exclusively (filename, error))
    goto error;

  if (!_dbus_string_append_byte (&encoded, '\n'))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }
  
  if (!_dbus_string_save_to_file (&encoded, filename, error))
    goto error;

  if (!_dbus_make_file_world_readable (filename, error))
    goto error;

  _dbus_string_free (&encoded);

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  return TRUE;
  
 error:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  _dbus_string_free (&encoded);
  return FALSE;        
}
Beispiel #3
0
/**
 * Checks whether a certain name has an owner.
 *
 * @param connection the connection
 * @param name the name
 * @param error location to store any errors
 * @returns #TRUE if the name exists, #FALSE if not or on error
 */
dbus_bool_t
dbus_bus_name_has_owner (DBusConnection *connection,
			 const char     *name,
                         DBusError      *error)
{
  DBusMessage *message, *reply;
  dbus_bool_t exists;

  _dbus_return_val_if_fail (connection != NULL, FALSE);
  _dbus_return_val_if_fail (name != NULL, FALSE);
  _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE);
  _dbus_return_val_if_error_is_set (error, FALSE);
  
  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                          DBUS_PATH_DBUS,
                                          DBUS_INTERFACE_DBUS,
                                          "NameHasOwner");
  if (message == NULL)
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  if (!dbus_message_append_args (message,
				 DBUS_TYPE_STRING, &name,
				 DBUS_TYPE_INVALID))
    {
      dbus_message_unref (message);
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
  dbus_message_unref (message);

  if (reply == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      return FALSE;
    }

  if (!dbus_message_get_args (reply, error,
                              DBUS_TYPE_BOOLEAN, &exists,
                              DBUS_TYPE_INVALID))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return FALSE;
    }
  
  dbus_message_unref (reply);
  return exists;
}
Beispiel #4
0
/**
 * Removes a previously-added match rule "by value" (the most
 * recently-added identical rule gets removed).  The "rule" argument
 * is the string form of a match rule.
 *
 * If you pass #NULL for the error, this function will not
 * block; otherwise it will. See detailed explanation in
 * docs for dbus_bus_add_match().
 * 
 * @param connection connection to the message bus
 * @param rule textual form of match rule
 * @param error location to store any errors
 */
void
dbus_bus_remove_match (DBusConnection *connection,
                       const char     *rule,
                       DBusError      *error)
{
  DBusMessage *msg;

  _dbus_return_if_fail (rule != NULL);
  
  msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                      DBUS_PATH_DBUS,
                                      DBUS_INTERFACE_DBUS,
                                      "RemoveMatch");

  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule,
                                 DBUS_TYPE_INVALID))
    {
      dbus_message_unref (msg);
      _DBUS_SET_OOM (error);
      return;
    }

  send_no_return_values (connection, msg, error);

  dbus_message_unref (msg);
}
Beispiel #5
0
/**
 * Starts a service that will request ownership of the given name.
 * The returned result will be one of be one of
 * #DBUS_START_REPLY_SUCCESS or #DBUS_START_REPLY_ALREADY_RUNNING if
 * successful.  Pass #NULL if you don't care about the result.
 * 
 * The flags parameter is for future expansion, currently you should
 * specify 0.
 *
 * @param connection the connection
 * @param name the name we want the new service to request
 * @param flags the flags (should always be 0 for now)
 * @param result a place to store the result or #NULL
 * @param error location to store any errors
 * @returns #TRUE if the activation succeeded, #FALSE if not
 */
dbus_bool_t
dbus_bus_start_service_by_name (DBusConnection *connection,
                                const char     *name,
                                dbus_uint32_t   flags,
                                dbus_uint32_t  *result,
                                DBusError      *error)
{
  DBusMessage *msg;
  DBusMessage *reply;

  _dbus_return_val_if_fail (connection != NULL, FALSE);
  _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE);
  
  msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                      DBUS_PATH_DBUS,
                                      DBUS_INTERFACE_DBUS,
                                      "StartServiceByName");

  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &name,
			  	 DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID))
    {
      dbus_message_unref (msg);
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  reply = dbus_connection_send_with_reply_and_block (connection, msg,
                                                     -1, error);
  dbus_message_unref (msg);

  if (reply == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      return FALSE;
    }

  if (dbus_set_error_from_message (error, reply))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return FALSE;
    }

  if (result != NULL &&
      !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32,
	      		      result, DBUS_TYPE_INVALID))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return FALSE;
    }
  
  dbus_message_unref (reply);
  return TRUE;
}
/**
 * Write the give UUID to a file.
 *
 * @param filename the file to write
 * @param uuid the UUID to save
 * @param error used to raise an error
 * @returns #FALSE on error
 */
dbus_bool_t
_dbus_write_uuid_file (const DBusString *filename,
                       const DBusGUID   *uuid,
                       DBusError        *error)
{
  DBusString encoded;

  if (!_dbus_string_init (&encoded))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  if (!_dbus_uuid_encode (uuid, &encoded))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }
  
  if (!_dbus_string_append_byte (&encoded, '\n'))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }
  
  if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error))
    goto error;

  _dbus_string_free (&encoded);

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  return TRUE;
  
 error:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  _dbus_string_free (&encoded);
  return FALSE;        
}
static dbus_bool_t
delimit_token (DBusString *token,
               DBusList **retval,
               DBusError *error)
{
    char *str;

    str = _dbus_strdup (_dbus_string_get_data (token));
    if (!str)
    {
        _DBUS_SET_OOM (error);
        return FALSE;
    }

    if (!_dbus_list_append (retval, str))
    {
        dbus_free (str);
        _DBUS_SET_OOM (error);
        return FALSE;
    }

    return TRUE;
}
static void
xml_text_reader_error (void *arg, xmlErrorPtr xml_error)
{
  DBusError *error = arg;

#if 0
  _dbus_verbose ("XML_ERROR level=%d, domain=%d, code=%d, msg=%s\n",
                 xml_error->level, xml_error->domain,
                 xml_error->code, xml_error->message);
#endif

  if (!dbus_error_is_set (error))
    {
      if (xml_error->code == XML_ERR_NO_MEMORY)
        _DBUS_SET_OOM (error);
      else if (xml_error->level == XML_ERR_ERROR ||
               xml_error->level == XML_ERR_FATAL)
        dbus_set_error (error, DBUS_ERROR_FAILED,
                        "Error loading config file: '%s'",
                        xml_error->message);
    }
}
Beispiel #9
0
DBusConnection *
test_try_connect_to_bus (TestMainContext *ctx,
    const gchar *address,
    GError **gerror)
{
  DBusConnection *conn;
  DBusError error = DBUS_ERROR_INIT;

  conn = dbus_connection_open_private (address, &error);

  if (conn == NULL)
    goto fail;

  if (!dbus_bus_register (conn, &error))
    goto fail;

  g_assert (dbus_bus_get_unique_name (conn) != NULL);

  if (ctx != NULL && !test_connection_try_setup (ctx, conn))
    {
      _DBUS_SET_OOM (&error);
      goto fail;
    }

  return conn;

fail:
  if (gerror != NULL)
    *gerror = g_dbus_error_new_for_dbus_error (error.name, error.message);

  if (conn != NULL)
    {
      dbus_connection_close (conn);
      dbus_connection_unref (conn);
    }

  dbus_error_free (&error);
  return FALSE;
}
Beispiel #10
0
/**
 * Fills n_bytes of the given buffer with random bytes.
 *
 * @param buffer an allocated buffer
 * @param n_bytes the number of bytes in buffer to write to
 * @param error location to store reason for failure
 * @returns #TRUE on success
 */
dbus_bool_t
_dbus_generate_random_bytes_buffer (char      *buffer,
                                    int        n_bytes,
                                    DBusError *error)
{
  DBusString str;

  if (!_dbus_string_init (&str))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (!_dbus_generate_random_bytes (&str, n_bytes, error))
    {
      _dbus_string_free (&str);
      return FALSE;
    }

  _dbus_string_copy_to_buffer (&str, buffer, n_bytes);

  _dbus_string_free (&str);
  return TRUE;
}
/**
 * Try to open a new transport for the given address entry.  (This
 * opens a client-side-of-the-connection transport.)
 * 
 * @param entry the address entry
 * @param error location to store reason for failure.
 * @returns new transport of #NULL on failure.
 */
DBusTransport*
_dbus_transport_open (DBusAddressEntry *entry,
                      DBusError        *error)
{
  DBusTransport *transport;
  const char *address_problem_type;
  const char *address_problem_field;
  const char *address_problem_other;
  const char *method;
  const char *expected_guid_orig;
  char *expected_guid;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  transport = NULL;
  address_problem_type = NULL;
  address_problem_field = NULL;
  address_problem_other = NULL;
  expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
  expected_guid = _dbus_strdup (expected_guid_orig);

  if (expected_guid_orig != NULL && expected_guid == NULL)
    {
      _DBUS_SET_OOM (error);
      return NULL;
    }
  
  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)
        {
          address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on";
          goto bad_address;
        }
          
      if (path == NULL && abstract == NULL)
        {
          address_problem_type = "unix";
          address_problem_field = "path or abstract";  
          goto bad_address;
        }

      if (path != NULL && abstract != NULL)
        {
          address_problem_other = "can't specify both \"path\" and \"abstract\" options in an address";
          goto bad_address;
        }

      if (path)
        transport = _dbus_transport_new_for_domain_socket (path, FALSE,
                                                           error);
      else
        transport = _dbus_transport_new_for_domain_socket (abstract, TRUE,
                                                           error);
    }
  else if (strcmp (method, "tcp") == 0)
    {
      const char *host = dbus_address_entry_get_value (entry, "host");
      const char *port = dbus_address_entry_get_value (entry, "port");
      DBusString  str;
      long lport;
      dbus_bool_t sresult;
          
      if (port == NULL)
        {
          address_problem_type = "tcp";
          address_problem_field = "port";
          goto bad_address;
        }

      _dbus_string_init_const (&str, port);
      sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
      _dbus_string_free (&str);
          
      if (sresult == FALSE || lport <= 0 || lport > 65535)
        {
          address_problem_other = "Port is not an integer between 0 and 65535";
          goto bad_address;
        }
          
      transport = _dbus_transport_new_for_tcp_socket (host, lport, error);
    }
#ifdef DBUS_BUILD_TESTS
  else if (strcmp (method, "debug-pipe") == 0)
    {
      const char *name = dbus_address_entry_get_value (entry, "name");

      if (name == NULL)
        {
          address_problem_type = "debug-pipe";
          address_problem_field = "name";
          goto bad_address;
        }
          
      transport = _dbus_transport_debug_pipe_new (name, error);
    }
#endif
  else
    {
      address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
      goto bad_address;
    }

  if (transport == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_free (expected_guid);
    }
  else
    {
      transport->expected_guid = expected_guid;
    }
  
  return transport;
  
 bad_address:
  dbus_free (expected_guid);
  
  if (address_problem_type != NULL)
    dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
                    "Address of type %s was missing argument %s",
                    address_problem_type, address_problem_field);
  else
    dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
                    "Could not parse address: %s",
                    address_problem_other);

  return NULL;
}
Beispiel #12
0
/**
 * Try to open a new transport for the given address entry.  (This
 * opens a client-side-of-the-connection transport.)
 * 
 * @param entry the address entry
 * @param error location to store reason for failure.
 * @returns new transport of #NULL on failure.
 */
DBusTransport*
_dbus_transport_open (DBusAddressEntry *entry,
                      DBusError        *error)
{
  DBusTransport *transport;
  const char *expected_guid_orig;
  char *expected_guid;
  int i;
  DBusError tmp_error = DBUS_ERROR_INIT;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  transport = NULL;
  expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
  expected_guid = _dbus_strdup (expected_guid_orig);

  if (expected_guid_orig != NULL && expected_guid == NULL)
    {
      _DBUS_SET_OOM (error);
      return NULL;
    }

  for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
    {
      DBusTransportOpenResult result;

      _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
      result = (* open_funcs[i].func) (entry, &transport, &tmp_error);

      switch (result)
        {
        case DBUS_TRANSPORT_OPEN_OK:
          _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
          goto out;
          break;
        case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
          _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
          /* keep going through the loop of open funcs */
          break;
        case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
          _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
          goto out;
          break;
        case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
          _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
          goto out;
          break;
        }
    }

 out:
  
  if (transport == NULL)
    {
      if (!dbus_error_is_set (&tmp_error))
        _dbus_set_bad_address (&tmp_error,
                               NULL, NULL,
                               "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
      
      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
      dbus_move_error(&tmp_error, error);
      dbus_free (expected_guid);
    }
  else
    {
      _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);

      /* In the case of autostart the initial guid is NULL
       * and the autostart transport recursively calls
       * _dbus_open_transport wich returns a transport
       * with a guid.  That guid is the definitive one.
       *
       * FIXME: if more transports are added they may have
       * an effect on the expected_guid semantics (i.e. 
       * expected_guid and transport->expected_guid may
       * both have values).  This is very unlikely though
       * we should either throw asserts here for those 
       * corner cases or refactor the code so it is 
       * clearer on what is expected and what is not
       */
      if(expected_guid)
        transport->expected_guid = expected_guid;
    }

  return transport;
}
BusConfigParser*
bus_config_load (const DBusString      *file,
                 dbus_bool_t            is_toplevel,
                 const BusConfigParser *parent,
                 DBusError             *error)

{
  xmlTextReader *reader;
  BusConfigParser *parser;
  DBusString dirname, data;
  DBusError tmp_error;
  int ret;
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  parser = NULL;
  reader = NULL;

  if (!_dbus_string_init (&dirname))
    {
      _DBUS_SET_OOM (error);
      return NULL;
    }

  if (!_dbus_string_init (&data))
    {
      _DBUS_SET_OOM (error);
      _dbus_string_free (&dirname);
      return NULL;
    }

  if (is_toplevel)
    {
      /* xmlMemSetup only fails if one of the functions is NULL */
    /*
      xmlMemSetup (dbus_free,
                   dbus_malloc,
                   dbus_realloc,
                   _dbus_strdup);
     */              
      xmlInitParser ();
      xmlSetGenericErrorFunc (NULL, xml_shut_up);
    }

  if (!_dbus_string_get_dirname (file, &dirname))
    {
      _DBUS_SET_OOM (error);
      goto failed;
    }
  
  parser = bus_config_parser_new (&dirname, is_toplevel, parent);
  if (parser == NULL)
    {
      _DBUS_SET_OOM (error);
      goto failed;
    }
  
  if (!_dbus_file_get_contents (&data, file, error))
    goto failed;

  reader = xmlReaderForMemory (_dbus_string_get_const_data (&data), 
                               _dbus_string_get_length (&data),
			       NULL, NULL, 0);
  if (reader == NULL)
    {
      _DBUS_SET_OOM (error);
      goto failed;
    }

  xmlTextReaderSetParserProp (reader, XML_PARSER_SUBST_ENTITIES, 1);

  dbus_error_init (&tmp_error);
  xmlTextReaderSetStructuredErrorHandler (reader, xml_text_reader_error, &tmp_error);

  while ((ret = xmlTextReaderRead (reader)) == 1)
    {
      int type;
      
      if (dbus_error_is_set (&tmp_error))
        goto reader_out;

      type = xmlTextReaderNodeType (reader);
      if (type == -1)
        {
          _DBUS_MAYBE_SET_OOM (&tmp_error);
          goto reader_out;
        }

      switch ((xmlReaderTypes) type) {
      case XML_READER_TYPE_ELEMENT:
	xml_text_start_element (parser, reader, &tmp_error);
	break;

      case XML_READER_TYPE_TEXT:
      case XML_READER_TYPE_CDATA:
	{
	  DBusString content;
	  const char *value;
#ifdef __SYMBIAN32__
	  value = (const char *) xmlTextReaderConstValue (reader);
#else
	  value = xmlTextReaderConstValue (reader);
#endif
	  if (value != NULL)
	    {
	      _dbus_string_init_const (&content, value);
	      bus_config_parser_content (parser, &content, &tmp_error);
	    }
          else
            _DBUS_MAYBE_SET_OOM (&tmp_error);
	  break;
	}

      case XML_READER_TYPE_DOCUMENT_TYPE:
	{
	  const char *name;
#ifdef __SYMBIAN32__
	  name = (const char *) xmlTextReaderConstName (reader);
#else
	  name = xmlTextReaderConstName (reader);
#endif
	  if (name != NULL)
	    bus_config_parser_check_doctype (parser, name, &tmp_error);
          else
            _DBUS_MAYBE_SET_OOM (&tmp_error);
	  break;
	}

      case XML_READER_TYPE_END_ELEMENT:
	{
	  const char *name;
#ifdef __SYMBIAN32__
	  name = (const char *) xmlTextReaderConstName (reader);
#else
	  name = xmlTextReaderConstName (reader);
#endif
	  if (name != NULL)
	    bus_config_parser_end_element (parser, name, &tmp_error);
          else
            _DBUS_MAYBE_SET_OOM (&tmp_error);
	  break;
	}

      case XML_READER_TYPE_DOCUMENT:
      case XML_READER_TYPE_DOCUMENT_FRAGMENT:
      case XML_READER_TYPE_PROCESSING_INSTRUCTION:
      case XML_READER_TYPE_COMMENT:
      case XML_READER_TYPE_ENTITY:
      case XML_READER_TYPE_NOTATION:
      case XML_READER_TYPE_WHITESPACE:
      case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
      case XML_READER_TYPE_END_ENTITY:
      case XML_READER_TYPE_XML_DECLARATION:
	/* nothing to do, just read on */
	break;

      case XML_READER_TYPE_NONE:
      case XML_READER_TYPE_ATTRIBUTE:
      case XML_READER_TYPE_ENTITY_REFERENCE:
	_dbus_assert_not_reached ("unexpected nodes in XML");
      }

      if (dbus_error_is_set (&tmp_error))
        goto reader_out;
    }

  if (ret == -1)
    _DBUS_MAYBE_SET_OOM (&tmp_error);

 reader_out:
  xmlFreeTextReader (reader);
  reader = NULL;
  if (dbus_error_is_set (&tmp_error))
    {
      dbus_move_error (&tmp_error, error);
      goto failed;
    }
  
  if (!bus_config_parser_finished (parser, error))
    goto failed;
  _dbus_string_free (&dirname);
  _dbus_string_free (&data);
  if (is_toplevel)
    xmlCleanupParser();
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  return parser;
  
 failed:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  _dbus_string_free (&dirname);
  _dbus_string_free (&data);
  if (is_toplevel)
    xmlCleanupParser();
  if (parser)
    bus_config_parser_unref (parser);
  _dbus_assert (reader == NULL); /* must go to reader_out first */
  return NULL;
}
static dbus_bool_t
xml_text_start_element (BusConfigParser   *parser,
			xmlTextReader     *reader,
			DBusError         *error)
{
  const char *name;
  int n_attributes;
  const char **attribute_names, **attribute_values;
  dbus_bool_t ret;
  int i, status, is_empty;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  ret = FALSE;
  attribute_names = NULL;
  attribute_values = NULL;

#ifdef __SYMBIAN32__
  name = (const char *) xmlTextReaderConstName (reader);
#else
  name = xmlTextReaderConstName (reader);
#endif
  n_attributes = xmlTextReaderAttributeCount (reader);
  is_empty = xmlTextReaderIsEmptyElement (reader);

  if (name == NULL || n_attributes < 0 || is_empty == -1)
    {
      _DBUS_MAYBE_SET_OOM (error);
      goto out;
    }

  attribute_names = dbus_new0 (const char *, n_attributes + 1);
  attribute_values = dbus_new0 (const char *, n_attributes + 1);
  if (attribute_names == NULL || attribute_values == NULL)
    {
      _DBUS_SET_OOM (error);
      goto out;
    }
  i = 0;
  while ((status = xmlTextReaderMoveToNextAttribute (reader)) == 1)
    {
      _dbus_assert (i < n_attributes);
#ifdef __SYMBIAN32__
      attribute_names[i] = (const char *) xmlTextReaderConstName (reader);
      attribute_values[i] = (const char *) xmlTextReaderConstValue (reader);
#else
      attribute_names[i] = xmlTextReaderConstName (reader);
      attribute_values[i] = (xmlTextReaderConstValue (reader);
#endif
      if (attribute_names[i] == NULL || attribute_values[i] == NULL)
	{ 
          _DBUS_MAYBE_SET_OOM (error);
	  goto out;
	}
      i++;
    }
  if (status == -1)
    {
      _DBUS_MAYBE_SET_OOM (error);
      goto out;
    }
  _dbus_assert (i == n_attributes);

  ret = bus_config_parser_start_element (parser, name,
					 attribute_names, attribute_values,
					 error);
  if (ret && is_empty == 1)
    ret = bus_config_parser_end_element (parser, name, error);

 out:
  dbus_free (attribute_names);
  dbus_free (attribute_values);

  return ret;
}
/**
 * Assigns an error name and message to a DBusError.
 * Does nothing if error is #NULL.
 *
 * The format may be #NULL, which means a (pretty much useless)
 * default message will be deduced from the name. This is not a good
 * idea, just go ahead and provide a useful error message. It won't
 * hurt you.
 *
 * If no memory can be allocated for the error message, 
 * an out-of-memory error message will be set instead.
 *
 * @param error the error.or #NULL
 * @param name the error name
 * @param format printf-style format string.
 */
void
dbus_set_error (DBusError  *error,
		const char *name,
		const char *format,
		...)
{
  DBusRealError *real;
  DBusString str;
  va_list args;
  
  if (error == NULL)
    return;

  /* it's a bug to pile up errors */
  _dbus_return_if_error_is_set (error);
  _dbus_return_if_fail (name != NULL);
  
  _dbus_assert (error->name == NULL);
  _dbus_assert (error->message == NULL);

  if (!_dbus_string_init (&str))
    goto nomem;
  
  if (format == NULL)
    {
      if (!_dbus_string_append (&str,
                                message_from_error (name)))
        {
          _dbus_string_free (&str);
          goto nomem;
        }
    }
  else
    {
      va_start (args, format);
      if (!_dbus_string_append_printf_valist (&str, format, args))
        {
          _dbus_string_free (&str);
          va_end (args);
          goto nomem;
        }
      va_end (args);
    }

  real = (DBusRealError *)error;

  if (!_dbus_string_steal_data (&str, &real->message))
    {
      _dbus_string_free (&str);
      goto nomem;
    }
  _dbus_string_free (&str);
  
  real->name = _dbus_strdup (name);
  if (real->name == NULL)
    {
      dbus_free (real->message);
      real->message = NULL;
      goto nomem;
    }
  real->const_message = FALSE;

  return;
  
 nomem:
  _DBUS_SET_OOM (error);
}
Beispiel #16
0
/**
 * Get a printable string describing the command used to execute
 * the process with pid.  This string should only be used for
 * informative purposes such as logging; it may not be trusted.
 * 
 * The command is guaranteed to be printable ASCII and no longer
 * than max_len.
 * 
 * @param pid Process id
 * @param str Append command to this string
 * @param max_len Maximum length of returned command
 * @param error return location for errors
 * @returns #FALSE on error
 */
dbus_bool_t 
_dbus_command_for_pid (unsigned long  pid,
                       DBusString    *str,
                       int            max_len,
                       DBusError     *error)
{
  /* This is all Linux-specific for now */
  DBusString path;
  DBusString cmdline;
  int fd;
  
  if (!_dbus_string_init (&path)) 
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  if (!_dbus_string_init (&cmdline))
    {
      _DBUS_SET_OOM (error);
      _dbus_string_free (&path);
      return FALSE;
    }
  
  if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid))
    goto oom;
  
  fd = open (_dbus_string_get_const_data (&path), O_RDONLY);
  if (fd < 0) 
    {
      dbus_set_error (error,
                      _dbus_error_from_errno (errno),
                      "Failed to open \"%s\": %s",
                      _dbus_string_get_const_data (&path),
                      _dbus_strerror (errno));
      goto fail;
    }
  
  if (!_dbus_read (fd, &cmdline, max_len))
    {
      dbus_set_error (error,
                      _dbus_error_from_errno (errno),
                      "Failed to read from \"%s\": %s",
                      _dbus_string_get_const_data (&path),
                      _dbus_strerror (errno));      
      goto fail;
    }
  
  if (!_dbus_close (fd, error))
    goto fail;
  
  string_squash_nonprintable (&cmdline);  

  if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
    goto oom;

  _dbus_string_free (&cmdline);  
  _dbus_string_free (&path);
  return TRUE;
oom:
  _DBUS_SET_OOM (error);
fail:
  _dbus_string_free (&cmdline);
  _dbus_string_free (&path);
  return FALSE;
}
dbus_bool_t
_dbus_become_daemon (const DBusString *pidfile,
		     int               print_pid_fd,
                     DBusError        *error)
{
  const char *s;
  pid_t child_pid;
  int dev_null_fd;

  _dbus_verbose ("Becoming a daemon...\n");

  _dbus_verbose ("chdir to /\n");
  if (chdir ("/") < 0)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Could not chdir() to root directory");
      return FALSE;
    }

  _dbus_verbose ("forking...\n");
  switch ((child_pid = fork ()))
    {
    case -1:
      _dbus_verbose ("fork failed\n");
      dbus_set_error (error, _dbus_error_from_errno (errno),
                      "Failed to fork daemon: %s", _dbus_strerror (errno));
      return FALSE;
      break;

    case 0:
      _dbus_verbose ("in child, closing std file descriptors\n");

      /* silently ignore failures here, if someone
       * doesn't have /dev/null we may as well try
       * to continue anyhow
       */
      
      dev_null_fd = open ("/dev/null", O_RDWR);
      if (dev_null_fd >= 0)
        {
          dup2 (dev_null_fd, 0);
          dup2 (dev_null_fd, 1);
          
          s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
          if (s == NULL || *s == '\0')
            dup2 (dev_null_fd, 2);
          else
            _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
        }

      /* Get a predictable umask */
      _dbus_verbose ("setting umask\n");
      umask (022);
      break;

    default:
      if (pidfile)
        {
          _dbus_verbose ("parent writing pid file\n");
          if (!_dbus_write_pid_file (pidfile,
                                     child_pid,
                                     error))
            {
              _dbus_verbose ("pid file write failed, killing child\n");
              kill (child_pid, SIGTERM);
              return FALSE;
            }
        }

      /* Write PID if requested */
      if (print_pid_fd >= 0)
	{
	  DBusString pid;
	  int bytes;
	  
	  if (!_dbus_string_init (&pid))
	    {
	      _DBUS_SET_OOM (error);
              kill (child_pid, SIGTERM);
	      return FALSE;
	    }
	  
	  if (!_dbus_string_append_int (&pid, child_pid) ||
	      !_dbus_string_append (&pid, "\n"))
	    {
	      _dbus_string_free (&pid);
	      _DBUS_SET_OOM (error);
              kill (child_pid, SIGTERM);
	      return FALSE;
	    }
	  
	  bytes = _dbus_string_get_length (&pid);
	  if (_dbus_write_socket (print_pid_fd, &pid, 0, bytes) != bytes)
	    {
	      dbus_set_error (error, DBUS_ERROR_FAILED,
			      "Printing message bus PID: %s\n",
			      _dbus_strerror (errno));
	      _dbus_string_free (&pid);
              kill (child_pid, SIGTERM);
	      return FALSE;
	    }
	  
	  _dbus_string_free (&pid);
	}
      _dbus_verbose ("parent exiting\n");
      _exit (0);
      break;
    }

  _dbus_verbose ("calling setsid()\n");
  if (setsid () == -1)
    _dbus_assert_not_reached ("setsid() failed");
  
  return TRUE;
}
static DBusList*
tokenize_command_line (const char *command_line, DBusError *error)
{
    char current_quote;
    const char *p;
    DBusString current_token;
    DBusList *retval = NULL;
    dbus_bool_t quoted;;

    current_quote = '\0';
    quoted = FALSE;
    p = command_line;

    if (!_dbus_string_init (&current_token))
    {
        _DBUS_SET_OOM (error);
        return NULL;
    }

    while (*p)
    {
        if (current_quote == '\\')
        {
            if (*p == '\n')
            {
                /* we append nothing; backslash-newline become nothing */
            }
            else
            {
                if (!_dbus_string_append_byte (&current_token, '\\') ||
                        !_dbus_string_append_byte (&current_token, *p))
                {
                    _DBUS_SET_OOM (error);
                    goto error;
                }
            }

            current_quote = '\0';
        }
        else if (current_quote == '#')
        {
            /* Discard up to and including next newline */
            while (*p && *p != '\n')
                ++p;

            current_quote = '\0';

            if (*p == '\0')
                break;
        }
        else if (current_quote)
        {
            if (*p == current_quote &&
                    /* check that it isn't an escaped double quote */
                    !(current_quote == '"' && quoted))
            {
                /* close the quote */
                current_quote = '\0';
            }

            /* Everything inside quotes, and the close quote,
             * gets appended literally.
             */

            if (!_dbus_string_append_byte (&current_token, *p))
            {
                _DBUS_SET_OOM (error);
                goto error;
            }
        }
        else
        {
            switch (*p)
            {
            case '\n':
                if (!delimit_token (&current_token, &retval, error))
                    goto error;

                _dbus_string_free (&current_token);

                if (!_dbus_string_init (&current_token))
                {
                    _DBUS_SET_OOM (error);
                    goto init_error;
                }

                break;

            case ' ':
            case '\t':
                /* If the current token contains the previous char, delimit
                 * the current token. A nonzero length
                 * token should always contain the previous char.
                 */
                if (_dbus_string_get_length (&current_token) > 0)
                {
                    if (!delimit_token (&current_token, &retval, error))
                        goto error;

                    _dbus_string_free (&current_token);

                    if (!_dbus_string_init (&current_token))
                    {
                        _DBUS_SET_OOM (error);
                        goto init_error;
                    }

                }

                /* discard all unquoted blanks (don't add them to a token) */
                break;


            /* single/double quotes are appended to the token,
             * escapes are maybe appended next time through the loop,
             * comment chars are never appended.
             */

            case '\'':
            case '"':
                if (!_dbus_string_append_byte (&current_token, *p))
                {
                    _DBUS_SET_OOM (error);
                    goto error;
                }

            /* FALL THRU */

            case '#':
            case '\\':
                current_quote = *p;
                break;

            default:
                /* Combines rules 4) and 6) - if we have a token, append to it,
                 * otherwise create a new token.
                 */
                if (!_dbus_string_append_byte (&current_token, *p))
                {
                    _DBUS_SET_OOM (error);
                    goto error;
                }
                break;
            }
        }

        /* We need to count consecutive backslashes mod 2,
         * to detect escaped doublequotes.
         */
        if (*p != '\\')
            quoted = FALSE;
        else
            quoted = !quoted;

        ++p;
    }

    if (!delimit_token (&current_token, &retval, error))
        goto error;

    if (current_quote)
    {
        dbus_set_error_const (error, DBUS_ERROR_INVALID_ARGS, "Unclosed quotes in command line");
        goto error;
    }

    if (retval == NULL)
    {
        dbus_set_error_const (error, DBUS_ERROR_INVALID_ARGS, "No tokens found in command line");
        goto error;
    }

    _dbus_string_free (&current_token);

    return retval;

error:
    _dbus_string_free (&current_token);

init_error:
    if (retval)
    {
        _dbus_list_foreach (&retval, (DBusForeachFunction) dbus_free, NULL);
        _dbus_list_clear (&retval);
    }

    return NULL;
}
/**
 * Tries to interpret the address entry in a platform-specific
 * way, creating a platform-specific server type if appropriate.
 * Sets error if the result is not OK.
 *
 * @param entry an address entry
 * @param server_p location to store a new DBusServer, or #NULL on failure.
 * @param error location to store rationale for failure on bad address
 * @returns the outcome
 *
 */
DBusServerListenResult
_dbus_server_listen_platform_specific (DBusAddressEntry *entry,
                                       DBusServer      **server_p,
                                       DBusError        *error)
{
  const char *method;

  *server_p = NULL;

  method = dbus_address_entry_get_method (entry);

  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 (path == NULL && tmpdir == NULL && abstract == NULL)
        {
          _dbus_set_bad_address(error, "unix",
                                "path or tmpdir or abstract",
                                NULL);
          return DBUS_SERVER_LISTEN_BAD_ADDRESS;
        }

      if ((path && tmpdir) ||
          (path && abstract) ||
          (tmpdir && abstract))
        {
          _dbus_set_bad_address(error, NULL, NULL,
                                "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time");
          return DBUS_SERVER_LISTEN_BAD_ADDRESS;
        }

      if (tmpdir != NULL)
        {
          DBusString full_path;
          DBusString filename;

          if (!_dbus_string_init (&full_path))
            {
              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
              return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
            }

          if (!_dbus_string_init (&filename))
            {
              _dbus_string_free (&full_path);
              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
              return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
            }

          if (!_dbus_string_append (&filename,
                                    "dbus-") ||
              !_dbus_generate_random_ascii (&filename, 10) ||
              !_dbus_string_append (&full_path, tmpdir) ||
              !_dbus_concat_dir_and_file (&full_path, &filename))
            {
              _dbus_string_free (&full_path);
              _dbus_string_free (&filename);
              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
              return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
            }

          /* Always use abstract namespace if possible with tmpdir */

          *server_p =
            _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
#ifdef HAVE_ABSTRACT_SOCKETS
                                                TRUE,
#else
                                                FALSE,
#endif
                                                error);

          _dbus_string_free (&full_path);
          _dbus_string_free (&filename);
        }
      else
        {
          if (path)
            *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error);
          else
            *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
        }

      if (*server_p != NULL)
        {
          _DBUS_ASSERT_ERROR_IS_CLEAR(error);
          return DBUS_SERVER_LISTEN_OK;
        }
      else
        {
          _DBUS_ASSERT_ERROR_IS_SET(error);
          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
        }
    }
  else if (strcmp (method, "systemd") == 0)
    {
      int i, n, *fds;
      DBusString address;

      n = _dbus_listen_systemd_sockets (&fds, error);
      if (n < 0)
        {
          _DBUS_ASSERT_ERROR_IS_SET (error);
          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
        }

      if (!_dbus_string_init (&address))
          goto systemd_oom;

      for (i = 0; i < n; i++)
        {
          if (i > 0)
            {
              if (!_dbus_string_append (&address, ";"))
                goto systemd_oom;
            }
          if (!_dbus_append_address_from_socket (fds[i], &address, error))
            goto systemd_err;
        }

      *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL);
      if (*server_p == NULL)
        goto systemd_oom;

      dbus_free (fds);

      return DBUS_SERVER_LISTEN_OK;
  systemd_oom:
      _DBUS_SET_OOM (error);
  systemd_err:
      for (i = 0; i < n; i++)
        {
          _dbus_close_socket (fds[i], NULL);
        }
      dbus_free (fds);
      _dbus_string_free (&address);

      return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
    }
#ifdef DBUS_ENABLE_LAUNCHD
  else if (strcmp (method, "launchd") == 0)
    {
      const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
      if (launchd_env_var == NULL)
        {
          _dbus_set_bad_address (error, "launchd", "env", NULL);
          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
        }
      *server_p = _dbus_server_new_for_launchd (launchd_env_var, error);

      if (*server_p != NULL)
        {
          _DBUS_ASSERT_ERROR_IS_CLEAR(error);
          return DBUS_SERVER_LISTEN_OK;
        }
      else
        {
          _DBUS_ASSERT_ERROR_IS_SET(error);
          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
        }
    }
#endif
  else
    {
      /* If we don't handle the method, we return NULL with the
       * error unset
       */
      _DBUS_ASSERT_ERROR_IS_CLEAR(error);
      return DBUS_SERVER_LISTEN_NOT_HANDLED;
    }
}
/**
 * Checks to see if the UID sent in is the console user
 *
 * @param uid UID of person to check 
 * @param error return location for errors
 * @returns #TRUE if the UID is the same as the console user and there are no errors
 */
dbus_bool_t
_dbus_is_console_user (dbus_uid_t uid,
		       DBusError *error)
{

  DBusUserDatabase *db;
  const DBusUserInfo *info;
  dbus_bool_t result = FALSE;

#ifdef HAVE_SYSTEMD
  /* check if we have logind */
  if (access ("/run/systemd/seats/", F_OK) >= 0)
    {
      int r;

      /* Check whether this user is logged in on at least one physical
         seat */
      r = sd_uid_get_seats (uid, 0, NULL);
      if (r < 0)
        {
          dbus_set_error (error, _dbus_error_from_errno (-r),
                          "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
                          uid,
                          _dbus_strerror (-r));
          return FALSE;
        }

      return (r > 0);
    }
#endif

#ifdef HAVE_CONSOLE_OWNER_FILE

  DBusString f;
  DBusStat st;

  if (!_dbus_string_init (&f))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
    {
      _dbus_string_free(&f);
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
    {
      _dbus_string_free(&f);
      return TRUE;
    }

  _dbus_string_free(&f);

#endif /* HAVE_CONSOLE_OWNER_FILE */

  if (!_dbus_user_database_lock_system ())
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  db = _dbus_user_database_get_system ();
  if (db == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
      _dbus_user_database_unlock_system ();
      return FALSE;
    }

  /* TPTD: this should be cache-safe, we've locked the DB and
    _dbus_user_at_console doesn't pass it on. */
  info = _dbus_user_database_lookup (db, uid, NULL, error);

  if (info == NULL)
    {
      _dbus_user_database_unlock_system ();
       return FALSE;
    }

  result = _dbus_user_at_console (info->username, error);

  _dbus_user_database_unlock_system ();

  return result;
}
Beispiel #21
0
void
_dbus_set_error_valist (DBusError  *error,
                        const char *name,
                        const char *format,
                        va_list     args)
{
  DBusRealError *real;
  DBusString str;

  _dbus_assert (name != NULL);

  if (error == NULL)
    return;

  _dbus_assert (error->name == NULL);
  _dbus_assert (error->message == NULL);

  if (!_dbus_string_init (&str))
    goto nomem;
  
  if (format == NULL)
    {
      if (!_dbus_string_append (&str,
                                message_from_error (name)))
        {
          _dbus_string_free (&str);
          goto nomem;
        }
    }
  else
    {
      if (!_dbus_string_append_printf_valist (&str, format, args))
        {
          _dbus_string_free (&str);
          goto nomem;
        }
    }

  real = (DBusRealError *)error;

  if (!_dbus_string_steal_data (&str, &real->message))
    {
      _dbus_string_free (&str);
      goto nomem;
    }
  _dbus_string_free (&str);
  
  real->name = _dbus_strdup (name);
  if (real->name == NULL)
    {
      dbus_free (real->message);
      real->message = NULL;
      goto nomem;
    }
  real->const_message = FALSE;

  return;
  
 nomem:
  _DBUS_SET_OOM (error);
}
Beispiel #22
0
static dbus_bool_t
_dbus_read_uuid_file_without_creating (const DBusString *filename,
                                       DBusGUID         *uuid,
                                       DBusError        *error)
{
  DBusString contents;
  DBusString decoded;
  int end;
  
  if (!_dbus_string_init (&contents))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (!_dbus_string_init (&decoded))
    {
      _dbus_string_free (&contents);
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  if (!_dbus_file_get_contents (&contents, filename, error))
    goto error;

  _dbus_string_chop_white (&contents);

  if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
    {
      dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
                      "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
                      _dbus_string_get_const_data (filename),
                      DBUS_UUID_LENGTH_HEX,
                      _dbus_string_get_length (&contents));
      goto error;
    }

  if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }

  if (end == 0)
    {
      dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
                      "UUID file '%s' contains invalid hex data",
                      _dbus_string_get_const_data (filename));
      goto error;
    }

  if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
    {
      dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
                      "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
                      _dbus_string_get_const_data (filename),
                      _dbus_string_get_length (&decoded),
                      DBUS_UUID_LENGTH_BYTES);
      goto error;
    }

  _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);

  _dbus_string_free (&decoded);
  _dbus_string_free (&contents);

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  return TRUE;
  
 error:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  _dbus_string_free (&contents);
  _dbus_string_free (&decoded);
  return FALSE;
}
/**
 * _dbus_shell_parse_argv:
 *
 * Parses a command line into an argument vector, in much the same way
 * the shell would, but without many of the expansions the shell would
 * perform (variable expansion, globs, operators, filename expansion,
 * etc. are not supported). The results are defined to be the same as
 * those you would get from a UNIX98 /bin/sh, as long as the input
 * contains none of the unsupported shell expansions. If the input
 * does contain such expansions, they are passed through
 * literally. Free the returned vector with dbus_free_string_array().
 *
 * @command_line: command line to parse
 * @argcp: return location for number of args
 * @argvp: return location for array of args
 * @error: error information
 **/
dbus_bool_t
_dbus_shell_parse_argv (const char *command_line,
                        int        *argcp,
                        char     ***argvp,
                        DBusError  *error)
{
    /* Code based on poptParseArgvString() from libpopt */
    int argc = 0;
    char **argv = NULL;
    DBusList *tokens = NULL;
    int i;
    DBusList *tmp_list;

    if (!command_line)
    {
        _dbus_verbose ("Command line is NULL\n");
        return FALSE;
    }

    tokens = tokenize_command_line (command_line, error);
    if (tokens == NULL)
    {
        _dbus_verbose ("No tokens for command line '%s'\n", command_line);
        return FALSE;
    }

    /* Because we can't have introduced any new blank space into the
     * tokens (we didn't do any new expansions), we don't need to
     * perform field splitting. If we were going to honor IFS or do any
     * expansions, we would have to do field splitting on each word
     * here. Also, if we were going to do any expansion we would need to
     * remove any zero-length words that didn't contain quotes
     * originally; but since there's no expansion we know all words have
     * nonzero length, unless they contain quotes.
     *
     * So, we simply remove quotes, and don't do any field splitting or
     * empty word removal, since we know there was no way to introduce
     * such things.
     */

    argc = _dbus_list_get_length (&tokens);
    argv = dbus_new (char *, argc + 1);
    if (!argv)
    {
        _DBUS_SET_OOM (error);
        goto error;
    }

    i = 0;
    tmp_list = tokens;
    while (tmp_list)
    {
        argv[i] = _dbus_shell_unquote (tmp_list->data);

        if (!argv[i])
        {
            int j;
            for (j = 0; j < i; j++)
                dbus_free(argv[j]);

            dbus_free (argv);
            _DBUS_SET_OOM (error);
            goto error;
        }

        tmp_list = _dbus_list_get_next_link (&tokens, tmp_list);
        ++i;
    }
    argv[argc] = NULL;

    _dbus_list_foreach (&tokens, (DBusForeachFunction) dbus_free, NULL);
    _dbus_list_clear (&tokens);

    if (argcp)
        *argcp = argc;

    if (argvp)
        *argvp = argv;
    else
        dbus_free_string_array (argv);

    return TRUE;

error:
    _dbus_list_foreach (&tokens, (DBusForeachFunction) dbus_free, NULL);
    _dbus_list_clear (&tokens);

    return FALSE;

}
Beispiel #24
0
/**
 * Connects to a bus daemon and registers the client with it.  If a
 * connection to the bus already exists, then that connection is
 * returned.  Caller owns a reference to the bus.
 *
 * @todo alex thinks we should nullify the connection when we get a disconnect-message.
 *
 * @param type bus type
 * @param error address where an error can be returned.
 * @returns a DBusConnection with new ref
 */
DBusConnection *
dbus_bus_get (DBusBusType  type,
	      DBusError   *error)
{
  const char *address;
  DBusConnection *connection;
  BusData *bd;
  DBusBusType address_type;

  _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL);
  _dbus_return_val_if_error_is_set (error, NULL);

  _DBUS_LOCK (bus);

  if (!init_connections_unlocked ())
    {
      _DBUS_UNLOCK (bus);
      _DBUS_SET_OOM (error);
      return NULL;
    }

  /* We want to use the activation address even if the
   * activating bus is the session or system bus,
   * per the spec.
   */
  address_type = type;
  
  /* Use the real type of the activation bus for getting its
   * connection, but only if the real type's address is available. (If
   * the activating bus isn't a well-known bus then
   * activation_bus_type == DBUS_BUS_STARTER)
   */
  if (type == DBUS_BUS_STARTER &&
      bus_connection_addresses[activation_bus_type] != NULL)
    type = activation_bus_type;
  
  if (bus_connections[type] != NULL)
    {
      connection = bus_connections[type];
      dbus_connection_ref (connection);
      
      _DBUS_UNLOCK (bus);
      return connection;
    }

  address = bus_connection_addresses[address_type];
  if (address == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Unable to determine the address of the message bus");
      _DBUS_UNLOCK (bus);
      return NULL;
    }

  connection = dbus_connection_open (address, error);
  
  if (!connection)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      _DBUS_UNLOCK (bus);
      return NULL;
    }

  /* By default we're bound to the lifecycle of
   * the message bus.
   */
  dbus_connection_set_exit_on_disconnect (connection,
                                          TRUE);
  
  if (!dbus_bus_register (connection, error))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_connection_close (connection);
      dbus_connection_unref (connection);

      _DBUS_UNLOCK (bus);
      return NULL;
    }

  bus_connections[type] = connection;
  bd = ensure_bus_data (connection);
  _dbus_assert (bd != NULL);

  bd->is_well_known = TRUE;

  _DBUS_UNLOCK (bus);
  return connection;
}
Beispiel #25
0
/**
 * Writes the given pid_to_write to a pidfile (if non-NULL) and/or to a
 * pipe (if non-NULL). Does nothing if pidfile and print_pid_pipe are both
 * NULL.
 *
 * @param pidfile the file to write to or #NULL
 * @param print_pid_pipe the pipe to write to or #NULL
 * @param pid_to_write the pid to write out
 * @param error error on failure
 * @returns FALSE if error is set
 */
dbus_bool_t
_dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
                                  DBusPipe         *print_pid_pipe,
                                  dbus_pid_t        pid_to_write,
                                  DBusError        *error)
{
  if (pidfile)
    {
      _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile));
      if (!_dbus_write_pid_file (pidfile,
                                 pid_to_write,
                                 error))
        {
          _dbus_verbose ("pid file write failed\n");
          _DBUS_ASSERT_ERROR_IS_SET(error);
          return FALSE;
        }
    }
  else
    {
      _dbus_verbose ("No pid file requested\n");
    }

  if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
    {
      DBusString pid;
      int bytes;

      _dbus_verbose ("writing our pid to pipe %d\n",
                     print_pid_pipe->fd);
      
      if (!_dbus_string_init (&pid))
        {
          _DBUS_SET_OOM (error);
          return FALSE;
        }
	  
      if (!_dbus_string_append_int (&pid, pid_to_write) ||
          !_dbus_string_append (&pid, "\n"))
        {
          _dbus_string_free (&pid);
          _DBUS_SET_OOM (error);
          return FALSE;
        }
	  
      bytes = _dbus_string_get_length (&pid);
      if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
        {
          /* _dbus_pipe_write sets error only on failure, not short write */
          if (error != NULL && !dbus_error_is_set(error))
            {
              dbus_set_error (error, DBUS_ERROR_FAILED,
                              "Printing message bus PID: did not write enough bytes\n");
            }
          _dbus_string_free (&pid);
          return FALSE;
        }
	  
      _dbus_string_free (&pid);
    }
  else
    {
      _dbus_verbose ("No pid pipe to write to\n");
    }

  return TRUE;
}
Beispiel #26
0
/**
 * Registers a connection with the bus. This must be the first
 * thing an application does when connecting to the message bus.
 * If registration succeeds, the unique name will be set,
 * and can be obtained using dbus_bus_get_unique_name().
 * 
 * @param connection the connection
 * @param error place to store errors
 * @returns #TRUE on success
 */
dbus_bool_t
dbus_bus_register (DBusConnection *connection,
                   DBusError      *error)
{
  DBusMessage *message, *reply;
  char *name;
  BusData *bd;
  dbus_bool_t retval;

  _dbus_return_val_if_fail (connection != NULL, FALSE);
  _dbus_return_val_if_error_is_set (error, FALSE);

  retval = FALSE;
  
  bd = ensure_bus_data (connection);
  if (bd == NULL)
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (bd->unique_name != NULL)
    {
      _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
      /* This isn't an error, it's a programming bug. We'll be nice
       * and not _dbus_assert_not_reached()
       */
      return TRUE;
    }
  
  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                          DBUS_PATH_DBUS,
                                          DBUS_INTERFACE_DBUS,
                                          "Hello"); 

  if (!message)
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);

  dbus_message_unref (message);
  
  if (reply == NULL)
    goto out;
  else if (dbus_set_error_from_message (error, reply))
    goto out;
  else if (!dbus_message_get_args (reply, error,
                                   DBUS_TYPE_STRING, &name,
                                   DBUS_TYPE_INVALID))
    goto out;
  
  bd->unique_name = _dbus_strdup (name);
  if (bd->unique_name == NULL)
    {
      _DBUS_SET_OOM (error);
      goto out;
    }
  
  retval = TRUE;
  
 out:
  if (reply)
    dbus_message_unref (reply);

  if (!retval)
    _DBUS_ASSERT_ERROR_IS_SET (error);
  
  return retval;
}
Beispiel #27
0
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter           **sitter_p,
                                   char                     **argv,
                                   char                     **envp,
                                   DBusSpawnChildSetupFunc    child_setup,
                                   void                      *user_data,
                                   DBusError                 *error)
{
  DBusBabysitter *sitter;
  HANDLE sitter_thread;
  int sitter_thread_id;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  *sitter_p = NULL;

  PING();
  sitter = _dbus_babysitter_new ();
  if (sitter == NULL)
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  sitter->child_setup = child_setup;
  sitter->user_data = user_data;

  sitter->executable = _dbus_strdup (argv[0]);
  if (sitter->executable == NULL)
    {
      _DBUS_SET_OOM (error);
      goto out0;
    }

  PING();
  if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
                               &sitter->socket_to_main,
                               FALSE, error))
    goto out0;

  sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
                                          DBUS_WATCH_READABLE,
                                          TRUE, handle_watch, sitter, NULL);
  PING();
  if (sitter->sitter_watch == NULL)
    {
      _DBUS_SET_OOM (error);
      goto out0;
    }

  PING();
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
      _DBUS_SET_OOM (error);
      goto out0;
    }

  sitter->argc = protect_argv (argv, &sitter->argv);
  if (sitter->argc == -1)
    {
      _DBUS_SET_OOM (error);
      goto out0;
    }
  sitter->envp = envp;

  PING();
  sitter_thread = (HANDLE) _beginthreadex (NULL, 0, babysitter,
                  sitter, 0, &sitter_thread_id);

  if (sitter_thread == 0)
    {
      PING();
      dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
                            "Failed to create new thread");
      goto out0;
    }
  CloseHandle (sitter_thread);

  PING();
  WaitForSingleObject (sitter->start_sync_event, INFINITE);

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

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  PING();
  return TRUE;

out0:
  _dbus_babysitter_unref (sitter);

  return FALSE;
}
Beispiel #28
0
/**
 * Asks the bus to return the uid of the named
 * connection.
 *
 * @param connection the connection
 * @param name a name owned by the connection
 * @param error location to store the error
 * @returns a result code, -1 if error is set
 */ 
unsigned long
dbus_bus_get_unix_user (DBusConnection *connection,
                        const char     *name,
                        DBusError      *error)
{
  DBusMessage *message, *reply;
  dbus_uint32_t uid;

  _dbus_return_val_if_fail (connection != NULL, DBUS_UID_UNSET);
  _dbus_return_val_if_fail (name != NULL, DBUS_UID_UNSET);
  _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), DBUS_UID_UNSET);
  _dbus_return_val_if_error_is_set (error, DBUS_UID_UNSET);
  
  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                          DBUS_PATH_DBUS,
                                          DBUS_INTERFACE_DBUS,
                                          "GetConnectionUnixUser");

  if (message == NULL)
    {
      _DBUS_SET_OOM (error);
      return DBUS_UID_UNSET;
    }
 
  if (!dbus_message_append_args (message,
				 DBUS_TYPE_STRING, &name,
				 DBUS_TYPE_INVALID))
    {
      dbus_message_unref (message);
      _DBUS_SET_OOM (error);
      return DBUS_UID_UNSET;
    }
  
  reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
                                                     error);
  
  dbus_message_unref (message);
  
  if (reply == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      return DBUS_UID_UNSET;
    }  

  if (dbus_set_error_from_message (error, reply))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return DBUS_UID_UNSET;
    }
  
  if (!dbus_message_get_args (reply, error,
                              DBUS_TYPE_UINT32, &uid,
                              DBUS_TYPE_INVALID))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return DBUS_UID_UNSET;
    }

  dbus_message_unref (reply);
  
  return (unsigned long) uid;
}
/**
 * Checks to see if the UID sent in is the console user
 *
 * @param uid UID of person to check 
 * @param error return location for errors
 * @returns #TRUE if the UID is the same as the console user and there are no errors
 */
dbus_bool_t
_dbus_is_console_user (dbus_uid_t uid,
		       DBusError *error)
{

  DBusUserDatabase *db;
  const DBusUserInfo *info;
  dbus_bool_t result = FALSE; 

#ifdef HAVE_CONSOLE_OWNER_FILE

  DBusString f;
  DBusStat st;

  if (!_dbus_string_init (&f))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
    {
      _dbus_string_free(&f);
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
    {
      _dbus_string_free(&f);
      return TRUE;
    }

  _dbus_string_free(&f);

#endif /* HAVE_CONSOLE_OWNER_FILE */

  _dbus_user_database_lock_system ();

  db = _dbus_user_database_get_system ();
  if (db == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
      _dbus_user_database_unlock_system ();
      return FALSE;
    }

  /* TPTD: this should be cache-safe, we've locked the DB and
    _dbus_user_at_console doesn't pass it on. */
  info = _dbus_user_database_lookup (db, uid, NULL, error);

  if (info == NULL)
    {
      _dbus_user_database_unlock_system ();
       return FALSE;
    }

  result = _dbus_user_at_console (info->username, error);

  _dbus_user_database_unlock_system ();

  return result;
}
Beispiel #30
0
/**
 * Asks the bus to assign the given name to this connection by invoking
 * the RequestName method on the bus. This method is fully documented
 * in the D-BUS specification. For quick reference, the flags and
 * result codes are discussed here, but the specification is the
 * canonical version of this information.
 *
 * The #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT flag indicates that
 * if the name is successfully requested, other applications
 * will not be able to take over the name. i.e. the name's
 * owner (the application calling this function) must let go of
 * the name, it will not lose it involuntarily.
 *
 * The #DBUS_NAME_FLAG_REPLACE_EXISTING flag indicates that the caller
 * would like to take over the name from the current owner.
 * If the current name owner used #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT
 * then this flag indicates that the caller would like to be placed
 * in the queue to own the name when the current owner lets go.
 *
 * If no flags are given, an application will receive the requested
 * name only if the name is currently unowned; and it will give
 * up the name if another application asks to take it over using
 * #DBUS_NAME_FLAG_REPLACE_EXISTING.
 *
 * This function returns a result code. The possible result codes
 * are as follows.
 * 
 * #DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER means that the name had no
 * existing owner, and the caller is now the primary owner; or that
 * the name had an owner, and the caller specified
 * #DBUS_NAME_FLAG_REPLACE_EXISTING, and the current owner did not
 * specify #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT.
 *
 * #DBUS_REQUEST_NAME_REPLY_IN_QUEUE happens only if the current owner
 * specified #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT and the caller specified
 * #DBUS_NAME_FLAG_REPLACE_EXISTING. In this case the caller ends up in
 * a queue to own the name after the current owner gives it up.
 *
 * #DBUS_REQUEST_NAME_REPLY_EXISTS happens if the name has an owner
 * #already and DBUS_NAME_FLAG_REPLACE_EXISTING was not specified.
 *
 * #DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER happens if an application
 * requests a name it already owns.
 *
 * When a service represents an application, say "text editor," then
 * it should specify #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT if it wants
 * the first editor started to be the user's editor vs. the last one
 * started.  Then any editor that can be the user's editor should
 * specify #DBUS_NAME_FLAG_REPLACE_EXISTING to either take over
 * (last-started-wins) or be queued up (first-started-wins) according
 * to whether #DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT was given.
 * 
 * @todo this all seems sort of broken. Shouldn't the flags be a property
 * of the name, not the app requesting the name? What are the use-cases
 * other than the "text editor" thing and how are we supporting them?
 * 
 * @param connection the connection
 * @param name the name to request
 * @param flags flags
 * @param error location to store the error
 * @returns a result code, -1 if error is set
 */ 
int
dbus_bus_request_name (DBusConnection *connection,
                       const char     *name,
                       unsigned int    flags,
                       DBusError      *error)
{
  DBusMessage *message, *reply;
  dbus_uint32_t result;

  _dbus_return_val_if_fail (connection != NULL, 0);
  _dbus_return_val_if_fail (name != NULL, 0);
  _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), 0);
  _dbus_return_val_if_error_is_set (error, 0);
  
  message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
                                          DBUS_PATH_DBUS,
                                          DBUS_INTERFACE_DBUS,
                                          "RequestName");

  if (message == NULL)
    {
      _DBUS_SET_OOM (error);
      return -1;
    }
 
  if (!dbus_message_append_args (message,
				 DBUS_TYPE_STRING, &name,
				 DBUS_TYPE_UINT32, &flags,
				 DBUS_TYPE_INVALID))
    {
      dbus_message_unref (message);
      _DBUS_SET_OOM (error);
      return -1;
    }
  
  reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
                                                     error);
  
  dbus_message_unref (message);
  
  if (reply == NULL)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      return -1;
    }  

  if (dbus_set_error_from_message (error, reply))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return -1;
    }
  
  if (!dbus_message_get_args (reply, error,
                              DBUS_TYPE_UINT32, &result,
                              DBUS_TYPE_INVALID))
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      dbus_message_unref (reply);
      return -1;
    }

  dbus_message_unref (reply);
  
  return result;
}