예제 #1
0
DBusServer *
_dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error)
  {
#ifdef DBUS_ENABLE_LAUNCHD
    DBusServer *server;
    DBusString address;
    int launchd_fd;
    launch_data_t sockets_dict, checkin_response;
    launch_data_t checkin_request;
    launch_data_t listening_fd_array, listening_fd;
    launch_data_t environment_dict, environment_param;
    const char *launchd_socket_path, *display;

    launchd_socket_path = _dbus_getenv (launchd_env_var);
    display = _dbus_getenv ("DISPLAY");

    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

    if (launchd_socket_path == NULL || *launchd_socket_path == '\0')
      {
        dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
                        "launchd's environment variable %s is empty, but should contain a socket path.\n", launchd_env_var);
        return NULL;
      }

    if (!_dbus_string_init (&address))
      {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        return NULL;
      }
    if (!_dbus_string_append (&address, "unix:path="))
      {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto l_failed_0;
      }
    if (!_dbus_string_append (&address, launchd_socket_path))
      {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto l_failed_0;
      }

    if ((checkin_request = launch_data_new_string (LAUNCH_KEY_CHECKIN)) == NULL)
      {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
                        "launch_data_new_string(\"%s\") Unable to create string.\n",
                        LAUNCH_KEY_CHECKIN);
        goto l_failed_0;
      }

    if ((checkin_response = launch_msg (checkin_request)) == NULL)
      {
        dbus_set_error (error, DBUS_ERROR_IO_ERROR,
                        "launch_msg(\"%s\") IPC failure: %s\n",
                        LAUNCH_KEY_CHECKIN, strerror (errno));
        goto l_failed_0;
      }

    if (LAUNCH_DATA_ERRNO == launch_data_get_type (checkin_response))
      {
        dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n",
                        strerror (launch_data_get_errno (checkin_response)));
        goto l_failed_0;
      }

    sockets_dict =
      launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_SOCKETS);
    if (NULL == sockets_dict)
      {
        dbus_set_error (error, DBUS_ERROR_IO_ERROR,
                        "No sockets found to answer requests on!\n");
        goto l_failed_0;
      }

    listening_fd_array =
      launch_data_dict_lookup (sockets_dict, "unix_domain_listener");
    if (NULL == listening_fd_array)
      {
        dbus_set_error (error, DBUS_ERROR_IO_ERROR,
                        "No known sockets found to answer requests on!\n");
        goto l_failed_0;
      }

    if (launch_data_array_get_count (listening_fd_array) != 1)
      {
        dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
                        "Expected 1 socket from launchd, got %d.\n",
                        launch_data_array_get_count (listening_fd_array));
        goto l_failed_0;
      }

    listening_fd = launch_data_array_get_index (listening_fd_array, 0);
    launchd_fd = launch_data_get_fd (listening_fd);

    _dbus_fd_set_close_on_exec (launchd_fd);

    if (launchd_fd < 0)
      {
        _DBUS_ASSERT_ERROR_IS_SET (error);
        goto l_failed_0;
  if (display == NULL || *display == '\0')
    {
      environment_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES);
      if (NULL == environment_dict)
        {
          _dbus_warn ("Unable to retrieve user environment from launchd.");
        }
      else
        {
          environment_param = launch_data_dict_lookup (environment_dict, "DISPLAY");
          if (NULL == environment_param)
            {
              _dbus_warn ("Unable to retrieve DISPLAY from launchd.");
            }
          else
            {
              display = launch_data_get_string(environment_param);
              dbus_setenv ("DISPLAY", display);
            }
        }
    }

      }

    server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0, error);
    if (server == NULL)
      {
        goto l_failed_0;
      }

    _dbus_string_free (&address);

    return server;

  l_failed_0:
    _dbus_string_free (&address);

    return NULL;
#else /* DBUS_ENABLE_LAUNCHD */
    dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
                    "address type 'launchd' requested, but launchd support not compiled in");
    return NULL;
#endif
  }
예제 #2
0
파일: desktop-file.c 프로젝트: d-bus/dbus
BusDesktopFile*
bus_desktop_file_load (DBusString *filename,
		       DBusError  *error)
{
  DBusString str;
  BusDesktopFileParser parser;
  DBusStat sb;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  /* Clearly there's a race here, but it's just to make it unlikely
   * that we do something silly, we still handle doing it below.
   */
  if (!_dbus_stat (filename, &sb, error))
    return NULL;

  if (sb.size > _DBUS_ONE_KILOBYTE * 128)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Desktop file size (%ld bytes) is too large", (long) sb.size);
      return NULL;
    }
  
  if (!_dbus_string_init (&str))
    {
      BUS_SET_OOM (error);
      return NULL;
    }
  
  if (!_dbus_file_get_contents (&str, filename, error))
    {
      _dbus_string_free (&str);
      return NULL;
    }

  if (!_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str)))
    {
      _dbus_string_free (&str);
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "invalid UTF-8");   
      return NULL;
    }
  
  parser.desktop_file = dbus_new0 (BusDesktopFile, 1);
  if (parser.desktop_file == NULL)
    {
      _dbus_string_free (&str);
      BUS_SET_OOM (error);
      return NULL;
    }
  
  parser.data = str;
  parser.line_num = 1;
  parser.pos = 0;
  parser.len = _dbus_string_get_length (&parser.data);
  parser.current_section = -1;

  while (parser.pos < parser.len)
    {
      if (_dbus_string_get_byte (&parser.data, parser.pos) == '[')
	{
	  if (!parse_section_start (&parser, error))
            {
              return NULL;
            }
	}
      else if (is_blank_line (&parser) ||
	       _dbus_string_get_byte (&parser.data, parser.pos) == '#')
	parse_comment_or_blank (&parser);
      else if (parser.current_section < 0)
	{
           dbus_set_error(error, DBUS_ERROR_FAILED,
                          "invalid service file: key=value before [Section]");
           return NULL;
	}
      else
	{
	  if (!parse_key_value (&parser, error))
            {
              return NULL;
            }
	}
    }

  _dbus_string_free (&parser.data);

  return parser.desktop_file;
}
/**
 * Does the chdir, fork, setsid, etc. to become a daemon process.
 *
 * @param pidfile #NULL, or pidfile to create
 * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
 * @param error return location for errors
 * @returns #FALSE on failure
 */
dbus_bool_t
_dbus_become_daemon (const DBusString *pidfile,
		     int               print_pid_fd,
                     DBusError        *error)
{
  const char *s;
  pid_t child_pid;
  int dev_null_fd;

  _dbus_verbose ("Becoming a daemon...\n");

  _dbus_verbose ("chdir to /\n");
  if (chdir ("/") < 0)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Could not chdir() to root directory");
      return FALSE;
    }

  _dbus_verbose ("forking...\n");
  switch ((child_pid = fork ()))
    {
    case -1:
      _dbus_verbose ("fork failed\n");
      dbus_set_error (error, _dbus_error_from_errno (errno),
                      "Failed to fork daemon: %s", _dbus_strerror (errno));
      return FALSE;
      break;

    case 0:
      _dbus_verbose ("in child, closing std file descriptors\n");

      /* silently ignore failures here, if someone
       * doesn't have /dev/null we may as well try
       * to continue anyhow
       */
      
      dev_null_fd = open ("/dev/null", O_RDWR);
      if (dev_null_fd >= 0)
        {
          dup2 (dev_null_fd, 0);
          dup2 (dev_null_fd, 1);
          
          s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
          if (s == NULL || *s == '\0')
            dup2 (dev_null_fd, 2);
          else
            _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
        }

      /* Get a predictable umask */
      _dbus_verbose ("setting umask\n");
      umask (022);
      break;

    default:
      if (pidfile)
        {
          _dbus_verbose ("parent writing pid file\n");
          if (!_dbus_write_pid_file (pidfile,
                                     child_pid,
                                     error))
            {
              _dbus_verbose ("pid file write failed, killing child\n");
              kill (child_pid, SIGTERM);
              return FALSE;
            }
        }

      /* Write PID if requested */
      if (print_pid_fd >= 0)
	{
	  DBusString pid;
	  int bytes;
	  
	  if (!_dbus_string_init (&pid))
	    {
	      _DBUS_SET_OOM (error);
              kill (child_pid, SIGTERM);
	      return FALSE;
	    }
	  
	  if (!_dbus_string_append_int (&pid, child_pid) ||
	      !_dbus_string_append (&pid, "\n"))
	    {
	      _dbus_string_free (&pid);
	      _DBUS_SET_OOM (error);
              kill (child_pid, SIGTERM);
	      return FALSE;
	    }
	  
	  bytes = _dbus_string_get_length (&pid);
	  if (_dbus_write_socket (print_pid_fd, &pid, 0, bytes) != bytes)
	    {
	      dbus_set_error (error, DBUS_ERROR_FAILED,
			      "Printing message bus PID: %s\n",
			      _dbus_strerror (errno));
	      _dbus_string_free (&pid);
              kill (child_pid, SIGTERM);
	      return FALSE;
	    }
	  
	  _dbus_string_free (&pid);
	}
      _dbus_verbose ("parent exiting\n");
      _exit (0);
      break;
    }

  _dbus_verbose ("calling setsid()\n");
  if (setsid () == -1)
    _dbus_assert_not_reached ("setsid() failed");
  
  return TRUE;
}
예제 #4
0
/**
 * Creates a new server listening on TCP.
 * If host is NULL, it will default to localhost.
 * If bind is NULL, it will default to the value for the host
 * parameter, and if that is NULL, then localhost
 * If bind is a hostname, it will be resolved and will listen
 * on all returned addresses.
 * If family is NULL, hostname resolution will try all address
 * families, otherwise it can be ipv4 or ipv6 to restrict the
 * addresses considered.
 *
 * @param host the hostname to report for the listen address
 * @param bind the hostname to listen on
 * @param port the port to listen on or 0 to let the OS choose
 * @param family
 * @param error location to store reason for failure.
 * @param use_nonce whether to use a nonce for low-level authentication (nonce-tcp transport) or not (tcp transport)
 * @returns the new server, or #NULL on failure.
 */
