/** * Tries to interpret the address entry in a platform-specific * way, creating a platform-specific server type if appropriate. * Sets error if the result is not OK. * * @param entry an address entry * @param server_p location to store a new DBusServer, or #NULL on failure. * @param error location to store rationale for failure on bad address * @returns the outcome * */ DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error) { const char *method; *server_p = NULL; method = dbus_address_entry_get_method (entry); if (strcmp (method, "unix") == 0) { const char *path = dbus_address_entry_get_value (entry, "path"); const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); const char *abstract = dbus_address_entry_get_value (entry, "abstract"); if (path == NULL && tmpdir == NULL && abstract == NULL) { _dbus_set_bad_address(error, "unix", "path or tmpdir or abstract", NULL); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } if ((path && tmpdir) || (path && abstract) || (tmpdir && abstract)) { _dbus_set_bad_address(error, NULL, NULL, "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } if (tmpdir != NULL) { DBusString full_path; DBusString filename; if (!_dbus_string_init (&full_path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_init (&filename)) { _dbus_string_free (&full_path); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_append (&filename, "dbus-") || !_dbus_generate_random_ascii (&filename, 10) || !_dbus_string_append (&full_path, tmpdir) || !_dbus_concat_dir_and_file (&full_path, &filename)) { _dbus_string_free (&full_path); _dbus_string_free (&filename); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } /* Always use abstract namespace if possible with tmpdir */ *server_p = _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), #ifdef HAVE_ABSTRACT_SOCKETS TRUE, #else FALSE, #endif error); _dbus_string_free (&full_path); _dbus_string_free (&filename); } else { if (path) *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); else *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); } if (*server_p != NULL) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_OK; } else { _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } else if (strcmp (method, "systemd") == 0) { int i, n, *fds; DBusString address; n = _dbus_listen_systemd_sockets (&fds, error); if (n < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if(!_dbus_string_init(&address)) goto oom; for (i = 0; i < n; i++) { if ( i > 0) { if(!_dbus_string_append (&address, ";")) goto oom; } if(!_dbus_append_address_from_socket (fds[i], &address)) goto oom; } *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL); if (*server_p == NULL) goto oom; dbus_free (fds); return DBUS_SERVER_LISTEN_OK; oom: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); for (i = 0; i < n; i++) { _dbus_close_socket (fds[i], NULL); } dbus_free (fds); _dbus_string_free (&address); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } #ifdef DBUS_ENABLE_LAUNCHD else if (strcmp (method, "launchd") == 0) { const char *launchd_env_var = dbus_address_entry_get_value (entry, "env"); if (launchd_env_var == NULL) { _dbus_set_bad_address (error, "launchd", "env", NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } *server_p = _dbus_server_new_for_launchd (launchd_env_var, error); if (*server_p != NULL) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_OK; } else { _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } #endif else { /* If we don't handle the method, we return NULL with the * error unset */ _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } }
DBusServer * _dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error) { #ifdef DBUS_ENABLE_LAUNCHD DBusServer *server; DBusString address; int launchd_fd; launch_data_t sockets_dict, checkin_response; launch_data_t checkin_request; launch_data_t listening_fd_array, listening_fd; launch_data_t environment_dict, environment_param; const char *launchd_socket_path, *display; launchd_socket_path = _dbus_getenv (launchd_env_var); display = _dbus_getenv ("DISPLAY"); _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (launchd_socket_path == NULL || *launchd_socket_path == '\0') { dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "launchd's environment variable %s is empty, but should contain a socket path.\n", launchd_env_var); return NULL; } if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_string_append (&address, "unix:path=")) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto l_failed_0; } if (!_dbus_string_append (&address, launchd_socket_path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto l_failed_0; } if ((checkin_request = launch_data_new_string (LAUNCH_KEY_CHECKIN)) == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "launch_data_new_string(\"%s\") Unable to create string.\n", LAUNCH_KEY_CHECKIN); goto l_failed_0; } if ((checkin_response = launch_msg (checkin_request)) == NULL) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "launch_msg(\"%s\") IPC failure: %s\n", LAUNCH_KEY_CHECKIN, strerror (errno)); goto l_failed_0; } if (LAUNCH_DATA_ERRNO == launch_data_get_type (checkin_response)) { dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n", strerror (launch_data_get_errno (checkin_response))); goto l_failed_0; } sockets_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_SOCKETS); if (NULL == sockets_dict) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "No sockets found to answer requests on!\n"); goto l_failed_0; } listening_fd_array = launch_data_dict_lookup (sockets_dict, "unix_domain_listener"); if (NULL == listening_fd_array) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "No known sockets found to answer requests on!\n"); goto l_failed_0; } if (launch_data_array_get_count (listening_fd_array) != 1) { dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, "Expected 1 socket from launchd, got %d.\n", launch_data_array_get_count (listening_fd_array)); goto l_failed_0; } listening_fd = launch_data_array_get_index (listening_fd_array, 0); launchd_fd = launch_data_get_fd (listening_fd); _dbus_fd_set_close_on_exec (launchd_fd); if (launchd_fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto l_failed_0; if (display == NULL || *display == '\0') { environment_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES); if (NULL == environment_dict) { _dbus_warn ("Unable to retrieve user environment from launchd."); } else { environment_param = launch_data_dict_lookup (environment_dict, "DISPLAY"); if (NULL == environment_param) { _dbus_warn ("Unable to retrieve DISPLAY from launchd."); } else { display = launch_data_get_string(environment_param); dbus_setenv ("DISPLAY", display); } } } } server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0); if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NO_SERVER, "Unable to listen on launchd fd %d.", launchd_fd); goto l_failed_0; } _dbus_string_free (&address); return server; l_failed_0: _dbus_string_free (&address); return NULL; #else /* DBUS_ENABLE_LAUNCHD */ dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "address type 'launchd' requested, but launchd support not compiled in"); return NULL; #endif }
/** * 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; }
/** * Creates a new server listening on TCP. * If host is NULL, it will default to localhost. * If bind is NULL, it will default to the value for the host * parameter, and if that is NULL, then localhost * If bind is a hostname, it will be resolved and will listen * on all returned addresses. * If family is NULL, hostname resolution will try all address * families, otherwise it can be ipv4 or ipv6 to restrict the * addresses considered. * * @param host the hostname to report for the listen address * @param bind the hostname to listen on * @param port the port to listen on or 0 to let the OS choose * @param family * @param error location to store reason for failure. * @param use_nonce whether to use a nonce for low-level authentication (nonce-tcp transport) or not (tcp transport) * @returns the new server, or #NULL on failure. */ DBusServer* _dbus_server_new_for_tcp_socket (const char *host, const char *bind, const char *port, const char *family, DBusError *error, dbus_bool_t use_nonce) { DBusServer *server; int *listen_fds = NULL; int nlisten_fds = 0, i; DBusString address; DBusString host_str; DBusString port_str; DBusNonceFile *noncefile; _DBUS_ASSERT_ERROR_IS_CLEAR (error); noncefile = NULL; if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_string_init (&port_str)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } if (host == NULL) host = "localhost"; if (port == NULL) port = "0"; if (bind == NULL) bind = host; else if (strcmp (bind, "*") == 0) bind = NULL; nlisten_fds =_dbus_listen_tcp_socket (bind, port, family, &port_str, &listen_fds, error); if (nlisten_fds <= 0) { _DBUS_ASSERT_ERROR_IS_SET(error); goto failed_1; } _dbus_string_init_const (&host_str, host); if (!_dbus_string_append (&address, use_nonce ? "nonce-tcp:host=" : "tcp:host=") || !_dbus_address_append_escaped (&address, &host_str) || !_dbus_string_append (&address, ",port=") || !_dbus_string_append (&address, _dbus_string_get_const_data(&port_str))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (family && (!_dbus_string_append (&address, ",family=") || !_dbus_string_append (&address, family))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (use_nonce) { noncefile = dbus_new0 (DBusNonceFile, 1); if (noncefile == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (!_dbus_noncefile_create (noncefile, error)) goto failed_3; if (!_dbus_string_append (&address, ",noncefile=") || !_dbus_address_append_escaped (&address, _dbus_noncefile_get_path (noncefile))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_4; } } server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address, noncefile); if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_4; } _dbus_string_free (&port_str); _dbus_string_free (&address); dbus_free(listen_fds); return server; failed_4: _dbus_noncefile_delete (noncefile, NULL); failed_3: dbus_free (noncefile); failed_2: for (i = 0 ; i < nlisten_fds ; i++) _dbus_close_socket (listen_fds[i], NULL); dbus_free(listen_fds); failed_1: _dbus_string_free (&port_str); failed_0: _dbus_string_free (&address); return NULL; }