/** * Creates a new transport for the "autostart" method. * This creates a client-side of a transport. * * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ static DBusTransport* _dbus_transport_new_for_autolaunch (DBusError *error) { DBusString address; DBusTransport *result = NULL; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_get_autolaunch_address (&address, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto out; } result = check_address (_dbus_string_get_const_data (&address), error); if (result == NULL) _DBUS_ASSERT_ERROR_IS_SET (error); else _DBUS_ASSERT_ERROR_IS_CLEAR (error); out: _dbus_string_free (&address); return result; }
/** * 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; }
/** * 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; }
static dbus_bool_t get_parameters_for_service (BusDesktopFile *desktop_file, const char *service_name, char **exec, char **user, DBusError *error) { char *exec_tmp; char *user_tmp; exec_tmp = NULL; user_tmp = NULL; /* check the name of the service */ if (!check_service_name (desktop_file, service_name, error)) goto failed; /* get the complete path of the executable */ if (!bus_desktop_file_get_string (desktop_file, DBUS_SERVICE_SECTION, DBUS_SERVICE_EXEC, &exec_tmp, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed; } /* get the user that should run this service - user is compulsary for system activation */ if (!bus_desktop_file_get_string (desktop_file, DBUS_SERVICE_SECTION, DBUS_SERVICE_USER, &user_tmp, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed; } /* only assign if all the checks passed */ *exec = exec_tmp; *user = user_tmp; return TRUE; failed: dbus_free (exec_tmp); dbus_free (user_tmp); return FALSE; }
static dbus_bool_t bus_driver_handle_reload_config (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { BusContext *context; dbus_bool_t retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = FALSE; context = bus_connection_get_context (connection); if (!bus_context_reload_config (context, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto out; } retval = TRUE; out: return retval; }
static dbus_bool_t handle_reload_watch (DBusWatch *watch, unsigned int flags, void *data) { DBusError error; DBusString str; _dbus_string_init (&str); if ((reload_pipe[RELOAD_READ_END] > 0) && _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1) { _dbus_warn ("Couldn't read from reload pipe.\n"); close_reload_pipe (); return TRUE; } _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); 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); } return TRUE; }
/* returns true if good things happen, or if we get OOM */ static dbus_bool_t bus_activation_helper_oom_test (void *data, dbus_bool_t have_memory) { const char *service; DBusError error; dbus_bool_t retval; service = (const char *) data; retval = TRUE; dbus_error_init (&error); if (!run_launch_helper (service, &error)) { _DBUS_ASSERT_ERROR_IS_SET (&error); /* we failed, but a OOM is good */ if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { _dbus_warn ("FAILED SELF TEST: Error: %s", error.message); retval = FALSE; } dbus_error_free (&error); } else { /* we succeeded, yay! */ _DBUS_ASSERT_ERROR_IS_CLEAR (&error); } return retval; }
/** * For use by the dbus-uuidgen binary ONLY, do not call this. * We can and will change this function without modifying * the libdbus soname. * * @param filename the file or #NULL for the machine ID file * @param uuid_p out param to return the uuid * @param create_if_not_found whether to create it if not already there * @param error error return * @returns #FALSE if error is set */ dbus_bool_t dbus_internal_do_not_use_get_uuid (const char *filename, char **uuid_p, dbus_bool_t create_if_not_found, DBusError *error) { DBusGUID uuid; if (filename) { DBusString filename_str; _dbus_string_init_const (&filename_str, filename); if (!_dbus_read_uuid_file (&filename_str, &uuid, create_if_not_found, error)) goto error; } else { if (!_dbus_read_local_machine_uuid (&uuid, create_if_not_found, error)) goto error; } if (!return_uuid(&uuid, uuid_p, error)) goto error; return TRUE; error: _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; }
static void send_no_return_values (DBusConnection *connection, DBusMessage *msg, DBusError *error) { if (error) { /* Block to check success codepath */ DBusMessage *reply; reply = dbus_connection_send_with_reply_and_block (connection, msg, -1, error); if (reply == NULL) _DBUS_ASSERT_ERROR_IS_SET (error); else dbus_message_unref (reply); } else { /* Silently-fail nonblocking codepath */ dbus_message_set_no_reply (msg, TRUE); dbus_connection_send (connection, msg, NULL); } }
static DBusTransportOpenResult _dbus_transport_open_autolaunch (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "autolaunch") == 0) { *transport_p = _dbus_transport_new_for_autolaunch (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; } }
/** * Creates a new transport for the given Unix domain socket * path. This creates a client-side of a transport. * * @todo once we add a way to escape paths in a dbus * address, this function needs to do escaping. * * @param path the path to the domain socket. * @param abstract #TRUE to use abstract socket namespace * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error) { int fd; DBusTransport *transport; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } fd = -1; if ((abstract && !_dbus_string_append (&address, "unix:abstract=")) || (!abstract && !_dbus_string_append (&address, "unix:path=")) || !_dbus_string_append (&address, path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } fd = _dbus_connect_unix_socket (path, abstract, error); if (fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed_0; } _dbus_verbose ("Successfully connected to unix socket %s\n", path); transport = _dbus_transport_new_for_socket (fd, NULL, &address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_1; } _dbus_string_free (&address); return transport; failed_1: _dbus_close_socket (fd, NULL); failed_0: _dbus_string_free (&address); return NULL; }
/** * Creates a new transport for the given VMWare Communication Interface * CID and port. This creates a client-side of a transport. * * @param cid the virtual machine context ID to connect to * @param port the port to connect to * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ static DBusTransport* _dbus_transport_new_for_vmci (const char *cid, const char *port, DBusError *error) { int fd; DBusTransport *transport; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } fd = -1; if (!_dbus_string_append (&address, "vmci:cid=") || !_dbus_string_append(&address, cid) || !_dbus_string_append(&address, "port=") || !_dbus_string_append(&address, port)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } fd = _dbus_connect_vmci (cid, port, error); if (fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed_0; } _dbus_verbose ("Successfully connected to vmci stream socket %s:%s\n", cid, port); transport = _dbus_transport_new_for_socket (fd, NULL, &address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_1; } _dbus_string_free (&address); return transport; failed_1: _dbus_close_socket (fd, NULL); failed_0: _dbus_string_free (&address); return NULL; }
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; }
static dbus_bool_t bus_driver_handle_activate_service (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { dbus_uint32_t flags; const char *name; dbus_bool_t retval; BusActivation *activation; _DBUS_ASSERT_ERROR_IS_CLEAR (error); activation = bus_connection_get_activation (connection); if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_verbose ("No memory to get arguments to StartServiceByName\n"); return FALSE; } retval = FALSE; if (!bus_activation_activate_service (activation, connection, transaction, FALSE, message, name, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_verbose ("bus_activation_activate_service() failed\n"); goto out; } retval = TRUE; out: return retval; }
BusContext* bus_context_new_test (const DBusString *test_data_dir, const char *filename) { DBusError error; DBusString config_file; DBusString relative; BusContext *context; if (!_dbus_string_init (&config_file)) { _dbus_warn ("No memory\n"); return NULL; } if (!_dbus_string_copy (test_data_dir, 0, &config_file, 0)) { _dbus_warn ("No memory\n"); _dbus_string_free (&config_file); return NULL; } _dbus_string_init_const (&relative, filename); if (!_dbus_concat_dir_and_file (&config_file, &relative)) { _dbus_warn ("No memory\n"); _dbus_string_free (&config_file); return NULL; } dbus_error_init (&error); context = bus_context_new (&config_file, BUS_CONTEXT_FLAG_NONE, NULL, NULL, NULL, &error); if (context == NULL) { _DBUS_ASSERT_ERROR_IS_SET (&error); _dbus_warn ("Failed to create debug bus context from configuration file %s: %s\n", filename, error.message); dbus_error_free (&error); _dbus_string_free (&config_file); return NULL; } _dbus_string_free (&config_file); return context; }
static dbus_bool_t bus_driver_handle_remove_match (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { BusMatchRule *rule; const char *text; DBusString str; BusMatchmaker *matchmaker; _DBUS_ASSERT_ERROR_IS_CLEAR (error); text = NULL; rule = NULL; if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID)) { _dbus_verbose ("No memory to get arguments to RemoveMatch\n"); goto failed; } _dbus_string_init_const (&str, text); rule = bus_match_rule_parse (connection, &str, error); if (rule == NULL) goto failed; /* Send the ack before we remove the rule, since the ack is undone * on transaction cancel, but rule removal isn't. */ if (!send_ack_reply (connection, transaction, message, error)) goto failed; matchmaker = bus_connection_get_matchmaker (connection); if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error)) goto failed; bus_match_rule_unref (rule); return TRUE; failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (rule) bus_match_rule_unref (rule); return FALSE; }
static dbus_bool_t do_load (const DBusString *full_path, Validity validity, dbus_bool_t oom_possible) { BusConfigParser *parser; DBusError error; dbus_error_init (&error); parser = bus_config_load (full_path, TRUE, NULL, &error); if (parser == NULL) { _DBUS_ASSERT_ERROR_IS_SET (&error); if (oom_possible && dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) { _dbus_verbose ("Failed to load valid file due to OOM\n"); dbus_error_free (&error); return TRUE; } else if (validity == VALID) { _dbus_warn ("Failed to load valid file but still had memory: %s\n", error.message); dbus_error_free (&error); return FALSE; } else { dbus_error_free (&error); return TRUE; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR (&error); bus_config_parser_unref (parser); if (validity == INVALID) { _dbus_warn ("Accepted invalid file\n"); return FALSE; } return TRUE; } }
/** * Opens a TCP socket transport. * * @param entry the address entry to try opening as a tcp transport. * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_socket(DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; dbus_bool_t isTcp; dbus_bool_t isNonceTcp; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); isTcp = strcmp (method, "tcp") == 0; isNonceTcp = strcmp (method, "nonce-tcp") == 0; if (isTcp || isNonceTcp) { const char *host = dbus_address_entry_get_value (entry, "host"); const char *port = dbus_address_entry_get_value (entry, "port"); const char *family = dbus_address_entry_get_value (entry, "family"); const char *noncefile = dbus_address_entry_get_value (entry, "noncefile"); if ((isNonceTcp == TRUE) != (noncefile != NULL)) { _dbus_set_bad_address (error, method, "noncefile", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (port == NULL) { _dbus_set_bad_address (error, method, "port", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, noncefile, 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; } }
/** * Creates a VMCI stream socket connected to the given cid and port. * The connection fd is returned, and is set up as nonblocking. * * This will set FD_CLOEXEC for the socket returned. * * @param path the path to UNIX domain socket * @param abstract #TRUE to use abstract namespace * @param error return location for error code * @returns connection file descriptor or -1 on error */ static int _dbus_connect_vmci (const char *cid_str, const char *port_str, DBusError *error) { int fd; size_t path_len; struct sockaddr_vm addr; unsigned int af_vmci, cid, port; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("connecting to VMCI stream socket %s:%s\n", cid_str, port_str); cid = atoi(cid_str); port = atoi(port_str); if ((af_vmci = VMCISock_GetAFValue()) < 0) { assert(0); } if (_dbus_open_socket(&fd, af_vmci, SOCK_STREAM, 0, error) < 0) { return fd; } _DBUS_ZERO (addr); addr.svm_family = af_vmci; addr.svm_cid = cid; addr.svm_port = port; if (connect (fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to connect to VMCI (cid, port): %s:%s: %s", cid_str, port_str, _dbus_strerror (errno)); _dbus_close (fd, NULL); fd = -1; return -1; } if (!_dbus_set_fd_nonblocking (fd, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_close (fd, NULL); fd = -1; return -1; } return fd; }
/** * sends the nonce over a given socket. Blocks while doing so. * * @param fd the file descriptor to write the nonce data to (usually a socket) * @param noncefile the noncefile location to read the nonce from * @param error contains error details if FALSE is returned * @return TRUE iff the nonce was successfully sent. Note that this does not * indicate whether the server accepted the nonce. */ dbus_bool_t _dbus_send_nonce (DBusSocket fd, const DBusString *noncefile, DBusError *error) { dbus_bool_t read_result; int send_result; DBusString nonce; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (_dbus_string_get_length (noncefile) == 0) return FALSE; if (!_dbus_string_init (&nonce)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } read_result = _dbus_read_nonce (noncefile, &nonce, error); if (!read_result) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_string_free (&nonce); return FALSE; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); send_result = _dbus_write_socket (fd, &nonce, 0, _dbus_string_get_length (&nonce)); _dbus_string_free (&nonce); if (send_result == -1) { dbus_set_error (error, _dbus_error_from_system_errno (), "Failed to send nonce (fd=%" DBUS_SOCKET_FORMAT "): %s", _dbus_socket_printable (fd), _dbus_strerror_from_errno ()); return FALSE; } return TRUE; }
/** * 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, "nonce-tcp") == 0) { const char *host; const char *port; const char *bind; const char *family; host = dbus_address_entry_get_value (entry, "host"); bind = dbus_address_entry_get_value (entry, "bind"); port = dbus_address_entry_get_value (entry, "port"); family = dbus_address_entry_get_value (entry, "family"); *server_p = _dbus_server_new_for_tcp_socket (host, bind, port, family, error, TRUE); if (*server_p) { _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 { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } }
/** * Tries to interpret the address entry as a debug pipe entry. * * 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_debug_pipe (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error) { const char *method; *server_p = NULL; method = dbus_address_entry_get_method (entry); if (strcmp (method, "debug-pipe") == 0) { const char *name = dbus_address_entry_get_value (entry, "name"); if (name == NULL) { _dbus_set_bad_address(error, "debug-pipe", "name", NULL); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } *server_p = _dbus_server_debug_pipe_new (name, error); if (*server_p) { _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 { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } }
/** * Opens a debug pipe transport, used in the test suite. * * @param entry the address entry to try opening as debug-pipe * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_debug_pipe (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "debug-pipe") == 0) { const char *name = dbus_address_entry_get_value (entry, "name"); if (name == NULL) { _dbus_set_bad_address (error, "debug-pipe", "name", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } *transport_p = _dbus_transport_debug_pipe_new (name, 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; } }
/** * 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; }
/** * Opens a VMCI stream socket transport. * * @param entry the address entry to try opening as a tcp transport. * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_vmci(DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; const char *cid; const char *port; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "vmci") != 0) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } cid = dbus_address_entry_get_value (entry, "cid"); port = dbus_address_entry_get_value (entry, "port"); if (0 || port == NULL) { _dbus_set_bad_address (error, method, "port", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } *transport_p = _dbus_transport_new_for_vmci (cid, port, 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; } }
static dbus_bool_t bus_driver_handle_reload_config (DBusConnection *connection, BusTransaction *transaction, DBusMessage *message, DBusError *error) { BusContext *context; DBusMessage *reply; _DBUS_ASSERT_ERROR_IS_CLEAR (error); reply = NULL; context = bus_connection_get_context (connection); if (!bus_context_reload_config (context, error)) goto failed; reply = dbus_message_new_method_return (message); if (reply == NULL) goto oom; if (! bus_transaction_send_from_driver (transaction, connection, reply)) goto oom; dbus_message_unref (reply); return TRUE; oom: BUS_SET_OOM (error); failed: _DBUS_ASSERT_ERROR_IS_SET (error); if (reply) dbus_message_unref (reply); return FALSE; }
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] > 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; }
static dbus_bool_t do_noncefile_create (DBusNonceFile *noncefile, DBusError *error, dbus_bool_t use_subdir) { dbus_bool_t ret; DBusString randomStr; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (noncefile); if (!_dbus_string_init (&randomStr)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (!_dbus_generate_random_ascii (&randomStr, 8)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (!_dbus_string_init (&noncefile->dir) || !_dbus_string_append (&noncefile->dir, _dbus_get_tmpdir())) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (use_subdir) { if (!_dbus_string_append (&noncefile->dir, "/dbus_nonce-") || !_dbus_string_append (&noncefile->dir, _dbus_string_get_const_data (&randomStr)) ) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (!_dbus_string_init (&noncefile->path) || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0) || !_dbus_string_append (&noncefile->dir, "/nonce")) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } if (!_dbus_create_directory (&noncefile->dir, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto on_error; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); } else { if (!_dbus_string_init (&noncefile->path) || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0) || !_dbus_string_append (&noncefile->path, "/dbus_nonce-") || !_dbus_string_append (&noncefile->path, _dbus_string_get_const_data (&randomStr))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto on_error; } } if (!generate_and_write_nonce (&noncefile->path, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); if (use_subdir) _dbus_delete_directory (&noncefile->dir, NULL); //we ignore possible errors deleting the dir and return the write error instead goto on_error; } _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_string_free (&randomStr); return TRUE; on_error: if (use_subdir) _dbus_delete_directory (&noncefile->dir, NULL); _dbus_string_free (&noncefile->dir); _dbus_string_free (&noncefile->path); _dbus_string_free (&randomStr); return FALSE; }
/** * Creates a new transport for the given hostname and port. * If host is NULL, it will default to localhost * * @param host the host to connect to * @param port the port to connect to * @param family the address family to connect to * @param noncefile path to nonce file * @param error location to store reason for failure. * @returns a new transport, or #NULL on failure. */ DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host, const char *port, const char *family, const char *noncefile, DBusError *error) { DBusSocket fd; DBusTransport *transport; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (host == NULL) host = "localhost"; if (!_dbus_string_append (&address, noncefile ? "nonce-tcp:" : "tcp:")) goto error; if (!_dbus_string_append (&address, "host=") || !_dbus_string_append (&address, host)) goto error; if (!_dbus_string_append (&address, ",port=") || !_dbus_string_append (&address, port)) goto error; if (family != NULL && (!_dbus_string_append (&address, ",family=") || !_dbus_string_append (&address, family))) goto error; if (noncefile != NULL && (!_dbus_string_append (&address, ",noncefile=") || !_dbus_string_append (&address, noncefile))) goto error; fd = _dbus_connect_tcp_socket_with_nonce (host, port, family, noncefile, error); if (!_dbus_socket_is_valid (fd)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_string_free (&address); return NULL; } _dbus_verbose ("Successfully connected to tcp socket %s:%s\n", host, port); transport = _dbus_transport_new_for_socket (fd, NULL, &address); _dbus_string_free (&address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_close_socket (fd, NULL); _dbus_socket_invalidate (&fd); } return transport; error: _dbus_string_free (&address); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; }
/** * Spawns a new process. * * On Unix platforms, the child_setup function is passed the given * user_data and is run in the child after fork() but before calling exec(). * This can be used to change uid, resource limits and so on. * On Windows, this functionality does not fit the multi-processing model * (Windows does the equivalent of fork() and exec() in a single API call), * and the child_setup function and its user_data are ignored. * * 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 * const *argv, char **env, DBusSpawnFlags flags, 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 if (flags & DBUS_SPAWN_REDIRECT_OUTPUT) { /* 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) { #ifdef __linux__ int fd = -1; #ifdef O_CLOEXEC fd = open ("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC); #endif if (fd < 0) { fd = open ("/proc/self/oom_score_adj", O_WRONLY); _dbus_fd_set_close_on_exec (fd); } if (fd >= 0) { if (write (fd, "0", sizeof (char)) < 0) _dbus_warn ("writing oom_score_adj error: %s", strerror (errno)); _dbus_close (fd, NULL); } #endif /* 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; }