Commit message: Better check for sessions

Do not allow other users to hijack a session checking that
the process is launched by the owner of the session.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
CVE: CVE-2020-25653
CWE: CWE-362
Vulnerability description: A race condition vulnerability was found in the way the spice-vdagentd daemon handled new client connections. This flaw may allow an unprivileged local guest user to become the active agent for spice-vdagentd, possibly resulting in a denial of service or information leakage from the host. The highest threat from this vulnerability is to data confidentiality as well as system availability. This flaw affects spice-vdagent versions 0.20 and prior.

Project: spice-vd_agent
File: systemd-login.c

gboolean session_info_session_is_locked(struct session_info *si)
{
    gboolean locked;

    g_return_val_if_fail (si != NULL, FALSE);

    si_dbus_read_signals(si);
    si_dbus_read_properties(si);

    locked = (si->session_is_locked || si->session_locked_hint);
    if (si->verbose) {
        syslog(LOG_DEBUG, "(systemd-login) session is locked: %s",
               locked ? "yes" : "no");
    }
    return locked;
}

Project: spice-vd_agent
File: systemd-login.c

static void si_dbus_match_remove(struct session_info *si)
{
    DBusError error;
    if (si->dbus.match_session_signals == NULL)
        return;

    dbus_error_init(&error);
    dbus_bus_remove_match(si->dbus.system_connection,
                          si->dbus.match_session_signals,
                          &error);

    g_clear_pointer(&si->dbus.match_session_signals, g_free);
}

Project: spice-vd_agent
File: systemd-login.c

static DBusConnection *si_dbus_get_system_bus(void)
{
    DBusConnection *connection;
    DBusError error;

    dbus_error_init(&error);
    connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
    if (connection == NULL || dbus_error_is_set(&error)) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_WARNING, "Unable to connect to system bus: %s",
                   error.message);
            dbus_error_free(&error);
        } else {
            syslog(LOG_WARNING, "Unable to connect to system bus");
        }
        return NULL;
    }
    return connection;
}

Project: spice-vd_agent
File: console-kit.c

int session_info_get_fd(struct session_info *info)
{
    return info->fd;
}

Project: spice-vd_agent
File: console-kit.c

static void si_dbus_match_remove(struct session_info *info)
{
    DBusError error;
    if (info->match_seat_signals != NULL) {
        dbus_error_init(&error);
        dbus_bus_remove_match(info->connection,
                              info->match_seat_signals,
                              &error);
        if (info->verbose)
            syslog(LOG_DEBUG, "(console-kit) seat match removed: %s",
                   info->match_seat_signals);
        g_clear_pointer(&info->match_seat_signals, g_free);
    }

    if (info->match_session_signals != NULL) {
        dbus_error_init(&error);
        dbus_bus_remove_match(info->connection,
                              info->match_session_signals,
                              &error);

        if (info->verbose)
            syslog(LOG_DEBUG, "(console-kit) session match removed: %s",
                   info->match_session_signals);
        g_clear_pointer(&info->match_session_signals, g_free);
    }
}

Project: spice-vd_agent
File: console-kit.c

gboolean session_info_session_is_locked(struct session_info *info)
{
    gboolean locked;

    g_return_val_if_fail (info != NULL, FALSE);

    /* Not every system does emit Lock and Unlock signals (for instance, such
     * is the case for RHEL6) but most of the systems seems to emit the
     * IdleHintChanged. So use the IdleHint value.
     * systemd-login uses locked-hint which is not implemented in ConsoleKit,
     * see https://github.com/ConsoleKit2/ConsoleKit2/issues/89 */
    si_dbus_read_signals(info);
    locked = info->session_idle_hint;
    if (info->verbose) {
        syslog(LOG_DEBUG, "(console-kit) session is locked: %s",
               locked ? "yes" : "no");
    }
    return locked;
}

Project: spice-vd_agent
File: vdagentd.c

static bool check_uid_of_pid(pid_t pid, uid_t uid)
{
    char fn[128];
    struct stat st;

    snprintf(fn, sizeof(fn), "/proc/%u/status", (unsigned) pid);
    if (stat(fn, &st) != 0 || st.st_uid != uid) {
        return false;
    }
    return true;
}

Project: spice-vd_agent
File: systemd-login.c

