Beispiel #1
0
static const gchar *
lookup_method_action_and_details (gpointer instance,
                                  InvocationClient *client,
                                  uid_t uid,
                                  const GDBusMethodInfo *method,
                                  PolkitDetails **details)
{
  GObjectClass *object_class;
  const gchar *message;

  /* Exception: The Job interface is not marked up like all our others */
  if (UDISKS_IS_JOB (instance) && g_str_equal (method->name, "Cancel"))
    {
      *details = polkit_details_new ();
      polkit_details_insert (*details, "polkit.message",
                             N_("Authentication is required to cancel a job"));

      /* This is a thread-safe call */
      if (uid != udisks_job_get_started_by_uid (instance))
        return "org.freedesktop.udisks2.cancel-job-other-user";
      else
        return "org.freedesktop.udisks2.cancel-job";
    }

  *details = NULL;

  object_class = G_OBJECT_GET_CLASS (instance);
  if (g_object_class_find_property (object_class, "polkit-details") != NULL)
    {
      ObjectGetDetails ogd = { instance, NULL };

      g_main_context_invoke (NULL, object_get_polkit_details, &details);

      g_mutex_lock (&inv.mutex);
      while (ogd.details == NULL)
        g_cond_wait (&inv.wait_cond, &inv.mutex);
      g_mutex_unlock (&inv.mutex);

      *details = ogd.details;
    }

  if (!*details || polkit_details_lookup (*details, "polkit.message"))
    {
      message = g_dbus_annotation_info_lookup (method->annotations, "polkit.message");
      if (message)
        {
          if (!*details)
            *details = polkit_details_new ();
          polkit_details_insert (*details, "polkit.message", message);
        }
    }

  return g_dbus_annotation_info_lookup (method->annotations, "polkit.action_id");
}
/**
 * pk_action_lookup_get_details:
 **/