DBusServer*
_dbus_server_new_for_tcp_socket (const char     *host,
                                 const char     *bind,
                                 const char     *port,
                                 const char     *family,
                                 DBusError      *error,
                                 dbus_bool_t    use_nonce)
{
  DBusServer *server;
  int *listen_fds = NULL;
  int nlisten_fds = 0, i;
  DBusString address;
  DBusString host_str;
  DBusString port_str;
  DBusNonceFile *noncefile;
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  noncefile = NULL;

  if (!_dbus_string_init (&address))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  if (!_dbus_string_init (&port_str))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_0;
    }

  if (host == NULL)
    host = "localhost";

  if (port == NULL)
    port = "0";

  if (bind == NULL)
    bind = host;
  else if (strcmp (bind, "*") == 0)
    bind = NULL;

  nlisten_fds =_dbus_listen_tcp_socket (bind, port, family,
                                        &port_str,
                                        &listen_fds, error);
  if (nlisten_fds <= 0)
    {
      _DBUS_ASSERT_ERROR_IS_SET(error);
      goto failed_1;
    }

  _dbus_string_init_const (&host_str, host);
  if (!_dbus_string_append (&address, use_nonce ? "nonce-tcp:host=" : "tcp:host=") ||
      !_dbus_address_append_escaped (&address, &host_str) ||
      !_dbus_string_append (&address, ",port=") ||
      !_dbus_string_append (&address, _dbus_string_get_const_data(&port_str)))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_2;
    }
  if (family &&
      (!_dbus_string_append (&address, ",family=") ||
       !_dbus_string_append (&address, family)))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_2;
    }

  if (use_nonce)
    {
      noncefile = dbus_new0 (DBusNonceFile, 1);
      if (noncefile == NULL)
        {
          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
          goto failed_2;
        }

      if (!_dbus_noncefile_create (noncefile, error))
          goto failed_3;

      if (!_dbus_string_append (&address, ",noncefile=") ||
          !_dbus_address_append_escaped (&address, _dbus_noncefile_get_path (noncefile)))
        {
          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
          goto failed_4;
        }

    }

  server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address, noncefile);
  if (server == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      if (noncefile != NULL)
        goto failed_4;
      else
        goto failed_2;
    }

  _dbus_string_free (&port_str);
  _dbus_string_free (&address);
  dbus_free(listen_fds);

  return server;

 failed_4:
  _dbus_noncefile_delete (noncefile, NULL);

 failed_3:
  dbus_free (noncefile);

 failed_2:
  for (i = 0 ; i < nlisten_fds ; i++)
    _dbus_close_socket (listen_fds[i], NULL);
  dbus_free(listen_fds);

 failed_1:
  _dbus_string_free (&port_str);

 failed_0:
  _dbus_string_free (&address);

  return NULL;
}
/**
 * Writes the given pid_to_write to a pidfile (if non-NULL) and/or to a
 * pipe (if non-NULL). Does nothing if pidfile and print_pid_pipe are both
 * NULL.
 *
 * @param pidfile the file to write to or #NULL
 * @param print_pid_pipe the pipe to write to or #NULL
 * @param pid_to_write the pid to write out
 * @param error error on failure
 * @returns FALSE if error is set
 */
dbus_bool_t
_dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
                                  DBusPipe         *print_pid_pipe,
                                  dbus_pid_t        pid_to_write,
                                  DBusError        *error)
{
  if (pidfile)
    {
      _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile));
      if (!_dbus_write_pid_file (pidfile,
                                 pid_to_write,
                                 error))
        {
          _dbus_verbose ("pid file write failed\n");
          _DBUS_ASSERT_ERROR_IS_SET(error);
          return FALSE;
        }
    }
  else
    {
      _dbus_verbose ("No pid file requested\n");
    }

  if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
    {
      DBusString pid;
      int bytes;

      _dbus_verbose ("writing our pid to pipe %"PRIuPTR"\n",
                     print_pid_pipe->fd_or_handle);
      
      if (!_dbus_string_init (&pid))
        {
          _DBUS_SET_OOM (error);
          return FALSE;
        }
	  
      if (!_dbus_string_append_int (&pid, pid_to_write) ||
          !_dbus_string_append (&pid, "\n"))
        {
          _dbus_string_free (&pid);
          _DBUS_SET_OOM (error);
          return FALSE;
        }
	  
      bytes = _dbus_string_get_length (&pid);
      if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
        {
          /* _dbus_pipe_write sets error only on failure, not short write */
          if (error != NULL && !dbus_error_is_set(error))
            {
              dbus_set_error (error, DBUS_ERROR_FAILED,
                              "Printing message bus PID: did not write enough bytes\n");
            }
          _dbus_string_free (&pid);
          return FALSE;
        }
	  
      _dbus_string_free (&pid);
    }
  else
    {
      _dbus_verbose ("No pid pipe to write to\n");
    }

  return TRUE;
}
예제 #6
0
/**
 * Appends the contents of the given file to the string,
 * returning error code. At the moment, won't open a file
 * more than a megabyte in size.
 *
 * @param str the string to append to
 * @param filename filename to load
 * @param error place to set an error
 * @returns #FALSE if error was set
 */
dbus_bool_t
_dbus_file_get_contents (DBusString       *str,
                         const DBusString *filename,
                         DBusError        *error)
{
  HANDLE hnd;
  DWORD fsize;
  DWORD fsize_hi;
  int orig_len;
  unsigned int total;
  const char *filename_c;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  filename_c = _dbus_string_get_const_data (filename);

  hnd = CreateFileA (filename_c, GENERIC_READ,
                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (hnd == INVALID_HANDLE_VALUE)
    {
      char *emsg = _dbus_win_error_string (GetLastError ());
      dbus_set_error (error, _dbus_win_error_from_last_error (),
                       "Failed to open \"%s\": %s", filename_c, emsg);
      _dbus_win_free_error_string (emsg);
      return FALSE;
    }

  _dbus_verbose ("file %s hnd %p opened\n", filename_c, hnd);
  
  fsize = GetFileSize (hnd, &fsize_hi);
  if (fsize == 0xFFFFFFFF && GetLastError() != NO_ERROR)
    { 
      char *emsg = _dbus_win_error_string (GetLastError ());
      dbus_set_error (error, _dbus_win_error_from_last_error (),
                      "Failed to get file size for \"%s\": %s",
                      filename_c, emsg);
      _dbus_win_free_error_string (emsg);

      _dbus_verbose ("GetFileSize() failed: %s", emsg);

      CloseHandle (hnd);

      return FALSE;
    }

  if (fsize_hi != 0 || fsize > _DBUS_ONE_MEGABYTE)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "File size %lu/%lu of \"%s\" is too large.",
                      (unsigned long) fsize_hi,
                      (unsigned long) fsize, filename_c);
      CloseHandle (hnd);
      return FALSE;
    }

  total = 0;
  orig_len = _dbus_string_get_length (str);
  if (fsize > 0)
    {
      int bytes_read;

      while (total < fsize)
        {
          bytes_read = _dbus_file_read (hnd, str, fsize - total, error);
          if (bytes_read <= 0)
            {
              if (bytes_read == 0)
                {
                  dbus_set_error (error, DBUS_ERROR_FAILED,
                                  "Premature EOF reading \"%s\"",
                                  filename_c);
                }
              else
                _DBUS_ASSERT_ERROR_IS_SET (error);

              CloseHandle (hnd);
              _dbus_string_set_length (str, orig_len);
              return FALSE;
            }
          else
            total += bytes_read;
        }

      CloseHandle (hnd);
      return TRUE;
    }
  else
    {
      CloseHandle (hnd);
      return TRUE;
    }
}
예제 #7
0
static dbus_bool_t
__ni_objectmodel_bonding_set_slaves(ni_dbus_object_t *object,
				const ni_dbus_property_t *property,
				const ni_dbus_variant_t *result,
				DBusError *error)
{
	ni_bonding_t *bond;
	ni_dbus_variant_t *var;
	unsigned int i;

	if (!(bond = __ni_objectmodel_bonding_write_handle(object, error)))
		return FALSE;

	if (!ni_dbus_variant_is_dict_array(result)) {
		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
				"%s.%s property - expected dict array",
				object->path, property->name);
		return FALSE;
	}

	ni_string_free(&bond->primary_slave);
	ni_string_free(&bond->active_slave);
	ni_string_array_destroy(&bond->slave_names);
	for (i = 0, var = result->variant_array_value; i < result->array.len; ++i, ++var) {
		dbus_bool_t is_primary = FALSE;
		dbus_bool_t is_active = FALSE;
		const char *slave_name;

		if (!ni_dbus_dict_get_string(var, "device", &slave_name)) {
			dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
					"%s.%s property - missing device attribute",
					object->path, property->name);
			return FALSE;
		}
		if (ni_string_array_index(&bond->slave_names, slave_name) != -1) {
			dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
				"%s.%s property - duplicate slave devices",
				object->path, property->name);
			return FALSE;
		}

		if (ni_dbus_dict_get_bool(var, "primary", &is_primary) && is_primary) {
			if (bond->primary_slave) {
				dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
					"%s.%s property - duplicate primary device",
					object->path, property->name);
				return FALSE;
			}
			ni_string_dup(&bond->primary_slave, slave_name);
		}
		if (ni_dbus_dict_get_bool(var, "active", &is_active) && is_active) {
			if (bond->active_slave) {
				dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
					"%s.%s property - duplicate active device",
					object->path, property->name);
				return FALSE;
			}
			ni_string_dup(&bond->active_slave, slave_name);
		}

		ni_string_array_append(&bond->slave_names, slave_name);
	}
	return TRUE;
}
예제 #8
0
static dbus_bool_t
fill_group_info (DBusGroupInfo    *info,
                 dbus_gid_t        gid,
                 const DBusString *groupname,
                 DBusError        *error)
{
  const char *group_c_str;

  _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
  _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);

  if (groupname)
    group_c_str = _dbus_string_get_const_data (groupname);
  else
    group_c_str = NULL;
  
  /* For now assuming that the getgrnam() and getgrgid() flavors
   * always correspond to the pwnam flavors, if not we have
   * to add more configure checks.
   */
  
