Home | History | Annotate | Download | only in dbus
      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