Example #1
0
static void _dbus_steadyflow_iapp_service_set_visible (SteadyflowIAppService* self, GVariant* parameters, GDBusMethodInvocation* invocation) {
	GError* error = NULL;
	GVariantIter _arguments_iter;
	gboolean visible = FALSE;
	GVariant* _tmp1_;
	GDBusMessage* _reply_message;
	GVariant* _reply;
	GVariantBuilder _reply_builder;
	g_variant_iter_init (&_arguments_iter, parameters);
	_tmp1_ = g_variant_iter_next_value (&_arguments_iter);
	visible = g_variant_get_boolean (_tmp1_);
	g_variant_unref (_tmp1_);
	steadyflow_iapp_service_set_visible (self, visible, &error);
	if (error) {
		g_dbus_method_invocation_return_gerror (invocation, error);
		return;
	}
	_reply_message = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
	g_variant_builder_init (&_reply_builder, G_VARIANT_TYPE_TUPLE);
	_reply = g_variant_builder_end (&_reply_builder);
	g_dbus_message_set_body (_reply_message, _reply);
	g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), _reply_message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
	g_object_unref (invocation);
	g_object_unref (_reply_message);
}
Example #2
0
static gboolean
photos_thumbnailer_handle_cancel (PhotosThumbnailer *self,
                                  GDBusMethodInvocation *invocation,
                                  guint serial)
{
  GCancellable *cancellable;
  GDBusConnection *connection;
  GDBusMethodInvocation *invocation_ongoing;
  GHashTableIter iter;

  g_return_val_if_fail (PHOTOS_IS_THUMBNAILER (self), FALSE);
  g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), FALSE);

  photos_debug (PHOTOS_DEBUG_THUMBNAILER, "Handling Cancel for %u", serial);
  g_application_hold (G_APPLICATION (self));

  connection = g_dbus_method_invocation_get_connection (invocation);

  g_hash_table_iter_init (&iter, self->cancellables);
  while (g_hash_table_iter_next (&iter, (gpointer *) &invocation_ongoing, (gpointer *) &cancellable))
    {
      GDBusConnection *connection_ongoing;
      GDBusMessage *message_ongoing;
      guint32 serial_ongoing;

      connection_ongoing = g_dbus_method_invocation_get_connection (invocation_ongoing);
      message_ongoing = g_dbus_method_invocation_get_message (invocation_ongoing);
      serial_ongoing = g_dbus_message_get_serial (message_ongoing);

      if (connection == connection_ongoing && (guint32) serial == serial_ongoing)
        {
          g_cancellable_cancel (cancellable);
          photos_thumbnailer_dbus_complete_cancel (self->skeleton, invocation);
          goto out;
        }
    }

  g_dbus_method_invocation_return_error_literal (invocation, PHOTOS_ERROR, 0, "Invalid serial");

 out:
  photos_debug (PHOTOS_DEBUG_THUMBNAILER, "Completed Cancel");
  g_application_release (G_APPLICATION (self));
  return TRUE;
}
Example #3
0
static void
portal_add_named (GDBusMethodInvocation *invocation,
                  GVariant *parameters,
                  const char *app_id)
{
  GDBusMessage *message;
  GUnixFDList *fd_list;
  g_autofree char *id = NULL;
  g_autofree char *proc_path = NULL;
  int parent_fd_id, parent_fd, fds_len, fd_flags;
  const int *fds;
  char parent_path_buffer[PATH_MAX+1];
  g_autofree char *path = NULL;
  ssize_t symlink_size;
  struct stat parent_st_buf;
  const char *filename;
  gboolean reuse_existing, persistent;
  g_autoptr(GVariant) filename_v = NULL;

  g_variant_get (parameters, "(h@aybb)", &parent_fd_id, &filename_v, &reuse_existing, &persistent);
  filename = g_variant_get_bytestring (filename_v);

  /* This is only allowed from the host, or else we could leak existance of files */
  if (*app_id != 0)
    {
      g_dbus_method_invocation_return_error (invocation, XDG_APP_PORTAL_ERROR, XDG_APP_PORTAL_ERROR_NOT_ALLOWED,
                                             "Not enough permissions");
      return;
    }

  message = g_dbus_method_invocation_get_message (invocation);
  fd_list = g_dbus_message_get_unix_fd_list (message);

  parent_fd = -1;
  if (fd_list != NULL)
    {
      fds = g_unix_fd_list_peek_fds (fd_list, &fds_len);
      if (parent_fd_id < fds_len)
        parent_fd = fds[parent_fd_id];
    }

  if (strchr (filename, '/') != NULL)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             XDG_APP_PORTAL_ERROR, XDG_APP_PORTAL_ERROR_INVALID_ARGUMENT,
                                             "Invalid filename passed");
      return;
    }

  proc_path = g_strdup_printf ("/proc/self/fd/%d", parent_fd);

  if (parent_fd == -1 ||
      /* Must be able to get fd flags */
      (fd_flags = fcntl (parent_fd, F_GETFL)) == -1 ||
      /* Must be O_PATH */
      ((fd_flags & O_PATH) != O_PATH) ||
      /* Must not be O_NOFOLLOW (because we want the target file) */
      ((fd_flags & O_NOFOLLOW) == O_PATH) ||
      /* Must be able to fstat */
      fstat (parent_fd, &parent_st_buf) < 0 ||
      /* Must be a directory file */
      (parent_st_buf.st_mode & S_IFMT) != S_IFDIR ||
      /* Must be able to read path from /proc/self/fd */
      /* This is an absolute and (at least at open time) symlink-expanded path */
      (symlink_size = readlink (proc_path, parent_path_buffer, sizeof (parent_path_buffer) - 1)) < 0)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             XDG_APP_PORTAL_ERROR, XDG_APP_PORTAL_ERROR_INVALID_ARGUMENT,
                                             "Invalid fd passed");
      return;
    }

  if (parent_st_buf.st_dev == fuse_dev)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             XDG_APP_PORTAL_ERROR, XDG_APP_PORTAL_ERROR_INVALID_ARGUMENT,
                                             "Invalid fd passed");
      return;
    }

  parent_path_buffer[symlink_size] = 0;

  path = g_build_filename (parent_path_buffer, filename, NULL);

  g_debug ("portal_add_named %s", path);

  AUTOLOCK(db);

  id = do_create_doc (&parent_st_buf, path, reuse_existing, persistent);

  g_dbus_method_invocation_return_value (invocation,
                                         g_variant_new ("(s)", id));
}
Example #4
0
static void
portal_add (GDBusMethodInvocation *invocation,
            GVariant *parameters,
            const char *app_id)
{
  GDBusMessage *message;
  GUnixFDList *fd_list;
  g_autofree char *id = NULL;
  g_autofree char *proc_path = NULL;
  int fd_id, fd, fds_len, fd_flags;
  glnx_fd_close int dir_fd = -1;
  const int *fds;
  char path_buffer[PATH_MAX+1];
  ssize_t symlink_size;
  struct stat st_buf, real_st_buf, real_parent_st_buf;
  g_autofree char *dirname = NULL;
  g_autofree char *name = NULL;
  gboolean reuse_existing, persistent;

  g_variant_get (parameters, "(hbb)", &fd_id, &reuse_existing, &persistent);

  message = g_dbus_method_invocation_get_message (invocation);
  fd_list = g_dbus_message_get_unix_fd_list (message);

  fd = -1;
  if (fd_list != NULL)
    {
      fds = g_unix_fd_list_peek_fds (fd_list, &fds_len);
      if (fd_id < fds_len)
        fd = fds[fd_id];
    }

  proc_path = g_strdup_printf ("/proc/self/fd/%d", fd);

  if (fd == -1 ||
      /* Must be able to get fd flags */
      (fd_flags = fcntl (fd, F_GETFL)) == -1 ||
      /* Must be O_PATH */
      ((fd_flags & O_PATH) != O_PATH) ||
      /* Must not be O_NOFOLLOW (because we want the target file) */
      ((fd_flags & O_NOFOLLOW) == O_PATH) ||
      /* Must be able to fstat */
      fstat (fd, &st_buf) < 0 ||
      /* Must be a regular file */
      (st_buf.st_mode & S_IFMT) != S_IFREG ||
      /* Must be able to read path from /proc/self/fd */
      /* This is an absolute and (at least at open time) symlink-expanded path */
      (symlink_size = readlink (proc_path, path_buffer, sizeof (path_buffer) - 1)) < 0)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             XDG_APP_PORTAL_ERROR, XDG_APP_PORTAL_ERROR_INVALID_ARGUMENT,
                                             "Invalid fd passed");
      return;
    }

  path_buffer[symlink_size] = 0;

  /* We open the parent directory and do the stat in that, so that we have
     trustworthy parent dev/ino for later verification. Otherwise the caller
     could later replace a parent with a symlink and make us read some other file */
  dirname = g_path_get_dirname (path_buffer);
  name = g_path_get_basename (path_buffer);
  dir_fd = open (dirname, O_CLOEXEC|O_PATH);

  if (fstat (dir_fd, &real_parent_st_buf) < 0 ||
      fstatat (dir_fd, name, &real_st_buf, AT_SYMLINK_NOFOLLOW) < 0 ||
      st_buf.st_dev != real_st_buf.st_dev ||
      st_buf.st_ino != real_st_buf.st_ino)
    {
      /* Don't leak any info about real file path existance, etc */
      g_dbus_method_invocation_return_error (invocation,
                                             XDG_APP_PORTAL_ERROR, XDG_APP_PORTAL_ERROR_INVALID_ARGUMENT,
                                             "Invalid fd passed");
      return;
    }

  g_debug ("portal_add %s", path_buffer);

  if (st_buf.st_dev == fuse_dev)
    {
      /* The passed in fd is on the fuse filesystem itself */
      g_autoptr(XdgAppDbEntry) old_entry = NULL;

      id = xdp_fuse_lookup_id_for_inode (st_buf.st_ino);
      g_debug ("path on fuse, id %s", id);
      if (id == NULL)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 XDG_APP_PORTAL_ERROR, XDG_APP_PORTAL_ERROR_INVALID_ARGUMENT,
                                                 "Invalid fd passed");
          return;
        }

      /* Don't lock the db before doing the fuse call above, because it takes takes a lock
         that can block something calling back, causing a deadlock on the db lock */

      AUTOLOCK(db);

      /* If the entry doesn't exist anymore, fail.  Also fail if not
         resuse_existing, because otherwise the user could use this to
         get a copy with permissions and thus escape later permission
         revocations */
      old_entry = xdg_app_db_lookup (db, id);
      if (old_entry == NULL ||
          !reuse_existing)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 XDG_APP_PORTAL_ERROR, XDG_APP_PORTAL_ERROR_INVALID_ARGUMENT,
                                                 "Invalid fd passed");
          return;
        }
    }
  else
    {
      {
        AUTOLOCK(db);

        id = do_create_doc (&real_parent_st_buf, path_buffer, reuse_existing, persistent);

        if (app_id[0] != '\0')
          {
            g_autoptr(XdgAppDbEntry) entry = NULL;
            XdpPermissionFlags perms =
              XDP_PERMISSION_FLAGS_GRANT_PERMISSIONS |
              XDP_PERMISSION_FLAGS_READ |
              XDP_PERMISSION_FLAGS_WRITE;
            {
              entry = xdg_app_db_lookup (db, id);

              /* If its a unique one its safe for the creator to
                 delete it at will */
              if (!reuse_existing)
                perms |= XDP_PERMISSION_FLAGS_DELETE;

              do_set_permissions (entry, id, app_id, perms);
            }
          }
      }

      /* Invalidate with lock dropped to avoid deadlock */
      xdp_fuse_invalidate_doc_app (id, NULL);
      if (app_id[0] != '\0')
        xdp_fuse_invalidate_doc_app (id, app_id);
    }

  g_dbus_method_invocation_return_value (invocation,
                                         g_variant_new ("(s)", id));
}
Example #5
0
static void
handle_method_call (GDBusConnection       *connection,
                    const gchar           *sender,
                    const gchar           *object_path,
                    const gchar           *interface_name,
                    const gchar           *method_name,
                    GVariant              *parameters,
                    GDBusMethodInvocation *invocation,
                    gpointer               user_data)
{
  if (g_strcmp0 (method_name, "HelloWorld") == 0)
    {
      const gchar *greeting;

      g_variant_get (parameters, "(&s)", &greeting);

      if (g_strcmp0 (greeting, "Return Unregistered") == 0)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 G_IO_ERROR,
                                                 G_IO_ERROR_FAILED_HANDLED,
                                                 "As requested, here's a GError not registered (G_IO_ERROR_FAILED_HANDLED)");
        }
      else if (g_strcmp0 (greeting, "Return Registered") == 0)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 G_DBUS_ERROR,
                                                 G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
                                                 "As requested, here's a GError that is registered (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
        }
      else if (g_strcmp0 (greeting, "Return Raw") == 0)
        {
          g_dbus_method_invocation_return_dbus_error (invocation,
                                                      "org.gtk.GDBus.SomeErrorName",
                                                      "As requested, here's a raw D-Bus error");
        }
      else
        {
          gchar *response;
          response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting);
          g_dbus_method_invocation_return_value (invocation,
                                                 g_variant_new ("(s)", response));
          g_free (response);
        }
    }
  else if (g_strcmp0 (method_name, "EmitSignal") == 0)
    {
      GError *local_error;
      gdouble speed_in_mph;
      gchar *speed_as_string;

      g_variant_get (parameters, "(d)", &speed_in_mph);
      speed_as_string = g_strdup_printf ("%g mph!", speed_in_mph);

      local_error = NULL;
      g_dbus_connection_emit_signal (connection,
                                     NULL,
                                     object_path,
                                     interface_name,
                                     "VelocityChanged",
                                     g_variant_new ("(ds)",
                                                    speed_in_mph,
                                                    speed_as_string),
                                     &local_error);
      g_assert_no_error (local_error);
      g_free (speed_as_string);

      g_dbus_method_invocation_return_value (invocation, NULL);
    }
  else if (g_strcmp0 (method_name, "GimmeStdout") == 0)
    {
#ifdef G_OS_UNIX
      if (g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
        {
          GDBusMessage *reply;
          GUnixFDList *fd_list;
          GError *error;

          fd_list = g_unix_fd_list_new ();
          error = NULL;
          g_unix_fd_list_append (fd_list, STDOUT_FILENO, &error);
          g_assert_no_error (error);

          reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
          g_dbus_message_set_unix_fd_list (reply, fd_list);

          error = NULL;
          g_dbus_connection_send_message (connection,
                                          reply,
                                          G_DBUS_SEND_MESSAGE_FLAGS_NONE,
                                          NULL, /* out_serial */
                                          &error);
          g_assert_no_error (error);

          g_object_unref (invocation);
          g_object_unref (fd_list);
          g_object_unref (reply);
        }
      else
        {
          g_dbus_method_invocation_return_dbus_error (invocation,
                                                      "org.gtk.GDBus.Failed",
                                                      "Your message bus daemon does not support file descriptor passing (need D-Bus >= 1.3.0)");
        }
#else
      g_dbus_method_invocation_return_dbus_error (invocation,
                                                  "org.gtk.GDBus.NotOnUnix",
                                                  "Your OS does not support file descriptor passing");
#endif
    }
}