si_dbus_read_signals(struct session_info *si)
{
    DBusMessage *message = NULL;

    dbus_connection_read_write(si->dbus.system_connection, 0);
    message = dbus_connection_pop_message(si->dbus.system_connection);
    while (message != NULL) {
        const char *member;

        member = dbus_message_get_member (message);
        if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) {
            si->session_is_locked = TRUE;
        } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) {
            si->session_is_locked = FALSE;
        } else {
            if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
                syslog(LOG_WARNING, "(systemd-login) received non signal message");
            } else if (si->verbose) {
                syslog(LOG_DEBUG, "(systemd-login) Signal not handled: %s", member);
            }
        }

        dbus_message_unref(message);
        dbus_connection_read_write(si->dbus.system_connection, 0);
        message = dbus_connection_pop_message(si->dbus.system_connection);
    }
}

Project: spice-vd_agent
File: dummy-session-info.c

uid_t session_info_uid_for_session(struct session_info *si, const char *session)
{
    return -1;
}

Project: spice-vd_agent
File: dummy-session-info.c

int session_info_get_fd(struct session_info *si)
{
    return -1;
}

Project: spice-vd_agent
File: dummy-session-info.c

struct session_info *session_info_create(int verbose)
{
    return NULL;
}

Project: spice-vd_agent
File: dummy-session-info.c

const char *session_info_get_active_session(struct session_info *si)
{
    return NULL;
}

Project: spice-vd_agent
File: console-kit.c

static void si_dbus_match_rule_update(struct session_info *info)
{
    DBusError error;

    if (info->connection == NULL)
        return;

    si_dbus_match_remove(info);

    /* Seat signals */
    if (info->seat != NULL) {
        info->match_seat_signals =
            g_strdup_printf ("type='signal',interface='%s',path='%s',"
                             "member='ActiveSessionChanged'",
                             INTERFACE_CONSOLE_KIT_SEAT,
                             info->seat);
        if (info->verbose)
            syslog(LOG_DEBUG, "(console-kit) seat match: %s",
                   info->match_seat_signals);

        dbus_error_init(&error);
        dbus_bus_add_match(info->connection,
                           info->match_seat_signals,
                           &error);
        if (dbus_error_is_set(&error)) {
            syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
                   error.message);
            dbus_error_free(&error);
            g_clear_pointer(&info->match_seat_signals, g_free);
        }
    }

    /* Session signals */
    if (info->active_session != NULL) {
        info->match_session_signals =
            g_strdup_printf ("type='signal',interface='%s',path='%s'",
                             INTERFACE_CONSOLE_KIT_SESSION,
                             info->active_session);
        if (info->verbose)
            syslog(LOG_DEBUG, "(console-kit) session match: %s",
                   info->match_session_signals);

        dbus_error_init(&error);
        dbus_bus_add_match(info->connection,
                           info->match_session_signals,
                           &error);
        if (dbus_error_is_set(&error)) {
            syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
                   error.message);
            dbus_error_free(&error);
            g_clear_pointer(&info->match_session_signals, g_free);
        }
    }
}

Project: spice-vd_agent
File: dummy-session-info.c

gboolean session_info_session_is_locked(G_GNUC_UNUSED struct session_info *si)
{
    return FALSE;
}

Project: spice-vd_agent
File: systemd-login.c

static void si_dbus_match_rule_update(struct session_info *si)
{
    DBusError error;

    if (si->dbus.system_connection == NULL ||
            si->session == NULL)
        return;

    si_dbus_match_remove(si);

    si->dbus.match_session_signals =
        g_strdup_printf ("type='signal',interface='%s',path='"
                         LOGIND_SESSION_OBJ_TEMPLATE"'",
                         LOGIND_SESSION_INTERFACE,
                         si->session);
    if (si->verbose)
        syslog(LOG_DEBUG, "logind match: %s", si->dbus.match_session_signals);

    dbus_error_init(&error);
    dbus_bus_add_match(si->dbus.system_connection,
                       si->dbus.match_session_signals,
                       &error);
    if (dbus_error_is_set(&error)) {
        syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
               error.message);
        dbus_error_free(&error);
        g_clear_pointer(&si->dbus.match_session_signals, g_free);
    }
}

Project: spice-vd_agent
File: dummy-session-info.c