#if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
  {
    struct group *g;
    int result;
    size_t buflen;
    char *buf;
    struct group g_str;
    dbus_bool_t b;

    /* retrieve maximum needed size for buf */
    buflen = sysconf (_SC_GETGR_R_SIZE_MAX);

    /* sysconf actually returns a long, but everything else expects size_t,
     * so just recast here.
     * https://bugs.freedesktop.org/show_bug.cgi?id=17061
     */
    if ((long) buflen <= 0)
      buflen = 1024;

    result = -1;
    while (1)
      {
        buf = dbus_malloc (buflen);
        if (buf == NULL)
          {
            dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
            return FALSE;
          }

        g = NULL;
#ifdef HAVE_POSIX_GETPWNAM_R
        if (group_c_str)
          result = getgrnam_r (group_c_str, &g_str, buf, buflen,
                               &g);
        else
          result = getgrgid_r (gid, &g_str, buf, buflen,
                               &g);
#else
        g = getgrnam_r (group_c_str, &g_str, buf, buflen);
        result = 0;
#endif /* !HAVE_POSIX_GETPWNAM_R */
        /* Try a bigger buffer if ERANGE was returned:
           https://bugs.freedesktop.org/show_bug.cgi?id=16727
        */
        if (result == ERANGE && buflen < 512 * 1024)
          {
            dbus_free (buf);
            buflen *= 2;
          }
        else
          {
            break;
          }
      }

    if (result == 0 && g == &g_str)
      {
        b = fill_user_info_from_group (g, info, error);
        dbus_free (buf);
        return b;
      }
    else
      {
        dbus_set_error (error, _dbus_error_from_errno (errno),
                        "Group %s unknown or failed to look it up\n",
                        group_c_str ? group_c_str : "???");
        dbus_free (buf);
        return FALSE;
      }
  }
#else /* ! HAVE_GETPWNAM_R */
  {
    /* I guess we're screwed on thread safety here */
    struct group *g;

    g = getgrnam (group_c_str);

    if (g != NULL)
      {
        return fill_user_info_from_group (g, info, error);
      }
    else
      {
        dbus_set_error (error, _dbus_error_from_errno (errno),
                        "Group %s unknown or failed to look it up\n",
                        group_c_str ? group_c_str : "???");
        return FALSE;
      }
  }
#endif  /* ! HAVE_GETPWNAM_R */
}
예제 #9
0
/**
 * Creates a new server listening on the given Unix domain socket.
 *
 * @param path the path for the domain socket.
 * @param abstract #TRUE to use abstract socket namespace
 * @param error location to store reason for failure.
 * @returns the new server, or #NULL on failure.
 */
DBusServer*
_dbus_server_new_for_domain_socket (const char     *path,
                                    dbus_bool_t     abstract,
                                    DBusError      *error)
{
  DBusServer *server;
  int listen_fd;
  DBusString address;
  char *path_copy;
  DBusString path_str;
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  if (!_dbus_string_init (&address))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  _dbus_string_init_const (&path_str, path);
  if ((abstract &&
       !_dbus_string_append (&address, "unix:abstract=")) ||
      (!abstract &&
       !_dbus_string_append (&address, "unix:path=")) ||
      !_dbus_address_append_escaped (&address, &path_str))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_0;
    }

  path_copy = _dbus_strdup (path);
  if (path_copy == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_0;
    }
  
  listen_fd = _dbus_listen_unix_socket (path, abstract, error);

  if (listen_fd < 0)
    {
      _DBUS_ASSERT_ERROR_IS_SET (error);
      goto failed_1;
    }
  
  server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0);
  if (server == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto failed_2;
    }

  _dbus_server_socket_own_filename(server, path_copy);
  
  _dbus_string_free (&address);
  
  return server;

 failed_2:
  _dbus_close_socket (listen_fd, NULL);
 failed_1:
  dbus_free (path_copy);
 failed_0:
  _dbus_string_free (&address);

  return NULL;
}
/**
 * Creates the client-side transport for
 * a debug-pipe connection connected to the
 * given debug-pipe server name.
 * 
 * @param server_name name of server to connect to
 * @param error address where an error can be returned.
 * @returns #NULL on no memory or transport
 */
DBusTransport*
_dbus_transport_debug_pipe_new (const char     *server_name,
                                DBusError      *error)
{
  DBusTransport *client_transport;
  DBusTransport *server_transport;
  DBusConnection *connection;
  int client_fd, server_fd;
  DBusServer *server;
  DBusString address;
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  if (server_pipe_hash == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL);
      return NULL;
    }
  
  server = _dbus_hash_table_lookup_string (server_pipe_hash,
                                           server_name);
  if (server == NULL ||
      ((DBusServerDebugPipe*)server)->disconnected)
    {
      dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL);
      return NULL;
    }

  if (!_dbus_string_init (&address))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  if (!_dbus_string_append (&address, "debug-pipe:name=") ||
      !_dbus_string_append (&address, server_name))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      _dbus_string_free (&address);
      return NULL;
    }
  
  if (!_dbus_full_duplex_pipe (&client_fd, &server_fd, FALSE,
                               NULL))
    {
      _dbus_verbose ("failed to create full duplex pipe\n");
      dbus_set_error (error, DBUS_ERROR_FAILED, "Could not create full-duplex pipe");
      _dbus_string_free (&address);
      return NULL;
    }

  client_transport = _dbus_transport_new_for_socket (client_fd,
                                                     NULL, &address);
  if (client_transport == NULL)
    {
      _dbus_close_socket (client_fd, NULL);
      _dbus_close_socket (server_fd, NULL);
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      _dbus_string_free (&address);
      return NULL;
    }

  _dbus_string_free (&address);
  
  client_fd = -1;

  server_transport = _dbus_transport_new_for_socket (server_fd,
                                                     &server->guid_hex, NULL);
  if (server_transport == NULL)
    {
      _dbus_transport_unref (client_transport);
      _dbus_close_socket (server_fd, NULL);
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  server_fd = -1;

  if (!_dbus_transport_set_auth_mechanisms (server_transport,
                                            (const char**) server->auth_mechanisms))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      _dbus_transport_unref (server_transport);
      _dbus_transport_unref (client_transport);
      return NULL;
    }
  
  connection = _dbus_connection_new_for_transport (server_transport);
  _dbus_transport_unref (server_transport);
  server_transport = NULL;
  
  if (connection == NULL)
    {
      _dbus_transport_unref (client_transport);
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return NULL;
    }

  /* See if someone wants to handle this new connection,
   * self-referencing for paranoia
   */
  if (server->new_connection_function)
    {
      dbus_server_ref (server);
      (* server->new_connection_function) (server, connection,
                                           server->new_connection_data);
      dbus_server_unref (server);
    }
  
  /* If no one grabbed a reference, the connection will die,
   * and the client transport will get an immediate disconnect
   */
  _dbus_connection_close_if_only_one_ref (connection);
  dbus_connection_unref (connection);

  return client_transport;
}
예제 #11
0
/**
 * Get a printable string describing the command used to execute
 * the process with pid.  This string should only be used for
 * informative purposes such as logging; it may not be trusted.
 * 
 * The command is guaranteed to be printable ASCII and no longer
 * than max_len.
 * 
 * @param pid Process id
 * @param str Append command to this string
 * @param max_len Maximum length of returned command
 * @param error return location for errors
 * @returns #FALSE on error
 */
dbus_bool_t 
_dbus_command_for_pid (unsigned long  pid,
                       DBusString    *str,
                       int            max_len,
                       DBusError     *error)
{
  /* This is all Linux-specific for now */
  DBusString path;
  DBusString cmdline;
  int fd;
  
  if (!_dbus_string_init (&path)) 
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  if (!_dbus_string_init (&cmdline))
    {
      _DBUS_SET_OOM (error);
      _dbus_string_free (&path);
      return FALSE;
    }
  
  if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid))
    goto oom;
  
  fd = open (_dbus_string_get_const_data (&path), O_RDONLY);
  if (fd < 0) 
    {
      dbus_set_error (error,
                      _dbus_error_from_errno (errno),
                      "Failed to open \"%s\": %s",
                      _dbus_string_get_const_data (&path),
                      _dbus_strerror (errno));
      goto fail;
    }
  
  if (!_dbus_read (fd, &cmdline, max_len))
    {
      dbus_set_error (error,
                      _dbus_error_from_errno (errno),
                      "Failed to read from \"%s\": %s",
                      _dbus_string_get_const_data (&path),
                      _dbus_strerror (errno));      
      goto fail;
    }
  
  if (!_dbus_close (fd, error))
    goto fail;
  
  string_squash_nonprintable (&cmdline);  

  if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
    goto oom;

  _dbus_string_free (&cmdline);  
  _dbus_string_free (&path);
  return TRUE;
