D-Bus  1.10.12
dbus-transport-unix.c
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   DBusSocket fd = DBUS_SOCKET_INIT;
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   if ((abstract &&
00075        !_dbus_string_append (&address, "unix:abstract=")) ||
00076       (!abstract &&
00077        !_dbus_string_append (&address, "unix:path=")) ||
00078       !_dbus_string_append (&address, path))
00079     {
00080       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00081       goto failed_0;
00082     }
00083   
00084   fd.fd = _dbus_connect_unix_socket (path, abstract, error);
00085   if (fd.fd < 0)
00086     {
00087       _DBUS_ASSERT_ERROR_IS_SET (error);
00088       goto failed_0;
00089     }
00090 
00091   _dbus_verbose ("Successfully connected to unix socket %s\n",
00092                  path);
00093 
00094   transport = _dbus_transport_new_for_socket (fd, NULL, &address);
00095   if (transport == NULL)
00096     {
00097       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00098       goto failed_1;
00099     }
00100   
00101   _dbus_string_free (&address);
00102   
00103   return transport;
00104 
00105  failed_1:
00106   _dbus_close_socket (fd, NULL);
00107  failed_0:
00108   _dbus_string_free (&address);
00109   return NULL;
00110 }
00111 
00123 static DBusTransport*
00124 _dbus_transport_new_for_exec (const char     *path,
00125                               char *const     argv[],
00126                               DBusError      *error)
00127 {
00128   DBusSocket fd = DBUS_SOCKET_INIT;
00129   DBusTransport *transport;
00130   DBusString address;
00131   unsigned i;
00132   char *escaped;
00133 
00134   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00135 
00136   if (!_dbus_string_init (&address))
00137     {
00138       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00139       return NULL;
00140     }
00141 
00142   escaped = dbus_address_escape_value (path);
00143   if (!escaped)
00144     {
00145       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00146       goto failed;
00147     }
00148 
00149   if (!_dbus_string_append (&address, "unixexec:path=") ||
00150       !_dbus_string_append (&address, escaped))
00151     {
00152       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00153       dbus_free (escaped);
00154       goto failed;
00155     }
00156 
00157   dbus_free (escaped);
00158 
00159   if (argv)
00160     {
00161       for (i = 0; argv[i]; i++)
00162         {
00163           dbus_bool_t success;
00164 
00165           escaped = dbus_address_escape_value (argv[i]);
00166           if (!escaped)
00167             {
00168               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00169               goto failed;
00170             }
00171 
00172           success = _dbus_string_append_printf (&address, ",argv%u=%s", i, escaped);
00173           dbus_free (escaped);
00174 
00175           if (!success)
00176             {
00177               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00178               goto failed;
00179             }
00180         }
00181     }
00182 
00183   fd.fd = _dbus_connect_exec (path, argv, error);
00184   if (fd.fd < 0)
00185     {
00186       _DBUS_ASSERT_ERROR_IS_SET (error);
00187       goto failed;
00188     }
00189 
00190   _dbus_verbose ("Successfully connected to process %s\n",
00191                  path);
00192 
00193   transport = _dbus_transport_new_for_socket (fd, NULL, &address);
00194   if (transport == NULL)
00195     {
00196       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00197       goto failed;
00198     }
00199 
00200   _dbus_string_free (&address);
00201 
00202   return transport;
00203 
00204  failed:
00205   if (fd.fd >= 0)
00206     _dbus_close_socket (fd, NULL);
00207 
00208   _dbus_string_free (&address);
00209   return NULL;
00210 }
00211 
00220 DBusTransportOpenResult
00221 _dbus_transport_open_platform_specific (DBusAddressEntry  *entry,
00222                                         DBusTransport    **transport_p,
00223                                         DBusError         *error)
00224 {
00225   const char *method;
00226   
00227   method = dbus_address_entry_get_method (entry);
00228   _dbus_assert (method != NULL);
00229 
00230   if (strcmp (method, "unix") == 0)
00231     {
00232       const char *path = dbus_address_entry_get_value (entry, "path");
00233       const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
00234       const char *abstract = dbus_address_entry_get_value (entry, "abstract");
00235           
00236       if (tmpdir != NULL)
00237         {
00238           _dbus_set_bad_address (error, NULL, NULL,
00239                                  "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on");
00240           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
00241         }
00242           
00243       if (path == NULL && abstract == NULL)
00244         {
00245           _dbus_set_bad_address (error, "unix",
00246                                  "path or abstract",
00247                                  NULL);
00248           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
00249         }
00250 
00251       if (path != NULL && abstract != NULL)
00252         {
00253           _dbus_set_bad_address (error, NULL, NULL,
00254                                  "can't specify both \"path\" and \"abstract\" options in an address");
00255           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
00256         }
00257 
00258       if (path)
00259         *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE,
00260                                                            error);
00261       else
00262         *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE,
00263                                                            error);
00264       if (*transport_p == NULL)
00265         {
00266           _DBUS_ASSERT_ERROR_IS_SET (error);
00267           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00268         }
00269       else
00270         {
00271           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00272           return DBUS_TRANSPORT_OPEN_OK;
00273         }
00274     }
00275   else if (strcmp (method, "unixexec") == 0)
00276     {
00277       const char *path;
00278       unsigned i;
00279       char **argv;
00280 
00281       path = dbus_address_entry_get_value (entry, "path");
00282       if (path == NULL)
00283         {
00284           _dbus_set_bad_address (error, NULL, NULL,
00285                                  "No process path specified");
00286           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
00287         }
00288 
00289       /* First count argv arguments */
00290       for (i = 1; ; i++)
00291         {
00292           char t[4+20+1]; /* "argv" plus space for a formatted base 10 64bit integer, plus NUL */
00293 
00294           snprintf (t, sizeof(t), "argv%u", i);
00295 
00296           if (!dbus_address_entry_get_value (entry, t))
00297             break;
00298         }
00299 
00300       /* Allocate string array */
00301       argv = dbus_new0 (char*, i+1);
00302       if (!argv)
00303         {
00304           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00305           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00306         }
00307 
00308       /* Fill in string array */
00309       for (i = 0; ; i++)
00310         {
00311           char t[4+20+1];
00312           const char *p;
00313 
00314           snprintf (t, sizeof(t), "argv%u", i);
00315 
00316           p = dbus_address_entry_get_value (entry, t);
00317           if (!p)
00318             {
00319               if (i == 0)
00320                 /* If argv0 isn't specified, fill in the path instead */
00321                 p = path;
00322               else
00323                 break;
00324             }
00325 
00326           argv[i] = _dbus_strdup (p);
00327           if (!argv[i])
00328             {
00329               dbus_free_string_array (argv);
00330               dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00331               return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00332             }
00333         }
00334 
00335       *transport_p = _dbus_transport_new_for_exec (path, argv, error);
00336       dbus_free_string_array (argv);
00337 
00338       if (*transport_p == NULL)
00339         {
00340           _DBUS_ASSERT_ERROR_IS_SET (error);
00341           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00342         }
00343       else
00344         {
00345           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00346           return DBUS_TRANSPORT_OPEN_OK;
00347         }
00348     }
00349 #ifdef DBUS_ENABLE_LAUNCHD
00350   else if (strcmp (method, "launchd") == 0)
00351     {
00352       DBusError tmp_error = DBUS_ERROR_INIT;
00353       const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
00354       const char *launchd_socket;
00355       DBusString socket_path;
00356       dbus_bool_t valid_socket;
00357 
00358       if (!_dbus_string_init (&socket_path))
00359         {
00360           _DBUS_SET_OOM (error);
00361           return FALSE;
00362         }
00363 
00364       if (launchd_env_var == NULL)
00365         {
00366           _dbus_set_bad_address (error, "launchd", "env", NULL);
00367           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
00368         }
00369 
00370       valid_socket = _dbus_lookup_launchd_socket (&socket_path, launchd_env_var, error);
00371 
00372       if (dbus_error_is_set(error))
00373         {
00374           _dbus_string_free(&socket_path);
00375           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00376         }
00377 
00378       if (!valid_socket)
00379         {
00380           dbus_set_error(&tmp_error, DBUS_ERROR_BAD_ADDRESS,
00381                          "launchd's env var %s does not exist", launchd_env_var);
00382           dbus_error_free(error);
00383           dbus_move_error(&tmp_error, error);
00384           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00385         }
00386 
00387       launchd_socket = _dbus_string_get_const_data(&socket_path);
00388       *transport_p = _dbus_transport_new_for_domain_socket (launchd_socket, FALSE, error);
00389 
00390       if (*transport_p == NULL)
00391         {
00392           _DBUS_ASSERT_ERROR_IS_SET (error);
00393           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
00394         }
00395       else
00396         {
00397           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00398           return DBUS_TRANSPORT_OPEN_OK;
00399         }
00400     }
00401 #endif
00402   else
00403     {
00404       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00405       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
00406     }
00407 }
00408 
00411 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00412 
00413 dbus_bool_t
00414 _dbus_transport_unix_test (void)
00415 {
00416   DBusConnection *c;
00417   DBusError error;
00418   dbus_bool_t ret;
00419   const char *address;
00420 
00421   dbus_error_init (&error);
00422 
00423   c = dbus_connection_open ("unixexec:argv0=false,argv1=foobar,path=/bin/false", &error);
00424   _dbus_assert (c != NULL);
00425   _dbus_assert (!dbus_error_is_set (&error));
00426 
00427   address = _dbus_connection_get_address (c);
00428   _dbus_assert (address != NULL);
00429 
00430   /* Let's see if the address got parsed, reordered and formatted correctly */
00431   ret = strcmp (address, "unixexec:path=/bin/false,argv0=false,argv1=foobar") == 0;
00432 
00433   dbus_connection_unref (c);
00434 
00435   return ret;
00436 }
00437 
00438 #endif