1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24#include <config.h> 25#include "dbus-internals.h" 26#include "dbus-server-unix.h" 27#include "dbus-server-socket.h" 28#include "dbus-transport-unix.h" 29#include "dbus-connection-internal.h" 30#include "dbus-sysdeps-unix.h" 31#include "dbus-string.h" 32 33/** 34 * @defgroup DBusServerUnix DBusServer implementations for UNIX 35 * @ingroup DBusInternals 36 * @brief Implementation details of DBusServer on UNIX 37 * 38 * @{ 39 */ 40 41/** 42 * Tries to interpret the address entry in a platform-specific 43 * way, creating a platform-specific server type if appropriate. 44 * Sets error if the result is not OK. 45 * 46 * @param entry an address entry 47 * @param server_p location to store a new DBusServer, or #NULL on failure. 48 * @param error location to store rationale for failure on bad address 49 * @returns the outcome 50 * 51 */ 52DBusServerListenResult 53_dbus_server_listen_platform_specific (DBusAddressEntry *entry, 54 DBusServer **server_p, 55 DBusError *error) 56{ 57 const char *method; 58 59 *server_p = NULL; 60 61 method = dbus_address_entry_get_method (entry); 62 63 if (strcmp (method, "unix") == 0) 64 { 65 const char *path = dbus_address_entry_get_value (entry, "path"); 66 const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); 67 const char *abstract = dbus_address_entry_get_value (entry, "abstract"); 68 69 if (path == NULL && tmpdir == NULL && abstract == NULL) 70 { 71 _dbus_set_bad_address(error, "unix", 72 "path or tmpdir or abstract", 73 NULL); 74 return DBUS_SERVER_LISTEN_BAD_ADDRESS; 75 } 76 77 if ((path && tmpdir) || 78 (path && abstract) || 79 (tmpdir && abstract)) 80 { 81 _dbus_set_bad_address(error, NULL, NULL, 82 "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"); 83 return DBUS_SERVER_LISTEN_BAD_ADDRESS; 84 } 85 86 if (tmpdir != NULL) 87 { 88 DBusString full_path; 89 DBusString filename; 90 91 if (!_dbus_string_init (&full_path)) 92 { 93 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 94 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 95 } 96 97 if (!_dbus_string_init (&filename)) 98 { 99 _dbus_string_free (&full_path); 100 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 101 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 102 } 103 104 if (!_dbus_string_append (&filename, 105 "dbus-") || 106 !_dbus_generate_random_ascii (&filename, 10) || 107 !_dbus_string_append (&full_path, tmpdir) || 108 !_dbus_concat_dir_and_file (&full_path, &filename)) 109 { 110 _dbus_string_free (&full_path); 111 _dbus_string_free (&filename); 112 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 113 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 114 } 115 116 /* Always use abstract namespace if possible with tmpdir */ 117 118 *server_p = 119 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), 120#ifdef HAVE_ABSTRACT_SOCKETS 121 TRUE, 122#else 123 FALSE, 124#endif 125 error); 126 127 _dbus_string_free (&full_path); 128 _dbus_string_free (&filename); 129 } 130 else 131 { 132 if (path) 133 *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); 134 else 135 *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); 136 } 137 138 if (*server_p != NULL) 139 { 140 _DBUS_ASSERT_ERROR_IS_CLEAR(error); 141 return DBUS_SERVER_LISTEN_OK; 142 } 143 else 144 { 145 _DBUS_ASSERT_ERROR_IS_SET(error); 146 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 147 } 148 } 149 else if (strcmp (method, "systemd") == 0) 150 { 151 int n, *fds; 152 DBusString address; 153 154 n = _dbus_listen_systemd_sockets (&fds, error); 155 if (n < 0) 156 { 157 _DBUS_ASSERT_ERROR_IS_SET (error); 158 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 159 } 160 161 _dbus_string_init_const (&address, "systemd:"); 162 163 *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL); 164 if (*server_p == NULL) 165 { 166 int i; 167 168 for (i = 0; i < n; i++) 169 { 170 _dbus_close_socket (fds[i], NULL); 171 } 172 dbus_free (fds); 173 174 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 175 return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; 176 } 177 178 dbus_free (fds); 179 180 return DBUS_SERVER_LISTEN_OK; 181 } 182 else 183 { 184 /* If we don't handle the method, we return NULL with the 185 * error unset 186 */ 187 _DBUS_ASSERT_ERROR_IS_CLEAR(error); 188 return DBUS_SERVER_LISTEN_NOT_HANDLED; 189 } 190} 191 192/** 193 * Creates a new server listening on the given Unix domain socket. 194 * 195 * @param path the path for the domain socket. 196 * @param abstract #TRUE to use abstract socket namespace 197 * @param error location to store reason for failure. 198 * @returns the new server, or #NULL on failure. 199 */ 200DBusServer* 201_dbus_server_new_for_domain_socket (const char *path, 202 dbus_bool_t abstract, 203 DBusError *error) 204{ 205 DBusServer *server; 206 int listen_fd; 207 DBusString address; 208 char *path_copy; 209 DBusString path_str; 210 211 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 212 213 if (!_dbus_string_init (&address)) 214 { 215 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 216 return NULL; 217 } 218 219 _dbus_string_init_const (&path_str, path); 220 if ((abstract && 221 !_dbus_string_append (&address, "unix:abstract=")) || 222 (!abstract && 223 !_dbus_string_append (&address, "unix:path=")) || 224 !_dbus_address_append_escaped (&address, &path_str)) 225 { 226 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 227 goto failed_0; 228 } 229 230 path_copy = _dbus_strdup (path); 231 if (path_copy == NULL) 232 { 233 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 234 goto failed_0; 235 } 236 237 listen_fd = _dbus_listen_unix_socket (path, abstract, error); 238 239 if (listen_fd < 0) 240 { 241 _DBUS_ASSERT_ERROR_IS_SET (error); 242 goto failed_1; 243 } 244 245 server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0); 246 if (server == NULL) 247 { 248 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 249 goto failed_2; 250 } 251 252 _dbus_server_socket_own_filename(server, path_copy); 253 254 _dbus_string_free (&address); 255 256 return server; 257 258 failed_2: 259 _dbus_close_socket (listen_fd, NULL); 260 failed_1: 261 dbus_free (path_copy); 262 failed_0: 263 _dbus_string_free (&address); 264 265 return NULL; 266} 267 268/** @} */ 269