oom:
  _DBUS_SET_OOM (error);
fail:
  _dbus_string_free (&cmdline);
  _dbus_string_free (&path);
  return FALSE;
}
/**
 * Creates a new debug server using an in-process pipe
 *
 * @param server_name the name of the server.
 * @param error address where an error can be returned.
 * @returns a new server, or #NULL on failure.
 */
DBusServer*
_dbus_server_debug_pipe_new (const char     *server_name,
                             DBusError      *error)
{
  DBusServerDebugPipe *debug_server;
  DBusString address;
  DBusString name_str;
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  if (!pipe_hash_ref ())
    return NULL;
  
  if (_dbus_hash_table_lookup_string (server_pipe_hash, server_name) != NULL)
    {
      dbus_set_error (error, DBUS_ERROR_ADDRESS_IN_USE, NULL);
      pipe_hash_unref ();
      return NULL;
    }
  
  debug_server = dbus_new0 (DBusServerDebugPipe, 1);
  if (debug_server == NULL)
    goto nomem_0;

  if (!_dbus_string_init (&address))
    goto nomem_1;

  _dbus_string_init_const (&name_str, server_name);
  if (!_dbus_string_append (&address, "debug-pipe:name=") ||
      !_dbus_address_append_escaped (&address, &name_str))
    goto nomem_2;
  
  debug_server->name = _dbus_strdup (server_name);
  if (debug_server->name == NULL)
    goto nomem_2;
  
  if (!_dbus_server_init_base (&debug_server->base,
			       &debug_vtable, &address))
    goto nomem_3;

  if (!_dbus_hash_table_insert_string (server_pipe_hash,
				       debug_server->name,
				       debug_server))
    goto nomem_4;

  _dbus_string_free (&address);

  /* server keeps the pipe hash ref */

  _dbus_server_trace_ref (&debug_server->base, 0, 1, "debug_pipe_new");
  return (DBusServer *)debug_server;

 nomem_4:
  _dbus_server_finalize_base (&debug_server->base);
 nomem_3:
  dbus_free (debug_server->name);
 nomem_2:
  _dbus_string_free (&address);
 nomem_1:
  dbus_free (debug_server);
 nomem_0:
  pipe_hash_unref ();
  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  return NULL;
}
예제 #13
0
파일: tuntap.c 프로젝트: mijos/wicked
/*
 * Create a new TUN/TAP interface
 */
static ni_netdev_t *
__ni_objectmodel_tuntap_create(ni_netdev_t *cfg, DBusError *error)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *dev = NULL;
	const char *iftype;
	const ni_tuntap_t *tuntap;
	const char *err;
	int rv;

	iftype = ni_linktype_type_to_name(cfg->link.type);
	if (cfg->link.type != NI_IFTYPE_TUN && cfg->link.type != NI_IFTYPE_TAP) {
		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
			"BUG: Cannot handle %s type in tun/tap factory", iftype);
		return NULL;
	}

	ni_debug_dbus("%s.newDevice(name=%s)", iftype, cfg->name);
	tuntap = ni_netdev_get_tuntap(cfg);
	if ((err = ni_tuntap_validate(tuntap))) {
		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err);
		return NULL;
	}

	if (ni_string_empty(cfg->name)) {
		if (ni_string_empty(cfg->name) &&
		    (cfg->name = (char *) ni_netdev_make_name(nc, iftype, 0))) {
			ni_string_dup(&cfg->name, cfg->name);
		} else {
			dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
				"Unable to create %s interface: "
				"name argument missed", iftype);
			return NULL;
		}
		cfg->name = NULL;
	} else if(!ni_string_eq(cfg->name, cfg->name)) {
		ni_string_dup(&cfg->name, cfg->name);
	}

	if (cfg->link.type == NI_IFTYPE_TAP && cfg->link.hwaddr.len) {
		if (cfg->link.hwaddr.type == ARPHRD_VOID)
			cfg->link.hwaddr.type = ARPHRD_ETHER;

		if (cfg->link.hwaddr.type != ARPHRD_ETHER
		||  cfg->link.hwaddr.len != ni_link_address_length(ARPHRD_ETHER)) {
			dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
					"Cannot create %s interface: "
					"invalid ethernet address '%s'", iftype,
					ni_link_address_print(&cfg->link.hwaddr));
			return NULL;
		}
	}

	if ((rv = ni_system_tuntap_create(nc, cfg, &dev)) < 0) {
		if (rv != -NI_ERROR_DEVICE_EXISTS || dev == NULL
		|| (cfg->name && dev && !ni_string_eq(dev->name, cfg->name))) {
			ni_dbus_set_error_from_code(error, rv,
				"Unable to create %s interface %s",
				iftype, cfg->name);
			return NULL;
		}
		ni_debug_dbus("%s interface exists (and name matches)", iftype);
	}

	if (dev->link.type != cfg->link.type) {
		dbus_set_error(error,
			DBUS_ERROR_FAILED,
			"Unable to create %s: existing interface %s is of type %s",
			iftype, dev->name, ni_linktype_type_to_name(dev->link.type));
		return NULL;
	}

	return dev;
}
예제 #14
0
파일: tuntap.c 프로젝트: mijos/wicked
static dbus_bool_t
ni_objectmodel_tuntap_change(ni_dbus_object_t *object, const ni_dbus_method_t *method,
				unsigned int argc, const ni_dbus_variant_t *argv,
				ni_dbus_message_t *reply, DBusError *error)
{
	ni_netconfig_t *nc = ni_global_state_handle(0);
	ni_netdev_t *dev, *cfg;
	ni_tuntap_t *tuntap;
	const char *err;
	const char *iftype_name;

	/* we've already checked that argv matches our signature */
	ni_assert(argc == 1);

	if (!(dev = ni_objectmodel_unwrap_netif(object, error)) ||
	    !(cfg = __ni_objectmodel_tuntap_device_arg(&argv[0], dev->link.type)) ||
	    !(ni_netdev_get_tuntap(dev))) {
		ni_dbus_error_invalid_args(error, object->path, method->name);
		return FALSE;
	}

	/* changeDevice method is only needed in case of TAP devices */
	if (dev->link.type != NI_IFTYPE_TAP)
		return TRUE;

	iftype_name = ni_linktype_type_to_name(dev->link.type);

	tuntap = ni_netdev_get_tuntap(cfg);
	if ((err = ni_tuntap_validate(tuntap))) {
		dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err);
		return FALSE;
	}

	cfg->link.ifindex = dev->link.ifindex;
	if (ni_string_empty(cfg->name))
		ni_string_dup(&cfg->name, dev->name);

	if (ni_netdev_device_is_up(dev)) {
		ni_debug_objectmodel("Skipping %s changeDevice call on %s: "
				"device is up", iftype_name, dev->name);
		return TRUE;
	}

	if (ni_system_tap_change(nc, dev, cfg) < 0) {
		dbus_set_error(error,
				DBUS_ERROR_FAILED,
				"Unable to change %s properties on interface %s",
				iftype_name, dev->name);
		return FALSE;
	}

	if (cfg->link.hwaddr.type == ARPHRD_VOID)
		cfg->link.hwaddr.type = ARPHRD_ETHER;
	if (ni_system_hwaddr_change(nc, dev, &cfg->link.hwaddr) < 0) {
		ni_error("Unable to change hwaddr on %s interface %s",
				iftype_name, dev->name);
		/* fail? */
	}

	return TRUE;
}
예제 #15
0
/**
 * Looks up a uid or username in the user database.  Only one of name
 * or UID can be provided. There are wrapper functions for this that
 * are better to use, this one does no locking or anything on the
 * database and otherwise sort of sucks.
 *
 * @param db the database
 * @param uid the user ID or #DBUS_UID_UNSET
 * @param username username or #NULL 
 * @param error error to fill in
 * @returns the entry in the database
 */
DBusUserInfo*
_dbus_user_database_lookup (DBusUserDatabase *db,
                            dbus_uid_t        uid,
                            const DBusString *username,
                            DBusError        *error)
{
  DBusUserInfo *info;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);

  /* See if the username is really a number */
  if (uid == DBUS_UID_UNSET)
    {
      unsigned long n;

      if (_dbus_is_a_number (username, &n))
        uid = n;
    }

#ifdef DBUS_ENABLE_USERDB_CACHE  
  if (uid != DBUS_UID_UNSET)
    info = _dbus_hash_table_lookup_ulong (db->users, uid);
  else
    info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));

  if (info)
    {
      _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
                     info->uid);
      return info;
    }
  else
#else 
  if (1)
