1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-server-unix.c Server implementation for Unix network protocols. 3 * 4 * Copyright (C) 2002, 2003, 2004 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include "dbus-internals.h" 25 #include "dbus-server-unix.h" 26 #include "dbus-server-socket.h" 27 #include "dbus-transport-unix.h" 28 #include "dbus-connection-internal.h" 29 #include "dbus-sysdeps-unix.h" 30 #include "dbus-string.h" 31 32 /** 33 * @defgroup DBusServerUnix DBusServer implementations for UNIX 34 * @ingroup DBusInternals 35 * @brief Implementation details of DBusServer on UNIX 36 * 37 * @{ 38 */ 39 40 /** 41 * Tries to interpret the address entry in a platform-specific 42 * way, creating a platform-specific server type if appropriate. 43 * Sets error if the result is not OK. 44 * 45 * @param entry an address entry 46 * @param server_p location to store a new DBusServer, or #NULL on failure. 47 * @param error location to store rationale for failure on bad address 48 * @returns the outcome 49 * 50 */ 51 DBusServerListenResult 52 _dbus_server_listen_platform_specific (DBusAddressEntry *entry, 53 DBusServer **server_p, 54 DBusError *error) 55 { 56 const char *method; 57 58 *server_p = NULL; 59 60 method = dbus_address_entry_get_method (entry); 61 62 if (strcmp (method, "unix") == 0) 63 { 64 const char *path = dbus_address_entry_get_value (entry, "path"); 65 const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); 66 const char *abstract = dbus_address_entry_get_value (entry, "abstract"); 67 68 if (path == NULL && tmpdir == NULL && abstract == NULL) 69 { 70 _dbus_set_bad_address(error, "unix", 71 "path or tmpdir or abstract", 72 NULL); 73 return DBUS_SERVER_LISTEN_BAD_ADDRESS; 74 } 75 76 if ((path && tmpdir) || 77 (path && abstract) || 78 (tmpdir && abstract)) 79 { 80 _dbus_set_bad_address(error, NULL, NULL, 81 "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"); 82 return DBUS_SERVER_LISTEN_BAD_ADDRESS; 83 } 84 85 if (tmpdir != NULL) 86 { 87 DBusString full_path; 88 DBusString filename; 89 90 if (!_dbus_string_init (&full_path)) 91 { 92 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 93 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 94 } 95 96 if (!_dbus_string_init (&filename)) 97 { 98 _dbus_string_free (&full_path); 99 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 100 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 101 } 102 103 if (!_dbus_string_append (&filename, 104 "dbus-") || 105 !_dbus_generate_random_ascii (&filename, 10) || 106 !_dbus_string_append (&full_path, tmpdir) || 107 !_dbus_concat_dir_and_file (&full_path, &filename)) 108 { 109 _dbus_string_free (&full_path); 110 _dbus_string_free (&filename); 111 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 112 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 113 } 114 115 /* Always use abstract namespace if possible with tmpdir */ 116 117 *server_p = 118 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), 119 #ifdef HAVE_ABSTRACT_SOCKETS 120 TRUE, 121 #else 122 FALSE, 123 #endif 124 error); 125 126 _dbus_string_free (&full_path); 127 _dbus_string_free (&filename); 128 } 129 else 130 { 131 if (path) 132 *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); 133 else 134 *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); 135 } 136 137 if (*server_p != NULL) 138 { 139 _DBUS_ASSERT_ERROR_IS_CLEAR(error); 140 return DBUS_SERVER_LISTEN_OK; 141 } 142 else 143 { 144 _DBUS_ASSERT_ERROR_IS_SET(error); 145 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 146 } 147 } 148 else 149 { 150 /* If we don't handle the method, we return NULL with the 151 * error unset 152 */ 153 _DBUS_ASSERT_ERROR_IS_CLEAR(error); 154 return DBUS_SERVER_LISTEN_NOT_HANDLED; 155 } 156 } 157 158 /** 159 * Creates a new server listening on the given Unix domain socket. 160 * 161 * @param path the path for the domain socket. 162 * @param abstract #TRUE to use abstract socket namespace 163 * @param error location to store reason for failure. 164 * @returns the new server, or #NULL on failure. 165 */ 166 DBusServer* 167 _dbus_server_new_for_domain_socket (const char *path, 168 dbus_bool_t abstract, 169 DBusError *error) 170 { 171 DBusServer *server; 172 int listen_fd; 173 DBusString address; 174 char *path_copy; 175 DBusString path_str; 176 177 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 178 179 if (!_dbus_string_init (&address)) 180 { 181 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 182 return NULL; 183 } 184 185 _dbus_string_init_const (&path_str, path); 186 if ((abstract && 187 !_dbus_string_append (&address, "unix:abstract=")) || 188 (!abstract && 189 !_dbus_string_append (&address, "unix:path=")) || 190 !_dbus_address_append_escaped (&address, &path_str)) 191 { 192 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 193 goto failed_0; 194 } 195 196 path_copy = _dbus_strdup (path); 197 if (path_copy == NULL) 198 { 199 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 200 goto failed_0; 201 } 202 203 listen_fd = _dbus_listen_unix_socket (path, abstract, error); 204 _dbus_fd_set_close_on_exec (listen_fd); 205 206 if (listen_fd < 0) 207 { 208 _DBUS_ASSERT_ERROR_IS_SET (error); 209 goto failed_1; 210 } 211 212 server = _dbus_server_new_for_socket (listen_fd, &address); 213 if (server == NULL) 214 { 215 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 216 goto failed_2; 217 } 218 219 _dbus_server_socket_own_filename(server, path_copy); 220 221 _dbus_string_free (&address); 222 223 return server; 224 225 failed_2: 226 _dbus_close_socket (listen_fd, NULL); 227 failed_1: 228 dbus_free (path_copy); 229 failed_0: 230 _dbus_string_free (&address); 231 232 return NULL; 233 } 234 235 /** @} */ 236 237