static BusDesktopFileSection* new_section (BusDesktopFile *desktop_file, const char *name) { int n; char *name_copy; if (desktop_file->n_allocated_sections == desktop_file->n_sections) { if (!grow_sections (desktop_file)) return NULL; } name_copy = _dbus_strdup (name); if (name_copy == NULL) return NULL; n = desktop_file->n_sections; desktop_file->sections[n].section_name = name_copy; desktop_file->sections[n].n_lines = 0; desktop_file->sections[n].lines = NULL; desktop_file->sections[n].n_allocated_lines = 0; if (!grow_lines_in_section (&desktop_file->sections[n])) { dbus_free (desktop_file->sections[n].section_name); desktop_file->sections[n].section_name = NULL; return NULL; } desktop_file->n_sections += 1; return &desktop_file->sections[n]; }
dbus_bool_t bus_desktop_file_get_string (BusDesktopFile *desktop_file, const char *section, const char *keyname, char **val, DBusError *error) { const char *raw; _DBUS_ASSERT_ERROR_IS_CLEAR (error); *val = NULL; if (!bus_desktop_file_get_raw (desktop_file, section, keyname, &raw)) { dbus_set_error (error, DBUS_ERROR_FAILED, "No \"%s\" key in .service file\n", keyname); return FALSE; } *val = _dbus_strdup (raw); if (*val == NULL) { BUS_SET_OOM (error); return FALSE; } return TRUE; }
static dbus_bool_t init_session_address (void) { dbus_bool_t retval; retval = FALSE; /* First, look in the environment. This is the normal case on * freedesktop.org/Unix systems. */ get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION], "DBUS_SESSION_BUS_ADDRESS"); if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) { dbus_bool_t supported; DBusString addr; DBusError error = DBUS_ERROR_INIT; if (!_dbus_string_init (&addr)) return FALSE; supported = FALSE; /* So it's not in the environment - let's try a platform-specific method. * On MacOS, this involves asking launchd. On Windows (not specified yet) * we might do a COM lookup. * Ignore errors - if we failed, fall back to autolaunch. */ retval = _dbus_lookup_session_address (&supported, &addr, &error); if (supported && retval) { retval =_dbus_string_steal_data (&addr, &bus_connection_addresses[DBUS_BUS_SESSION]); } else if (supported && !retval) { if (dbus_error_is_set(&error)) _dbus_warn ("Dynamic session lookup supported but failed: %s\n", error.message); else _dbus_warn ("Dynamic session lookup supported but failed silently\n"); } _dbus_string_free (&addr); } else retval = TRUE; if (!retval) return FALSE; /* The DBUS_SESSION_BUS_DEFAULT_ADDRESS should have really been named * DBUS_SESSION_BUS_FALLBACK_ADDRESS. */ if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) bus_connection_addresses[DBUS_BUS_SESSION] = _dbus_strdup (DBUS_SESSION_BUS_DEFAULT_ADDRESS); if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) return FALSE; return TRUE; }
static void save_machine_uuid (const char *uuid_arg) { if (strlen (uuid_arg) != 32) { fprintf (stderr, "machine ID '%s' looks like it's the wrong length, should be 32 hex digits", uuid_arg); exit (1); } machine_uuid = _dbus_strdup (uuid_arg); }
/** * Returns the address of the server, as a newly-allocated * string which must be freed by the caller. * * @param server the server * @returns the address or #NULL if no memory */ char* dbus_server_get_address (DBusServer *server) { char *retval; _dbus_return_val_if_fail (server != NULL, NULL); SERVER_LOCK (server); retval = _dbus_strdup (server->address); SERVER_UNLOCK (server); return retval; }
static dbus_bool_t auth_via_windows_user_function (DBusTransport *transport) { DBusCredentials *auth_identity; dbus_bool_t allow; DBusConnection *connection; DBusAllowWindowsUserFunction windows_user_function; void *windows_user_data; char *windows_sid; /* Dropping the lock here probably isn't that safe. */ auth_identity = _dbus_auth_get_identity (transport->auth); _dbus_assert (auth_identity != NULL); connection = transport->connection; windows_user_function = transport->windows_user_function; windows_user_data = transport->unix_user_data; windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity)); if (windows_sid == NULL) { /* OOM */ return FALSE; } _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); _dbus_connection_unlock (connection); allow = (* windows_user_function) (connection, windows_sid, windows_user_data); _dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME); _dbus_connection_lock (connection); if (allow) { _dbus_verbose ("Client SID '%s' authorized\n", windows_sid); } else { _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n", _dbus_credentials_get_windows_sid (auth_identity)); _dbus_transport_disconnect (transport); } return allow; }
/** * Add a Windows user SID to the credentials. * * @param credentials the object * @param windows_sid the user SID * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials, const char *windows_sid) { char *copy; copy = _dbus_strdup (windows_sid); if (copy == NULL) return FALSE; dbus_free (credentials->windows_sid); credentials->windows_sid = copy; return TRUE; }
static dbus_bool_t get_from_env (char **connection_p, const char *env_var) { const char *s; _dbus_assert (*connection_p == NULL); s = _dbus_getenv (env_var); if (s == NULL || *s == '\0') return TRUE; /* successfully didn't use the env var */ else { *connection_p = _dbus_strdup (s); return *connection_p != NULL; } }
/** * Sets the unique name of the connection. Can only be used if you * registered with the bus manually (i.e. if you did not call * dbus_bus_register()). Can only be called once per connection. * * @param connection the connection * @param unique_name the unique name * @returns #FALSE if not enough memory */ dbus_bool_t dbus_bus_set_unique_name (DBusConnection *connection, const char *unique_name) { BusData *bd; _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (unique_name != NULL, FALSE); bd = ensure_bus_data (connection); if (bd == NULL) return FALSE; _dbus_assert (bd->unique_name == NULL); bd->unique_name = _dbus_strdup (unique_name); return bd->unique_name != NULL; }
dbus_bool_t bus_registry_list_services (BusRegistry *registry, char ***listp, int *array_len) { int i, j, len; char **retval; DBusHashIter iter; len = _dbus_hash_table_get_n_entries (registry->service_hash); retval = dbus_new (char *, len + 1); if (retval == NULL) return FALSE; _dbus_hash_iter_init (registry->service_hash, &iter); i = 0; while (_dbus_hash_iter_next (&iter)) { BusService *service = _dbus_hash_iter_get_value (&iter); retval[i] = _dbus_strdup (service->name); if (retval[i] == NULL) goto error; i++; } retval[i] = NULL; if (array_len) *array_len = len; *listp = retval; return TRUE; error: for (j = 0; j < i; j++) dbus_free (retval[j]); dbus_free (retval); return FALSE; }
static dbus_bool_t fill_user_info_from_group (struct group *g, DBusGroupInfo *info, DBusError *error) { _dbus_assert (g->gr_name != NULL); info->gid = g->gr_gid; info->groupname = _dbus_strdup (g->gr_name); /* info->members = dbus_strdupv (g->gr_mem) */ if (info->groupname == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return FALSE; } return TRUE; }
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; }
dbus_bool_t bus_desktop_file_get_string (BusDesktopFile *desktop_file, const char *section, const char *keyname, char **val) { const char *raw; *val = NULL; if (!bus_desktop_file_get_raw (desktop_file, section, keyname, &raw)) return FALSE; *val = _dbus_strdup (raw); /* FIXME we don't distinguish "key not found" from "out of memory" here, * which is broken. */ if (*val == NULL) return FALSE; return TRUE; }
/** * See dbus_connection_get_windows_user(). * * @param transport the transport * @param windows_sid_p return location for the user ID * @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it */ dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport, char **windows_sid_p) { DBusCredentials *auth_identity; *windows_sid_p = NULL; if (!transport->authenticated) return FALSE; auth_identity = _dbus_auth_get_identity (transport->auth); if (_dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID)) { /* If no memory, we are supposed to return TRUE and set NULL */ *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity)); return TRUE; } else return FALSE; }
/** * 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); }
/** * Unquotes a string as the shell (/bin/sh) would. Only handles * quotes; if a string contains file globs, arithmetic operators, * variables, backticks, redirections, or other special-to-the-shell * features, the result will be different from the result a real shell * would produce (the variables, backticks, etc. will be passed * through literally instead of being expanded). This function is * guaranteed to succeed if applied to the result of * _dbus_shell_quote(). If it fails, it returns %NULL. * The @quoted_string need not actually contain quoted or * escaped text; _dbus_shell_unquote() simply goes through the string and * unquotes/unescapes anything that the shell would. Both single and * double quotes are handled, as are escapes including escaped * newlines. The return value must be freed with dbus_free(). * * Shell quoting rules are a bit strange. Single quotes preserve the * literal string exactly. escape sequences are not allowed; not even * \' - if you want a ' in the quoted text, you have to do something * like 'foo'\''bar'. Double quotes allow $, `, ", \, and newline to * be escaped with backslash. Otherwise double quotes preserve things * literally. * * @quoted_string: shell-quoted string **/ char* _dbus_shell_unquote (const char *quoted_string) { char *unquoted; char *end; char *start; char *ret; DBusString retval; unquoted = _dbus_strdup (quoted_string); if (unquoted == NULL) return NULL; start = unquoted; end = unquoted; if (!_dbus_string_init (&retval)) { dbus_free (unquoted); return NULL; } /* The loop allows cases such as * "foo"blah blah'bar'woo foo"baz"la la la\'\''foo' */ while (*start) { /* Append all non-quoted chars, honoring backslash escape */ while (*start && !(*start == '"' || *start == '\'')) { if (*start == '\\') { /* all characters can get escaped by backslash, * except newline, which is removed if it follows * a backslash outside of quotes */ ++start; if (*start) { if (*start != '\n') { if (!_dbus_string_append_byte (&retval, *start)) goto error; } ++start; } } else { if (!_dbus_string_append_byte (&retval, *start)) goto error; ++start; } } if (*start) { if (!unquote_string_inplace (start, &end)) goto error; else { if (!_dbus_string_append (&retval, start)) goto error; start = end; } } } ret = _dbus_strdup (_dbus_string_get_data (&retval)); if (!ret) goto error; dbus_free (unquoted); _dbus_string_free (&retval); return ret; error: dbus_free (unquoted); _dbus_string_free (&retval); return NULL; }
/** * 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; }
/** * Creates a new server listening on the given Unix domain socket. * * @param path the path for the domain socket. * @param abstract #TRUE to use abstract socket namespace * @param error location to store reason for failure. * @returns the new server, or #NULL on failure. */ DBusServer* _dbus_server_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error) { DBusServer *server; int listen_fd; DBusString address; char *path_copy; DBusString path_str; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } _dbus_string_init_const (&path_str, path); if ((abstract && !_dbus_string_append (&address, "unix:abstract=")) || (!abstract && !_dbus_string_append (&address, "unix:path=")) || !_dbus_address_append_escaped (&address, &path_str)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } if (abstract) { path_copy = NULL; } else { path_copy = _dbus_strdup (path); if (path_copy == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } } listen_fd = _dbus_listen_unix_socket (path, abstract, error); if (listen_fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed_1; } server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0); if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (path_copy != NULL) _dbus_server_socket_own_filename(server, path_copy); _dbus_string_free (&address); return server; failed_2: _dbus_close_socket (listen_fd, NULL); failed_1: dbus_free (path_copy); failed_0: _dbus_string_free (&address); return NULL; }
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; }
/** * 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; }
/** * Returns #TRUE if we have been authenticated. Will return #TRUE * even if the transport is disconnected. * * @todo we drop connection->mutex when calling the unix_user_function, * which may not be safe really. * * @param transport the transport * @returns whether we're authenticated */ dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport) { if (transport->authenticated) return TRUE; else { dbus_bool_t maybe_authenticated; if (transport->disconnected) return FALSE; /* paranoia ref since we call user callbacks sometimes */ _dbus_connection_ref_unlocked (transport->connection); maybe_authenticated = (!(transport->send_credentials_pending || transport->receive_credentials_pending)); if (maybe_authenticated) { switch (_dbus_auth_do_work (transport->auth)) { case DBUS_AUTH_STATE_AUTHENTICATED: /* leave as maybe_authenticated */ break; default: maybe_authenticated = FALSE; } } if (maybe_authenticated && !transport->is_server) { const char *server_guid; server_guid = _dbus_auth_get_guid_from_server (transport->auth); _dbus_assert (server_guid != NULL); if (transport->expected_guid && strcmp (transport->expected_guid, server_guid) != 0) { _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n", transport->expected_guid, server_guid); _dbus_transport_disconnect (transport); _dbus_connection_unref_unlocked (transport->connection); return FALSE; } if (transport->expected_guid == NULL) { transport->expected_guid = _dbus_strdup (server_guid); if (transport->expected_guid == NULL) { _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME); return FALSE; } } } /* If we've authenticated as some identity, check that the auth * identity is the same as our own identity. In the future, we * may have API allowing applications to specify how this is * done, for example they may allow connection as any identity, * but then impose restrictions on certain identities. * Or they may give certain identities extra privileges. */ if (maybe_authenticated && transport->is_server) { DBusCredentials auth_identity; _dbus_auth_get_identity (transport->auth, &auth_identity); if (transport->unix_user_function != NULL) { dbus_bool_t allow; DBusConnection *connection; DBusAllowUnixUserFunction unix_user_function; void *unix_user_data; /* Dropping the lock here probably isn't that safe. */ connection = transport->connection; unix_user_function = transport->unix_user_function; unix_user_data = transport->unix_user_data; _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); _dbus_connection_unlock (connection); allow = (* unix_user_function) (connection, auth_identity.uid, unix_user_data); _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME); _dbus_connection_lock (connection); if (allow) { _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid); } else { _dbus_verbose ("Client UID "DBUS_UID_FORMAT " was rejected, disconnecting\n", auth_identity.uid); _dbus_transport_disconnect (transport); _dbus_connection_unref_unlocked (connection); return FALSE; } } else { DBusCredentials our_identity; _dbus_credentials_from_current_process (&our_identity); if (!_dbus_credentials_match (&our_identity, &auth_identity)) { _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT " but our UID is "DBUS_UID_FORMAT", disconnecting\n", auth_identity.uid, our_identity.uid); _dbus_transport_disconnect (transport); _dbus_connection_unref_unlocked (transport->connection); return FALSE; } else { _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT " matching our UID "DBUS_UID_FORMAT"\n", auth_identity.uid, our_identity.uid); } } } transport->authenticated = maybe_authenticated; _dbus_connection_unref_unlocked (transport->connection); return maybe_authenticated; } }
/** * Spawns a new process. The executable name and argv[0] * are the same, both are provided in argv[0]. The child_setup * function is passed the given user_data and is run in the child * just before calling exec(). * * Also creates a "babysitter" which tracks the status of the * child process, advising the parent if the child exits. * If the spawn fails, no babysitter is created. * If sitter_p is #NULL, no babysitter is kept. * * @param sitter_p return location for babysitter or #NULL * @param argv the executable and arguments * @param env the environment (not used on unix yet) * @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, char **argv, char **env, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error) { DBusBabysitter *sitter; int child_err_report_pipe[2] = { -1, -1 }; int babysitter_pipe[2] = { -1, -1 }; pid_t pid; _DBUS_ASSERT_ERROR_IS_CLEAR (error); 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->executable = _dbus_strdup (argv[0]); if (sitter->executable == 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_full_duplex_pipe (&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], 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); 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]); /* Create the child that will exec () */ grandchild_pid = fork (); if (grandchild_pid < 0) { write_err_and_exit (babysitter_pipe[1], CHILD_FORK_FAILED); _dbus_assert_not_reached ("Got to code after write_err_and_exit()"); } else if (grandchild_pid == 0) { 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 { babysit (grandchild_pid, babysitter_pipe[1]); _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]); sitter->socket_to_babysitter = babysitter_pipe[0]; babysitter_pipe[0] = -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]); close_and_invalidate (&babysitter_pipe[1]); if (sitter != NULL) _dbus_babysitter_unref (sitter); return FALSE; }
static dbus_bool_t init_connections_unlocked (void) { if (!initialized) { const char *s; int i; i = 0; while (i < N_BUS_TYPES) { bus_connections[i] = NULL; ++i; } /* Don't init these twice, we may run this code twice if * init_connections_unlocked() fails midway through. * In practice, each block below should contain only one * "return FALSE" or running through twice may not * work right. */ if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) { _dbus_verbose ("Filling in system bus address...\n"); if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SYSTEM], "DBUS_SYSTEM_BUS_ADDRESS")) return FALSE; } if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) { /* Use default system bus address if none set in environment */ bus_connection_addresses[DBUS_BUS_SYSTEM] = _dbus_strdup (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS); if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) return FALSE; _dbus_verbose (" used default system bus \"%s\"\n", bus_connection_addresses[DBUS_BUS_SYSTEM]); } else _dbus_verbose (" used env var system bus \"%s\"\n", bus_connection_addresses[DBUS_BUS_SYSTEM]); if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) { _dbus_verbose ("Filling in session bus address...\n"); if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION], "DBUS_SESSION_BUS_ADDRESS")) return FALSE; if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) bus_connection_addresses[DBUS_BUS_SESSION] = _dbus_strdup (DBUS_SESSION_BUS_DEFAULT_ADDRESS); if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) return FALSE; _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ? bus_connection_addresses[DBUS_BUS_SESSION] : "none set"); } if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL) { _dbus_verbose ("Filling in activation bus address...\n"); if (!get_from_env (&bus_connection_addresses[DBUS_BUS_STARTER], "DBUS_STARTER_ADDRESS")) return FALSE; _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_STARTER] ? bus_connection_addresses[DBUS_BUS_STARTER] : "none set"); } if (bus_connection_addresses[DBUS_BUS_STARTER] != NULL) { s = _dbus_getenv ("DBUS_STARTER_BUS_TYPE"); if (s != NULL) { _dbus_verbose ("Bus activation type was set to \"%s\"\n", s); if (strcmp (s, "system") == 0) activation_bus_type = DBUS_BUS_SYSTEM; else if (strcmp (s, "session") == 0) activation_bus_type = DBUS_BUS_SESSION; } } else { /* Default to the session bus instead if available */ if (bus_connection_addresses[DBUS_BUS_SESSION] != NULL) { bus_connection_addresses[DBUS_BUS_STARTER] = _dbus_strdup (bus_connection_addresses[DBUS_BUS_SESSION]); if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL) return FALSE; } } /* If we return FALSE we have to be sure that restarting * the above code will work right */ if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", NULL)) return FALSE; if (!_dbus_setenv ("DBUS_ACTIVATION_BUS_TYPE", NULL)) return FALSE; if (!_dbus_register_shutdown_func (addresses_shutdown_func, NULL)) return FALSE; initialized = TRUE; } return initialized; }
/** * 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; }
/* This code only gets executed the first time the * config files are parsed. It is not executed * when config files are reloaded. */ static dbus_bool_t process_config_first_time_only (BusContext *context, BusConfigParser *parser, const DBusString *address, BusContextFlags flags, DBusError *error) { DBusString log_prefix; DBusList *link; DBusList **addresses; const char *user, *pidfile; char **auth_mechanisms; DBusList **auth_mechanisms_list; int len; dbus_bool_t retval; _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = FALSE; auth_mechanisms = NULL; pidfile = NULL; _dbus_init_system_log (TRUE); if (flags & BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION) context->systemd_activation = TRUE; else context->systemd_activation = FALSE; /* Check for an existing pid file. Of course this is a race; * we'd have to use fcntl() locks on the pid file to * avoid that. But we want to check for the pid file * before overwriting any existing sockets, etc. */ if (flags & BUS_CONTEXT_FLAG_WRITE_PID_FILE) pidfile = bus_config_parser_get_pidfile (parser); if (pidfile != NULL) { DBusString u; DBusStat stbuf; _dbus_string_init_const (&u, pidfile); if (_dbus_stat (&u, &stbuf, NULL)) { #ifdef DBUS_CYGWIN DBusString p; long /* int */ pid; _dbus_string_init (&p); _dbus_file_get_contents(&p, &u, NULL); _dbus_string_parse_int(&p, 0, &pid, NULL); _dbus_string_free(&p); if ((kill((int)pid, 0))) { dbus_set_error(NULL, DBUS_ERROR_FILE_EXISTS, "pid %ld not running, removing stale pid file\n", pid); _dbus_delete_file(&u, NULL); } else { #endif dbus_set_error (error, DBUS_ERROR_FAILED, "The pid file \"%s\" exists, if the message bus is not running, remove this file", pidfile); goto failed; #ifdef DBUS_CYGWIN } #endif } } /* keep around the pid filename so we can delete it later */ context->pidfile = _dbus_strdup (pidfile); /* note that type may be NULL */ context->type = _dbus_strdup (bus_config_parser_get_type (parser)); if (bus_config_parser_get_type (parser) != NULL && context->type == NULL) goto oom; user = bus_config_parser_get_user (parser); if (user != NULL) { context->user = _dbus_strdup (user); if (context->user == NULL) goto oom; } /* Set up the prefix for syslog messages */ if (!_dbus_string_init (&log_prefix)) goto oom; if (context->type && !strcmp (context->type, "system")) { if (!_dbus_string_append (&log_prefix, "[system] ")) goto oom; } else if (context->type && !strcmp (context->type, "session")) { DBusCredentials *credentials; credentials = _dbus_credentials_new_from_current_process (); if (!credentials) goto oom; if (!_dbus_string_append (&log_prefix, "[session ")) { _dbus_credentials_unref (credentials); goto oom; } if (!_dbus_credentials_to_string_append (credentials, &log_prefix)) { _dbus_credentials_unref (credentials); goto oom; } if (!_dbus_string_append (&log_prefix, "] ")) { _dbus_credentials_unref (credentials); goto oom; } _dbus_credentials_unref (credentials); } if (!_dbus_string_steal_data (&log_prefix, &context->log_prefix)) goto oom; _dbus_string_free (&log_prefix); /* Build an array of auth mechanisms */ auth_mechanisms_list = bus_config_parser_get_mechanisms (parser); len = _dbus_list_get_length (auth_mechanisms_list); if (len > 0) { int i; auth_mechanisms = dbus_new0 (char*, len + 1); if (auth_mechanisms == NULL) goto oom; i = 0; link = _dbus_list_get_first_link (auth_mechanisms_list); while (link != NULL) { auth_mechanisms[i] = _dbus_strdup (link->data); if (auth_mechanisms[i] == NULL) goto oom; link = _dbus_list_get_next_link (auth_mechanisms_list, link); i += 1; } }
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); }
/** * 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 DBusCondVar* dbus_fake_condvar_new (void) { return (DBusCondVar*) _dbus_strdup ("FakeCondvar"); }
void bus_set_watched_dirs (BusContext *context, DBusList **directories) { int new_fds[MAX_DIRS_TO_WATCH]; char *new_dirs[MAX_DIRS_TO_WATCH]; DBusList *link; int i, j, fd; struct kevent ev; #ifdef O_CLOEXEC dbus_bool_t cloexec_done = 0; #endif if (!_init_kqueue (context)) goto out; for (i = 0; i < MAX_DIRS_TO_WATCH; i++) { new_fds[i] = -1; new_dirs[i] = NULL; } i = 0; link = _dbus_list_get_first_link (directories); while (link != NULL) { new_dirs[i++] = (char *)link->data; link = _dbus_list_get_next_link (directories, link); } /* Look for directories in both the old and new sets, if * we find one, move its data into the new set. */ for (i = 0; new_dirs[i]; i++) { for (j = 0; j < num_fds; j++) { if (dirs[j] && strcmp (new_dirs[i], dirs[j]) == 0) { new_fds[i] = fds[j]; new_dirs[i] = dirs[j]; fds[j] = -1; dirs[j] = NULL; break; } } } /* Any directory we find in "fds" with a nonzero fd must * not be in the new set, so perform cleanup now. */ for (j = 0; j < num_fds; j++) { if (fds[j] != -1) { close (fds[j]); dbus_free (dirs[j]); fds[j] = -1; dirs[j] = NULL; } } for (i = 0; new_dirs[i]; i++) { if (new_fds[i] == -1) { /* FIXME - less lame error handling for failing to add a watch; * we may need to sleep. */ #ifdef O_CLOEXEC fd = open (new_dirs[i], O_RDONLY | O_CLOEXEC); cloexec_done = (fd >= 0); if (fd < 0 && errno == EINVAL) #endif { fd = open (new_dirs[i], O_RDONLY); } if (fd < 0) { if (errno != ENOENT) { _dbus_warn ("Cannot open directory '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno)); goto out; } else { new_fds[i] = -1; new_dirs[i] = NULL; continue; } } #ifdef O_CLOEXEC if (!cloexec_done) #endif { _dbus_fd_set_close_on_exec (fd); } EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_RENAME, 0, 0); if (kevent (kq, &ev, 1, NULL, 0, NULL) == -1) { _dbus_warn ("Cannot setup a kevent for '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno)); close (fd); goto out; } new_fds[i] = fd; new_dirs[i] = _dbus_strdup (new_dirs[i]); if (!new_dirs[i]) { /* FIXME have less lame handling for OOM, we just silently fail to * watch. (In reality though, the whole OOM handling in dbus is * stupid but we won't go into that in this comment =) ) */ close (fd); new_fds[i] = -1; } } } num_fds = i; for (i = 0; i < MAX_DIRS_TO_WATCH; i++) { fds[i] = new_fds[i]; dirs[i] = new_dirs[i]; } out: ; }
/** * Returns #TRUE if we have been authenticated. Will return #TRUE * even if the transport is disconnected. * * @todo we drop connection->mutex when calling the unix_user_function, * and windows_user_function, which may not be safe really. * * @param transport the transport * @returns whether we're authenticated */ dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport) { if (transport->authenticated) return TRUE; else { dbus_bool_t maybe_authenticated; if (transport->disconnected) return FALSE; /* paranoia ref since we call user callbacks sometimes */ _dbus_connection_ref_unlocked (transport->connection); maybe_authenticated = (!(transport->send_credentials_pending || transport->receive_credentials_pending)); if (maybe_authenticated) { switch (_dbus_auth_do_work (transport->auth)) { case DBUS_AUTH_STATE_AUTHENTICATED: /* leave as maybe_authenticated */ break; default: maybe_authenticated = FALSE; } } /* If we're the client, verify the GUID */ if (maybe_authenticated && !transport->is_server) { const char *server_guid; server_guid = _dbus_auth_get_guid_from_server (transport->auth); _dbus_assert (server_guid != NULL); if (transport->expected_guid && strcmp (transport->expected_guid, server_guid) != 0) { _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n", transport->expected_guid, server_guid); _dbus_transport_disconnect (transport); _dbus_connection_unref_unlocked (transport->connection); return FALSE; } if (transport->expected_guid == NULL) { transport->expected_guid = _dbus_strdup (server_guid); if (transport->expected_guid == NULL) { _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME); return FALSE; } } } /* If we're the server, see if we want to allow this identity to proceed. */ if (maybe_authenticated && transport->is_server) { dbus_bool_t allow; DBusCredentials *auth_identity; auth_identity = _dbus_auth_get_identity (transport->auth); _dbus_assert (auth_identity != NULL); /* If we have an auth'd user and a user function, delegate * deciding whether auth credentials are good enough to the * app; otherwise, use our default decision process. */ if (transport->unix_user_function != NULL && _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID)) { allow = auth_via_unix_user_function (transport); } else if (transport->windows_user_function != NULL && _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID)) { allow = auth_via_windows_user_function (transport); } else { allow = auth_via_default_rules (transport); } if (!allow) maybe_authenticated = FALSE; } transport->authenticated = maybe_authenticated; _dbus_connection_unref_unlocked (transport->connection); return maybe_authenticated; } }