/**
 * polkit_backend_session_monitor_get_session_for_subject:
 * @monitor: A #PolkitBackendSessionMonitor.
 * @subject: A #PolkitSubject.
 * @error: Return location for error.
 *
 * Gets the session corresponding to @subject or %NULL if no session exists.
 *
 * Returns: %NULL if @error is set otherwise a #PolkitUnixSession that should be freed with g_object_unref().
 */
PolkitSubject *
polkit_backend_session_monitor_get_session_for_subject (PolkitBackendSessionMonitor *monitor,
                                                        PolkitSubject               *subject,
                                                        GError                     **error)
{
  PolkitUnixProcess *tmp_process = NULL;
  PolkitUnixProcess *process = NULL;
  PolkitSubject *session = NULL;
  char *session_id = NULL;
  pid_t pid;
#if HAVE_SD_UID_GET_DISPLAY
  uid_t uid;
#endif

  if (POLKIT_IS_UNIX_PROCESS (subject))
    process = POLKIT_UNIX_PROCESS (subject); /* We already have a process */
  else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
    {
      /* Convert bus name to process */
      tmp_process = (PolkitUnixProcess*)polkit_system_bus_name_get_process_sync (POLKIT_SYSTEM_BUS_NAME (subject), NULL, error);
      if (!tmp_process)
	goto out;
      process = tmp_process;
    }
  else
    {
      g_set_error (error,
                   POLKIT_ERROR,
                   POLKIT_ERROR_NOT_SUPPORTED,
                   "Cannot get session for subject of type %s",
                   g_type_name (G_TYPE_FROM_INSTANCE (subject)));
    }

  /* Now do process -> pid -> same session */
  g_assert (process != NULL);
  pid = polkit_unix_process_get_pid (process);

  if (sd_pid_get_session (pid, &session_id) >= 0)
    {
      session = polkit_unix_session_new (session_id);
      goto out;
    }

#if HAVE_SD_UID_GET_DISPLAY
  /* Now do process -> uid -> graphical session (systemd version 213)*/
  if (sd_pid_get_owner_uid (pid, &uid) < 0)
    goto out;

  if (sd_uid_get_display (uid, &session_id) >= 0)
    {
      session = polkit_unix_session_new (session_id);
      goto out;
    }
#endif

 out:
  free (session_id);
  if (tmp_process) g_object_unref (tmp_process);
  return session;
}
/**
 * polkit_system_bus_name_set_name:
 * @system_bus_name: A #PolkitSystemBusName.
 * @name: A unique system bus name.
 *
 * Sets the unique system bus name for @system_bus_name.
 */
void
polkit_system_bus_name_set_name (PolkitSystemBusName *system_bus_name,
                                 const gchar         *name)
{
  g_return_if_fail (POLKIT_IS_SYSTEM_BUS_NAME (system_bus_name));
  g_return_if_fail (g_dbus_is_unique_name (name));
  g_free (system_bus_name->name);
  system_bus_name->name = g_strdup (name);
}
/**
 * polkit_backend_session_monitor_get_user:
 * @monitor: A #PolkitBackendSessionMonitor.
 * @subject: A #PolkitSubject.
 * @error: Return location for error.
 *
 * Gets the user corresponding to @subject or %NULL if no user exists.
 *
 * Returns: %NULL if @error is set otherwise a #PolkitUnixUser that should be freed with g_object_unref().
 */