char *session_info_session_for_pid(struct session_info *si, uint32_t pid)
{
    return NULL;
}

Project: spice-vd_agent
File: systemd-login.c

gboolean session_info_is_user(struct session_info *si)
{
    gchar *class = NULL;
    gboolean ret;

    g_return_val_if_fail (si != NULL, TRUE);
    g_return_val_if_fail (si->session != NULL, TRUE);

    if (sd_session_get_class(si->session, &class) != 0) {
        syslog(LOG_WARNING, "Unable to get class from session: %s",
               si->session);
        return TRUE;
    }

    if (si->verbose)
        syslog(LOG_DEBUG, "(systemd-login) class for %s is %s",
               si->session, class);

    ret = (g_strcmp0(class, "user") == 0);
    g_free(class);

    return ret;
}

Project: spice-vd_agent
File: systemd-login.c

char *session_info_session_for_pid(struct session_info *si, uint32_t pid)
{
    int i;
    int r;
    GStrv sessions = NULL;
    char *session = NULL;
    uid_t uid;

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

    /* If we could not get a session for the pid then the agent is probably
     * running in a systemd managed session. In that case we simply assume
     * it is actually part of the newest graphical session we can find. */
    r = sd_pid_get_owner_uid(pid, &uid);
    if (r < 0) {
        syslog(LOG_ERR, "Error getting owner UID for pid %u: %s",
               pid, strerror(-r));
        goto out;
    }

    r = sd_uid_get_sessions(uid, 0, &sessions);
    if (r < 0) {
        syslog(LOG_ERR, "Error getting sessions for UID %d: %s",
               (int) uid, strerror(-r));
        goto out;
    }

    for (i = 0; sessions[i] != NULL; i++) {
        char *session_type = NULL;

        r = sd_session_get_type(sessions[i], &session_type);

        if (r < 0) {
            syslog(LOG_ERR, "Error getting session type for session %s: %s",
                   sessions[i], strerror(-r));
            continue;
        }

        if (g_strcmp0(session_type, "wayland") == 0 ||
            g_strcmp0(session_type, "x11") == 0 ||
            g_strcmp0(session_type, "mir") == 0) {

            /* We prefer the newest session (i.e. last entry) from the
             * user, assuming that any old session that still exist has
             * just not yet died properly. */
            if (session != NULL)
                free (session);
            session = g_strdup(sessions[i]);
        }

        free(session_type);
    }

    g_strfreev(sessions);

out:
    if (session != NULL && si->verbose) {
        syslog(LOG_INFO, "Session for pid %u: %s", pid, session);
    }

    return session;
}

Project: spice-vd_agent
File: systemd-login.c

int session_info_get_fd(struct session_info *si)
{
    return sd_login_monitor_get_fd(si->mon);
}

Project: spice-vd_agent
File: dummy-session-info.c

gboolean session_info_is_user(struct session_info *si)
{
    return TRUE;
}

Project: spice-vd_agent
File: systemd-login.c

uid_t session_info_uid_for_session(struct session_info *si, const char *session)
{
    uid_t ret = -1;
    if (sd_session_get_uid(session, &ret) < 0) {
        return -1;
    }
    return ret;
}

Project: spice-vd_agent
File: systemd-login.c