#endif
    {
      if (uid != DBUS_UID_UNSET)
	_dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
		       uid);
      else
	_dbus_verbose ("No cache for user \"%s\"\n",
		       _dbus_string_get_const_data (username));
      
      info = dbus_new0 (DBusUserInfo, 1);
      if (info == NULL)
        {
          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
          return NULL;
        }

      if (uid != DBUS_UID_UNSET)
        {
          if (!_dbus_user_info_fill_uid (info, uid, error))
            {
              _DBUS_ASSERT_ERROR_IS_SET (error);
              _dbus_user_info_free_allocated (info);
              return NULL;
            }
        }
      else
        {
          if (!_dbus_user_info_fill (info, username, error))
            {
              _DBUS_ASSERT_ERROR_IS_SET (error);
              _dbus_user_info_free_allocated (info);
              return NULL;
            }
        }

      /* be sure we don't use these after here */
      uid = DBUS_UID_UNSET;
      username = NULL;

      /* insert into hash */
      if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info))
        {
          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
          _dbus_user_info_free_allocated (info);
          return NULL;
        }

      if (!_dbus_hash_table_insert_string (db->users_by_name,
                                           info->username,
                                           info))
        {
          _dbus_hash_table_remove_ulong (db->users, info->uid);
          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
          return NULL;
        }
      
      return info;
    }
}
예제 #16
0
/**
 * Tries to interpret the address entry in a platform-specific
 * way, creating a platform-specific server type if appropriate.
 * Sets error if the result is not OK.
 * 
 * @param entry an address entry
 * @param server_p location to store a new DBusServer, or #NULL on failure.
 * @param error location to store rationale for failure on bad address
 * @returns the outcome
 * 
 */
DBusServerListenResult
_dbus_server_listen_platform_specific (DBusAddressEntry *entry,
                                       DBusServer      **server_p,
                                       DBusError        *error)
{
  const char *method;

  *server_p = NULL;
  
  method = dbus_address_entry_get_method (entry);

  if (strcmp (method, "unix") == 0)
    {
      const char *path = dbus_address_entry_get_value (entry, "path");
      const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
      const char *abstract = dbus_address_entry_get_value (entry, "abstract");
          
      if (path == NULL && tmpdir == NULL && abstract == NULL)
        {
          _dbus_set_bad_address(error, "unix",
                                "path or tmpdir or abstract",
                                NULL);
          return DBUS_SERVER_LISTEN_BAD_ADDRESS;
        }

      if ((path && tmpdir) ||
          (path && abstract) ||
          (tmpdir && abstract))
        {
          _dbus_set_bad_address(error, NULL, NULL,
                                "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time");
          return DBUS_SERVER_LISTEN_BAD_ADDRESS;
        }

      if (tmpdir != NULL)
        {
          DBusString full_path;
          DBusString filename;
              
          if (!_dbus_string_init (&full_path))
            {
              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
              return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
            }
                  
          if (!_dbus_string_init (&filename))
            {
              _dbus_string_free (&full_path);
              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
              return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
            }
              
          if (!_dbus_string_append (&filename,
                                    "dbus-") ||
              !_dbus_generate_random_ascii (&filename, 10) ||
              !_dbus_string_append (&full_path, tmpdir) ||
              !_dbus_concat_dir_and_file (&full_path, &filename))
            {
              _dbus_string_free (&full_path);
              _dbus_string_free (&filename);
              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
              return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
            }
              
          /* Always use abstract namespace if possible with tmpdir */
              
          *server_p =
            _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
#ifdef HAVE_ABSTRACT_SOCKETS
                                                TRUE,
#else
                                                FALSE,
#endif
                                                error);

          _dbus_string_free (&full_path);
          _dbus_string_free (&filename);
        }
      else
        {
          if (path)
            *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error);
          else
            *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
        }

      if (*server_p != NULL)
        {
          _DBUS_ASSERT_ERROR_IS_CLEAR(error);
          return DBUS_SERVER_LISTEN_OK;
        }
      else
        {
          _DBUS_ASSERT_ERROR_IS_SET(error);
          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
        }
    }
  else
    {
      /* If we don't handle the method, we return NULL with the
       * error unset
       */
      _DBUS_ASSERT_ERROR_IS_CLEAR(error);
      return DBUS_SERVER_LISTEN_NOT_HANDLED;
    }
}
예제 #17
0
/* This code only gets executed the first time the
 * config files are parsed.  It is not executed
 * when config files are reloaded.
 */
static dbus_bool_t
process_config_first_time_only (BusContext      *context,
				BusConfigParser *parser,
				DBusError       *error)
{
  DBusString log_prefix;
  DBusList *link;
  DBusList **addresses;
  const char *user, *pidfile;
  char **auth_mechanisms;
  DBusList **auth_mechanisms_list;
  int len;
  dbus_bool_t retval;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  retval = FALSE;
  auth_mechanisms = NULL;

  /* Check for an existing pid file. Of course this is a race;
   * we'd have to use fcntl() locks on the pid file to
   * avoid that. But we want to check for the pid file
   * before overwriting any existing sockets, etc.
   */
  pidfile = bus_config_parser_get_pidfile (parser);
  if (pidfile != NULL)
    {
      DBusString u;
      DBusStat stbuf;
      
      _dbus_string_init_const (&u, pidfile);

      if (_dbus_stat (&u, &stbuf, NULL))
        {
          dbus_set_error (error, DBUS_ERROR_FAILED,
		                  "The pid file \"%s\" exists, if the message bus is not running, remove this file",
                          pidfile);
	      goto failed;
        }
    }

  /* keep around the pid filename so we can delete it later */
  context->pidfile = _dbus_strdup (pidfile);

  /* note that type may be NULL */
  context->type = _dbus_strdup (bus_config_parser_get_type (parser));
  if (bus_config_parser_get_type (parser) != NULL && context->type == NULL)
    goto oom;

  user = bus_config_parser_get_user (parser);
  if (user != NULL)
    {
      context->user = _dbus_strdup (user);
      if (context->user == NULL)
        goto oom;
    }

  /* Set up the prefix for syslog messages */
  if (!_dbus_string_init (&log_prefix))
    goto oom;
  if (context->type && !strcmp (context->type, "system"))
    {
      if (!_dbus_string_append (&log_prefix, "[system] "))
        goto oom;
    }
  else if (context->type && !strcmp (context->type, "session"))
    {
      DBusCredentials *credentials;

      credentials = _dbus_credentials_new_from_current_process ();
      if (!credentials)
        goto oom;
      if (!_dbus_string_append (&log_prefix, "[session "))
        goto oom;
      if (!_dbus_credentials_to_string_append (credentials, &log_prefix))
        goto oom;
      if (!_dbus_string_append (&log_prefix, "] "))
        goto oom;
      _dbus_credentials_unref (credentials);
    }
  if (!_dbus_string_steal_data (&log_prefix, &context->log_prefix))
    goto oom;
  _dbus_string_free (&log_prefix);

  /* Build an array of auth mechanisms */

  auth_mechanisms_list = bus_config_parser_get_mechanisms (parser);
  len = _dbus_list_get_length (auth_mechanisms_list);

  if (len > 0)
    {
      int i;

      auth_mechanisms = dbus_new0 (char*, len + 1);
      if (auth_mechanisms == NULL)
        goto oom;

      i = 0;
      link = _dbus_list_get_first_link (auth_mechanisms_list);
      while (link != NULL)
        {
          auth_mechanisms[i] = _dbus_strdup (link->data);
          if (auth_mechanisms[i] == NULL)
            goto oom;
          link = _dbus_list_get_next_link (auth_mechanisms_list, link);
        }
    }
예제 #18
0
파일: apparmor.c 프로젝트: d-bus/dbus
/**
 * Check if Apparmor security controls allow the connection to eavesdrop on
 * other connections.
 *
 * @param connection the connection attempting to eavesdrop.
 * @param bustype name of the bus
 * @param error the reason for failure when FALSE is returned
 * @returns TRUE if eavesdropping is permitted
 */
dbus_bool_t
bus_apparmor_allows_eavesdropping (DBusConnection     *connection,
                                   const char         *bustype,
                                   DBusError          *error)
{
#ifdef HAVE_APPARMOR
  BusAppArmorConfinement *con = NULL;
  DBusString qstr, auxdata;
  int allow = FALSE, audit = TRUE;
  dbus_bool_t free_auxdata = FALSE;
  unsigned long pid;
  int res, serrno = 0;

  if (!apparmor_enabled)
    return TRUE;

  con = bus_connection_dup_apparmor_confinement (connection);

  if (is_unconfined (con->label, con->mode))
    {
      allow = TRUE;
      audit = FALSE;
      goto out;
    }

  if (!_dbus_string_init (&qstr))
    goto oom;

  if (!build_eavesdrop_query (&qstr, con->label, bustype))
    {
      _dbus_string_free (&qstr);
      goto oom;
    }

  res = aa_query_label (AA_DBUS_EAVESDROP,
                        _dbus_string_get_data (&qstr),
                        _dbus_string_get_length (&qstr),
                        &allow, &audit);
  _dbus_string_free (&qstr);
  if (res == -1)
    {
      serrno = errno;
      set_error_from_query_errno (error, serrno);
      goto audit;
    }

  /* Don't fail operations on profiles in complain mode */
  if (modestr_is_complain (con->mode))
    allow = TRUE;

  if (!allow)
    dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
                    "Connection \"%s\" is not allowed to eavesdrop due to "
                    "AppArmor policy",
                    bus_connection_is_active (connection) ?
                    bus_connection_get_name (connection) : "(inactive)");

  if (!audit)
    goto out;

 audit:
  if (!_dbus_string_init (&auxdata))
    goto oom;
  free_auxdata = TRUE;

  if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
    goto oom;

  if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
    goto oom;

  if (!_dbus_append_pair_str (&auxdata, "mask", "eavesdrop"))
    goto oom;

  if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
      !_dbus_append_pair_uint (&auxdata, "pid", pid))
    goto oom;

  if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
    goto oom;

  log_message (allow, "eavesdrop", &auxdata);

 out:
  if (con != NULL)
    bus_apparmor_confinement_unref (con);
  if (free_auxdata)
    _dbus_string_free (&auxdata);

  return allow;

 oom:
  if (error != NULL && !dbus_error_is_set (error))
    BUS_SET_OOM (error);
  allow = FALSE;
  goto out;

