Blame src/dbus/abrt_problems2_session.c

Packit 8ea169
/*
Packit 8ea169
  Copyright (C) 2015  ABRT team
Packit 8ea169
Packit 8ea169
  This program is free software; you can redistribute it and/or modify
Packit 8ea169
  it under the terms of the GNU General Public License as published by
Packit 8ea169
  the Free Software Foundation; either version 2 of the License, or
Packit 8ea169
  (at your option) any later version.
Packit 8ea169
Packit 8ea169
  This program is distributed in the hope that it will be useful,
Packit 8ea169
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8ea169
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8ea169
  GNU General Public License for more details.
Packit 8ea169
Packit 8ea169
  You should have received a copy of the GNU General Public License along
Packit 8ea169
  with this program; if not, write to the Free Software Foundation, Inc.,
Packit 8ea169
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Packit 8ea169
*/
Packit 8ea169
Packit 8ea169
#ifdef HAVE_CONFIG_H
Packit 8ea169
#include <config.h>
Packit 8ea169
#endif
Packit 8ea169
Packit 8ea169
#include "abrt_problems2_session.h"
Packit 8ea169
Packit 8ea169
#include "libabrt.h"
Packit 8ea169
Packit 8ea169
static PolkitAuthority *s_pk_authority;
Packit 8ea169
Packit 8ea169
PolkitAuthority *abrt_p2_session_class_set_polkit_authority(PolkitAuthority *pk_authority)
Packit 8ea169
{
Packit 8ea169
    if (s_pk_authority != NULL)
Packit 8ea169
    {
Packit 8ea169
        log_warning("Session: polkit Authority already initialized");
Packit 8ea169
Packit 8ea169
        /*
Packit 8ea169
         * Introduce something like this to libreport
Packit 8ea169
        if (g_verbose > 3)
Packit 8ea169
            abort();
Packit 8ea169
        */
Packit 8ea169
        return s_pk_authority;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    s_pk_authority = pk_authority;
Packit 8ea169
Packit 8ea169
    return s_pk_authority;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
PolkitAuthority *abrt_p2_session_class_polkit_authority(void)
Packit 8ea169
{
Packit 8ea169
    if (s_pk_authority == NULL)
Packit 8ea169
        log_debug("Session: Polkit Authority not-yet initialized");
Packit 8ea169
Packit 8ea169
    return s_pk_authority;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
PolkitAuthority *abrt_p2_session_class_release_polkit_authority(void)
Packit 8ea169
{
Packit 8ea169
    PolkitAuthority *pk_authority = s_pk_authority;
Packit 8ea169
    s_pk_authority = NULL;
Packit 8ea169
    return pk_authority;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
typedef struct
Packit 8ea169
{
Packit 8ea169
    char     *p2s_caller;
Packit 8ea169
    uid_t    p2s_uid;
Packit 8ea169
    int      p2s_state;
Packit 8ea169
    GList    *p2s_tasks;
Packit 8ea169
    uint32_t p2s_task_indexer;
Packit 8ea169
    GHashTable *p2s_tokens;
Packit 8ea169
    struct check_auth_cb_params *p2s_auth_rq;
Packit 8ea169
    PolkitSubject *p2s_pk_subject;
Packit 8ea169
} AbrtP2SessionPrivate;
Packit 8ea169
Packit 8ea169
enum
Packit 8ea169
{
Packit 8ea169
    ABRT_P2_SESSION_STATE_INIT,
Packit 8ea169
    ABRT_P2_SESSION_STATE_PENDING,
Packit 8ea169
    ABRT_P2_SESSION_STATE_AUTH,
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
struct _AbrtP2Session
Packit 8ea169
{
Packit 8ea169
    GObject parent_instance;
Packit 8ea169
    AbrtP2SessionPrivate *pv;
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
G_DEFINE_TYPE_WITH_PRIVATE(AbrtP2Session, abrt_p2_session, G_TYPE_OBJECT)
Packit 8ea169
Packit 8ea169
struct check_auth_cb_params
Packit 8ea169
{
Packit 8ea169
    AbrtP2Session *session;
Packit 8ea169
    GCancellable *cancellable;
Packit 8ea169
    PolkitDetails *details;
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
enum {
Packit 8ea169
    SN_AUTHORIZATION_CHANGED,
Packit 8ea169
    SN_LAST_SIGNAL
Packit 8ea169
} SignalNumber;
Packit 8ea169
Packit 8ea169
static guint s_signals[SN_LAST_SIGNAL] = { 0 };
Packit 8ea169
Packit 8ea169
static void abrt_p2_session_finalize(GObject *gobject)
Packit 8ea169
{
Packit 8ea169
    AbrtP2SessionPrivate *pv = abrt_p2_session_get_instance_private(ABRT_P2_SESSION(gobject));
Packit 8ea169
    free(pv->p2s_caller);
Packit 8ea169
    g_hash_table_destroy(pv->p2s_tokens);
Packit 8ea169
Packit 8ea169
    /* If there is ongoing authorization, */
Packit 8ea169
    /* tell the callback that it must not touch session.*/
Packit 8ea169
    if (pv->p2s_auth_rq != NULL)
Packit 8ea169
        pv->p2s_auth_rq->session = NULL;
Packit 8ea169
Packit 8ea169
    if (pv->p2s_pk_subject != NULL)
Packit 8ea169
        g_object_unref(pv->p2s_pk_subject);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void abrt_p2_session_class_init(AbrtP2SessionClass *klass)
Packit 8ea169
{
Packit 8ea169
    GObjectClass *object_class = G_OBJECT_CLASS(klass);
Packit 8ea169
    object_class->finalize = abrt_p2_session_finalize;
Packit 8ea169
Packit 8ea169
    s_signals[SN_AUTHORIZATION_CHANGED] = g_signal_new ("authorization-changed",
Packit 8ea169
                                                        G_TYPE_FROM_CLASS (klass),
Packit 8ea169
                                                        G_SIGNAL_RUN_LAST,
Packit 8ea169
                                                        G_STRUCT_OFFSET(AbrtP2SessionClass, authorization_changed),
Packit 8ea169
                                                        /*accumulator*/NULL, /*accu_data*/NULL,
Packit 8ea169
                                                        g_cclosure_marshal_VOID__INT,
Packit 8ea169
                                                        G_TYPE_NONE,
Packit 8ea169
                                                        /*n_params*/1,
Packit 8ea169
                                                        G_TYPE_INT);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void abrt_p2_session_init(AbrtP2Session *self)
Packit 8ea169
{
Packit 8ea169
    self->pv = abrt_p2_session_get_instance_private(self);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void emit_authorization_changed(AbrtP2Session *session,
Packit 8ea169
            AbrtP2SessionAuthChangedStatus status)
Packit 8ea169
{
Packit 8ea169
    g_signal_emit(session,
Packit 8ea169
                  s_signals[SN_AUTHORIZATION_CHANGED],
Packit 8ea169
                  0,
Packit 8ea169
                  (gint32)status);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void change_state(AbrtP2Session *session, int new_state)
Packit 8ea169
{
Packit 8ea169
    if (session->pv->p2s_state == new_state)
Packit 8ea169
        return;
Packit 8ea169
Packit 8ea169
    AbrtP2SessionAuthChangedStatus value = -1;
Packit 8ea169
    int old_state = session->pv->p2s_state;
Packit 8ea169
    session->pv->p2s_state = new_state;
Packit 8ea169
Packit 8ea169
    if      (old_state == ABRT_P2_SESSION_STATE_INIT    && new_state == ABRT_P2_SESSION_STATE_PENDING)
Packit 8ea169
    {
Packit 8ea169
        log_debug("Authorization request is pending");
Packit 8ea169
        value = ABRT_P2_SESSION_CHANGED_PENDING;
Packit 8ea169
    }
Packit 8ea169
    else if (old_state == ABRT_P2_SESSION_STATE_INIT    && new_state == ABRT_P2_SESSION_STATE_AUTH)
Packit 8ea169
    {
Packit 8ea169
        log_debug("Authorization has been granted");
Packit 8ea169
        value = ABRT_P2_SESSION_CHANGED_AUTHORIZED;
Packit 8ea169
    }
Packit 8ea169
    else if (old_state == ABRT_P2_SESSION_STATE_PENDING && new_state == ABRT_P2_SESSION_STATE_AUTH)
Packit 8ea169
    {
Packit 8ea169
        log_debug("Authorization has been acquired");
Packit 8ea169
        value = ABRT_P2_SESSION_CHANGED_AUTHORIZED;
Packit 8ea169
    }
Packit 8ea169
    else if (old_state == ABRT_P2_SESSION_STATE_AUTH    && new_state == ABRT_P2_SESSION_STATE_INIT)
Packit 8ea169
    {
Packit 8ea169
        log_debug("Authorization request has been lost");
Packit 8ea169
        value = ABRT_P2_SESSION_CHANGED_NOT_AUTHORIZED;
Packit 8ea169
    }
Packit 8ea169
    else if (old_state == ABRT_P2_SESSION_STATE_PENDING && new_state == ABRT_P2_SESSION_STATE_INIT)
Packit 8ea169
    {
Packit 8ea169
        log_debug("Authorization request has failed");
Packit 8ea169
        value = ABRT_P2_SESSION_CHANGED_FAILED;
Packit 8ea169
    }
Packit 8ea169
    else
Packit 8ea169
        goto forgotten_state;
Packit 8ea169
Packit 8ea169
    emit_authorization_changed(session, value);
Packit 8ea169
    return;
Packit 8ea169
Packit 8ea169
forgotten_state:
Packit 8ea169
    error_msg("BUG: unsupported state, current : %d, new : %d",
Packit 8ea169
              session->pv->p2s_state,
Packit 8ea169
              new_state);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
#ifdef HAVE_POLKIT
Packit 8ea169
static void check_authorization_callback(GObject *source,
Packit 8ea169
            GAsyncResult *res,
Packit 8ea169
            gpointer user_data)
Packit 8ea169
{
Packit 8ea169
    GError *error = NULL;
Packit 8ea169
    PolkitAuthorizationResult *result = NULL;
Packit 8ea169
    result = polkit_authority_check_authorization_finish(POLKIT_AUTHORITY(source),
Packit 8ea169
                                                         res,
Packit 8ea169
                                                         &error);
Packit 8ea169
Packit 8ea169
    int new_state = ABRT_P2_SESSION_STATE_INIT;
Packit 8ea169
    if (result == NULL)
Packit 8ea169
    {
Packit 8ea169
       error_msg("Polkit authorization failed: %s", error->message);
Packit 8ea169
       g_error_free(error);
Packit 8ea169
    }
Packit 8ea169
    else
Packit 8ea169
    {
Packit 8ea169
        if (polkit_authorization_result_get_is_authorized(result))
Packit 8ea169
            new_state = ABRT_P2_SESSION_STATE_AUTH;
Packit 8ea169
        else
Packit 8ea169
            /* We do not support polkit_authorization_result_get_is_challenge */
Packit 8ea169
            log_debug("Not authorized");
Packit 8ea169
Packit 8ea169
        g_object_unref(result);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    struct check_auth_cb_params *params = (struct check_auth_cb_params *)user_data;
Packit 8ea169
    AbrtP2Session *session = params->session;
Packit 8ea169
    g_object_unref(params->cancellable);
Packit 8ea169
Packit 8ea169
    if (params->details != NULL)
Packit 8ea169
        g_object_unref(params->details);
Packit 8ea169
Packit 8ea169
    free(params);
Packit 8ea169
Packit 8ea169
    /* It might happen that the session had been destroyed before the callback
Packit 8ea169
     * was called (e.g. if you programmatically cancel the operation, this
Packit 8ea169
     * callback is called in the next main loop iteration). */
Packit 8ea169
    if (session != NULL)
Packit 8ea169
    {
Packit 8ea169
        change_state(session, new_state);
Packit 8ea169
        session->pv->p2s_auth_rq = NULL;
Packit 8ea169
    }
Packit 8ea169
    else
Packit 8ea169
        log_debug("Operation finished after the session had been destroyed");
Packit 8ea169
}
Packit 8ea169
#endif
Packit 8ea169
Packit 8ea169
static void authorization_request_initialize(AbrtP2Session *session, GVariant *parameters)
Packit 8ea169
{
Packit 8ea169
#ifdef HAVE_POLKIT
Packit 8ea169
    struct check_auth_cb_params *auth_rq = xmalloc(sizeof(*auth_rq));
Packit 8ea169
    auth_rq->session = session;
Packit 8ea169
    auth_rq->cancellable = g_cancellable_new();
Packit 8ea169
Packit 8ea169
    auth_rq->details = NULL;
Packit 8ea169
    if (parameters != NULL)
Packit 8ea169
    {
Packit 8ea169
        GVariant *message = g_variant_lookup_value(parameters,
Packit 8ea169
                                                   "message",
Packit 8ea169
                                                   G_VARIANT_TYPE_STRING);
Packit 8ea169
Packit 8ea169
        if (message != NULL)
Packit 8ea169
        {
Packit 8ea169
            auth_rq->details = polkit_details_new();
Packit 8ea169
            polkit_details_insert(auth_rq->details,
Packit 8ea169
                                  "polkit.message",
Packit 8ea169
                                  g_variant_get_string(message,
Packit 8ea169
                                                       NULL));
Packit 8ea169
Packit 8ea169
            g_variant_unref(message);
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    session->pv->p2s_auth_rq = auth_rq;
Packit 8ea169
    change_state(session, ABRT_P2_SESSION_STATE_PENDING);
Packit 8ea169
Packit 8ea169
    /* http://www.freedesktop.org/software/polkit/docs/latest/polkit-apps.html
Packit 8ea169
     */
Packit 8ea169
    if (session->pv->p2s_pk_subject == NULL)
Packit 8ea169
        session->pv->p2s_pk_subject = polkit_system_bus_name_new(session->pv->p2s_caller);
Packit 8ea169
Packit 8ea169
    /* If you cancel this operation programmatically, you might get the
Packit 8ea169
     * following warning message:
Packit 8ea169
         WARNING **: Error cancelling authorization check:
Packit 8ea169
         GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed:
Packit 8ea169
         No such cancellation_id `cancellation-id-1' for name :1.257
Packit 8ea169
Packit 8ea169
       The message is returned by polkitbackend and it just means that there
Packit 8ea169
       were nothing to cancel. Probably because the operation was already
Packit 8ea169
       finished or not-yet started.
Packit 8ea169
       */
Packit 8ea169
    polkit_authority_check_authorization(abrt_p2_session_class_polkit_authority(),
Packit 8ea169
                                         session->pv->p2s_pk_subject,
Packit 8ea169
                                         "org.freedesktop.problems.getall",
Packit 8ea169
                                         auth_rq->details,
Packit 8ea169
                                         POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
Packit 8ea169
                                         auth_rq->cancellable,
Packit 8ea169
                                         check_authorization_callback,
Packit 8ea169
                                         auth_rq);
Packit 8ea169
#else
Packit 8ea169
    change_state(session, ABRT_P2_SESSION_STATE_AUTH);
Packit 8ea169
#endif
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
AbrtP2Session *abrt_p2_session_new(char *caller, uid_t uid)
Packit 8ea169
{
Packit 8ea169
    AbrtP2Session *session = g_object_new(TYPE_ABRT_P2_SESSION, NULL);
Packit 8ea169
    session->pv->p2s_caller = caller;
Packit 8ea169
    session->pv->p2s_uid = uid;
Packit 8ea169
Packit 8ea169
    if (session->pv->p2s_uid == 0)
Packit 8ea169
        session->pv->p2s_state = ABRT_P2_SESSION_STATE_AUTH;
Packit 8ea169
    else
Packit 8ea169
        session->pv->p2s_state = ABRT_P2_SESSION_STATE_INIT;
Packit 8ea169
Packit 8ea169
    session->pv->p2s_tokens = g_hash_table_new_full(g_str_hash,
Packit 8ea169
                                                    g_str_equal,
Packit 8ea169
                                                    g_free,
Packit 8ea169
                                                    NULL);
Packit 8ea169
Packit 8ea169
    return session;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
const char *abrt_p2_session_generate_token(AbrtP2Session *session,
Packit 8ea169
            unsigned int duration,
Packit 8ea169
            GError **error)
Packit 8ea169
{
Packit 8ea169
    if (session->pv->p2s_state != ABRT_P2_SESSION_STATE_AUTH)
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                    "Session is not authorized");
Packit 8ea169
        return NULL;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
#define SESSION_TOKEN_LENGTH 16
Packit 8ea169
    static const char *const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Packit 8ea169
Packit 8ea169
    if (duration == 0)
Packit 8ea169
        duration = 5;
Packit 8ea169
Packit 8ea169
    FILE *urandom = fopen("/dev/urandom", "rb");
Packit 8ea169
Packit 8ea169
    if (urandom == NULL)
Packit 8ea169
    {
Packit 8ea169
        perror_msg("fopen(/dev/urandom, rb)");
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                    "Failed to open /dev/urandom for reading");
Packit 8ea169
        return NULL;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    unsigned int seed = 0;
Packit 8ea169
    const size_t r = fread(&seed, 1, sizeof(seed), urandom);
Packit 8ea169
    fclose(urandom);
Packit 8ea169
Packit 8ea169
    if (sizeof(seed) != r)
Packit 8ea169
    {
Packit 8ea169
        perror_msg("fread(unsigned int, /dev/urandom)");
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                    "Failed to read 'unsigned int' from /dev/urandom");
Packit 8ea169
        return NULL;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    char *token = xmalloc((SESSION_TOKEN_LENGTH + 1) * sizeof(char));
Packit 8ea169
    for (char *iter = token; iter < token + SESSION_TOKEN_LENGTH; ++iter)
Packit 8ea169
        *iter = alphabet[(int)(strlen(alphabet) * (rand_r(&seed) / (double)RAND_MAX))];
Packit 8ea169
Packit 8ea169
    token[SESSION_TOKEN_LENGTH] = '\0';
Packit 8ea169
Packit 8ea169
    const time_t curtime = time(NULL);
Packit 8ea169
    if (curtime == ((time_t) -1))
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                    "Cannot get current time");
Packit 8ea169
        free(token);
Packit 8ea169
        return NULL;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    g_hash_table_insert(session->pv->p2s_tokens,
Packit 8ea169
                        token,
Packit 8ea169
                        GINT_TO_POINTER(curtime + duration));
Packit 8ea169
Packit 8ea169
    return token;
Packit 8ea169
#undef SESSION_TOKEN_LENGTH
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int abrt_p2_session_revoke_token(AbrtP2Session *session,
Packit 8ea169
            const char *token)
Packit 8ea169
{
Packit 8ea169
    return g_hash_table_remove(session->pv->p2s_tokens, token) ? 0 : 1;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static AbrtP2SessionAuthRequestRet abrt_p2_session_authorize_peer_with_token(
Packit 8ea169
            AbrtP2Session *session,
Packit 8ea169
            AbrtP2Session *peer_session,
Packit 8ea169
            const char *token,
Packit 8ea169
            GError **error)
Packit 8ea169
{
Packit 8ea169
    if (session->pv->p2s_state != ABRT_P2_SESSION_STATE_AUTH)
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
Packit 8ea169
                    "Not authorized session cannot pass authorization");
Packit 8ea169
        return ABRT_P2_SESSION_AUTHORIZE_FAILED;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (session->pv->p2s_uid != peer_session->pv->p2s_uid)
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
Packit 8ea169
                    "Session owners do not match");
Packit 8ea169
        return ABRT_P2_SESSION_AUTHORIZE_FAILED;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    const gpointer expire = g_hash_table_lookup(session->pv->p2s_tokens, token);
Packit 8ea169
    if (expire == NULL)
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
Packit 8ea169
                    "No such token");
Packit 8ea169
        return ABRT_P2_SESSION_AUTHORIZE_FAILED;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    const time_t curtime = time(NULL);
Packit 8ea169
    if (curtime == ((time_t) -1))
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                    "Cannot get current time");
Packit 8ea169
        return ABRT_P2_SESSION_AUTHORIZE_FAILED;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (curtime > (time_t)(GPOINTER_TO_INT(expire)))
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
Packit 8ea169
                    "Token has already expired");
Packit 8ea169
        return ABRT_P2_SESSION_AUTHORIZE_FAILED;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    g_hash_table_remove(session->pv->p2s_tokens, token);
Packit 8ea169
    abrt_p2_session_grant_authorization(peer_session);
Packit 8ea169
Packit 8ea169
    log_info("Granted authorization to peer session on '%s' bus",
Packit 8ea169
             peer_session->pv->p2s_caller);
Packit 8ea169
Packit 8ea169
    return ABRT_P2_SESSION_AUTHORIZE_GRANTED;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static int abrt_p2_session_cmp_caller(AbrtP2Session *lhs, const char *bus_name)
Packit 8ea169
{
Packit 8ea169
    return strcmp(lhs->pv->p2s_caller, bus_name);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static AbrtP2SessionAuthRequestRet _abrt_p2_session_begin_auth(AbrtP2Session *session,
Packit 8ea169
            GVariant *parameters,
Packit 8ea169
            GList *peers,
Packit 8ea169
            GError **error)
Packit 8ea169
{
Packit 8ea169
    AbrtP2SessionAuthRequestRet ret = ABRT_P2_SESSION_AUTHORIZE_FAILED;
Packit 8ea169
Packit 8ea169
    GVariant *peer_bus = g_variant_lookup_value(parameters,
Packit 8ea169
                                                "problems2.peer-bus",
Packit 8ea169
                                                G_VARIANT_TYPE_STRING);
Packit 8ea169
Packit 8ea169
    GVariant *peer_token = g_variant_lookup_value(parameters,
Packit 8ea169
                                             "problems2.peer-token",
Packit 8ea169
                                             G_VARIANT_TYPE_STRING);
Packit 8ea169
Packit 8ea169
    if (!peer_bus && !peer_token)
Packit 8ea169
    {
Packit 8ea169
        authorization_request_initialize(session, parameters);
Packit 8ea169
        ret = ABRT_P2_SESSION_AUTHORIZE_ACCEPTED;
Packit 8ea169
    }
Packit 8ea169
    else if (peer_bus && peer_token)
Packit 8ea169
    {
Packit 8ea169
        const gchar *bus = g_variant_get_string(peer_bus, NULL);
Packit 8ea169
        GList *tmp = g_list_find_custom(peers,
Packit 8ea169
                                        bus,
Packit 8ea169
                                        (GCompareFunc)abrt_p2_session_cmp_caller);
Packit 8ea169
        if (tmp == NULL)
Packit 8ea169
        {
Packit 8ea169
            g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                        "No peer session for bus '%s'",
Packit 8ea169
                        g_variant_get_string(peer_bus, NULL));
Packit 8ea169
            goto finito;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        AbrtP2Session *peer_session = (AbrtP2Session *)tmp->data;
Packit 8ea169
        const gchar *token = g_variant_get_string(peer_token, NULL);
Packit 8ea169
        ret = abrt_p2_session_authorize_peer_with_token(peer_session,
Packit 8ea169
                                                        session,
Packit 8ea169
                                                        token,
Packit 8ea169
                                                        error);
Packit 8ea169
    }
Packit 8ea169
    else /* if ((peer_bus && !peer_token) || (!peer_bus && peer_token)) */
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                    "Invalid parameters peer-bus and peer-token.");
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
finito:
Packit 8ea169
    if (peer_bus != NULL)
Packit 8ea169
        g_variant_unref(peer_bus);
Packit 8ea169
Packit 8ea169
    if (peer_token != NULL)
Packit 8ea169
        g_variant_unref(peer_token);
Packit 8ea169
Packit 8ea169
    return ret;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
AbrtP2SessionAuthRequestRet abrt_p2_session_authorize(AbrtP2Session *session,
Packit 8ea169
            GVariant *parameters,
Packit 8ea169
            GList *peers,
Packit 8ea169
            GError **error)
Packit 8ea169
{
Packit 8ea169
    switch(session->pv->p2s_state)
Packit 8ea169
    {
Packit 8ea169
        case ABRT_P2_SESSION_STATE_INIT:
Packit 8ea169
            return _abrt_p2_session_begin_auth(session, parameters, peers, error);
Packit 8ea169
Packit 8ea169
        case ABRT_P2_SESSION_STATE_PENDING:
Packit 8ea169
            return ABRT_P2_SESSION_AUTHORIZE_PENDING;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_SESSION_STATE_AUTH:
Packit 8ea169
            return ABRT_P2_SESSION_AUTHORIZE_GRANTED;
Packit 8ea169
Packit 8ea169
        default:
Packit 8ea169
            error_msg("BUG: %s: forgotten state -> %d", __func__, session->pv->p2s_state);
Packit 8ea169
            return ABRT_P2_SESSION_AUTHORIZE_FAILED;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
void abrt_p2_session_revoke_authorization(AbrtP2Session *session)
Packit 8ea169
{
Packit 8ea169
    if (session->pv->p2s_uid == 0)
Packit 8ea169
        return;
Packit 8ea169
Packit 8ea169
    switch(session->pv->p2s_state)
Packit 8ea169
    {
Packit 8ea169
        case ABRT_P2_SESSION_STATE_AUTH:
Packit 8ea169
            change_state(session, ABRT_P2_SESSION_STATE_INIT);
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_SESSION_STATE_PENDING:
Packit 8ea169
            g_cancellable_cancel(session->pv->p2s_auth_rq->cancellable);
Packit 8ea169
            change_state(session, ABRT_P2_SESSION_STATE_INIT);
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_SESSION_STATE_INIT:
Packit 8ea169
            /* pass */
Packit 8ea169
            break;
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
AbrtP2SessionAuthRequestRet abrt_p2_session_grant_authorization(AbrtP2Session *session)
Packit 8ea169
{
Packit 8ea169
    switch(session->pv->p2s_state)
Packit 8ea169
    {
Packit 8ea169
        case ABRT_P2_SESSION_STATE_AUTH:
Packit 8ea169
            /* pass */
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_SESSION_STATE_PENDING:
Packit 8ea169
            g_cancellable_cancel(session->pv->p2s_auth_rq->cancellable);
Packit 8ea169
            change_state(session, ABRT_P2_SESSION_STATE_AUTH);
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_SESSION_STATE_INIT:
Packit 8ea169
            change_state(session, ABRT_P2_SESSION_STATE_AUTH);
Packit 8ea169
            break;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    return ABRT_P2_SESSION_AUTHORIZE_GRANTED;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
uid_t abrt_p2_session_uid(AbrtP2Session *session)
Packit 8ea169
{
Packit 8ea169
    return session->pv->p2s_uid;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
const char *abrt_p2_session_caller(AbrtP2Session *session)
Packit 8ea169
{
Packit 8ea169
    return session->pv->p2s_caller;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int abrt_p2_session_is_authorized(AbrtP2Session *session)
Packit 8ea169
{
Packit 8ea169
    return session->pv->p2s_state == ABRT_P2_SESSION_STATE_AUTH;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int abrt_p2_session_check_sanity(AbrtP2Session *session,
Packit 8ea169
            const char *caller,
Packit 8ea169
            uid_t caller_uid,
Packit 8ea169
            GError **error)
Packit 8ea169
{
Packit 8ea169
    if (strcmp(session->pv->p2s_caller, caller) == 0 && session->pv->p2s_uid == caller_uid)
Packit 8ea169
        /* the session node is sane */
Packit 8ea169
        return 0;
Packit 8ea169
Packit 8ea169
    log_warning("Problems2 Session object does not belong to UID %d", caller_uid);
Packit 8ea169
Packit 8ea169
    g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                "Your Problems2 Session is broken. Check system logs for more details.");
Packit 8ea169
    return -1;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
uint32_t abrt_p2_session_add_task(AbrtP2Session *session,
Packit 8ea169
            AbrtP2Task *task,
Packit 8ea169
            GError **error)
Packit 8ea169
{
Packit 8ea169
    if (session->pv->p2s_task_indexer == (UINT32_MAX - 1))
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                    "Reached the limit of task per session.");
Packit 8ea169
Packit 8ea169
        return UINT32_MAX;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (abrt_p2_session_owns_task(session, task) == 0)
Packit 8ea169
    {
Packit 8ea169
        g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
Packit 8ea169
                    "Task is already owned by the session");
Packit 8ea169
Packit 8ea169
        return UINT32_MAX;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    session->pv->p2s_tasks = g_list_prepend(session->pv->p2s_tasks, task);
Packit 8ea169
Packit 8ea169
    return session->pv->p2s_task_indexer++;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
void abrt_p2_session_remove_task(AbrtP2Session *session,
Packit 8ea169
            AbrtP2Task *task,
Packit 8ea169
            GError **error)
Packit 8ea169
{
Packit 8ea169
    session->pv->p2s_tasks = g_list_remove(session->pv->p2s_tasks, task);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
GList *abrt_p2_session_tasks(AbrtP2Session *session)
Packit 8ea169
{
Packit 8ea169
    return session->pv->p2s_tasks;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int abrt_p2_session_owns_task(AbrtP2Session *session,
Packit 8ea169
            AbrtP2Task *task)
Packit 8ea169
{
Packit 8ea169
    return !(g_list_find(session->pv->p2s_tasks, task));
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int abrt_p2_session_tasks_count(AbrtP2Session *session)
Packit 8ea169
{
Packit 8ea169
    return g_list_length(session->pv->p2s_tasks);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void abrt_p2_session_dispose_task(AbrtP2Task *task,
Packit 8ea169
            gint32 status)
Packit 8ea169
{
Packit 8ea169
    switch(status)
Packit 8ea169
    {
Packit 8ea169
        case ABRT_P2_TASK_STATUS_STOPPED:
Packit 8ea169
            {
Packit 8ea169
                GError *local_error = NULL;
Packit 8ea169
                abrt_p2_task_cancel(task, &local_error);
Packit 8ea169
                if (local_error != NULL)
Packit 8ea169
                {
Packit 8ea169
                    error_msg("Task garbage collector failed to cancel task: %s",
Packit 8ea169
                              local_error->message);
Packit 8ea169
Packit 8ea169
                    g_error_free(local_error);
Packit 8ea169
                }
Packit 8ea169
Packit 8ea169
                /* In case of errors, this could cause problems, but I
Packit 8ea169
                 * don't have better plan yet. */
Packit 8ea169
                log_debug("Disposed new/stopped task: %p", task);
Packit 8ea169
                g_object_unref(task);
Packit 8ea169
            }
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_TASK_STATUS_NEW:
Packit 8ea169
            log_debug("Disposed new task: %p", task);
Packit 8ea169
            g_object_unref(task);
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_TASK_STATUS_FAILED:
Packit 8ea169
            log_debug("Disposed failed task: %p", task);
Packit 8ea169
            g_object_unref(task);
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_TASK_STATUS_CANCELED:
Packit 8ea169
            log_debug("Disposed canceled task: %p", task);
Packit 8ea169
            g_object_unref(task);
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_TASK_STATUS_DONE:
Packit 8ea169
            log_debug("Disposed done task: %p", task);
Packit 8ea169
            g_object_unref(task);
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        case ABRT_P2_TASK_STATUS_RUNNING:
Packit 8ea169
            error_msg("BUG: cannot dispose RUNNING task");
Packit 8ea169
            abort();
Packit 8ea169
            break;
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void abrt_p2_session_delayed_dispose_task(AbrtP2Task *task,
Packit 8ea169
            gint32 status,
Packit 8ea169
            gpointer user_data)
Packit 8ea169
{
Packit 8ea169
    if (status == ABRT_P2_TASK_STATUS_RUNNING)
Packit 8ea169
    {
Packit 8ea169
        error_msg("BUG: task to dispose must not change state to RUNNING");
Packit 8ea169
Packit 8ea169
        abort();
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    log_debug("Going to dispose delayed task: %p: %d",
Packit 8ea169
              task,
Packit 8ea169
              status);
Packit 8ea169
Packit 8ea169
    abrt_p2_session_dispose_task(task, status);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
void abrt_p2_session_clean_tasks(AbrtP2Session *session)
Packit 8ea169
{
Packit 8ea169
    GList *task = session->pv->p2s_tasks;
Packit 8ea169
    session->pv->p2s_tasks = NULL;
Packit 8ea169
Packit 8ea169
    while (task != NULL)
Packit 8ea169
    {
Packit 8ea169
        AbrtP2Task *t = ABRT_P2_TASK(task->data);
Packit 8ea169
Packit 8ea169
        task = g_list_delete_link(task, task);
Packit 8ea169
Packit 8ea169
        const AbrtP2TaskStatus status = abrt_p2_task_status(t);
Packit 8ea169
        if (status != ABRT_P2_TASK_STATUS_RUNNING)
Packit 8ea169
        {
Packit 8ea169
            abrt_p2_session_dispose_task(t, status);
Packit 8ea169
            continue;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        log_debug("Delaying disposal of running task: %p", t);
Packit 8ea169
Packit 8ea169
        g_signal_connect(t,
Packit 8ea169
                         "status-changed",
Packit 8ea169
                         G_CALLBACK(abrt_p2_session_delayed_dispose_task),
Packit 8ea169
                         NULL);
Packit 8ea169
Packit 8ea169
        GError *local_error = NULL;
Packit 8ea169
        abrt_p2_task_cancel(t, &local_error);
Packit 8ea169
Packit 8ea169
        if (local_error != NULL)
Packit 8ea169
        {
Packit 8ea169
            error_msg("Task garbage collector failed to cancel running task: %s",
Packit 8ea169
                      local_error->message);
Packit 8ea169
Packit 8ea169
            g_error_free(local_error);
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
}