si_dbus_read_properties(struct session_info *si)
{
    dbus_bool_t locked_hint, ret;
    DBusMessageIter iter, iter_variant;
    gint type;
    DBusError error;
    DBusMessage *message = NULL;
    DBusMessage *reply = NULL;
    gchar *session_object;
    const gchar *interface, *property;

    if (si->session == NULL)
        return;

    session_object = g_strdup_printf(LOGIND_SESSION_OBJ_TEMPLATE, si->session);
    message = dbus_message_new_method_call(LOGIND_INTERFACE,
                                           session_object,
                                           DBUS_PROPERTIES_INTERFACE,
                                           "Get");
    g_free (session_object);
    if (message == NULL) {
        syslog(LOG_ERR, "Unable to create dbus message");
        goto exit;
    }

    interface = LOGIND_SESSION_INTERFACE;
    property = SESSION_PROP_LOCKED_HINT;
    ret = dbus_message_append_args(message,
                                   DBUS_TYPE_STRING, &interface,
                                   DBUS_TYPE_STRING, &property,
                                   DBUS_TYPE_INVALID);
    if (!ret) {
        syslog(LOG_ERR, "Unable to request locked-hint");
        goto exit;
    }

    dbus_error_init(&error);
    reply = dbus_connection_send_with_reply_and_block(si->dbus.system_connection,
                                                      message,
                                                      -1,
                                                      &error);
    if (reply == NULL) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR, "Properties.Get failed (locked-hint) due %s", error.message);
            dbus_error_free(&error);
        } else {
            syslog(LOG_ERR, "Properties.Get failed (locked-hint)");
        }
        goto exit;
    }

    dbus_message_iter_init(reply, &iter);
    type = dbus_message_iter_get_arg_type(&iter);
    if (type != DBUS_TYPE_VARIANT) {
        syslog(LOG_ERR, "expected a variant, got a '%c' instead", type);
        goto exit;
    }

    dbus_message_iter_recurse(&iter, &iter_variant);
    type = dbus_message_iter_get_arg_type(&iter_variant);
    if (type != DBUS_TYPE_BOOLEAN) {
        syslog(LOG_ERR, "expected a boolean, got a '%c' instead", type);
        goto exit;
    }
    dbus_message_iter_get_basic(&iter_variant, &locked_hint);

    si->session_locked_hint = (locked_hint) ? TRUE : FALSE;
exit:
    if (reply != NULL) {
        dbus_message_unref(reply);
    }

    if (message != NULL) {
        dbus_message_unref(message);
    }
}

Project: spice-vd_agent
File: systemd-login.c

const char *session_info_get_active_session(struct session_info *si)
{
    int r;
    char *old_session = si->session;

    si->session = NULL;
    r = sd_seat_get_active("seat0", &si->session, NULL);
    /* ENOENT happens when a seat is switching from one session to another */
    if (r < 0 && r != -ENOENT)
        syslog(LOG_ERR, "Error getting active session: %s",
                strerror(-r));

    if (si->verbose && si->session &&
            (!old_session || strcmp(old_session, si->session)))
        syslog(LOG_INFO, "Active session: %s", si->session);

    sd_login_monitor_flush(si->mon);
    g_free(old_session);

    si_dbus_match_rule_update(si);
    return si->session;
}

Project: spice-vd_agent
File: systemd-login.c

void session_info_destroy(struct session_info *si)
{
    if (!si)
        return;

    si_dbus_match_remove(si);
    if (si->dbus.system_connection) {
        dbus_connection_close(si->dbus.system_connection);
    }
    sd_login_monitor_unref(si->mon);
    g_free(si->session);
    g_free(si);
}

Project: spice-vd_agent
File: systemd-login.c

struct session_info *session_info_create(int verbose)
{
    struct session_info *si;
    int r;

    si = g_new0(struct session_info, 1);
    si->verbose = verbose;
    si->session_is_locked = FALSE;

    r = sd_login_monitor_new("session", &si->mon);
    if (r < 0) {
        syslog(LOG_ERR, "Error creating login monitor: %s", strerror(-r));
        g_free(si);
        return NULL;
    }

    si->dbus.system_connection = si_dbus_get_system_bus();
    return si;
}

Project: spice-vd_agent
File: console-kit.c

struct session_info *session_info_create(int verbose)
{
    struct session_info *info;
    DBusError error;

    info = g_new0(struct session_info, 1);
    info->verbose = verbose;
    info->session_is_locked = FALSE;
    info->session_idle_hint = FALSE;

    dbus_error_init(&error);
    info->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
    if (info->connection == NULL || dbus_error_is_set(&error)) {
        if (dbus_error_is_set(&error)) {
             syslog(LOG_ERR, "Unable to connect to system bus: %s",
                    error.message);
             dbus_error_free(&error);
        } else
             syslog(LOG_ERR, "Unable to connect to system bus");
        g_free(info);
        return NULL;
    }

    if (!dbus_connection_get_unix_fd(info->connection, &info->fd)) {
        syslog(LOG_ERR, "Unable to get connection fd");
        session_info_destroy(info);
        return NULL;
    }

    if (!console_kit_get_first_seat(info)) {
        session_info_destroy(info);
        return NULL;
    }

    si_dbus_match_rule_update(info);
    return info;
}