#else
  return TRUE;
#endif /* HAVE_APPARMOR */
}
예제 #19
0
/**
 * Writes a string out to a file. If the file exists,
 * it will be atomically overwritten by the new data.
 *
 * @param str the string to write out
 * @param filename the file to save string to
 * @param world_readable if true, ensure file is world readable
 * @param error error to be filled in on failure
 * @returns #FALSE on failure
 */
dbus_bool_t
_dbus_string_save_to_file (const DBusString *str,
                           const DBusString *filename,
                           dbus_bool_t       world_readable,
                           DBusError        *error)
{
  HANDLE hnd;
  int bytes_to_write;
  const char *filename_c;
  DBusString tmp_filename;
  const char *tmp_filename_c;
  int total;
  const char *str_c;
  dbus_bool_t need_unlink;
  dbus_bool_t retval;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  hnd = INVALID_HANDLE_VALUE;
  retval = FALSE;
  need_unlink = FALSE;

  if (!_dbus_string_init (&tmp_filename))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return FALSE;
    }

  if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      _dbus_string_free (&tmp_filename);
      return FALSE;
    }

  if (!_dbus_string_append (&tmp_filename, "."))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      _dbus_string_free (&tmp_filename);
      return FALSE;
    }

#define N_TMP_FILENAME_RANDOM_BYTES 8
  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      _dbus_string_free (&tmp_filename);
      return FALSE;
    }

  filename_c = _dbus_string_get_const_data (filename);
  tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);

  /* TODO - support world-readable in an atomic fashion */
  hnd = CreateFileA (tmp_filename_c, GENERIC_WRITE,
                     FILE_SHARE_READ | FILE_SHARE_WRITE,
                     NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,
                     INVALID_HANDLE_VALUE);
  if (hnd == INVALID_HANDLE_VALUE)
    {
      char *emsg = _dbus_win_error_string (GetLastError ());
      dbus_set_error (error, _dbus_win_error_from_last_error (),
                       "Could not create \"%s\": %s", filename_c, emsg);
      _dbus_win_free_error_string (emsg);
      goto out;
    }
  if (world_readable)
    {
      if (! _dbus_make_file_world_readable (&tmp_filename, error))
        goto out;
    }

  _dbus_verbose ("tmp file %s hnd %p opened\n", tmp_filename_c, hnd);

  need_unlink = TRUE;

  total = 0;
  bytes_to_write = _dbus_string_get_length (str);
  str_c = _dbus_string_get_const_data (str);

  while (total < bytes_to_write)
    {
      DWORD bytes_written;
      BOOL res;

      res = WriteFile (hnd, str_c + total, bytes_to_write - total,
                       &bytes_written, NULL);

      if (res == 0 || bytes_written <= 0)
        {
          char *emsg = _dbus_win_error_string (GetLastError ());
          dbus_set_error (error, _dbus_win_error_from_last_error (),
                           "Could not write to %s: %s", tmp_filename_c, emsg);
          _dbus_win_free_error_string (emsg);
          goto out;
        }

      total += bytes_written;
    }

  if (CloseHandle (hnd) == 0)
    {
      char *emsg = _dbus_win_error_string (GetLastError ());
      dbus_set_error (error, _dbus_win_error_from_last_error (),
                       "Could not close file %s: %s", tmp_filename_c, emsg);
      _dbus_win_free_error_string (emsg);
      goto out;
    }

  hnd = INVALID_HANDLE_VALUE;

  /* Unlike rename(), MoveFileEx() can replace existing files */
  if (!MoveFileExA (tmp_filename_c, filename_c, MOVEFILE_REPLACE_EXISTING))
    {
      char *emsg = _dbus_win_error_string (GetLastError ());
      dbus_set_error (error, _dbus_win_error_from_last_error (),
                       "Could not rename %s to %s: %s",
                       tmp_filename_c, filename_c, emsg);
      _dbus_win_free_error_string (emsg);

      goto out;
    }

  need_unlink = FALSE;

  retval = TRUE;

 out:
  /* close first, then unlink */

  if (hnd != INVALID_HANDLE_VALUE)
    CloseHandle (hnd);

  if (need_unlink && DeleteFileA (tmp_filename_c) == 0)
    {
      char *emsg = _dbus_win_error_string (GetLastError ());
      _dbus_verbose ("Failed to unlink temp file %s: %s", tmp_filename_c,
                     emsg);
      _dbus_win_free_error_string (emsg);
    }

  _dbus_string_free (&tmp_filename);

  if (!retval)
    _DBUS_ASSERT_ERROR_IS_SET (error);

  return retval;
}
예제 #20
0
파일: apparmor.c 프로젝트: d-bus/dbus
/**
 * Returns true if the given connection can acquire a service,
 * using the tasks security context
 *
 * @param connection connection that wants to own the service
 * @param bustype name of the bus
 * @param service_name the name of the service to acquire
 * @param error the reason for failure when FALSE is returned
 * @returns TRUE if acquire is permitted
 */
dbus_bool_t
bus_apparmor_allows_acquire_service (DBusConnection     *connection,
                                     const char         *bustype,
                                     const char         *service_name,
                                     DBusError          *error)
{

#ifdef HAVE_APPARMOR
  BusAppArmorConfinement *con = NULL;
  DBusString qstr, auxdata;
  dbus_bool_t free_auxdata = FALSE;
  /* the AppArmor API uses pointers to int for pointers to boolean, and
   * int is not strictly guaranteed to be the same as dbus_bool_t */
  int allow = FALSE, audit = TRUE;
  unsigned long pid;
  int res, serrno = 0;

  if (!apparmor_enabled)
    return TRUE;

  _dbus_assert (connection != NULL);

  con = bus_connection_dup_apparmor_confinement (connection);

  if (is_unconfined (con->label, con->mode))
    {
      allow = TRUE;
      audit = FALSE;
      goto out;
    }

  if (!_dbus_string_init (&qstr))
    goto oom;

  if (!build_service_query (&qstr, con->label, bustype, service_name))
    {
      _dbus_string_free (&qstr);
      goto oom;
    }

  res = aa_query_label (AA_DBUS_BIND,
                        _dbus_string_get_data (&qstr),
                        _dbus_string_get_length (&qstr),
                        &allow, &audit);
  _dbus_string_free (&qstr);
  if (res == -1)
    {
      serrno = errno;
      set_error_from_query_errno (error, serrno);
      goto audit;
    }

  /* Don't fail operations on profiles in complain mode */
  if (modestr_is_complain (con->mode))
      allow = TRUE;

  if (!allow)
    dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
                    "Connection \"%s\" is not allowed to own the service "
                    "\"%s\" due to AppArmor policy",
                    bus_connection_is_active (connection) ?
                     bus_connection_get_name (connection) : "(inactive)",
                    service_name);

  if (!audit)
    goto out;

 audit:
  if (!_dbus_string_init (&auxdata))
    goto oom;
  free_auxdata = TRUE;

  if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
    goto oom;

  if (!_dbus_append_pair_str (&auxdata, "name", service_name))
    goto oom;

  if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
    goto oom;

  if (!_dbus_append_mask (&auxdata, AA_DBUS_BIND))
    goto oom;

  if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
      !_dbus_append_pair_uint (&auxdata, "pid", pid))
    goto oom;

  if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
    goto oom;

  log_message (allow, "bind", &auxdata);

 out:
  if (con != NULL)
    bus_apparmor_confinement_unref (con);
  if (free_auxdata)
    _dbus_string_free (&auxdata);
  return allow;

 oom:
  if (error != NULL && !dbus_error_is_set (error))
    BUS_SET_OOM (error);
  allow = FALSE;
  goto out;

#else
  return TRUE;
#endif /* HAVE_APPARMOR */
}
예제 #21
0
/**
 * Spawns a new process. The child_setup
 * function is passed the given user_data and is run in the child
 * just before calling exec().
 *
 * Also creates a "babysitter" which tracks the status of the
 * child process, advising the parent if the child exits.
 * If the spawn fails, no babysitter is created.
 * If sitter_p is #NULL, no babysitter is kept.
 *
 * @param sitter_p return location for babysitter or #NULL
 * @param log_name the name under which to log messages about this process being spawned
 * @param argv the executable and arguments
 * @param env the environment, or #NULL to copy the parent's
 * @param child_setup function to call in child pre-exec()
 * @param user_data user data for setup function
 * @param error error object to be filled in if function fails
 * @returns #TRUE on success, #FALSE if error is filled in
 */
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
                                   const char               *log_name,
                                   char                    **argv,
                                   char                    **env,
                                   DBusSpawnChildSetupFunc   child_setup,
                                   void                     *user_data,
                                   DBusError                *error)
{
  DBusBabysitter *sitter;
  int child_err_report_pipe[2] = { -1, -1 };
  DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT };
  pid_t pid;
#ifdef HAVE_SYSTEMD
  int fd_out = -1;
  int fd_err = -1;
