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; } }
static ReadStatus read_pid (int fd, pid_t *buf, DBusError *error) { size_t bytes = 0; ReadStatus retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = READ_STATUS_OK; while (TRUE) { ssize_t chunk; size_t to_read; to_read = sizeof (pid_t) - bytes; if (to_read == 0) break; again: chunk = read (fd, ((char*)buf) + bytes, to_read); if (chunk < 0 && errno == EINTR) goto again; if (chunk < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FAILED, "Failed to read from child pipe (%s)", _dbus_strerror (errno)); retval = READ_STATUS_ERROR; break; } else if (chunk == 0) { retval = READ_STATUS_EOF; break; /* EOF */ } else /* chunk > 0 */ bytes += chunk; } return retval; }
dbus_bool_t bus_driver_send_service_owner_changed (const char *service_name, const char *old_owner, const char *new_owner, BusTransaction *transaction, DBusError *error) { DBusMessage *message; dbus_bool_t retval; const char *null_service; _DBUS_ASSERT_ERROR_IS_CLEAR (error); null_service = ""; _dbus_verbose ("sending name owner changed: %s [%s -> %s]\n", service_name, old_owner ? old_owner : null_service, new_owner ? new_owner : null_service); message = dbus_message_new_signal (DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameOwnerChanged"); if (message == NULL) { BUS_SET_OOM (error); return FALSE; } if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) goto oom; if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &service_name, DBUS_TYPE_STRING, old_owner ? &old_owner : &null_service, DBUS_TYPE_STRING, new_owner ? &new_owner : &null_service, DBUS_TYPE_INVALID)) goto oom; _dbus_assert (dbus_message_has_signature (message, "sss")); retval = bus_dispatch_matches (transaction, NULL, NULL, message, error); dbus_message_unref (message); return retval; oom: dbus_message_unref (message); BUS_SET_OOM (error); 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; } }
/** * 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; }
/** * Thin wrapper around the read() system call that appends * the data it reads to the DBusString buffer. It appends * up to the given count. * * @param hnd the HANDLE to read from * @param buffer the buffer to append data to * @param count the amount of data to read * @param error place to set an error * @returns the number of bytes read or -1 */ static int _dbus_file_read (HANDLE hnd, DBusString *buffer, int count, DBusError *error) { BOOL result; DWORD bytes_read; int start; char *data; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (count >= 0); start = _dbus_string_get_length (buffer); if (!_dbus_string_lengthen (buffer, count)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return -1; } data = _dbus_string_get_data_len (buffer, start, count); result = ReadFile (hnd, data, count, &bytes_read, NULL); if (result == 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Failed to read from 0x%x: %s", hnd, emsg); _dbus_win_free_error_string (emsg); return -1; } if (bytes_read) { /* put length back (doesn't actually realloc) */ _dbus_string_set_length (buffer, start + bytes_read); #if 0 if (bytes_read > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_read); #endif } return bytes_read; }
static dbus_bool_t make_pipe (int p[2], DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (pipe (p) < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FAILED, "Failed to create pipe for communicating with child process (%s)", _dbus_strerror (errno)); return FALSE; } return TRUE; }
dbus_bool_t bus_config_parser_check_doctype (BusConfigParser *parser, const char *doctype, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (strcmp (doctype, "busconfig") != 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Configuration file has the wrong document type %s", doctype); return FALSE; } else return TRUE; }
static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection, DBusMessage *hello_message, BusTransaction *transaction, DBusError *error) { DBusMessage *welcome; const char *name; _DBUS_ASSERT_ERROR_IS_CLEAR (error); name = bus_connection_get_name (connection); _dbus_assert (name != NULL); welcome = dbus_message_new_method_return (hello_message); if (welcome == NULL) { BUS_SET_OOM (error); return FALSE; } if (!dbus_message_append_args (welcome, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { dbus_message_unref (welcome); BUS_SET_OOM (error); return FALSE; } _dbus_assert (dbus_message_has_signature (welcome, DBUS_TYPE_STRING_AS_STRING)); if (!bus_transaction_send_from_driver (transaction, connection, welcome)) { dbus_message_unref (welcome); BUS_SET_OOM (error); return FALSE; } else { dbus_message_unref (welcome); return TRUE; } }
/** * Get next file in the directory. Will not return "." or ".." on * UNIX. If an error occurs, the contents of "filename" are * undefined. The error is never set if the function succeeds. * * This function is not re-entrant, and not necessarily thread-safe. * Only use it for test code or single-threaded utilities. * * @param iter the iterator * @param filename string to be set to the next file in the dir * @param error return location for error * @returns #TRUE if filename was filled in with a new filename */ dbus_bool_t _dbus_directory_get_next_file (DBusDirIter *iter, DBusString *filename, DBusError *error) { struct dirent *ent; int err; _DBUS_ASSERT_ERROR_IS_CLEAR (error); again: errno = 0; ent = readdir (iter->d); if (!ent) { err = errno; if (err != 0) dbus_set_error (error, _dbus_error_from_errno (err), "%s", _dbus_strerror (err)); return FALSE; } else if (ent->d_name[0] == '.' && (ent->d_name[1] == '\0' || (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) goto again; else { _dbus_string_set_length (filename, 0); if (!_dbus_string_append (filename, ent->d_name)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "No memory to read directory entry"); return FALSE; } else { return TRUE; } } }
/** * close a pipe. * * @param pipe the pipe instance * @param error return location for an error * @returns #FALSE if error is set */ int _dbus_pipe_close (DBusPipe *pipe, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (_close (pipe->fd) != 0) { dbus_set_error (error, _dbus_error_from_system_errno (), "Could not close pipe fd %d: %s", pipe->fd, _dbus_strerror_from_errno ()); return -1; } else { _dbus_pipe_invalidate (pipe); return 0; } }
dbus_bool_t bus_driver_send_service_lost (DBusConnection *connection, const char *service_name, BusTransaction *transaction, DBusError *error) { DBusMessage *message; _DBUS_ASSERT_ERROR_IS_CLEAR (error); message = dbus_message_new_signal (DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameLost"); if (message == NULL) { BUS_SET_OOM (error); return FALSE; } if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) || !dbus_message_append_args (message, DBUS_TYPE_STRING, &service_name, DBUS_TYPE_INVALID)) { dbus_message_unref (message); BUS_SET_OOM (error); return FALSE; } if (!bus_transaction_send_from_driver (transaction, connection, message)) { dbus_message_unref (message); BUS_SET_OOM (error); return FALSE; } else { dbus_message_unref (message); return TRUE; } }
dbus_bool_t _dbus_delete_directory (const DBusString *filename, DBusError *error) { const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); if (rmdir (filename_c) != 0) { dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to remove directory %s: %s\n", filename_c, _dbus_strerror (errno)); return FALSE; } return TRUE; }
static void report_error (BusDesktopFileParser *parser, char *message, const char *error_name, DBusError *error) { const char *section_name = NULL; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (parser->current_section != -1) section_name = parser->desktop_file->sections[parser->current_section].section_name; if (section_name) dbus_set_error (error, error_name, "Error in section %s at line %d: %s\n", section_name, parser->line_num, message); else dbus_set_error (error, error_name, "Error at line %d: %s\n", parser->line_num, message); }
static dbus_bool_t make_pipe (int p[2], DBusError *error) { int retval; #ifdef HAVE_PIPE2 dbus_bool_t cloexec_done; retval = pipe2 (p, O_CLOEXEC); cloexec_done = retval >= 0; /* Check if kernel seems to be too old to know pipe2(). We assume that if pipe2 is available, O_CLOEXEC is too. */ if (retval < 0 && errno == ENOSYS) #endif { retval = pipe(p); } _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (retval < 0) { dbus_set_error (error, DBUS_ERROR_SPAWN_FAILED, "Failed to create pipe for communicating with child process (%s)", _dbus_strerror (errno)); return FALSE; } #ifdef HAVE_PIPE2 if (!cloexec_done) #endif { _dbus_fd_set_close_on_exec (p[0]); _dbus_fd_set_close_on_exec (p[1]); } return TRUE; }
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; }
/** * reads the nonce from the nonce file and stores it in a string * * @param fname the file to read the nonce from * @param nonce returns the nonce. Must be an initialized string, the nonce will be appended. * @param error error object to report possible errors * @return FALSE iff reading the nonce fails (error is set then) */ dbus_bool_t _dbus_read_nonce (const DBusString *fname, DBusString *nonce, DBusError* error) { FILE *fp; char buffer[17]; size_t nread; buffer[sizeof buffer - 1] = '\0'; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("reading nonce from file: %s\n", _dbus_string_get_const_data (fname)); fp = fopen (_dbus_string_get_const_data (fname), "rb"); if (!fp) { dbus_set_error (error, _dbus_error_from_system_errno (), "Failed to open %s for read: %s", _dbus_string_get_const_data (fname), _dbus_strerror_from_errno ()); return FALSE; } nread = fread (buffer, 1, sizeof buffer - 1, fp); fclose (fp); if (!nread) { dbus_set_error (error, DBUS_ERROR_FILE_NOT_FOUND, "Could not read nonce from file %s", _dbus_string_get_const_data (fname)); return FALSE; } if (!_dbus_string_append_len (nonce, buffer, sizeof buffer - 1 )) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } return TRUE; }
/** Creates the given file, failing if the file already exists. * * @param filename the filename * @param error error location * @returns #TRUE if we created the file and it didn't exist */ dbus_bool_t _dbus_create_file_exclusively (const DBusString *filename, DBusError *error) { HANDLE hnd; const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); filename_c = _dbus_string_get_const_data (filename); hnd = CreateFileA (filename_c, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (hnd == INVALID_HANDLE_VALUE) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not create file %s: %s", filename_c, emsg); _dbus_win_free_error_string (emsg); return FALSE; } _dbus_verbose ("exclusive file %s hnd %p opened\n", filename_c, hnd); if (CloseHandle (hnd) == 0) { char *emsg = _dbus_win_error_string (GetLastError ()); dbus_set_error (error, _dbus_win_error_from_last_error (), "Could not close file %s: %s", filename_c, emsg); _dbus_win_free_error_string (emsg); return FALSE; } 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 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; }
/** * deletes the noncefile and frees the DBusNonceFile object. * * If noncefile_location points to #NULL, nothing is freed or deleted, * similar to dbus_error_free(). * * @param noncefile_location the nonce file to delete. Contents will be freed and cleared to #NULL. * @param error error details if the nonce file could not be deleted * @return TRUE */ dbus_bool_t _dbus_noncefile_delete (DBusNonceFile **noncefile_location, DBusError *error) { DBusNonceFile *noncefile; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (noncefile_location != NULL); noncefile = *noncefile_location; *noncefile_location = NULL; if (noncefile == NULL) { /* Nothing to do */ return TRUE; } _dbus_delete_directory (&noncefile->dir, error); _dbus_string_free (&noncefile->dir); _dbus_string_free (&noncefile->path); dbus_free (noncefile); return TRUE; }
/* this function is self-cancelling if you cancel the transaction */ dbus_bool_t bus_service_remove_owner (BusService *service, DBusConnection *connection, BusTransaction *transaction, DBusError *error) { BusOwner *primary_owner; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* We send out notifications before we do any work we * might have to undo if the notification-sending failed */ /* Send service lost message */ primary_owner = bus_service_get_primary_owner (service); if (primary_owner != NULL && primary_owner->conn == connection) { if (!bus_driver_send_service_lost (connection, service->name, transaction, error)) return FALSE; } else { /* if we are not the primary owner then just remove us from the queue */ DBusList *link; BusOwner *temp_owner; link = _bus_service_find_owner_link (service, connection); _dbus_list_unlink (&service->owners, link); temp_owner = (BusOwner *)link->data; bus_owner_unref (temp_owner); _dbus_list_free_link (link); return TRUE; } if (service->owners == NULL) { _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners"); } else if (_dbus_list_length_is_one (&service->owners)) { if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), NULL, transaction, error)) return FALSE; } else { DBusList *link; BusOwner *new_owner; DBusConnection *new_owner_conn; link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); link = _dbus_list_get_next_link (&service->owners, link); _dbus_assert (link != NULL); new_owner = (BusOwner *)link->data; new_owner_conn = new_owner->conn; if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), bus_connection_get_name (new_owner_conn), transaction, error)) return FALSE; /* This will be our new owner */ if (!bus_driver_send_service_acquired (new_owner_conn, service->name, transaction, error)) return FALSE; } if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) { BUS_SET_OOM (error); return FALSE; } bus_service_unlink_owner (service, primary_owner); if (service->owners == NULL) bus_service_unlink (service); return TRUE; }
BusService* bus_registry_ensure (BusRegistry *registry, const DBusString *service_name, DBusConnection *owner_connection_if_created, dbus_uint32_t flags, BusTransaction *transaction, DBusError *error) { BusService *service; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (owner_connection_if_created != NULL); _dbus_assert (transaction != NULL); service = _dbus_hash_table_lookup_string (registry->service_hash, _dbus_string_get_const_data (service_name)); if (service != NULL) return service; service = _dbus_mem_pool_alloc (registry->service_pool); if (service == NULL) { BUS_SET_OOM (error); return NULL; } service->registry = registry; service->refcount = 1; _dbus_verbose ("copying string %p '%s' to service->name\n", service_name, _dbus_string_get_const_data (service_name)); if (!_dbus_string_copy_data (service_name, &service->name)) { _dbus_mem_pool_dealloc (registry->service_pool, service); BUS_SET_OOM (error); return NULL; } _dbus_verbose ("copied string %p '%s' to '%s'\n", service_name, _dbus_string_get_const_data (service_name), service->name); if (!bus_driver_send_service_owner_changed (service->name, NULL, bus_connection_get_name (owner_connection_if_created), transaction, error)) { bus_service_unref (service); return NULL; } if (!bus_activation_service_created (bus_context_get_activation (registry->context), service->name, transaction, error)) { bus_service_unref (service); return NULL; } if (!bus_service_add_owner (service, owner_connection_if_created, flags, transaction, error)) { bus_service_unref (service); return NULL; } if (!_dbus_hash_table_insert_string (registry->service_hash, service->name, service)) { /* The add_owner gets reverted on transaction cancel */ BUS_SET_OOM (error); return NULL; } return service; }
dbus_bool_t bus_service_swap_owner (BusService *service, DBusConnection *connection, BusTransaction *transaction, DBusError *error) { DBusList *swap_link; BusOwner *primary_owner; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* We send out notifications before we do any work we * might have to undo if the notification-sending failed */ /* Send service lost message */ primary_owner = bus_service_get_primary_owner (service); if (primary_owner == NULL || primary_owner->conn != connection) _dbus_assert_not_reached ("Tried to swap a non primary owner"); if (!bus_driver_send_service_lost (connection, service->name, transaction, error)) return FALSE; if (service->owners == NULL) { _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners"); } else if (_dbus_list_length_is_one (&service->owners)) { _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue"); } else { DBusList *link; BusOwner *new_owner; DBusConnection *new_owner_conn; link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); link = _dbus_list_get_next_link (&service->owners, link); _dbus_assert (link != NULL); new_owner = (BusOwner *)link->data; new_owner_conn = new_owner->conn; if (!bus_driver_send_service_owner_changed (service->name, bus_connection_get_name (connection), bus_connection_get_name (new_owner_conn), transaction, error)) return FALSE; /* This will be our new owner */ if (!bus_driver_send_service_acquired (new_owner_conn, service->name, transaction, error)) return FALSE; } if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) { BUS_SET_OOM (error); return FALSE; } /* unlink the primary and make it the second link */ swap_link = _dbus_list_get_first_link (&service->owners); _dbus_list_unlink (&service->owners, swap_link); _dbus_list_insert_after_link (&service->owners, _dbus_list_get_first_link (&service->owners), swap_link); return TRUE; }
/** * 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; }
/* this function is self-cancelling if you cancel the transaction */ dbus_bool_t bus_service_add_owner (BusService *service, DBusConnection *connection, dbus_uint32_t flags, BusTransaction *transaction, DBusError *error) { BusOwner *bus_owner; DBusList *bus_owner_link; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* Send service acquired message first, OOM will result * in cancelling the transaction */ if (service->owners == NULL) { if (!bus_driver_send_service_acquired (connection, service->name, transaction, error)) return FALSE; } bus_owner_link = _bus_service_find_owner_link (service, connection); if (bus_owner_link == NULL) { bus_owner = bus_owner_new (service, connection, flags); if (bus_owner == NULL) { BUS_SET_OOM (error); return FALSE; } bus_owner_set_flags (bus_owner, flags); if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL) { if (!_dbus_list_append (&service->owners, bus_owner)) { bus_owner_unref (bus_owner); BUS_SET_OOM (error); return FALSE; } } else { if (!_dbus_list_insert_after (&service->owners, _dbus_list_get_first_link (&service->owners), bus_owner)) { bus_owner_unref (bus_owner); BUS_SET_OOM (error); return FALSE; } } } else { /* Update the link since we are already in the queue * No need for operations that can produce OOM */ bus_owner = (BusOwner *) bus_owner_link->data; if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING) { DBusList *link; _dbus_list_unlink (&service->owners, bus_owner_link); link = _dbus_list_get_first_link (&service->owners); _dbus_assert (link != NULL); _dbus_list_insert_after_link (&service->owners, link, bus_owner_link); } bus_owner_set_flags (bus_owner, flags); return TRUE; } if (!add_cancel_ownership_to_transaction (transaction, service, bus_owner)) { bus_service_unlink_owner (service, bus_owner); BUS_SET_OOM (error); return FALSE; } return TRUE; }
/** * Looks up a gid or group name in the user database. Only one of * name or GID can be provided. There are wrapper functions for this * that are better to use, this one does no locking or anything on the * database and otherwise sort of sucks. * * @param db the database * @param gid the group ID or #DBUS_GID_UNSET * @param groupname group name or #NULL * @param error error to fill in * @returns the entry in the database */ DBusGroupInfo* _dbus_user_database_lookup_group (DBusUserDatabase *db, dbus_gid_t gid, const DBusString *groupname, DBusError *error) { DBusGroupInfo *info; _DBUS_ASSERT_ERROR_IS_CLEAR (error); /* See if the group is really a number */ if (gid == DBUS_UID_UNSET) { unsigned long n; if (_dbus_is_a_number (groupname, &n)) gid = n; } #ifdef DBUS_ENABLE_USERDB_CACHE if (gid != DBUS_GID_UNSET) info = _dbus_hash_table_lookup_ulong (db->groups, gid); else info = _dbus_hash_table_lookup_string (db->groups_by_name, _dbus_string_get_const_data (groupname)); if (info) { _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n", info->gid); return info; } else #else if (1) #endif { if (gid != DBUS_GID_UNSET) _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n", gid); else _dbus_verbose ("No cache for groupname \"%s\"\n", _dbus_string_get_const_data (groupname)); info = dbus_new0 (DBusGroupInfo, 1); if (info == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (gid != DBUS_GID_UNSET) { if (!_dbus_group_info_fill_gid (info, gid, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_group_info_free_allocated (info); return NULL; } } else { if (!_dbus_group_info_fill (info, groupname, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_group_info_free_allocated (info); return NULL; } } /* don't use these past here */ gid = DBUS_GID_UNSET; groupname = NULL; if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_group_info_free_allocated (info); return NULL; } if (!_dbus_hash_table_insert_string (db->groups_by_name, info->groupname, info)) { _dbus_hash_table_remove_ulong (db->groups, info->gid); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } return info; } }
/** * 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; }
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; }
DBusUserInfo* _dbus_user_database_lookup (DBusUserDatabase *db, dbus_uid_t uid, const DBusString *username, DBusError *error) { DBusUserInfo *info; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_assert (uid != DBUS_UID_UNSET || username != NULL); /* See if the username is really a number */ if (uid == DBUS_UID_UNSET) { unsigned long n; if (_dbus_is_a_number (username, &n)) uid = n; } if (uid != DBUS_UID_UNSET) info = _dbus_hash_table_lookup_ulong (db->users, uid); else info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username)); if (info) { _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n", info->uid); return info; } else { if (uid != DBUS_UID_UNSET) _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n", uid); else _dbus_verbose ("No cache for user \"%s\"\n", _dbus_string_get_const_data (username)); info = dbus_new0 (DBusUserInfo, 1); if (info == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (uid != DBUS_UID_UNSET) { if (!_dbus_user_info_fill_uid (info, uid, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_user_info_free_allocated (info); return NULL; } } else { if (!_dbus_user_info_fill (info, username, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_user_info_free_allocated (info); return NULL; } } /* be sure we don't use these after here */ uid = DBUS_UID_UNSET; username = NULL; /* insert into hash */ if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_user_info_free_allocated (info); return NULL; } if (!_dbus_hash_table_insert_string (db->users_by_name, info->username, info)) { _dbus_hash_table_remove_ulong (db->users, info->uid); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } return info; } }