Blame src/dbus/abrt-dbus.c

Packit 8ea169
#include <dbus/dbus.h>
Packit 8ea169
#include <gio/gio.h>
Packit 8ea169
#include <stdlib.h>
Packit 8ea169
#include <sys/types.h>
Packit 8ea169
#include <pwd.h>
Packit 8ea169
#include <grp.h>
Packit 8ea169
#include "libabrt.h"
Packit 8ea169
#include "abrt-polkit.h"
Packit 8ea169
#include "abrt_glib.h"
Packit 8ea169
#include <libreport/dump_dir.h>
Packit 8ea169
#include "problem_api.h"
Packit 8ea169
Packit 8ea169
#include "abrt_problems2_entry.h"
Packit 8ea169
#include "abrt_problems2_service.h"
Packit 8ea169
Packit 8ea169
Packit 8ea169
static GMainLoop *loop;
Packit 8ea169
static guint g_timeout_source;
Packit 8ea169
/* default, settable with -t: */
Packit 8ea169
static unsigned g_timeout_value = 120;
Packit 8ea169
static guint g_signal_crash;
Packit 8ea169
static guint g_signal_dup_crash;
Packit 8ea169
Packit 8ea169
/* ---------------------------------------------------------------------------------------------------- */
Packit 8ea169
Packit 8ea169
static GDBusNodeInfo *introspection_data = NULL;
Packit 8ea169
Packit 8ea169
/* Introspection data for the service we are exporting */
Packit 8ea169
static const gchar introspection_xml[] =
Packit 8ea169
  "<node>"
Packit 8ea169
  "  <interface name='"ABRT_DBUS_IFACE"'>"
Packit 8ea169
  "    <method name='NewProblem'>"
Packit 8ea169
  "      <arg type='a{ss}' name='problem_data' direction='in'/>"
Packit 8ea169
  "      <arg type='s' name='problem_id' direction='out'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='GetProblems'>"
Packit 8ea169
  "      <arg type='as' name='response' direction='out'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='GetAllProblems'>"
Packit 8ea169
  "      <arg type='as' name='response' direction='out'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='GetForeignProblems'>"
Packit 8ea169
  "      <arg type='as' name='response' direction='out'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='GetInfo'>"
Packit 8ea169
  "      <arg type='s' name='problem_dir' direction='in'/>"
Packit 8ea169
  "      <arg type='as' name='element_names' direction='in'/>"
Packit 8ea169
  "      <arg type='a{ss}' name='response' direction='out'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='SetElement'>"
Packit 8ea169
  "      <arg type='s' name='problem_dir' direction='in'/>"
Packit 8ea169
  "      <arg type='s' name='name' direction='in'/>"
Packit 8ea169
  "      <arg type='s' name='value' direction='in'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='DeleteElement'>"
Packit 8ea169
  "      <arg type='s' name='problem_dir' direction='in'/>"
Packit 8ea169
  "      <arg type='s' name='name' direction='in'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='TestElementExists'>"
Packit 8ea169
  "      <arg type='s' name='problem_dir' direction='in'/>"
Packit 8ea169
  "      <arg type='s' name='name' direction='in'/>"
Packit 8ea169
  "      <arg type='b' name='response' direction='out'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='GetProblemData'>"
Packit 8ea169
  "      <arg type='s' name='problem_dir' direction='in'/>"
Packit 8ea169
  "      <arg type='a{s(its)}' name='problem_data' direction='out'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='ChownProblemDir'>"
Packit 8ea169
  "      <arg type='s' name='problem_dir' direction='in'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='DeleteProblem'>"
Packit 8ea169
  "      <arg type='as' name='problem_dir' direction='in'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='FindProblemByElementInTimeRange'>"
Packit 8ea169
  "      <arg type='s' name='element' direction='in'/>"
Packit 8ea169
  "      <arg type='s' name='value' direction='in'/>"
Packit 8ea169
  "      <arg type='x' name='timestamp_from' direction='in'/>"
Packit 8ea169
  "      <arg type='x' name='timestamp_to' direction='in'/>"
Packit 8ea169
  "      <arg type='b' name='all_users' direction='in'/>"
Packit 8ea169
  "      <arg type='as' name='response' direction='out'/>"
Packit 8ea169
  "    </method>"
Packit 8ea169
  "    <method name='Quit' />"
Packit 8ea169
  "  </interface>"
Packit 8ea169
  "</node>";