#endif
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  _dbus_assert (argv[0] != NULL);

  if (sitter_p != NULL)
    *sitter_p = NULL;

  sitter = NULL;

  sitter = _dbus_babysitter_new ();
  if (sitter == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return FALSE;
    }

  sitter->log_name = _dbus_strdup (log_name);
  if (sitter->log_name == NULL && log_name != NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  if (sitter->log_name == NULL)
    sitter->log_name = _dbus_strdup (argv[0]);

  if (sitter->log_name == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
  
  if (!make_pipe (child_err_report_pipe, error))
    goto cleanup_and_fail;

  if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
    goto cleanup_and_fail;

  /* Setting up the babysitter is only useful in the parent,
   * but we don't want to run out of memory and fail
   * after we've already forked, since then we'd leak
   * child processes everywhere.
   */
  sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
                                         DBUS_WATCH_READABLE,
                                         TRUE, handle_watch, sitter, NULL);
  if (sitter->error_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
        
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
    {
      /* we need to free it early so the destructor won't try to remove it
       * without it having been added, which DBusLoop doesn't allow */
      _dbus_watch_invalidate (sitter->error_watch);
      _dbus_watch_unref (sitter->error_watch);
      sitter->error_watch = NULL;

      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd,
                                          DBUS_WATCH_READABLE,
                                          TRUE, handle_watch, sitter, NULL);
  if (sitter->sitter_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
      /* we need to free it early so the destructor won't try to remove it
       * without it having been added, which DBusLoop doesn't allow */
      _dbus_watch_invalidate (sitter->sitter_watch);
      _dbus_watch_unref (sitter->sitter_watch);
      sitter->sitter_watch = NULL;

      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

#ifdef HAVE_SYSTEMD
  /* This may fail, but it's not critical.
   * In particular, if we were compiled with journald support but are now
   * running on a non-systemd system, this is going to fail, so we
   * have to cope gracefully. */
  fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE);
  fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE);
#endif

  pid = fork ();
  
  if (pid < 0)
    {
      dbus_set_error (error,
		      DBUS_ERROR_SPAWN_FORK_FAILED,
		      "Failed to fork (%s)",
		      _dbus_strerror (errno));
      goto cleanup_and_fail;
    }
  else if (pid == 0)
    {
      /* Immediate child, this is the babysitter process. */
      int grandchild_pid;
      
      /* Be sure we crash if the parent exits
       * and we write to the err_report_pipe
       */
      signal (SIGPIPE, SIG_DFL);

      /* Close the parent's end of the pipes. */
      close_and_invalidate (&child_err_report_pipe[READ_END]);
      close_and_invalidate (&babysitter_pipe[0].fd);
      
      /* Create the child that will exec () */
      grandchild_pid = fork ();
      
      if (grandchild_pid < 0)
	{
	  write_err_and_exit (babysitter_pipe[1].fd,
			      CHILD_FORK_FAILED);
          _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
	}
      else if (grandchild_pid == 0)
      {
          /* Go back to ignoring SIGPIPE, since it's evil
           */
          signal (SIGPIPE, SIG_IGN);

          close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
	  /* log to systemd journal if possible */
	  if (fd_out >= 0)
            dup2 (fd_out, STDOUT_FILENO);
	  if (fd_err >= 0)
            dup2 (fd_err, STDERR_FILENO);
          close_and_invalidate (&fd_out);
          close_and_invalidate (&fd_err);
#endif
	  do_exec (child_err_report_pipe[WRITE_END],
		   argv,
		   env,
		   child_setup, user_data);
          _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
	}
      else
	{
          close_and_invalidate (&child_err_report_pipe[WRITE_END]);
#ifdef HAVE_SYSTEMD
          close_and_invalidate (&fd_out);
          close_and_invalidate (&fd_err);
#endif
          babysit (grandchild_pid, babysitter_pipe[1].fd);
          _dbus_assert_not_reached ("Got to code after babysit()");
	}
    }
  else
    {      
      /* Close the uncared-about ends of the pipes */
      close_and_invalidate (&child_err_report_pipe[WRITE_END]);
      close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
      close_and_invalidate (&fd_out);
      close_and_invalidate (&fd_err);
#endif

      sitter->socket_to_babysitter = babysitter_pipe[0];
      babysitter_pipe[0].fd = -1;
      
      sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
      child_err_report_pipe[READ_END] = -1;

      sitter->sitter_pid = pid;

      if (sitter_p != NULL)
        *sitter_p = sitter;
      else
        _dbus_babysitter_unref (sitter);

      dbus_free_string_array (env);

      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      
      return TRUE;
    }

 cleanup_and_fail:

  _DBUS_ASSERT_ERROR_IS_SET (error);
  
  close_and_invalidate (&child_err_report_pipe[READ_END]);
  close_and_invalidate (&child_err_report_pipe[WRITE_END]);
  close_and_invalidate (&babysitter_pipe[0].fd);
  close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
  close_and_invalidate (&fd_out);
  close_and_invalidate (&fd_err);
#endif

  if (sitter != NULL)
    _dbus_babysitter_unref (sitter);
  
  return FALSE;
}
예제 #22
0
EXPORT_C
#endif
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
                                   char                    **argv,
                                   DBusSpawnChildSetupFunc   child_setup,
                                   void                     *user_data,
                                   DBusError                *error)
{

#ifndef __SYMBIAN32__
  DBusBabysitter *sitter;
  int child_err_report_pipe[2] = { -1, -1 };
  int babysitter_pipe[2] = { -1, -1 };
  pid_t pid;
  
  #ifndef __SYMBIAN32__
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  *sitter_p = NULL;
  sitter = NULL;

  sitter = _dbus_babysitter_new ();
  if (sitter == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return FALSE;
    }

  sitter->executable = _dbus_strdup (argv[0]);
  if (sitter->executable == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
  
  if (!make_pipe (child_err_report_pipe, error))
    goto cleanup_and_fail;

  _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
  _dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]);

  if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
    goto cleanup_and_fail;

  _dbus_fd_set_close_on_exec (babysitter_pipe[0]);
  _dbus_fd_set_close_on_exec (babysitter_pipe[1]);

  /* Setting up the babysitter is only useful in the parent,
   * but we don't want to run out of memory and fail
   * after we've already forked, since then we'd leak
   * child processes everywhere.
   */
  sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
                                         DBUS_WATCH_READABLE,
                                         TRUE, handle_watch, sitter, NULL);
  if (sitter->error_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
        
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
                                          DBUS_WATCH_READABLE,
                                          TRUE, handle_watch, sitter, NULL);
  if (sitter->sitter_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  pid = fork ();
  
  if (pid < 0)
    {
      dbus_set_error (error,
		      DBUS_ERROR_SPAWN_FORK_FAILED,
		      "Failed to fork (%s)",
		      _dbus_strerror (errno));
      goto cleanup_and_fail;
    }
  else if (pid == 0)
    {
      /* Immediate child, this is the babysitter process. */
      int grandchild_pid;
      
      /* Be sure we crash if the parent exits
       * and we write to the err_report_pipe
       */
#ifndef __SYMBIAN32__       
      signal (SIGPIPE, SIG_DFL);
#endif      

      /* Close the parent's end of the pipes. */
      close_and_invalidate (&child_err_report_pipe[READ_END]);
      close_and_invalidate (&babysitter_pipe[0]);
      
      /* Create the child that will exec () */
      grandchild_pid = fork ();
      
      if (grandchild_pid < 0)
	{
	  write_err_and_exit (babysitter_pipe[1],
			      CHILD_FORK_FAILED);
          _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
	}
      else if (grandchild_pid == 0)
	{
	  do_exec (child_err_report_pipe[WRITE_END],
		   argv,
		   child_setup, user_data);
          _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
	}
      else
	{
          babysit (grandchild_pid, babysitter_pipe[1]);
          _dbus_assert_not_reached ("Got to code after babysit()");
	}
    }
  else
    {      
      /* Close the uncared-about ends of the pipes */
      close_and_invalidate (&child_err_report_pipe[WRITE_END]);
      close_and_invalidate (&babysitter_pipe[1]);

      sitter->socket_to_babysitter = babysitter_pipe[0];
      babysitter_pipe[0] = -1;
      
      sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
      child_err_report_pipe[READ_END] = -1;

      sitter->sitter_pid = pid;

      if (sitter_p != NULL)
        *sitter_p = sitter;
      else
        _dbus_babysitter_unref (sitter);

      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      
      return TRUE;
    }

 cleanup_and_fail:

  _DBUS_ASSERT_ERROR_IS_SET (error);
  
  close_and_invalidate (&child_err_report_pipe[READ_END]);
  close_and_invalidate (&child_err_report_pipe[WRITE_END]);
  close_and_invalidate (&babysitter_pipe[0]);
  close_and_invalidate (&babysitter_pipe[1]);

  if (sitter != NULL)
    _dbus_babysitter_unref (sitter);
  #endif
  return FALSE;
  
  
#else


/*
FILE* ChildProcessStream;
 ChildProcessStream =popen(argv[0], "r");
	if (ChildProcessStream == NULL)
	{
	 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
                      "Failed to execute service process");
     	 return FALSE;
      
	}
*/
 //static pid_t Childpid; //have to make it static for thread fuction to access it
 pid_t childPid;
 int retVal; 
 
 //pthread_t thread;

 retVal = posix_spawn(&childPid, argv[0], NULL,NULL, NULL, NULL);
  	if (retVal!=0)
	{
	 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
                      "Failed to execute service process");
     	 return FALSE;
      
	}

/*
 pthread_create(&thread, NULL, (void*)&thread_fun, &Childpid);
//(void) waitpid(Childpid, NULL, 0);
//printf("\r\n*** Child process finished ***\r\n");

*/

if(!retVal)
	return TRUE;
else
	return FALSE;