static PolkitDetails *
pk_action_lookup_get_details (PolkitBackendActionLookup *lookup, const gchar *action_id,
			      PolkitDetails *action_details, PolkitActionDescription *action_description)
{
	const gchar *str;
	const gchar *title;
	gchar **package_ids;
	gchar *text;
	guint len;
	PolkitDetails *details;

	if (!g_str_has_prefix (action_id, "org.freedesktop.packagekit."))
		return NULL;

	details = polkit_details_new ();

	/* role */
	str = polkit_details_lookup (action_details, "role");
	if (str != NULL) {
		/* TRANSLATORS: the trasaction role, e.g. update-system */
		polkit_details_insert (details, _("Role"), str);
	}

	/* only-trusted */
	str = polkit_details_lookup (action_details, "only-trusted");
	if (str != NULL) {
		/* TRANSLATORS: if the transaction is forced to install only trusted packages */
		polkit_details_insert (details, _("Only trusted"), str);
	}

	/* command line */
	str = polkit_details_lookup (action_details, "cmdline");
	if (str != NULL) {
		/* TRANSLATORS: the command line of the thing that wants the authentication */
		polkit_details_insert (details, _("Command line"), str);
	}

	/* packages */
	str = polkit_details_lookup (action_details, "package_ids");
	if (str != NULL) {
		package_ids = pk_package_ids_from_string (str);
		text = pk_action_lookup_package_ids_to_string (package_ids);
		len = g_strv_length (package_ids);

		/* TRANSLATORS: title, the names of the packages that the method is processing */
		title = ngettext ("Package", "Packages", len);
		polkit_details_insert (details, title, text);

		g_strfreev (package_ids);
		g_free (text);
	}

	return details;
}
Beispiel #3
0
static gboolean
flatpak_authorize_method_handler (GDBusInterfaceSkeleton *interface,
                                  GDBusMethodInvocation  *invocation,
                                  gpointer                user_data)
{
  const gchar *method_name = g_dbus_method_invocation_get_method_name (invocation);
  const gchar *sender = g_dbus_method_invocation_get_sender (invocation);
  GVariant *parameters = g_dbus_method_invocation_get_parameters (invocation);
  g_autoptr(AutoPolkitSubject) subject = polkit_system_bus_name_new (sender);
  g_autoptr(AutoPolkitDetails) details = polkit_details_new ();
  const gchar *action = NULL;
  gboolean authorized = FALSE;

  /* Ensure we don't idle exit */
  schedule_idle_callback ();

  if (on_session_bus)
    {
      /* This is test code, make sure it never runs with privileges */
      g_assert (geteuid () != 0);
      g_assert (getuid () != 0);
      g_assert (getegid () != 0);
      g_assert (getgid () != 0);
      authorized = TRUE;
    }
  else if (g_strcmp0 (method_name, "Deploy") == 0)
    {
      const char *ref, *origin;
      guint32 flags;
      gboolean is_update, is_app;

      g_variant_get_child (parameters, 1, "u", &flags);
      g_variant_get_child (parameters, 2, "&s", &ref);
      g_variant_get_child (parameters, 3, "&s", &origin);

      is_update = (flags & FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE) != 0;
      is_app = g_str_has_prefix (ref, "app/");

      if (is_update)
        {
          if (is_app)
            action = "org.freedesktop.Flatpak.app-update";
          else
            action = "org.freedesktop.Flatpak.runtime-update";
        }
      else
        {
          if (is_app)
            action = "org.freedesktop.Flatpak.app-install";
          else
            action = "org.freedesktop.Flatpak.runtime-install";
        }

      polkit_details_insert (details, "origin", origin);
      polkit_details_insert (details, "ref", ref);
    }
  else if (g_strcmp0 (method_name, "DeployAppstream") == 0)
    {
      const char *arch, *origin;

      g_variant_get_child (parameters, 1, "&s", &origin);
      g_variant_get_child (parameters, 2, "&s", &arch);

      action = "org.freedesktop.Flatpak.appstream-update";

      polkit_details_insert (details, "origin", origin);
      polkit_details_insert (details, "arch", arch);
    }
  else if (g_strcmp0 (method_name, "InstallBundle") == 0)
    {
      const char *path;

      g_variant_get_child (parameters, 0, "^&ay", &path);

      action = "org.freedesktop.Flatpak.install-bundle";

      polkit_details_insert (details, "path", path);
    }
  else if (g_strcmp0 (method_name, "Uninstall") == 0)
    {
      const char *ref;
      gboolean is_app;

      g_variant_get_child (parameters, 1, "&s", &ref);

      is_app = g_str_has_prefix (ref, "app/");
      if (is_app)
        action = "org.freedesktop.Flatpak.app-uninstall";
      else
        action = "org.freedesktop.Flatpak.runtime-uninstall";

      polkit_details_insert (details, "ref", ref);
    }
  else if (g_strcmp0 (method_name, "ConfigureRemote") == 0)
    {
      const char *remote;

      g_variant_get_child (parameters, 1, "&s", &remote);

      action = "org.freedesktop.Flatpak.configure-remote";

      polkit_details_insert (details, "remote", remote);
    }

  if (action)
    {
      g_autoptr(AutoPolkitAuthorizationResult) result;
      g_autoptr(GError) error = NULL;

      result = polkit_authority_check_authorization_sync (authority, subject,
                                                          action, details,
                                                          POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
                                                          NULL, &error);
      if (result == NULL)
        {
          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
                                                 "Authorization error: %s", error->message);
          return FALSE;
        }

      authorized = polkit_authorization_result_get_is_authorized (result);
    }

  if (!authorized)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             G_DBUS_ERROR,
                                             G_DBUS_ERROR_ACCESS_DENIED,
                                             "Flatpak system operation %s not allowed for user", method_name);
    }

  return authorized;
}
Beispiel #4
0
/**
 * udisks_daemon_util_check_authorization_sync:
 * @daemon: A #UDisksDaemon.
 * @object: (allow-none): The #GDBusObject that the call is on or %NULL.
 * @action_id: The action id to check for.
 * @options: (allow-none): A #GVariant to check for the <quote>auth.no_user_interaction</quote> option or %NULL.
 * @message: The message to convey (use N_).
 * @invocation: The invocation to check for.
 *
 * Checks if the caller represented by @invocation is authorized for
 * the action identified by @action_id, optionally displaying @message
 * if authentication is needed. Additionally, if the caller is not
 * authorized, the appropriate error is already returned to the caller
 * via @invocation.
 *
 * The calling thread is blocked for the duration of the authorization
 * check which could be a very long time since it may involve
 * presenting an authentication dialog and having a human user use
 * it. If <quote>auth.no_user_interaction</quote> in @options is %TRUE
 * no authentication dialog will be presented and the check is not
 * expected to take a long time.
 *
 * See <xref linkend="udisks-polkit-details"/> for the variables that
 * can be used in @message but note that not all variables can be used
 * in all checks. For example, any check involving a #UDisksDrive or a
 * #UDisksBlock object can safely include the fragment
 * <quote>$(drive)</quote> since it will always expand to the name of
 * the drive, e.g. <quote>INTEL SSDSA2MH080G1GC (/dev/sda1)</quote> or
 * the block device file e.g. <quote>/dev/vg_lucifer/lv_root</quote>
 * or <quote>/dev/sda1</quote>. However this won't work for operations
 * that isn't on a drive or block device, for example calls on the
 * <link linkend="gdbus-interface-org-freedesktop-UDisks2-Manager.top_of_page">Manager</link>
 * object.
 *
 * Returns: %TRUE if caller is authorized, %FALSE if not.
 */