Packit 8ea169
Packit 8ea169
/* ---------------------------------------------------------------------------------------------------- */
Packit 8ea169
Packit 8ea169
/* forward */
Packit 8ea169
static gboolean on_timeout_cb(gpointer user_data);
Packit 8ea169
Packit 8ea169
static void kill_timeout(void)
Packit 8ea169
{
Packit 8ea169
    if (g_timeout_source == 0)
Packit 8ea169
        return;
Packit 8ea169
Packit 8ea169
    log_info("Removing timeout");
Packit 8ea169
    guint tm = g_timeout_source;
Packit 8ea169
    g_timeout_source = 0;
Packit 8ea169
    g_source_remove(tm);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void run_timeout(void)
Packit 8ea169
{
Packit 8ea169
    if (g_timeout_source != 0)
Packit 8ea169
        return;
Packit 8ea169
Packit 8ea169
    log_info("Setting a new timeout");
Packit 8ea169
    g_timeout_source = g_timeout_add_seconds(g_timeout_value, on_timeout_cb, NULL);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
Packit 8ea169
bool allowed_problem_dir(const char *dir_name)
Packit 8ea169
{
Packit 8ea169
    if (!dir_is_in_dump_location(dir_name))
Packit 8ea169
    {
Packit 8ea169
        error_msg("Bad problem directory name '%s', should start with: '%s'", dir_name, g_settings_dump_location);
Packit 8ea169
        return false;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (!dir_has_correct_permissions(dir_name, DD_PERM_DAEMONS))
Packit 8ea169
    {
Packit 8ea169
        error_msg("Problem directory '%s' has invalid owner, groop or mode", dir_name);
Packit 8ea169
        return false;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    return true;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
bool allowed_problem_element(GDBusMethodInvocation *invocation, const char *element)
Packit 8ea169
{
Packit 8ea169
    if (str_is_correct_filename(element))
Packit 8ea169
        return true;
Packit 8ea169
Packit 8ea169
    log_notice("'%s' is not a valid element name", element);
Packit 8ea169
    char *error = xasprintf(_("'%s' is not a valid element name"), element);
Packit 8ea169
    g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
            "org.freedesktop.problems.InvalidElement",
Packit 8ea169
            error);
Packit 8ea169
Packit 8ea169
    free(error);
Packit 8ea169
    return false;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static char *handle_new_problem(GVariant *problem_info, uid_t caller_uid, char **error)
Packit 8ea169
{
Packit 8ea169
    char *problem_id = NULL;
Packit 8ea169
    problem_data_t *pd = problem_data_new();
Packit 8ea169
Packit 8ea169
    GVariantIter *iter;
Packit 8ea169
    g_variant_get(problem_info, "a{ss}", &iter);
Packit 8ea169
    gchar *key, *value;
Packit 8ea169
    while (g_variant_iter_loop(iter, "{ss}", &key, &value))
Packit 8ea169
    {
Packit 8ea169
        if (allowed_new_user_problem_entry(caller_uid, key, value) == false)
Packit 8ea169
        {
Packit 8ea169
            *error = xasprintf("You are not allowed to create element '%s' containing '%s'", key, value);
Packit 8ea169
            goto finito;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        problem_data_add_text_editable(pd, key, value);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (caller_uid != 0 || problem_data_get_content_or_NULL(pd, FILENAME_UID) == NULL)
Packit 8ea169
    {   /* set uid field to caller's uid if caller is not root or root doesn't pass own uid */
Packit 8ea169
        log_info("Adding UID %d to problem data", caller_uid);
Packit 8ea169
        char buf[sizeof(uid_t) * 3 + 2];
Packit 8ea169
        snprintf(buf, sizeof(buf), "%d", caller_uid);
Packit 8ea169
        problem_data_add_text_noteditable(pd, FILENAME_UID, buf);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    /* At least it should generate local problem identifier UUID */
Packit 8ea169
    problem_data_add_basics(pd);
Packit 8ea169
Packit 8ea169
    problem_id = problem_data_save(pd);
Packit 8ea169
    if (problem_id)
Packit 8ea169
        notify_new_path(problem_id);
Packit 8ea169
    else if (error)
Packit 8ea169
        *error = xasprintf("Cannot create a new problem");
Packit 8ea169
Packit 8ea169
finito:
Packit 8ea169
    problem_data_free(pd);
Packit 8ea169
    return problem_id;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void return_InvalidProblemDir_error(GDBusMethodInvocation *invocation, const char *dir_name)
Packit 8ea169
{
Packit 8ea169
    char *msg = xasprintf(_("'%s' is not a valid problem directory"), dir_name);
Packit 8ea169
    g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                      "org.freedesktop.problems.InvalidProblemDir",
Packit 8ea169
                                      msg);
Packit 8ea169
Packit 8ea169
    free(msg);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
enum {
Packit 8ea169
    OPEN_FAIL_NO_REPLY = 1 << 0,
Packit 8ea169
    OPEN_AUTH_ASK      = 1 << 1,
Packit 8ea169
    OPEN_AUTH_FAIL     = 1 << 2,
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
static struct dump_dir *open_dump_directory(GDBusMethodInvocation *invocation,
Packit 8ea169
    const gchar *caller, uid_t caller_uid, const char *problem_dir, int dd_flags, int flags)
Packit 8ea169
{
Packit 8ea169
    if (!allowed_problem_dir(problem_dir))
Packit 8ea169
    {
Packit 8ea169
        log_warning("UID=%d attempted to access not allowed problem directory '%s'",
Packit 8ea169
                caller_uid, problem_dir);
Packit 8ea169
        if (!(flags & OPEN_FAIL_NO_REPLY))
Packit 8ea169
            return_InvalidProblemDir_error(invocation, problem_dir);
Packit 8ea169
        return NULL;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_FD_ONLY);
Packit 8ea169
    if (dd == NULL)
Packit 8ea169
    {
Packit 8ea169
        perror_msg("can't open problem directory '%s'", problem_dir);
Packit 8ea169
        if (!(flags & OPEN_FAIL_NO_REPLY))
Packit 8ea169
            return_InvalidProblemDir_error(invocation, problem_dir);
Packit 8ea169
        return NULL;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (!dd_accessible_by_uid(dd, caller_uid))
Packit 8ea169
    {
Packit 8ea169
        if (errno == ENOTDIR)
Packit 8ea169
        {
Packit 8ea169
            log_notice("Requested directory does not exist '%s'", problem_dir);
Packit 8ea169
            if (!(flags & OPEN_FAIL_NO_REPLY))
Packit 8ea169
                return_InvalidProblemDir_error(invocation, problem_dir);
Packit 8ea169
            dd_close(dd);
Packit 8ea169
            return NULL;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        if (   !(flags & OPEN_AUTH_ASK)
Packit 8ea169
            || polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
Packit 8ea169
        {
Packit 8ea169
            log_notice("not authorized");
Packit 8ea169
            if (!(flags & OPEN_FAIL_NO_REPLY))
Packit 8ea169
                g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                              "org.freedesktop.problems.AuthFailure",
Packit 8ea169
                                              _("Not Authorized"));
Packit 8ea169
            dd_close(dd);
Packit 8ea169
            return NULL;
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    dd = dd_fdopendir(dd, dd_flags);
Packit 8ea169
    if (dd == NULL)
Packit 8ea169
    {
Packit 8ea169
        log_notice("Can't open the problem '%s' with flags %x0", problem_dir, dd_flags);
Packit 8ea169
        if (!(flags & OPEN_FAIL_NO_REPLY))
Packit 8ea169
            g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                "org.freedesktop.problems.Failure",
Packit 8ea169
                                _("Can't open the problem"));
Packit 8ea169
    }
Packit 8ea169
    return dd;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/*
Packit 8ea169
 * Checks element's rights and does not open directory if element is protected.
Packit 8ea169
 * Checks problem's rights and does not open directory if user hasn't got
Packit 8ea169
 * access to a problem.
Packit 8ea169
 *
Packit 8ea169
 * Returns a dump directory opend for writing or NULL.
Packit 8ea169
 *
Packit 8ea169
 * If any operation from the above listed fails, immediately returns D-Bus
Packit 8ea169
 * error to a D-Bus caller.
Packit 8ea169
 */
Packit 8ea169
static struct dump_dir *open_directory_for_modification_of_element(
Packit 8ea169
    GDBusMethodInvocation *invocation,
Packit 8ea169
    uid_t caller_uid,
Packit 8ea169
    const char *problem_id,
Packit 8ea169
    const char *element)
Packit 8ea169
{
Packit 8ea169
    static const char *const protected_elements[] = {
Packit 8ea169
        FILENAME_TIME,
Packit 8ea169
        FILENAME_UID,
Packit 8ea169
        NULL,
Packit 8ea169
    };
Packit 8ea169
Packit 8ea169
    for (const char *const *protected = protected_elements; *protected; ++protected)
Packit 8ea169
    {
Packit 8ea169
        if (strcmp(*protected, element) == 0)
Packit 8ea169
        {
Packit 8ea169
            log_notice("'%s' element of '%s' can't be modified", element, problem_id);
Packit 8ea169
            char *error = xasprintf(_("'%s' element can't be modified"), element);
Packit 8ea169
            g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                        "org.freedesktop.problems.ProtectedElement",
Packit 8ea169
                                        error);
Packit 8ea169
            free(error);
Packit 8ea169
            return NULL;
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    return open_dump_directory(invocation, /*caller*/NULL, caller_uid, problem_id, /*Read/Write*/0,
Packit 8ea169
                               OPEN_AUTH_FAIL);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
Packit 8ea169
/*
Packit 8ea169
 * Lists problems which have given element and were seen in given time interval
Packit 8ea169
 */
Packit 8ea169
Packit 8ea169
struct field_and_time_range {
Packit 8ea169
    GList *list;
Packit 8ea169
    const char *element;
Packit 8ea169
    const char *value;
Packit 8ea169
    unsigned long timestamp_from;
Packit 8ea169
    unsigned long timestamp_to;
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
static int add_dirname_to_GList_if_matches(struct dump_dir *dd, void *arg)
Packit 8ea169
{
Packit 8ea169
    struct field_and_time_range *me = arg;
Packit 8ea169
Packit 8ea169
    char *field_data = dd_load_text(dd, me->element);
Packit 8ea169
    int brk = (strcmp(field_data, me->value) != 0);
Packit 8ea169
    free(field_data);
Packit 8ea169
    if (brk)
Packit 8ea169
        return 0;
Packit 8ea169
Packit 8ea169
    field_data = dd_load_text(dd, FILENAME_LAST_OCCURRENCE);
Packit 8ea169
    long val = atol(field_data);
Packit 8ea169
    free(field_data);
Packit 8ea169
    if (val < me->timestamp_from || val > me->timestamp_to)
Packit 8ea169
        return 0;
Packit 8ea169
Packit 8ea169
    me->list = g_list_prepend(me->list, xstrdup(dd->dd_dirname));
Packit 8ea169
    return 0;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static GList *get_problem_dirs_for_element_in_time(uid_t uid,
Packit 8ea169
                const char *element,
Packit 8ea169
                const char *value,
Packit 8ea169
                unsigned long timestamp_from,
Packit 8ea169
                unsigned long timestamp_to)
Packit 8ea169
{
Packit 8ea169
    if (timestamp_to == 0) /* not sure this is possible, but... */
Packit 8ea169
        timestamp_to = time(NULL);
Packit 8ea169
Packit 8ea169
    struct field_and_time_range me = {
Packit 8ea169
        .list = NULL,
Packit 8ea169
        .element = element,
Packit 8ea169
        .value = value,
Packit 8ea169
        .timestamp_from = timestamp_from,
Packit 8ea169
        .timestamp_to = timestamp_to,
Packit 8ea169
    };
Packit 8ea169
Packit 8ea169
    for_each_problem_in_dir(g_settings_dump_location, uid, add_dirname_to_GList_if_matches, &me);
Packit 8ea169
Packit 8ea169
    return g_list_reverse(me.list);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
Packit 8ea169
static void handle_method_call(GDBusConnection *connection,
Packit 8ea169
                        const gchar *caller,
Packit 8ea169
                        const gchar *object_path,
Packit 8ea169
                        const gchar *interface_name,
Packit 8ea169
                        const gchar *method_name,
Packit 8ea169
                        GVariant    *parameters,
Packit 8ea169
                        GDBusMethodInvocation *invocation,
Packit 8ea169
                        gpointer    user_data)
Packit 8ea169
{
Packit 8ea169
    uid_t caller_uid;
Packit 8ea169
    GVariant *response;
Packit 8ea169
Packit 8ea169
    GError *error = NULL;
Packit 8ea169
    caller_uid = abrt_p2_service_caller_uid(ABRT_P2_SERVICE(user_data), caller, &error);
Packit 8ea169
    if (caller_uid == (uid_t) -1)
Packit 8ea169
    {
Packit 8ea169
        g_dbus_method_invocation_return_gerror(invocation, error);
Packit 8ea169
        g_error_free(error);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    log_notice("caller_uid:%ld method:'%s'", (long)caller_uid, method_name);
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "NewProblem") == 0)
Packit 8ea169
    {
Packit 8ea169
        char *error = NULL;
Packit 8ea169
        char *problem_id = handle_new_problem(g_variant_get_child_value(parameters, 0), caller_uid, &error);
Packit 8ea169
        if (!problem_id)
Packit 8ea169
        {
Packit 8ea169
            g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                                      "org.freedesktop.problems.Failure",
Packit 8ea169
                                                      error);
Packit 8ea169
            free(error);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
        /* else */
Packit 8ea169
        response = g_variant_new("(s)", problem_id);
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, response);
Packit 8ea169
        free(problem_id);
Packit 8ea169
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "GetProblems") == 0)
Packit 8ea169
    {
Packit 8ea169
        GList *dirs = get_problem_dirs_for_uid(caller_uid, g_settings_dump_location);
Packit 8ea169
        response = variant_from_string_list(dirs);
Packit 8ea169
        list_free_with_free(dirs);
Packit 8ea169
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, response);
Packit 8ea169
        //I was told that g_dbus_method frees the response
Packit 8ea169
        //g_variant_unref(response);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "GetAllProblems") == 0)
Packit 8ea169
    {
Packit 8ea169
        /*
Packit 8ea169
        - so, we have UID,
Packit 8ea169
        - if it's 0, then we don't have to check anything and just return all directories
Packit 8ea169
        - if uid != 0 then we want to ask for authorization
Packit 8ea169
        */
Packit 8ea169
        if (caller_uid != 0)
Packit 8ea169
        {
Packit 8ea169
            if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") == PolkitYes)
Packit 8ea169
                caller_uid = 0;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        GList * dirs = get_problem_dirs_for_uid(caller_uid, g_settings_dump_location);
Packit 8ea169
        response = variant_from_string_list(dirs);
Packit 8ea169
Packit 8ea169
        list_free_with_free(dirs);
Packit 8ea169
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, response);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "GetForeignProblems") == 0)
Packit 8ea169
    {
Packit 8ea169
        GList * dirs = get_problem_dirs_not_accessible_by_uid(caller_uid, g_settings_dump_location);
Packit 8ea169
        response = variant_from_string_list(dirs);
Packit 8ea169
        list_free_with_free(dirs);
Packit 8ea169
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, response);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "ChownProblemDir") == 0)
Packit 8ea169
    {
Packit 8ea169
        const gchar *problem_dir;
Packit 8ea169
        g_variant_get(parameters, "(&s)", &problem_dir);
Packit 8ea169
        log_notice("problem_dir:'%s'", problem_dir);
Packit 8ea169
Packit 8ea169
        if (!allowed_problem_dir(problem_dir))
Packit 8ea169
        {
Packit 8ea169
            return_InvalidProblemDir_error(invocation, problem_dir);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_FD_ONLY);
Packit 8ea169
        if (dd == NULL)
Packit 8ea169
        {
Packit 8ea169
            perror_msg("can't open problem directory '%s'", problem_dir);
Packit 8ea169
            return_InvalidProblemDir_error(invocation, problem_dir);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        int ddstat = dd_stat_for_uid(dd, caller_uid);
Packit 8ea169
        if (ddstat < 0)
Packit 8ea169
        {
Packit 8ea169
            if (errno == ENOTDIR)
Packit 8ea169
            {
Packit 8ea169
                log_notice("requested directory does not exist '%s'", problem_dir);
Packit 8ea169
            }
Packit 8ea169
            else
Packit 8ea169
            {
Packit 8ea169
                perror_msg("can't get stat of '%s'", problem_dir);
Packit 8ea169
            }
Packit 8ea169
Packit 8ea169
            return_InvalidProblemDir_error(invocation, problem_dir);
Packit 8ea169
Packit 8ea169
            dd_close(dd);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        /* It might happen that we will do chowing even if the UID is alreay fs
Packit 8ea169
         * owner, but DD_STAT_OWNED_BY_UID no longer denotes fs owner and this
Packit 8ea169
         * method has to ensure file system ownership for the uid.
Packit 8ea169
         */
Packit 8ea169
Packit 8ea169
        if ((ddstat & DD_STAT_ACCESSIBLE_BY_UID) == 0 &&
Packit 8ea169
                polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
Packit 8ea169
        {
Packit 8ea169
            log_notice("not authorized");
Packit 8ea169
            g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                              "org.freedesktop.problems.AuthFailure",
Packit 8ea169
                                              _("Not Authorized"));
Packit 8ea169
            dd_close(dd);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        dd = dd_fdopendir(dd, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
Packit 8ea169
        if (!dd)
Packit 8ea169
        {
Packit 8ea169
            return_InvalidProblemDir_error(invocation, problem_dir);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        int chown_res = dd_chown(dd, caller_uid);
Packit 8ea169
        if (chown_res != 0)
Packit 8ea169
            g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                              "org.freedesktop.problems.ChownError",
Packit 8ea169
                                              _("Chowning directory failed. Check system logs for more details."));
Packit 8ea169
        else
Packit 8ea169
            g_dbus_method_invocation_return_value(invocation, NULL);
Packit 8ea169
Packit 8ea169
        dd_close(dd);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "GetInfo") == 0)
Packit 8ea169
    {
Packit 8ea169
        /* Parameter tuple is (sas) */
Packit 8ea169
Packit 8ea169
	/* Get 1st param - problem dir name */
Packit 8ea169
        const gchar *problem_dir;
Packit 8ea169
        g_variant_get_child(parameters, 0, "&s", &problem_dir);
Packit 8ea169
        log_notice("problem_dir:'%s'", problem_dir);
Packit 8ea169
Packit 8ea169
        struct dump_dir *dd = open_dump_directory(invocation, caller, caller_uid,
Packit 8ea169
                problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES , OPEN_AUTH_ASK);
Packit 8ea169
        if (!dd)
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
	/* Get 2nd param - vector of element names */
Packit 8ea169
        GVariant *array = g_variant_get_child_value(parameters, 1);
Packit 8ea169
        GList *elements = string_list_from_variant(array);
Packit 8ea169
        g_variant_unref(array);
Packit 8ea169
Packit 8ea169
        GVariantBuilder *builder = NULL;
Packit 8ea169
        for (GList *l = elements; l; l = l->next)
Packit 8ea169
        {
Packit 8ea169
            const char *element_name = (const char*)l->data;
Packit 8ea169
            char *value = dd_load_text_ext(dd, element_name, 0
Packit 8ea169
                                                | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
Packit 8ea169
                                                | DD_FAIL_QUIETLY_ENOENT
Packit 8ea169
                                                | DD_FAIL_QUIETLY_EACCES);
Packit 8ea169
            log_notice("element '%s' %s", element_name, value ? "fetched" : "not found");
Packit 8ea169
            if (value)
Packit 8ea169
            {
Packit 8ea169
                if (!builder)
Packit 8ea169
                    builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
Packit 8ea169
Packit 8ea169
                /* g_variant_builder_add makes a copy. No need to xstrdup here */
Packit 8ea169
                g_variant_builder_add(builder, "{ss}", element_name, value);
Packit 8ea169
                free(value);
Packit 8ea169
            }
Packit 8ea169
        }
Packit 8ea169
        list_free_with_free(elements);
Packit 8ea169
        dd_close(dd);
Packit 8ea169
        /* It is OK to call g_variant_new("(a{ss})", NULL) because */
Packit 8ea169
        /* G_VARIANT_TYPE_TUPLE allows NULL value */
Packit 8ea169
        GVariant *response = g_variant_new("(a{ss})", builder);
Packit 8ea169
Packit 8ea169
        if (builder)
Packit 8ea169
            g_variant_builder_unref(builder);
Packit 8ea169
Packit 8ea169
        log_info("GetInfo: returning value for '%s'", problem_dir);
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, response);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "GetProblemData") == 0)
Packit 8ea169
    {
Packit 8ea169
        /* Parameter tuple is (s) */
Packit 8ea169
        const char *problem_id;
Packit 8ea169
Packit 8ea169
        g_variant_get(parameters, "(&s)", &problem_id);
Packit 8ea169
Packit 8ea169
        struct dump_dir *dd = open_dump_directory(invocation, caller, caller_uid,
Packit 8ea169
                    problem_id, DD_OPEN_READONLY, OPEN_AUTH_ASK);
Packit 8ea169
        if (!dd)
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
        problem_data_t *pd = create_problem_data_from_dump_dir(dd);
Packit 8ea169
        dd_close(dd);
Packit 8ea169
Packit 8ea169
        GVariantBuilder *response_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
Packit 8ea169
Packit 8ea169
        GHashTableIter pd_iter;
Packit 8ea169
        char *element_name;
Packit 8ea169
        struct problem_item *element_info;
Packit 8ea169
        g_hash_table_iter_init(&pd_iter, pd);
Packit 8ea169
        while (g_hash_table_iter_next(&pd_iter, (void**)&element_name, (void**)&element_info))
Packit 8ea169
        {
Packit 8ea169
            unsigned long size = 0;
Packit 8ea169
            if (problem_item_get_size(element_info, &size) != 0)
Packit 8ea169
            {
Packit 8ea169
                log_notice("Can't get stat of : '%s'", element_info->content);
Packit 8ea169
                continue;
Packit 8ea169
            }
Packit 8ea169
Packit 8ea169
            g_variant_builder_add(response_builder, "{s(its)}",
Packit 8ea169
                                                    element_name,
Packit 8ea169
                                                    (gint32)element_info->flags,
Packit 8ea169
                                                    (guint64)size,
Packit 8ea169
                                                    element_info->content);
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        GVariant *response = g_variant_new("(a{s(its)})", response_builder);
Packit 8ea169
        g_variant_builder_unref(response_builder);
Packit 8ea169
Packit 8ea169
        problem_data_free(pd);
Packit 8ea169
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, response);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "SetElement") == 0)
Packit 8ea169
    {
Packit 8ea169
        const char *problem_id;
Packit 8ea169
        const char *element;
Packit 8ea169
        const char *value;
Packit 8ea169
Packit 8ea169
        g_variant_get(parameters, "(&s&s&s)", &problem_id, &element, &value);
Packit 8ea169
Packit 8ea169
        if (!allowed_problem_element(invocation, element))
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
        struct dump_dir *dd = open_directory_for_modification_of_element(
Packit 8ea169
                                    invocation, caller_uid, problem_id, element);
Packit 8ea169
        if (!dd)
Packit 8ea169
            /* Already logged from open_directory_for_modification_of_element() */
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
        /* Is it good idea to make it static? Is it possible to change the max size while a single run? */
Packit 8ea169
        const double max_dir_size = g_settings_nMaxCrashReportsSize * (1024 * 1024);
Packit 8ea169
        const long item_size = dd_get_item_size(dd, element);
Packit 8ea169
        if (item_size < 0)
Packit 8ea169
        {
Packit 8ea169
            log_notice("Can't get size of '%s/%s'", problem_id, element);
Packit 8ea169
            char *error = xasprintf(_("Can't get size of '%s'"), element);
Packit 8ea169
            g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                                      "org.freedesktop.problems.Failure",
Packit 8ea169
                                                      error);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        const double requested_size = (double)strlen(value) - item_size;
Packit 8ea169
        /* Don't want to check the size limit in case of reducing of size */
Packit 8ea169
        if (requested_size > 0
Packit 8ea169
            && requested_size > (max_dir_size - get_dirsize(g_settings_dump_location)))
Packit 8ea169
        {
Packit 8ea169
            log_notice("No problem space left in '%s' (requested Bytes %f)", problem_id, requested_size);
Packit 8ea169
            g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                                      "org.freedesktop.problems.Failure",
Packit 8ea169
                                                      _("No problem space left"));
Packit 8ea169
        }
Packit 8ea169
        else
Packit 8ea169
        {
Packit 8ea169
            dd_save_text(dd, element, value);
Packit 8ea169
            g_dbus_method_invocation_return_value(invocation, NULL);
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        dd_close(dd);
Packit 8ea169
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "DeleteElement") == 0)
Packit 8ea169
    {
Packit 8ea169
        const char *problem_id;
Packit 8ea169
        const char *element;
Packit 8ea169
Packit 8ea169
        g_variant_get(parameters, "(&s&s)", &problem_id, &element);
Packit 8ea169
Packit 8ea169
        if (!allowed_problem_element(invocation, element))
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
        struct dump_dir *dd = open_directory_for_modification_of_element(
Packit 8ea169
                                    invocation, caller_uid, problem_id, element);
Packit 8ea169
        if (!dd)
Packit 8ea169
            /* Already logged from open_directory_for_modification_of_element() */
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
        const int res = dd_delete_item(dd, element);
Packit 8ea169
        dd_close(dd);
Packit 8ea169
Packit 8ea169
        if (res != 0)
Packit 8ea169
        {
Packit 8ea169
            log_notice("Can't delete the element '%s' from the problem directory '%s'", element, problem_id);
Packit 8ea169
            char *error = xasprintf(_("Can't delete the element '%s' from the problem directory '%s'"), element, problem_id);
Packit 8ea169
            g_dbus_method_invocation_return_dbus_error(invocation,
Packit 8ea169
                                          "org.freedesktop.problems.Failure",
Packit 8ea169
                                          error);
Packit 8ea169
            free(error);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, NULL);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "TestElementExists") == 0)
Packit 8ea169
    {
Packit 8ea169
        const char *problem_id;
Packit 8ea169
        const char *element;
Packit 8ea169
Packit 8ea169
        g_variant_get(parameters, "(&s&s)", &problem_id, &element);
Packit 8ea169
Packit 8ea169
        if (!allowed_problem_element(invocation, element))
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
        struct dump_dir *dd = open_dump_directory(invocation, caller, caller_uid,
Packit 8ea169
                problem_id, DD_OPEN_READONLY, OPEN_AUTH_ASK);
Packit 8ea169
        if (!dd)
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
        int ret = dd_exist(dd, element);
Packit 8ea169
        dd_close(dd);
Packit 8ea169
Packit 8ea169
        GVariant *response = g_variant_new("(b)", ret);
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, response);
Packit 8ea169
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "DeleteProblem") == 0)
Packit 8ea169
    {
Packit 8ea169
        /* Dbus parameters are always tuples.
Packit 8ea169
         * In this case, it's (as) - a tuple of one element (array of strings).
Packit 8ea169
         * Need to fetch the array:
Packit 8ea169
         */
Packit 8ea169
        GVariant *array = g_variant_get_child_value(parameters, 0);
Packit 8ea169
        GList *problem_dirs = string_list_from_variant(array);
Packit 8ea169
        g_variant_unref(array);
Packit 8ea169
Packit 8ea169
        for (GList *l = problem_dirs; l; l = l->next)
Packit 8ea169
        {
Packit 8ea169
            const char *dir_name = (const char*)l->data;
Packit 8ea169
            log_notice("dir_name:'%s'", dir_name);
Packit 8ea169
            if (!allowed_problem_dir(dir_name))
Packit 8ea169
            {
Packit 8ea169
                return_InvalidProblemDir_error(invocation, dir_name);
Packit 8ea169
                goto ret;
Packit 8ea169
            }
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        for (GList *l = problem_dirs; l; l = l->next)
Packit 8ea169
        {
Packit 8ea169
            const char *dir_name = (const char*)l->data;
Packit 8ea169
Packit 8ea169
            struct dump_dir *dd = open_dump_directory(invocation, caller, caller_uid,
Packit 8ea169
                        dir_name, /*Read/Write*/0, OPEN_FAIL_NO_REPLY | OPEN_AUTH_ASK);
Packit 8ea169
Packit 8ea169
            if (dd)
Packit 8ea169
            {
Packit 8ea169
                if (dd_delete(dd) != 0)
Packit 8ea169
                {
Packit 8ea169
                    error_msg("Failed to delete problem directory '%s'", dir_name);
Packit 8ea169
                    dd_close(dd);
Packit 8ea169
                }
Packit 8ea169
            }
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, NULL);
Packit 8ea169
 ret:
Packit 8ea169
        list_free_with_free(problem_dirs);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "FindProblemByElementInTimeRange") == 0)
Packit 8ea169
    {
Packit 8ea169
        const gchar *element;
Packit 8ea169
        const gchar *value;
Packit 8ea169
        glong timestamp_from;
Packit 8ea169
        glong timestamp_to;
Packit 8ea169
        gboolean all;
Packit 8ea169
Packit 8ea169
        g_variant_get_child(parameters, 0, "&s", &element);
Packit 8ea169
        g_variant_get_child(parameters, 1, "&s", &value);
Packit 8ea169
        g_variant_get_child(parameters, 2, "x", &timestamp_from);
Packit 8ea169
        g_variant_get_child(parameters, 3, "x", &timestamp_to);
Packit 8ea169
        g_variant_get_child(parameters, 4, "b", &all;;
Packit 8ea169
Packit 8ea169
        if (!allowed_problem_element(invocation, element))
Packit 8ea169
            return;
Packit 8ea169
Packit 8ea169
        if (all && polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") == PolkitYes)
Packit 8ea169
            caller_uid = 0;
Packit 8ea169
Packit 8ea169
        GList *dirs = get_problem_dirs_for_element_in_time(caller_uid, element, value, timestamp_from,
Packit 8ea169
                                                        timestamp_to);
Packit 8ea169
        response = variant_from_string_list(dirs);
Packit 8ea169
        list_free_with_free(dirs);
Packit 8ea169
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, response);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (g_strcmp0(method_name, "Quit") == 0)
Packit 8ea169
    {
Packit 8ea169
        g_dbus_method_invocation_return_value(invocation, NULL);
Packit 8ea169
        g_main_loop_quit(loop);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void handle_abrtd_problem_signals(GDBusConnection *connection,
Packit 8ea169
            const gchar     *sender_name,
Packit 8ea169
            const gchar     *object_path,
Packit 8ea169
            const gchar     *interface_name,
Packit 8ea169
            const gchar     *signal_name,
Packit 8ea169
            GVariant        *parameters,
Packit 8ea169
            gpointer         user_data)
Packit 8ea169
{
Packit 8ea169
    const char *dir;
Packit 8ea169
    g_variant_get (parameters, "(&s)", &dir;;
Packit 8ea169
Packit 8ea169
    log_debug("Caught '%s' signal from abrtd: '%s'", signal_name, dir);
Packit 8ea169
    AbrtP2Service *service = ABRT_P2_SERVICE(user_data);
Packit 8ea169
Packit 8ea169
    GError *error = NULL;
Packit 8ea169
    AbrtP2Object *obj = abrt_p2_service_get_entry_for_problem(service,
Packit 8ea169
                                                              dir,
Packit 8ea169
                                                              ABRT_P2_SERVICE_ENTRY_LOOKUP_OPTIONAL,
Packit 8ea169
                                                              &error);
Packit 8ea169
    if (error)
Packit 8ea169
    {
Packit 8ea169
        log_warning("Cannot notify '%s': failed to find entry: %s", dir, error->message);
Packit 8ea169
        g_error_free(error);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (obj == NULL)
Packit 8ea169
    {
Packit 8ea169
        AbrtP2Entry *entry = abrt_p2_entry_new_with_state(xstrdup(dir), ABRT_P2_ENTRY_STATE_COMPLETE);
Packit 8ea169
        if (entry == NULL)
Packit 8ea169
        {
Packit 8ea169
            log_warning("Cannot notify '%s': failed to access data", dir);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        obj = abrt_p2_service_register_entry(service, entry, &error);
Packit 8ea169
        if (error)
Packit 8ea169
        {
Packit 8ea169
            log_warning("Cannot notify '%s': failed to register entry: %s", dir, error->message);
Packit 8ea169
            g_error_free(error);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    AbrtP2Entry *entry = ABRT_P2_ENTRY(abrt_p2_object_get_node(obj));
Packit 8ea169
    if (abrt_p2_entry_state(entry) != ABRT_P2_ENTRY_STATE_COMPLETE)
Packit 8ea169
    {
Packit 8ea169
        log_debug("Not notifying temporary/deleted problem directory: %s", dir);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    abrt_p2_service_notify_entry_object(service, obj, &error);
Packit 8ea169
    if (error)
Packit 8ea169
    {
Packit 8ea169
        log_warning("Failed to notify '%s': %s", dir, error->message);
Packit 8ea169
        g_error_free(error);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static gboolean on_timeout_cb(gpointer user_data)
Packit 8ea169
{
Packit 8ea169
    g_main_loop_quit(loop);
Packit 8ea169
    return TRUE;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static const GDBusInterfaceVTable interface_vtable =
Packit 8ea169
{
Packit 8ea169
    .method_call = handle_method_call,
Packit 8ea169
    .get_property = NULL,
Packit 8ea169
    .set_property = NULL,
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
static void on_bus_acquired(GDBusConnection *connection,
Packit 8ea169
                 const gchar     *name,
Packit 8ea169
                 gpointer         user_data)
Packit 8ea169
{
Packit 8ea169
    guint registration_id;
Packit 8ea169
Packit 8ea169
    registration_id = g_dbus_connection_register_object(connection,
Packit 8ea169
                                                       ABRT_DBUS_OBJECT,
Packit 8ea169
                                                       introspection_data->interfaces[0],
Packit 8ea169
                                                       &interface_vtable,
Packit 8ea169
                                                       user_data,
Packit 8ea169
                                                       NULL,  /* user_data_free_func */
Packit 8ea169
                                                       NULL); /* GError** */
Packit 8ea169
    g_assert(registration_id > 0);
Packit 8ea169
Packit 8ea169
    GError *error = NULL;
Packit 8ea169
Packit 8ea169
    int r = abrt_p2_service_register_objects(ABRT_P2_SERVICE(user_data), connection, &error);
Packit 8ea169
    if (r == 0 || r == -EALREADY)
Packit 8ea169
    {
Packit 8ea169
        g_signal_crash = g_dbus_connection_signal_subscribe(connection,
Packit 8ea169
                                                            NULL,
Packit 8ea169
                                                            "org.freedesktop.Problems2",
Packit 8ea169
                                                            "ImportProblem",
Packit 8ea169
                                                            "/org/freedesktop/Problems2",
Packit 8ea169
                                                            NULL,
Packit 8ea169
                                                            G_DBUS_SIGNAL_FLAGS_NONE,
Packit 8ea169
                                                            handle_abrtd_problem_signals,
Packit 8ea169
                                                            user_data, NULL);
Packit 8ea169
Packit 8ea169
        g_signal_dup_crash = g_dbus_connection_signal_subscribe(connection,
Packit 8ea169
                                                            NULL,
Packit 8ea169
                                                            "org.freedesktop.Problems2",
Packit 8ea169
                                                            "ReloadProblem",
Packit 8ea169
                                                            "/org/freedesktop/Problems2",
Packit 8ea169
                                                            NULL,
Packit 8ea169
                                                            G_DBUS_SIGNAL_FLAGS_NONE,
Packit 8ea169
                                                            handle_abrtd_problem_signals,
Packit 8ea169
                                                            user_data, NULL);
Packit 8ea169
Packit 8ea169
        run_timeout();
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    error_msg("Failed to register Problems2 Objects: %s", error->message);
Packit 8ea169
    g_error_free(error);
Packit 8ea169
Packit 8ea169
    g_main_loop_quit(loop);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* not used
Packit 8ea169
static void on_name_acquired (GDBusConnection *connection,
Packit 8ea169
                  const gchar     *name,
Packit 8ea169
                  gpointer         user_data)
Packit 8ea169
{
Packit 8ea169
}
Packit 8ea169
*/
Packit 8ea169
Packit 8ea169
static void on_name_lost(GDBusConnection *connection,
Packit 8ea169
                      const gchar *name,
Packit 8ea169
                      gpointer user_data)
Packit 8ea169
{
Packit 8ea169
    g_print(_("The name '%s' has been lost, please check if other "
Packit 8ea169
              "service owning the name is not running.\n"), name);
Packit 8ea169
    exit(1);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
void configure_problems2_service(AbrtP2Service *p2_service)
Packit 8ea169
{
Packit 8ea169
    struct env_option {
Packit 8ea169
        const char *name;
Packit 8ea169
        void (*setter_unsigned)(AbrtP2Service *s, uid_t u, unsigned v);
Packit 8ea169
        void (*setter_off_t)(AbrtP2Service *s, uid_t u, off_t v);
Packit 8ea169
    } env_options[] = {
Packit 8ea169
        {   .name = "ABRT_DBUS_USER_CLIENTS",
Packit 8ea169
            .setter_unsigned = abrt_p2_service_set_user_clients_limit,
Packit 8ea169
        },
Packit 8ea169
        {   .name = "ABRT_DBUS_ELEMENTS_LIMIT",
Packit 8ea169
             .setter_unsigned = abrt_p2_service_set_elements_limit,
Packit 8ea169
        },
Packit 8ea169
        {   .name = "ABRT_DBUS_PROBLEMS_LIMIT",
Packit 8ea169
            .setter_unsigned = abrt_p2_service_set_user_problems_limit,
Packit 8ea169
        },
Packit 8ea169
        {   .name = "ABRT_DBUS_NEW_PROBLEM_THROTTLING_MAGNITUDE",
Packit 8ea169
            .setter_unsigned = abrt_p2_service_set_new_problem_throttling_magnitude,
Packit 8ea169
        },
Packit 8ea169
        {   .name = "ABRT_DBUS_NEW_PROBLEMS_BATCH",
Packit 8ea169
            .setter_unsigned = abrt_p2_service_set_new_problems_batch,
Packit 8ea169
        },
Packit 8ea169
        {   .name = "ABRT_DBUS_DATA_SIZE_LIMIT",
Packit 8ea169
            .setter_off_t = abrt_p2_service_set_data_size_limit,
Packit 8ea169
        },
Packit 8ea169
    };
Packit 8ea169
Packit 8ea169
    for (size_t i = 0; i < sizeof(env_options)/sizeof(env_options[0]); ++i)
Packit 8ea169
    {
Packit 8ea169
        const char *value = getenv(env_options[i].name);
Packit 8ea169
        if (value == NULL)
Packit 8ea169
            continue;
Packit 8ea169
Packit 8ea169
        errno = 0;
Packit 8ea169
        char *end = NULL;
Packit 8ea169
        const unsigned long limit = strtoul(value, &end, 10);
Packit 8ea169
        if (errno || value == end || *end != '\0')
Packit 8ea169
            error_msg_and_die("not a number in environment '%s': %s", env_options[i].name, value);
Packit 8ea169
Packit 8ea169
        if (env_options[i].setter_unsigned)
Packit 8ea169
        {
Packit 8ea169
            if (limit > UINT_MAX)
Packit 8ea169
                error_msg_and_die("an out of range number in environment '%s': %s", env_options[i].name, value);
Packit 8ea169
Packit 8ea169
            env_options[i].setter_unsigned(p2_service, (uid_t)-1, (unsigned int)limit);
Packit 8ea169
        }
Packit 8ea169
        else if (env_options[i].setter_off_t)
Packit 8ea169
        {
Packit 8ea169
            const off_t off_t_limit = limit;
Packit 8ea169
            env_options[i].setter_off_t(p2_service, (uid_t)-1, off_t_limit);
Packit 8ea169
        }
Packit 8ea169
        else
Packit 8ea169
            error_msg_and_die("Bug: invalid parser of environment values");
Packit 8ea169
Packit 8ea169
        log_debug("Used environment variable: %s", env_options[i].name);
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int main(int argc, char *argv[])
Packit 8ea169
{
Packit 8ea169
    /* I18n */
Packit 8ea169
    setlocale(LC_ALL, "");
Packit 8ea169
#if ENABLE_NLS
Packit 8ea169
    bindtextdomain(PACKAGE, LOCALEDIR);
Packit 8ea169
    textdomain(PACKAGE);
Packit 8ea169
#endif
Packit 8ea169
    guint owner_id;
Packit 8ea169
Packit 8ea169
    abrt_init(argv);
Packit 8ea169
Packit 8ea169
    const char *program_usage_string = _(
Packit 8ea169
        "& [options]"
Packit 8ea169
    );
Packit 8ea169
    enum {
Packit 8ea169
        OPT_v = 1 << 0,
Packit 8ea169
        OPT_t = 1 << 1,
Packit 8ea169
    };
Packit 8ea169
    /* Keep enum above and order of options below in sync! */
Packit 8ea169
    struct options program_options[] = {
Packit 8ea169
        OPT__VERBOSE(&g_verbose),
Packit 8ea169
        OPT_INTEGER('t', NULL, &g_timeout_value, _("Exit after NUM seconds of inactivity")),
Packit 8ea169
        OPT_END()
Packit 8ea169
    };
Packit 8ea169
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
Packit 8ea169
Packit 8ea169
    export_abrt_envvars(0);
Packit 8ea169
Packit 8ea169
    /* When dbus daemon starts us, it doesn't set PATH
Packit 8ea169
     * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE).
Packit 8ea169
     * In this case, set something sane:
Packit 8ea169
     */
Packit 8ea169
    const char *env_path = getenv("PATH");
Packit 8ea169
    if (!env_path || !env_path[0])
Packit 8ea169
        putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin");
Packit 8ea169
Packit 8ea169
    msg_prefix = "abrt-dbus"; /* for log_warning(), error_msg() and such */
Packit 8ea169
Packit 8ea169
    if (getuid() != 0)
Packit 8ea169
        error_msg_and_die(_("This program must be run as root."));
Packit 8ea169
Packit 8ea169
    glib_init();
Packit 8ea169
Packit 8ea169
    /* We are lazy here - we don't want to manually provide
Packit 8ea169
    * the introspection data structures - so we just build
Packit 8ea169
    * them from XML.
Packit 8ea169
    */
Packit 8ea169
    GError *err = NULL;
Packit 8ea169
    introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, &err;;
Packit 8ea169
    if (err != NULL)
Packit 8ea169
        error_msg_and_die("Invalid D-Bus interface: %s", err->message);
Packit 8ea169
Packit 8ea169
    AbrtP2Service *p2_service = abrt_p2_service_new(&err;;
Packit 8ea169
    if (p2_service == NULL)
Packit 8ea169
        error_msg_and_die("Failed to initialize Problems2 service: %s", err->message);
Packit 8ea169
Packit 8ea169
    g_signal_connect(p2_service, "new-client-connected", G_CALLBACK(kill_timeout), NULL);
Packit 8ea169
    g_signal_connect(p2_service, "all-clients-disconnected", G_CALLBACK(run_timeout), NULL);
Packit 8ea169
Packit 8ea169
    DBusConnection *con = dbus_connection_open("org.freedesktop.DBus", NULL);
Packit 8ea169
Packit 8ea169
    /* FIXME: I'm sorry but I'm not able to find out why the maximum message
Packit 8ea169
     * length limit is around 200kiB but the official configuration says
Packit 8ea169
     * something about 128MiB. Is it a bug in this code? */
Packit 8ea169
    /*long max_message_size = DBUS_MAXIMUM_MESSAGE_LENGTH;*/
Packit 8ea169
Packit 8ea169
    long max_message_unix_fds = 16;
Packit 8ea169
    if (con != NULL)
Packit 8ea169
    {
Packit 8ea169
        /*max_message_size = dbus_connection_get_max_message_size(con);*/
Packit 8ea169
        max_message_unix_fds = dbus_connection_get_max_message_unix_fds(con);
Packit 8ea169
        dbus_connection_close(con);
Packit 8ea169
    }
Packit 8ea169
    /*abrt_p2_service_set_max_message_size(p2_service, max_message_size);*/
Packit 8ea169
    abrt_p2_service_set_max_message_size(p2_service, 200000L);
Packit 8ea169
    abrt_p2_service_set_max_message_unix_fds(p2_service, max_message_unix_fds);
Packit 8ea169
Packit 8ea169
    configure_problems2_service(p2_service);
Packit 8ea169
Packit 8ea169
    owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
Packit 8ea169
                             ABRT_DBUS_NAME,
Packit 8ea169
                             G_BUS_NAME_OWNER_FLAGS_NONE,
Packit 8ea169
                             on_bus_acquired,
Packit 8ea169
                             NULL,
Packit 8ea169
                             on_name_lost,
Packit 8ea169
                             p2_service,
Packit 8ea169
                             g_object_unref);
Packit 8ea169
Packit 8ea169
    /* initialize the g_settings_dump_location */
Packit 8ea169
    load_abrt_conf();
Packit 8ea169
Packit 8ea169
    loop = g_main_loop_new(NULL, FALSE);
Packit 8ea169
    g_main_loop_run(loop);
Packit 8ea169
Packit 8ea169
    log_notice("Cleaning up");
Packit 8ea169
Packit 8ea169
    g_bus_unown_name(owner_id);
Packit 8ea169
Packit 8ea169
    g_dbus_node_info_unref(introspection_data);
Packit 8ea169
Packit 8ea169
    free_abrt_conf_data();
Packit 8ea169
Packit 8ea169
    return 0;
Packit 8ea169
}