/**
 * 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_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;
}
/**
 * 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;
}