PolkitIdentity *
polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor  *monitor,
                                                     PolkitSubject                *subject,
                                                     GError                      **error)
{
  PolkitIdentity *ret;
  guint32 uid;

  ret = NULL;

  if (POLKIT_IS_UNIX_PROCESS (subject))
    {
      uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
      if ((gint) uid == -1)
        {
          g_set_error (error,
                       POLKIT_ERROR,
                       POLKIT_ERROR_FAILED,
                       "Unix process subject does not have uid set");
          goto out;
        }
      ret = polkit_unix_user_new (uid);
    }
  else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
    {
      ret = (PolkitIdentity*)polkit_system_bus_name_get_user_sync (POLKIT_SYSTEM_BUS_NAME (subject), NULL, error);
    }
  else if (POLKIT_IS_UNIX_SESSION (subject))
    {

      if (sd_session_get_uid (polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (subject)), &uid) < 0)
        {
          g_set_error (error,
                       POLKIT_ERROR,
                       POLKIT_ERROR_FAILED,
                       "Error getting uid for session");
          goto out;
        }

      ret = polkit_unix_user_new (uid);
    }

 out:
  return ret;
}
static void
polkit_system_bus_name_exists (PolkitSubject       *subject,
                               GCancellable        *cancellable,
                               GAsyncReadyCallback  callback,
                               gpointer             user_data)
{
  GSimpleAsyncResult *simple;

  g_return_if_fail (POLKIT_IS_SYSTEM_BUS_NAME (subject));

  simple = g_simple_async_result_new (G_OBJECT (subject),
                                      callback,
                                      user_data,
                                      polkit_system_bus_name_exists);
  g_simple_async_result_run_in_thread (simple,
                                       exists_in_thread_func,
                                       G_PRIORITY_DEFAULT,
                                       cancellable);
  g_object_unref (simple);
}
/**
 * polkit_system_bus_name_get_user_sync:
 * @system_bus_name: A #PolkitSystemBusName.
 * @cancellable: (allow-none): A #GCancellable or %NULL.
 * @error: (allow-none): Return location for error or %NULL.
 *
 * Synchronously gets a #PolkitUnixUser object for @system_bus_name;
 * the calling thread is blocked until a reply is received.
 *
 * Returns: (allow-none) (transfer full): A #PolkitUnixUser object or %NULL if @error is set.
 **/
PolkitUnixUser *
polkit_system_bus_name_get_user_sync (PolkitSystemBusName  *system_bus_name,
				      GCancellable         *cancellable,
				      GError              **error)
{
  PolkitUnixUser *ret = NULL;
  guint32 uid;

  g_return_val_if_fail (POLKIT_IS_SYSTEM_BUS_NAME (system_bus_name), NULL);
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  if (!polkit_system_bus_name_get_creds_sync (system_bus_name, &uid, NULL,
					      cancellable, error))
    goto out;

  ret = (PolkitUnixUser*)polkit_unix_user_new (uid);

 out:
  return ret;
}
/**
 * polkit_system_bus_name_get_process_sync:
 * @system_bus_name: A #PolkitSystemBusName.
 * @cancellable: (allow-none): A #GCancellable or %NULL.
 * @error: (allow-none): Return location for error or %NULL.
 *
 * Synchronously gets a #PolkitUnixProcess object for @system_bus_name
 * - the calling thread is blocked until a reply is received.
 *
 * Returns: (allow-none) (transfer full): A #PolkitUnixProcess object or %NULL if @error is set.
 **/
PolkitSubject *
polkit_system_bus_name_get_process_sync (PolkitSystemBusName  *system_bus_name,
                                         GCancellable         *cancellable,
                                         GError              **error)
{
  PolkitSubject *ret = NULL;
  guint32 pid;
  guint32 uid;

  g_return_val_if_fail (POLKIT_IS_SYSTEM_BUS_NAME (system_bus_name), NULL);
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);

  if (!polkit_system_bus_name_get_creds_sync (system_bus_name, &uid, &pid,
					      cancellable, error))
    goto out;

  ret = polkit_unix_process_new_for_owner (pid, 0, uid);

 out:
  return ret;
}
/**
 * polkit_backend_session_monitor_get_session_for_subject:
 * @monitor: A #PolkitBackendSessionMonitor.
 * @subject: A #PolkitSubject.
 * @error: Return location for error.
 *
 * Gets the session corresponding to @subject or %NULL if no session exists.
 *
 * Returns: %NULL if @error is set otherwise a #PolkitUnixSession that should be freed with g_object_unref().
 */
