D-Bus
1.6.8
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-transport-unix.c UNIX socket subclasses of DBusTransport 00003 * 00004 * Copyright (C) 2002, 2003, 2004 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 00026 #include <stdio.h> 00027 00028 #include "dbus-internals.h" 00029 #include "dbus-connection-internal.h" 00030 #include "dbus-transport-unix.h" 00031 #include "dbus-transport-socket.h" 00032 #include "dbus-transport-protected.h" 00033 #include "dbus-watch.h" 00034 #include "dbus-sysdeps-unix.h" 00035 #include "dbus-test.h" 00036 00057 DBusTransport* 00058 _dbus_transport_new_for_domain_socket (const char *path, 00059 dbus_bool_t abstract, 00060 DBusError *error) 00061 { 00062 int fd; 00063 DBusTransport *transport; 00064 DBusString address; 00065 00066 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00067 00068 if (!_dbus_string_init (&address)) 00069 { 00070 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00071 return NULL; 00072 } 00073 00074 fd = -1; 00075 00076 if ((abstract && 00077 !_dbus_string_append (&address, "unix:abstract=")) || 00078 (!abstract && 00079 !_dbus_string_append (&address, "unix:path=")) || 00080 !_dbus_string_append (&address, path)) 00081 { 00082 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00083 goto failed_0; 00084 } 00085 00086 fd = _dbus_connect_unix_socket (path, abstract, error); 00087 if (fd < 0) 00088 { 00089 _DBUS_ASSERT_ERROR_IS_SET (error); 00090 goto failed_0; 00091 } 00092 00093 _dbus_verbose ("Successfully connected to unix socket %s\n", 00094 path); 00095 00096 transport = _dbus_transport_new_for_socket (fd, NULL, &address); 00097 if (transport == NULL) 00098 { 00099 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00100 goto failed_1; 00101 } 00102 00103 _dbus_string_free (&address); 00104 00105 return transport; 00106 00107 failed_1: 00108 _dbus_close_socket (fd, NULL); 00109 failed_0: 00110 _dbus_string_free (&address); 00111 return NULL; 00112 } 00113 00125 static DBusTransport* 00126 _dbus_transport_new_for_exec (const char *path, 00127 char *const argv[], 00128 DBusError *error) 00129 { 00130 int fd; 00131 DBusTransport *transport; 00132 DBusString address; 00133 unsigned i; 00134 char *escaped; 00135 00136 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00137 00138 if (!_dbus_string_init (&address)) 00139 { 00140 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00141 return NULL; 00142 } 00143 00144 fd = -1; 00145 00146 escaped = dbus_address_escape_value (path); 00147 if (!escaped) 00148 { 00149 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00150 goto failed; 00151 } 00152 00153 if (!_dbus_string_append (&address, "unixexec:path=") || 00154 !_dbus_string_append (&address, escaped)) 00155 { 00156 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00157 dbus_free (escaped); 00158 goto failed; 00159 } 00160 00161 dbus_free (escaped); 00162 00163 if (argv) 00164 { 00165 for (i = 0; argv[i]; i++) 00166 { 00167 dbus_bool_t success; 00168 00169 escaped = dbus_address_escape_value (argv[i]); 00170 if (!escaped) 00171 { 00172 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00173 goto failed; 00174 } 00175 00176 success = _dbus_string_append_printf (&address, ",argv%u=%s", i, escaped); 00177 dbus_free (escaped); 00178 00179 if (!success) 00180 { 00181 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00182 goto failed; 00183 } 00184 } 00185 } 00186 00187 fd = _dbus_connect_exec (path, argv, error); 00188 if (fd < 0) 00189 { 00190 _DBUS_ASSERT_ERROR_IS_SET (error); 00191 goto failed; 00192 } 00193 00194 _dbus_verbose ("Successfully connected to process %s\n", 00195 path); 00196 00197 transport = _dbus_transport_new_for_socket (fd, NULL, &address); 00198 if (transport == NULL) 00199 { 00200 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00201 goto failed; 00202 } 00203 00204 _dbus_string_free (&address); 00205 00206 return transport; 00207 00208 failed: 00209 if (fd >= 0) 00210 _dbus_close_socket (fd, NULL); 00211 00212 _dbus_string_free (&address); 00213 return NULL; 00214 } 00215 00224 DBusTransportOpenResult 00225 _dbus_transport_open_platform_specific (DBusAddressEntry *entry, 00226 DBusTransport **transport_p, 00227 DBusError *error) 00228 { 00229 const char *method; 00230 00231 method = dbus_address_entry_get_method (entry); 00232 _dbus_assert (method != NULL); 00233 00234 if (strcmp (method, "unix") == 0) 00235 { 00236 const char *path = dbus_address_entry_get_value (entry, "path"); 00237 const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); 00238 const char *abstract = dbus_address_entry_get_value (entry, "abstract"); 00239 00240 if (tmpdir != NULL) 00241 { 00242 _dbus_set_bad_address (error, NULL, NULL, 00243 "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on"); 00244 return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; 00245 } 00246 00247 if (path == NULL && abstract == NULL) 00248 { 00249 _dbus_set_bad_address (error, "unix", 00250 "path or abstract", 00251 NULL); 00252 return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; 00253 } 00254 00255 if (path != NULL && abstract != NULL) 00256 { 00257 _dbus_set_bad_address (error, NULL, NULL, 00258 "can't specify both \"path\" and \"abstract\" options in an address"); 00259 return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; 00260 } 00261 00262 if (path) 00263 *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE, 00264 error); 00265 else 00266 *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE, 00267 error); 00268 if (*transport_p == NULL) 00269 { 00270 _DBUS_ASSERT_ERROR_IS_SET (error); 00271 return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; 00272 } 00273 else 00274 { 00275 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00276 return DBUS_TRANSPORT_OPEN_OK; 00277 } 00278 } 00279 else if (strcmp (method, "unixexec") == 0) 00280 { 00281 const char *path; 00282 unsigned i; 00283 char **argv; 00284 00285 path = dbus_address_entry_get_value (entry, "path"); 00286 if (path == NULL) 00287 { 00288 _dbus_set_bad_address (error, NULL, NULL, 00289 "No process path specified"); 00290 return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; 00291 } 00292 00293 /* First count argv arguments */ 00294 for (i = 1; ; i++) 00295 { 00296 char t[4+20+1]; /* "argv" plus space for a formatted base 10 64bit integer, plus NUL */ 00297 00298 snprintf (t, sizeof(t), "argv%u", i); 00299 00300 if (!dbus_address_entry_get_value (entry, t)) 00301 break; 00302 } 00303 00304 /* Allocate string array */ 00305 argv = dbus_new0 (char*, i+1); 00306 if (!argv) 00307 { 00308 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00309 return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; 00310 } 00311 00312 /* Fill in string array */ 00313 for (i = 0; ; i++) 00314 { 00315 char t[4+20+1]; 00316 const char *p; 00317 00318 snprintf (t, sizeof(t), "argv%u", i); 00319 00320 p = dbus_address_entry_get_value (entry, t); 00321 if (!p) 00322 { 00323 if (i == 0) 00324 /* If argv0 isn't specified, fill in the path instead */ 00325 p = path; 00326 else 00327 break; 00328 } 00329 00330 argv[i] = _dbus_strdup (p); 00331 if (!argv[i]) 00332 { 00333 dbus_free_string_array (argv); 00334 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00335 return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; 00336 } 00337 } 00338 00339 *transport_p = _dbus_transport_new_for_exec (path, argv, error); 00340 dbus_free_string_array (argv); 00341 00342 if (*transport_p == NULL) 00343 { 00344 _DBUS_ASSERT_ERROR_IS_SET (error); 00345 return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; 00346 } 00347 else 00348 { 00349 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00350 return DBUS_TRANSPORT_OPEN_OK; 00351 } 00352 } 00353 #ifdef DBUS_ENABLE_LAUNCHD 00354 else if (strcmp (method, "launchd") == 0) 00355 { 00356 DBusError tmp_error = DBUS_ERROR_INIT; 00357 const char *launchd_env_var = dbus_address_entry_get_value (entry, "env"); 00358 const char *launchd_socket; 00359 DBusString socket_path; 00360 dbus_bool_t valid_socket; 00361 00362 if (!_dbus_string_init (&socket_path)) 00363 { 00364 _DBUS_SET_OOM (error); 00365 return FALSE; 00366 } 00367 00368 if (launchd_env_var == NULL) 00369 { 00370 _dbus_set_bad_address (error, "launchd", "env", NULL); 00371 return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; 00372 } 00373 00374 valid_socket = _dbus_lookup_launchd_socket (&socket_path, launchd_env_var, error); 00375 00376 if (dbus_error_is_set(error)) 00377 { 00378 _dbus_string_free(&socket_path); 00379 return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; 00380 } 00381 00382 if (!valid_socket) 00383 { 00384 dbus_set_error(&tmp_error, DBUS_ERROR_BAD_ADDRESS, 00385 "launchd's env var %s does not exist", launchd_env_var); 00386 dbus_error_free(error); 00387 dbus_move_error(&tmp_error, error); 00388 return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; 00389 } 00390 00391 launchd_socket = _dbus_string_get_const_data(&socket_path); 00392 *transport_p = _dbus_transport_new_for_domain_socket (launchd_socket, FALSE, error); 00393 00394 if (*transport_p == NULL) 00395 { 00396 _DBUS_ASSERT_ERROR_IS_SET (error); 00397 return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; 00398 } 00399 else 00400 { 00401 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00402 return DBUS_TRANSPORT_OPEN_OK; 00403 } 00404 } 00405 #endif 00406 else 00407 { 00408 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00409 return DBUS_TRANSPORT_OPEN_NOT_HANDLED; 00410 } 00411 } 00412 00415 #ifdef DBUS_BUILD_TESTS 00416 00417 dbus_bool_t 00418 _dbus_transport_unix_test (void) 00419 { 00420 DBusConnection *c; 00421 DBusError error; 00422 dbus_bool_t ret; 00423 const char *address; 00424 00425 dbus_error_init (&error); 00426 00427 c = dbus_connection_open ("unixexec:argv0=false,argv1=foobar,path=/bin/false", &error); 00428 _dbus_assert (c != NULL); 00429 _dbus_assert (!dbus_error_is_set (&error)); 00430 00431 address = _dbus_connection_get_address (c); 00432 _dbus_assert (address != NULL); 00433 00434 /* Let's see if the address got parsed, reordered and formatted correctly */ 00435 ret = strcmp (address, "unixexec:path=/bin/false,argv0=false,argv1=foobar") == 0; 00436 00437 dbus_connection_unref (c); 00438 00439 return ret; 00440 } 00441 00442 #endif