#endif  
}
예제 #23
0
파일: dbus-server.c 프로젝트: halfline/dbus
/**
 * Listens for new connections on the given address.  If there are
 * multiple semicolon-separated address entries in the address, tries
 * each one and listens on the first one that works.
 * 
 * Returns #NULL and sets error if listening fails for any reason.
 * Otherwise returns a new #DBusServer.
 * dbus_server_set_new_connection_function(),
 * dbus_server_set_watch_functions(), and
 * dbus_server_set_timeout_functions() should be called immediately to
 * render the server fully functional.
 *
 * To free the server, applications must call first
 * dbus_server_disconnect() and then dbus_server_unref().
 * 
 * @param address the address of this server.
 * @param error location to store reason for failure.
 * @returns a new #DBusServer, or #NULL on failure.
 * 
 */
DBusServer*
dbus_server_listen (const char     *address,
                    DBusError      *error)
{
  DBusServer *server;
  DBusAddressEntry **entries;
  int len, i;
  DBusError first_connect_error = DBUS_ERROR_INIT;
  dbus_bool_t handled_once;
  
  _dbus_return_val_if_fail (address != NULL, NULL);
  _dbus_return_val_if_error_is_set (error, NULL);
  
  if (!dbus_parse_address (address, &entries, &len, error))
    return NULL;

  server = NULL;
  handled_once = FALSE;

  for (i = 0; i < len; i++)
    {
      int j;

      for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
        {
          DBusServerListenResult result;
          DBusError tmp_error = DBUS_ERROR_INIT;

          result = (* listen_funcs[j].func) (entries[i],
                                             &server,
                                             &tmp_error);

          if (result == DBUS_SERVER_LISTEN_OK)
            {
              _dbus_assert (server != NULL);
              _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
              handled_once = TRUE;
              goto out;
            }
          else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED)
            {
              _dbus_assert (server == NULL);
              dbus_set_error (error,
                       DBUS_ERROR_ADDRESS_IN_USE,
                       "Address '%s' already used",
                       dbus_address_entry_get_method (entries[0]));
              handled_once = TRUE;
              goto out;
            }
          else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
            {
              _dbus_assert (server == NULL);
              _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
              dbus_move_error (&tmp_error, error);
              handled_once = TRUE;
              goto out;
            }
          else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
            {
              _dbus_assert (server == NULL);
              _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);

              /* keep trying addresses */
            }
          else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
            {
              _dbus_assert (server == NULL);
              _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
              if (!dbus_error_is_set (&first_connect_error))
                dbus_move_error (&tmp_error, &first_connect_error);
              else
                dbus_error_free (&tmp_error);

              handled_once = TRUE;
              
              /* keep trying addresses */
            }
        }

      _dbus_assert (server == NULL);
      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    }

 out:

  if (!handled_once)
    {
      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      if (len > 0)
        dbus_set_error (error,
                       DBUS_ERROR_BAD_ADDRESS,
                       "Unknown address type '%s'",
                       dbus_address_entry_get_method (entries[0]));
      else
        dbus_set_error (error,
                        DBUS_ERROR_BAD_ADDRESS,
                        "Empty address '%s'",
                        address);
    }
  
  dbus_address_entries_free (entries);

  if (server == NULL)
    {
      _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
                   dbus_error_is_set (error));
      
      if (error && dbus_error_is_set (error))
        {
          /* already set the error */
        }
      else
        {
          /* didn't set the error but either error should be
           * NULL or first_connect_error should be set.
           */
          _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
          dbus_move_error (&first_connect_error, error);
        }

      _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
      _DBUS_ASSERT_ERROR_IS_SET (error);

      return NULL;
    }
  else
    {
      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      return server;
    }
}
static dbus_bool_t
_dbus_read_uuid_file_without_creating (const DBusString *filename,
                                       DBusGUID         *uuid,
                                       DBusError        *error)
{
  DBusString contents;
  DBusString decoded;
  int end;
  
  if (!_dbus_string_init (&contents))
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  if (!_dbus_string_init (&decoded))
    {
      _dbus_string_free (&contents);
      _DBUS_SET_OOM (error);
      return FALSE;
    }
  
  if (!_dbus_file_get_contents (&contents, filename, error))
    goto error;

  _dbus_string_chop_white (&contents);

  if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
    {
      dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
                      "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
                      _dbus_string_get_const_data (filename),
                      DBUS_UUID_LENGTH_HEX,
                      _dbus_string_get_length (&contents));
      goto error;
    }

  if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
    {
      _DBUS_SET_OOM (error);
      goto error;
    }

  if (end == 0)
    {
      dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
                      "UUID file '%s' contains invalid hex data",
                      _dbus_string_get_const_data (filename));
      goto error;
    }

  if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
    {
      dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
                      "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
                      _dbus_string_get_const_data (filename),
                      _dbus_string_get_length (&decoded),
                      DBUS_UUID_LENGTH_BYTES);
      goto error;
    }

  _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);

  _dbus_string_free (&decoded);
  _dbus_string_free (&contents);

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  return TRUE;
  
 error:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  _dbus_string_free (&contents);
  _dbus_string_free (&decoded);
  return FALSE;
}
/**
 * Does the chdir, fork, setsid, etc. to become a daemon process.
 *
 * @param pidfile #NULL, or pidfile to create
 * @param print_pid_pipe pipe to print daemon's pid to, or -1 for none
 * @param error return location for errors
 * @param keep_umask #TRUE to keep the original umask
 * @returns #FALSE on failure
 */
dbus_bool_t
_dbus_become_daemon (const DBusString *pidfile,
                     DBusPipe         *print_pid_pipe,
                     DBusError        *error,
                     dbus_bool_t       keep_umask)
{
  const char *s;
  pid_t child_pid;
  int dev_null_fd;

  _dbus_verbose ("Becoming a daemon...\n");

  _dbus_verbose ("chdir to /\n");
  if (chdir ("/") < 0)
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Could not chdir() to root directory");
      return FALSE;
    }

  _dbus_verbose ("forking...\n");
  switch ((child_pid = fork ()))
    {
    case -1:
      _dbus_verbose ("fork failed\n");
      dbus_set_error (error, _dbus_error_from_errno (errno),
                      "Failed to fork daemon: %s", _dbus_strerror (errno));
      return FALSE;
      break;

    case 0:
      _dbus_verbose ("in child, closing std file descriptors\n");

      /* silently ignore failures here, if someone
       * doesn't have /dev/null we may as well try
       * to continue anyhow
       */
      
      dev_null_fd = open ("/dev/null", O_RDWR);
      if (dev_null_fd >= 0)
        {
          dup2 (dev_null_fd, 0);
          dup2 (dev_null_fd, 1);
          
          s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
          if (s == NULL || *s == '\0')
            dup2 (dev_null_fd, 2);
          else
            _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
        }

      if (!keep_umask)
        {
          /* Get a predictable umask */
          _dbus_verbose ("setting umask\n");
          umask (022);
        }

      _dbus_verbose ("calling setsid()\n");
      if (setsid () == -1)
        _dbus_assert_not_reached ("setsid() failed");
      
      break;

    default:
      if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe,
                                             child_pid, error))
        {
          _dbus_verbose ("pid file or pipe write failed: %s\n",
                         error->message);
          kill (child_pid, SIGTERM);
          return FALSE;
        }

      _dbus_verbose ("parent exiting\n");
      _exit (0);
      break;
    }
  
  return TRUE;
}
예제 #26
0
BusClientPolicy*
bus_policy_create_client_policy (BusPolicy      *policy,
                                 DBusConnection *connection,
                                 DBusError      *error)
{
  BusClientPolicy *client;
  dbus_uid_t uid;
  dbus_bool_t at_console;

  _dbus_assert (dbus_connection_get_is_authenticated (connection));
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  client = bus_client_policy_new ();
  if (client == NULL)
    goto nomem;

  if (!add_list_to_client (&policy->default_rules,
                           client))
    goto nomem;

  /* we avoid the overhead of looking up user's groups
   * if we don't have any group rules anyway
   */
  if (_dbus_hash_table_get_n_entries (policy->rules_by_gid) > 0)
    {
      unsigned long *groups;
      int n_groups;
      int i;
      
      if (!bus_connection_get_groups (connection, &groups, &n_groups, error))
        goto failed;
      
      i = 0;
      while (i < n_groups)
        {
          DBusList **list;
          
          list = _dbus_hash_table_lookup_ulong (policy->rules_by_gid,
                                                groups[i]);
          
          if (list != NULL)
            {
              if (!add_list_to_client (list, client))
                {
                  dbus_free (groups);
                  goto nomem;
                }
            }
          
          ++i;
        }

      dbus_free (groups);
    }

  if (!dbus_connection_get_unix_user (connection, &uid))
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "No user ID known for connection, cannot determine security policy\n");
      goto failed;
    }

  if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0)
    {
      DBusList **list;
      
      list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid,
                                            uid);

      if (list != NULL)
        {
          if (!add_list_to_client (list, client))
            goto nomem;
        }
    }

  /* Add console rules */
  at_console = _dbus_is_console_user (uid, error);

  if (at_console)
    {
      if (!add_list_to_client (&policy->at_console_true_rules, client))
        goto nomem;
    }
  else if (dbus_error_is_set (error) == TRUE)
    {
      goto failed;
    }
  else if (!add_list_to_client (&policy->at_console_false_rules, client))
    {
      goto nomem;
    }

  if (!add_list_to_client (&policy->mandatory_rules,
                           client))
    goto nomem;

  bus_client_policy_optimize (client);
  
  return client;

 nomem:
  BUS_SET_OOM (error);
 failed:
  _DBUS_ASSERT_ERROR_IS_SET (error);
  if (client)
    bus_client_policy_unref (client);
  return NULL;
}