PolkitSubject *
polkit_backend_session_monitor_get_session_for_subject (PolkitBackendSessionMonitor *monitor,
                                                        PolkitSubject               *subject,
                                                        GError                     **error)
{
  PolkitSubject *session;

  session = NULL;

  if (POLKIT_IS_UNIX_PROCESS (subject))
    {
      gchar *session_id;
      pid_t pid;

      pid = polkit_unix_process_get_pid (POLKIT_UNIX_PROCESS (subject));
      if (sd_pid_get_session (pid, &session_id) < 0)
        goto out;

      session = polkit_unix_session_new (session_id);
      free (session_id);
    }
  else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
    {
      guint32 pid;
      gchar *session_id;
      GVariant *result;

      result = g_dbus_connection_call_sync (monitor->system_bus,
                                            "org.freedesktop.DBus",
                                            "/org/freedesktop/DBus",
                                            "org.freedesktop.DBus",
                                            "GetConnectionUnixProcessID",
                                            g_variant_new ("(s)", polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject))),
                                            G_VARIANT_TYPE ("(u)"),
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1, /* timeout_msec */
                                            NULL, /* GCancellable */
                                            error);
      if (result == NULL)
        goto out;
      g_variant_get (result, "(u)", &pid);
      g_variant_unref (result);

      if (sd_pid_get_session (pid, &session_id) < 0)
        goto out;

      session = polkit_unix_session_new (session_id);
      free (session_id);
    }
  else
    {
      g_set_error (error,
                   POLKIT_ERROR,
                   POLKIT_ERROR_NOT_SUPPORTED,
                   "Cannot get user for subject of type %s",
                   g_type_name (G_TYPE_FROM_INSTANCE (subject)));
    }

 out:

  return session;
}
/**
 * polkit_backend_session_monitor_get_user:
 * @monitor: A #PolkitBackendSessionMonitor.
 * @subject: A #PolkitSubject.
 * @error: Return location for error.
 *
 * Gets the user corresponding to @subject or %NULL if no user exists.
 *
 * Returns: %NULL if @error is set otherwise a #PolkitUnixUser that should be freed with g_object_unref().
 */
PolkitIdentity *
polkit_backend_session_monitor_get_user_for_subject (PolkitBackendSessionMonitor  *monitor,
                                                     PolkitSubject                *subject,
                                                     GError                      **error)
{
  PolkitIdentity *ret;
  guint32 uid;

  ret = NULL;

  if (POLKIT_IS_UNIX_PROCESS (subject))
    {
      uid = polkit_unix_process_get_uid (POLKIT_UNIX_PROCESS (subject));
      if ((gint) uid == -1)
        {
          g_set_error (error,
                       POLKIT_ERROR,
                       POLKIT_ERROR_FAILED,
                       "Unix process subject does not have uid set");
          goto out;
        }
      ret = polkit_unix_user_new (uid);
    }
  else if (POLKIT_IS_SYSTEM_BUS_NAME (subject))
    {
      GVariant *result;

      result = g_dbus_connection_call_sync (monitor->system_bus,
                                            "org.freedesktop.DBus",
                                            "/org/freedesktop/DBus",
                                            "org.freedesktop.DBus",
                                            "GetConnectionUnixUser",
                                            g_variant_new ("(s)", polkit_system_bus_name_get_name (POLKIT_SYSTEM_BUS_NAME (subject))),
                                            G_VARIANT_TYPE ("(u)"),
                                            G_DBUS_CALL_FLAGS_NONE,
                                            -1, /* timeout_msec */
                                            NULL, /* GCancellable */
                                            error);
      if (result == NULL)
        goto out;
      g_variant_get (result, "(u)", &uid);
      g_variant_unref (result);

      ret = polkit_unix_user_new (uid);
    }
  else if (POLKIT_IS_UNIX_SESSION (subject))
    {

      if (sd_session_get_uid (polkit_unix_session_get_session_id (POLKIT_UNIX_SESSION (subject)), &uid) < 0)
        {
          g_set_error (error,
                       POLKIT_ERROR,
                       POLKIT_ERROR_FAILED,
                       "Error getting uid for session");
          goto out;
        }

      ret = polkit_unix_user_new (uid);
    }

 out:
  return ret;
}
/**
 * polkit_system_bus_name_get_name:
 * @system_bus_name: A #PolkitSystemBusName.
 *
 * Gets the unique system bus name for @system_bus_name.
 *
 * Returns: The unique system bus name for @system_bus_name. Do not
 * free, this string is owned by @system_bus_name.
 */
const gchar *
polkit_system_bus_name_get_name (PolkitSystemBusName *system_bus_name)
{
  g_return_val_if_fail (POLKIT_IS_SYSTEM_BUS_NAME (system_bus_name), NULL);
  return system_bus_name->name;
}