Project: spice-vd_agent
File: console-kit.c

static char *console_kit_get_first_seat(struct session_info *info)
{
    DBusError error;
    DBusMessage *message = NULL;
    DBusMessage *reply = NULL;
    DBusMessageIter iter, subiter;
    int type;
    char *seat = NULL;


    message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
                                           OBJ_PATH_CONSOLE_KIT_MANAGER,
                                           INTERFACE_CONSOLE_KIT_MANAGER,
                                           "GetSeats");
    if (message == NULL) {
        syslog(LOG_ERR, "Unable to create dbus message");
        goto exit;
    }

    dbus_error_init(&error);
    reply = dbus_connection_send_with_reply_and_block(info->connection,
                                                      message,
                                                      -1,
                                                      &error);
    if (reply == NULL || dbus_error_is_set(&error)) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR, "GetSeats failed: %s", error.message);
            dbus_error_free(&error);
        } else
            syslog(LOG_ERR, "GetSeats failed");
        goto exit;
    }

    dbus_message_iter_init(reply, &iter);
    type = dbus_message_iter_get_arg_type(&iter);
    if (type != DBUS_TYPE_ARRAY) {
        syslog(LOG_ERR,
               "expected an array return value, got a '%c' instead", type);
        goto exit;
    }

    dbus_message_iter_recurse(&iter, &subiter);
    type = dbus_message_iter_get_arg_type(&subiter);
    if (type != DBUS_TYPE_OBJECT_PATH) {
        syslog(LOG_ERR,
               "expected an object path element, got a '%c' instead", type);
        goto exit;
    }

    dbus_message_iter_get_basic(&subiter, &seat);
    info->seat = g_strdup(seat);

exit:
    if (reply != NULL) {
            dbus_message_unref(reply);
    }

    if (message != NULL) {
            dbus_message_unref(message);
    }

    syslog(LOG_INFO, "(console-kit) seat: %s", info->seat);
    return info->seat;
}

Project: spice-vd_agent
File: console-kit.c

uid_t session_info_uid_for_session(struct session_info *info, const char *session)
{
    DBusError error;
    DBusMessage *message = NULL;
    DBusMessage *reply = NULL;
    uint32_t uid;
    uid_t ret = -1;
    const char *err_msg;

    g_return_val_if_fail(info != NULL, ret);
    g_return_val_if_fail(info->connection != NULL, ret);
    g_return_val_if_fail(info->active_session != NULL, ret);

    dbus_error_init(&error);

    err_msg = "(console-kit) Unable to create dbus message for GetUnixUser";
    message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
                                           session,
                                           INTERFACE_CONSOLE_KIT_SESSION,
                                           "GetUnixUser");
    if (message == NULL) {
        goto exit;
    }

    err_msg = "(console-kit) GetUnixUser failed";
    reply = dbus_connection_send_with_reply_and_block(info->connection,
                                                      message,
                                                      -1,
                                                      &error);
    if (reply == NULL || dbus_error_is_set(&error)) {
        goto exit;
    }

    dbus_error_init(&error);
    err_msg = "(console-kit) fail to get session-type from reply";
    if (!dbus_message_get_args(reply,
                               &error,
                               DBUS_TYPE_UINT32, &uid,
                               DBUS_TYPE_INVALID)) {
        goto exit;
    }

    if (info->verbose) {
        syslog(LOG_DEBUG, "(console-kit) unix user is '%u'", (unsigned) uid);
    }

    err_msg = NULL;
    ret = uid;

exit:
    if (err_msg) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR, "%s: %s", err_msg, error.message);
            dbus_error_free(&error);
        } else {
            syslog(LOG_ERR, "%s", err_msg);
        }
    }
    if (reply != NULL) {
        dbus_message_unref(reply);
    }
    if (message != NULL) {
        dbus_message_unref(message);
    }
    return ret;
}

Project: spice-vd_agent
File: console-kit.c

