D-Bus 1.6.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   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