gboolean
udisks_daemon_util_check_authorization_sync (UDisksDaemon          *daemon,
                                             UDisksObject          *object,
                                             const gchar           *action_id,
                                             GVariant              *options,
                                             const gchar           *message,
                                             GDBusMethodInvocation *invocation)
{
  PolkitAuthority *authority = NULL;
  PolkitSubject *subject = NULL;
  PolkitDetails *details = NULL;
  PolkitCheckAuthorizationFlags flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
  PolkitAuthorizationResult *result = NULL;
  GError *error = NULL;
  gboolean ret = FALSE;
  UDisksBlock *block = NULL;
  UDisksDrive *drive = NULL;
  UDisksPartition *partition = NULL;
  UDisksObject *block_object = NULL;
  UDisksObject *drive_object = NULL;
  gboolean auth_no_user_interaction = FALSE;
  const gchar *details_device = NULL;
  gchar *details_drive = NULL;

  authority = udisks_daemon_get_authority (daemon);
  if (authority == NULL)
    {
      ret = check_authorization_no_polkit (daemon, object, action_id, options, message, invocation);
      goto out;
    }

  subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (invocation));
  if (options != NULL)
    {
      g_variant_lookup (options,
                        "auth.no_user_interaction",
                        "b",
                        &auth_no_user_interaction);
    }
  if (!auth_no_user_interaction)
    flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;

  details = polkit_details_new ();
  polkit_details_insert (details, "polkit.message", message);
  polkit_details_insert (details, "polkit.gettext_domain", "udisks2");

  /* Find drive associated with the block device, if any */
  if (object != NULL)
    {
      block = udisks_object_get_block (object);
      if (block != NULL)
        {
          block_object = g_object_ref (object);
          drive_object = udisks_daemon_find_object (daemon, udisks_block_get_drive (block));
          if (drive_object != NULL)
            drive = udisks_object_get_drive (drive_object);
        }

      partition = udisks_object_get_partition (object);

      if (drive == NULL)
        drive = udisks_object_get_drive (object);
    }

  if (block != NULL)
    details_device = udisks_block_get_preferred_device (block);

  /* If we have a drive, use vendor/model in the message (in addition to Block:preferred-device) */
  if (drive != NULL)
    {
      gchar *s;
      const gchar *vendor;
      const gchar *model;

      vendor = udisks_drive_get_vendor (drive);
      model = udisks_drive_get_model (drive);
      if (vendor == NULL)
        vendor = "";
      if (model == NULL)
        model = "";

      if (strlen (vendor) > 0 && strlen (model) > 0)
        s = g_strdup_printf ("%s %s", vendor, model);
      else if (strlen (vendor) > 0)
        s = g_strdup (vendor);
      else
        s = g_strdup (model);

      if (block != NULL)
        {
          details_drive = g_strdup_printf ("%s (%s)", s, udisks_block_get_preferred_device (block));
        }
      else
        {
          details_drive = s;
          s = NULL;
        }
      g_free (s);

      _safe_polkit_details_insert (details, "drive.wwn", udisks_drive_get_wwn (drive));
      _safe_polkit_details_insert (details, "drive.serial", udisks_drive_get_serial (drive));
      _safe_polkit_details_insert (details, "drive.vendor", udisks_drive_get_vendor (drive));
      _safe_polkit_details_insert (details, "drive.model", udisks_drive_get_model (drive));
      _safe_polkit_details_insert (details, "drive.revision", udisks_drive_get_revision (drive));
      if (udisks_drive_get_removable (drive))
        {
          const gchar *const *media_compat;
          GString *media_compat_str;
          const gchar *sep = ",";

          polkit_details_insert (details, "drive.removable", "true");
          _safe_polkit_details_insert (details, "drive.removable.bus", udisks_drive_get_connection_bus (drive));

          media_compat_str = g_string_new (NULL);
          media_compat = udisks_drive_get_media_compatibility (drive);
          if (media_compat)
            {
              guint i;

              for (i = 0; media_compat[i] && strlen(media_compat[i]); i++)
                {
                  if (i)
                    g_string_append (media_compat_str, sep);
                  g_string_append (media_compat_str, media_compat[i]);
                }
            }

          _safe_polkit_details_insert (details, "drive.removable.media", media_compat_str->str);
          g_string_free (media_compat_str, TRUE);
        }
    }

  if (block != NULL)
    {
      _safe_polkit_details_insert (details, "id.type",    udisks_block_get_id_type (block));
      _safe_polkit_details_insert (details, "id.usage",   udisks_block_get_id_usage (block));
      _safe_polkit_details_insert (details, "id.version", udisks_block_get_id_version (block));
      _safe_polkit_details_insert (details, "id.label",   udisks_block_get_id_label (block));
      _safe_polkit_details_insert (details, "id.uuid",    udisks_block_get_id_uuid (block));
    }

  if (partition != NULL)
    {
      _safe_polkit_details_insert_int    (details, "partition.number", udisks_partition_get_number (partition));
      _safe_polkit_details_insert        (details, "partition.type",   udisks_partition_get_type_ (partition));
      _safe_polkit_details_insert_uint64 (details, "partition.flags",  udisks_partition_get_flags (partition));
      _safe_polkit_details_insert        (details, "partition.name",   udisks_partition_get_name (partition));
      _safe_polkit_details_insert        (details, "partition.uuid",   udisks_partition_get_uuid (partition));
    }

  /* Fall back to Block:preferred-device */
  if (details_drive == NULL && block != NULL)
    details_drive = udisks_block_dup_preferred_device (block);

  if (details_device != NULL)
    polkit_details_insert (details, "device", details_device);
  if (details_drive != NULL)
    polkit_details_insert (details, "drive", details_drive);

  error = NULL;
  result = polkit_authority_check_authorization_sync (authority,
                                                      subject,
                                                      action_id,
                                                      details,
                                                      flags,
                                                      NULL, /* GCancellable* */
                                                      &error);
  if (result == NULL)
    {
      if (error->domain != POLKIT_ERROR)
        {
          /* assume polkit authority is not available (e.g. could be the service
           * manager returning org.freedesktop.systemd1.Masked)
           */
          g_error_free (error);
          ret = check_authorization_no_polkit (daemon, object, action_id, options, message, invocation);
        }
      else
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 UDISKS_ERROR,
                                                 UDISKS_ERROR_FAILED,
                                                 "Error checking authorization: %s (%s, %d)",
                                                 error->message,
                                                 g_quark_to_string (error->domain),
                                                 error->code);
          g_error_free (error);
        }
      goto out;
    }
  if (!polkit_authorization_result_get_is_authorized (result))
    {
      if (polkit_authorization_result_get_dismissed (result))
        g_dbus_method_invocation_return_error_literal (invocation,
                                                       UDISKS_ERROR,
                                                       UDISKS_ERROR_NOT_AUTHORIZED_DISMISSED,
                                                       "The authentication dialog was dismissed");
      else
        g_dbus_method_invocation_return_error_literal (invocation,
                                                       UDISKS_ERROR,
                                                       polkit_authorization_result_get_is_challenge (result) ?
                                                       UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN :
                                                       UDISKS_ERROR_NOT_AUTHORIZED,
                                                       "Not authorized to perform operation");
      goto out;
    }

  ret = TRUE;

 out:
  g_free (details_drive);
  g_clear_object (&block_object);
  g_clear_object (&drive_object);
  g_clear_object (&block);
  g_clear_object (&partition);
  g_clear_object (&drive);
  g_clear_object (&subject);
  g_clear_object (&details);
  g_clear_object (&result);
  return ret;
}