gboolean session_info_is_user(struct session_info *info)
{
    DBusError error;
    DBusMessage *message = NULL;
    DBusMessage *reply = NULL;
    gchar *session_type = NULL;
    gboolean ret = TRUE;

    g_return_val_if_fail (info != NULL, TRUE);
    g_return_val_if_fail (info->connection != NULL, TRUE);
    g_return_val_if_fail (info->active_session != NULL, TRUE);

    message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
                                           info->active_session,
                                           INTERFACE_CONSOLE_KIT_SESSION,
                                           "GetSessionType");
    if (message == NULL) {
        syslog(LOG_ERR,
               "(console-kit) Unable to create dbus message for GetSessionType");
        return TRUE;
    }

    dbus_error_init(&error);
    reply = dbus_connection_send_with_reply_and_block(info->connection,
                                                      message,
                                                      -1,
                                                      &error);
    if (reply == NULL || dbus_error_is_set(&error)) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR, "GetSessionType failed: %s", error.message);
            dbus_error_free(&error);
        } else
            syslog(LOG_ERR, "GetSessionType failed");
        goto exit;
    }

    dbus_error_init(&error);
    if (!dbus_message_get_args(reply,
                               &error,
                               DBUS_TYPE_STRING, &session_type,
                               DBUS_TYPE_INVALID)) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR,
                   "(console-kit) fail to get session-type from reply: %s",
                   error.message);
            dbus_error_free(&error);
        } else {
            syslog(LOG_ERR, "(console-kit) fail to get session-type from reply");
        }
        session_type = NULL;
        goto exit;
    }

    /* Empty session_type means user */
    if (info->verbose)
        syslog(LOG_DEBUG, "(console-kit) session-type is '%s'", session_type);

    ret = (g_strcmp0 (session_type, "LoginWindow") != 0);

exit:
    if (reply != NULL) {
        dbus_message_unref(reply);
    }
    if (message != NULL) {
        dbus_message_unref(message);
    }
    return ret;
}

Project: spice-vd_agent
File: console-kit.c

const char *session_info_get_active_session(struct session_info *info)
{
    DBusError error;
    DBusMessage *message = NULL;
    DBusMessage *reply = NULL;
    char *session = NULL;

    if (!info)
        return NULL;

    if (info->active_session)
        return console_kit_check_active_session_change(info);

    message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
                                           info->seat,
                                           INTERFACE_CONSOLE_KIT_SEAT,
                                           "GetActiveSession");
    if (message == NULL) {
        syslog(LOG_ERR, "Unable to create dbus message");
        goto exit;
    }

    dbus_error_init(&error);
    reply = dbus_connection_send_with_reply_and_block(info->connection,
                                                      message,
                                                      -1,
                                                      &error);
    if (reply == NULL || dbus_error_is_set(&error)) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR, "GetActiveSession failed: %s", error.message);
            dbus_error_free(&error);
        } else
            syslog(LOG_ERR, "GetActiveSession failed");
        goto exit;
    }

    dbus_error_init(&error);
    if (!dbus_message_get_args(reply,
                               &error,
                               DBUS_TYPE_OBJECT_PATH, &session,
                               DBUS_TYPE_INVALID)) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
            dbus_error_free(&error);
        } else
            syslog(LOG_ERR, "error getting ssid from reply");
        session = NULL;
        goto exit;
    }

    info->active_session = g_strdup(session);
    si_dbus_match_rule_update(info);

exit:
    if (reply != NULL) {
            dbus_message_unref(reply);
    }

    if (message != NULL) {
            dbus_message_unref(message);
    }

    /* In case the session was changed while we were running */
    return console_kit_check_active_session_change(info);
}

Project: spice-vd_agent
File: console-kit.c

void session_info_destroy(struct session_info *info)
{
    if (!info)
        return;

    si_dbus_match_remove(info);
    dbus_connection_close(info->connection);
    g_free(info->seat);
    g_free(info->active_session);
    g_free(info);
}

Project: spice-vd_agent
File: dummy-session-info.c

void session_info_destroy(struct session_info *si)
{
}

Project: spice-vd_agent
File: console-kit.c

char *session_info_session_for_pid(struct session_info *info, uint32_t pid)
{
    DBusError error;
    DBusMessage *message = NULL;
    DBusMessage *reply = NULL;
    DBusMessageIter args;
    char *ssid = NULL;

    if (!info)
        return NULL;

    message = dbus_message_new_method_call(INTERFACE_CONSOLE_KIT,
                                           OBJ_PATH_CONSOLE_KIT_MANAGER,
                                           INTERFACE_CONSOLE_KIT_MANAGER,
                                           "GetSessionForUnixProcess");
    if (message == NULL) {
        syslog(LOG_ERR, "Unable to create dbus message");
        goto exit;
    }

    dbus_message_iter_init_append(message, &args);
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
        syslog(LOG_ERR, "Unable to append dbus message args");
        goto exit;
    }

    dbus_error_init(&error);
    reply = dbus_connection_send_with_reply_and_block(info->connection,
                                                      message,
                                                      -1,
                                                      &error);
    if (reply == NULL || dbus_error_is_set(&error)) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR, "GetSessionForUnixProcess failed: %s",
                   error.message);
            dbus_error_free(&error);
        } else
            syslog(LOG_ERR, "GetSessionForUnixProcess failed");
        goto exit;
    }

    dbus_error_init(&error);
    if (!dbus_message_get_args(reply,
                               &error,
                               DBUS_TYPE_OBJECT_PATH, &ssid,
                               DBUS_TYPE_INVALID)) {
        if (dbus_error_is_set(&error)) {
            syslog(LOG_ERR, "error get ssid from reply: %s", error.message);
            dbus_error_free(&error);
        } else
            syslog(LOG_ERR, "error getting ssid from reply");
        ssid = NULL;
        goto exit;
    }

    ssid = strdup(ssid);

exit:
    if (reply != NULL) {
            dbus_message_unref(reply);
    }

    if (message != NULL) {
            dbus_message_unref(message);
    }

    return ssid;
}

Project: spice-vd_agent
File: console-kit.c

si_dbus_read_signals(struct session_info *info)
{
    DBusMessage *message = NULL;

    dbus_connection_read_write(info->connection, 0);
    message = dbus_connection_pop_message(info->connection);
    while (message != NULL) {
        const char *member;

        member = dbus_message_get_member (message);
        if (g_strcmp0(member, SEAT_SIGNAL_ACTIVE_SESSION_CHANGED) == 0) {
            DBusMessageIter iter;
            gint type;
            gchar *session;

            g_clear_pointer(&info->active_session, g_free);

            dbus_message_iter_init(message, &iter);
            type = dbus_message_iter_get_arg_type(&iter);
            /* Session should be an object path, but there is a bug in
               ConsoleKit where it sends a string rather than an object_path
               accept object_path too in case the bug ever gets fixed */
            if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
                dbus_message_iter_get_basic(&iter, &session);
                if (session != NULL && session[0] != '\0') {
                    info->active_session = g_strdup(session);
                    si_dbus_match_rule_update(info);
                } else {
                    syslog(LOG_WARNING, "(console-kit) received invalid session. "
                           "No active-session at the moment");
                }
            } else {
                syslog(LOG_ERR,
                       "ActiveSessionChanged message has unexpected type: '%c'",
                       type);
            }
        } else if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) {
            info->session_is_locked = TRUE;
        } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) {
            info->session_is_locked = FALSE;
        } else if (g_strcmp0(member, SESSION_SIGNAL_IDLE_HINT_CHANGED) == 0) {
            DBusMessageIter iter;
            gint type;
            dbus_bool_t idle_hint;

            dbus_message_iter_init(message, &iter);
            type = dbus_message_iter_get_arg_type(&iter);
            if (type == DBUS_TYPE_BOOLEAN) {
                dbus_message_iter_get_basic(&iter, &idle_hint);
                info->session_idle_hint = (idle_hint);
            } else {
                syslog(LOG_ERR,
                       "(console-kit) IdleHintChanged has unexpected type: '%c'",
                       type);
            }
        } else {
            if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
                syslog(LOG_WARNING, "(console-kit) received non signal message");
            } else if (info->verbose) {
                syslog(LOG_DEBUG, "(console-kit) Signal not handled: %s", member);
            }
        }

        dbus_message_unref(message);
        dbus_connection_read_write(info->connection, 0);
        message = dbus_connection_pop_message(info->connection);
    }
}

Project: spice-vd_agent
File: console-kit.c

static char *console_kit_check_active_session_change(struct session_info *info)
{
    si_dbus_read_signals(info);
    if (info->verbose)
        syslog(LOG_DEBUG, "(console-kit) active-session: '%s'",
               (info->active_session ? info->active_session : "None"));

    return info->active_session;
}