mtg minutes (planning)
by Jiri Moskovcak
My notes from yesterday's mtg, please attach yours. This should be our
main focus in the next sprint(s). Not ordered.
- teach client to send "microdump" (minimal set of information required
for the stats and deduplication - *without* any sensitive data) :
- arch
- compononet
- executable
- start_time
- crash_time
- os_release
- kernel_version
- packages involved in the crash
- extend server API to accept those microdumps
- django + JSON?
- storage for the microdumps
- design db schema
- rewrite the cache (can someone please elaborate??)
- visualize the crash trends
- client configuration should be part of Anaconda
- it should ask whether user wants to send those non-sensitive info
automatically or if ABRT should ask every time
- change the crash notification to be more Windows/Ubuntu like
- window in the centre of the screen instead of the notification bubble
- SEND / CLOSE / RESTART buttons
- https://wiki.ubuntu.com/Apport (no flames please ;)
- simplify the wizard by adding the *even groups*
--J.
12 years, 1 month
Re: [PATCH] new dbus API + polkit support
by Jiri Moskovcak
- new set of patches will arrive in a minute...
On 03/21/2012 03:52 PM, Nikola Pajkovsky wrote:
> Jiri Moskovcak<jmoskovc(a)redhat.com> writes:
>
>> +uid_t get_caller_uid(GDBusConnection *connection, const char *caller, GError *error)
>
> make it static
>
>> +{
>> + guint caller_uid;
>> +
>> + GDBusProxy * proxy = g_dbus_proxy_new_sync(connection,
>> + G_DBUS_PROXY_FLAGS_NONE,
>> + NULL,
>> + "org.freedesktop.DBus",
>> + "/org/freedesktop/DBus",
>> + "org.freedesktop.DBus",
>> + NULL,
>> +&error);
>> +
>> + GVariant *result = g_dbus_proxy_call_sync(proxy,
>> + "GetConnectionUnixUser",
>> + g_variant_new ("(s)", caller),
>> + G_DBUS_CALL_FLAGS_NONE,
>> + -1,
>> + NULL,
>> +&error);
>> +
>> + if (result == NULL) {
>> + /* this value shouldn't be used, beacuse error is set,
>> + * but return 99 -> nobody just to be sure
>> + */
>> + return 99;
>> + }
>
> you should use (uid_t) -1 casting instead of returning 99. it's more
> obviouse that you want to say: this is an error
>
- done
>> + g_variant_get(result, "(u)",&caller_uid);
>> + g_variant_unref(result);
>> +
>> + VERB2 log("Caller uid: %i\n", caller_uid);
>
> end of line is added by log()
>
>> + return caller_uid;
>> +}
>
>
>> +bool uid_in_group(uid_t uid, gid_t gid)
>
> make it static
>
- done
>> +{
>> + g_print("uid_in_group\n");
>
> use log()
>
- done
>> + char **tmp;
>> + struct passwd *pwd = getpwuid(uid);
>> + if (pwd&& (pwd->pw_gid == gid))
>> + return TRUE;
>
> if (!pwd)
> return FALSE;
>
> if (pwd->pw_gid == gid)
>
>> + struct group *grp = getgrgid(gid);
>> + if (pwd&& grp&& grp->gr_mem)
>
> now check
>
> if (!grp || !grp->gr_mem)
> return FALSE
>
- done
>> + {
>> + for (tmp = grp->gr_mem; *tmp != NULL; tmp++)
>> + {
>> + if (g_strcmp0(*tmp, pwd->pw_name) == 0)
>> + {
>> + VERB3 log("user %s belongs to group: %s\n", pwd->pw_name, grp->gr_name);
>> + return TRUE;
>> + }
>> + }
>> + }
>> + g_print("uid_in_gourp out\n");
>
> remove debgging msg
>
- done
>> + VERB2 log("WARN: user %s DOESN'T belong to group: %s\n", pwd->pw_name, grp->gr_name);
> ^^^ end line again
>
>> + return FALSE;
>> +}
>> +
>> +static void
>> +handle_method_call(GDBusConnection *connection,
>
> wrong coding style. we are using static void handle_....
>
- done
>> + const gchar *caller,
>> + const gchar *object_path,
>> + const gchar *interface_name,
>> + const gchar *method_name,
>> + GVariant *parameters,
>> + GDBusMethodInvocation *invocation,
>> + gpointer user_data)
>> +{
>
> this is multi-exit func, so I highly suggest to use *goto* and jump
> always to the end of func when error occurs.
>
- done
>> + reset_timeout();
>> + if (g_strcmp0(method_name, "GetProblems") == 0)
>> + {
>
> from here
>
>> + GError *error = NULL;
>> + GVariant *response;
>> + uid_t caller_uid;
>> +
>> +
>> + caller_uid = get_caller_uid(connection, caller, error);
>> +
>> + if (error)
>> + g_warning("Could not get unix user: %s", error->message);
>> + //die!
>> + else if (caller_uid == 99)
>
> use (uid_t) -1
>
- done
>> + //die
>> + g_warning("Could not get unix user, using 99 - nobody");
>
> to here it's always same in all *if* branches; please refactor it
>
- done
>
>> + //read config here!
>> + if (!g_settings_dump_location)
>> + g_settings_dump_location = (char*)"/var/spool/abrt";
>
> what does it mean?
>
- removed ;)
>> + response = get_problem_dirs_for_uid(caller_uid);
>> +
>> + g_dbus_method_invocation_return_value(invocation, response);
>> + //I was told that g_dbus_method frees the response
>> + //g_variant_unref(response);
>> + }
>> +
>> + else if (g_strcmp0(method_name, "GetAllProblems") == 0)
>> + {
>> + GVariant *response;
>> + GError *error = NULL;
>> + uid_t caller_uid;
>> +
>> +
>> + caller_uid = get_caller_uid(connection, caller, error);
>> +
>> + if (error)
>> + {
>> + g_warning("Could not get unix user: %s", error->message);
>> + //die!
>> + g_error_free(error);
>> + }
>> + else if (caller_uid == 99)
>> + //die
>> + g_warning("Could not get unix user, using 99 - nobody");
>> +
>> + /*
>> + - so, we have UID,
>> + - if it's 0, then we don't have to check anything and just return all directories
>> + - if uid != 0 then we want to ask for authorization
>> + */
>> +
>> + if (caller_uid != 0)
>> + {
>> + if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") == PolkitYes)
>> + caller_uid = 0;
>> + }
>
> here we will ask for the passwd and then we magically switch collse_uid
> to root (0)
>
- yes and it's correct, if authorization passes we want to treat caller
as if he was root
>> + response = get_problem_dirs_for_uid(caller_uid);
>> +
>> + g_dbus_method_invocation_return_value(invocation, response);
>> + }
>> +
>> + else if (g_strcmp0(method_name, "ChownProblemDir") == 0)
>> + {
>> + VERB2 log("ChownProblemDir");
>> +
>> + GError *error = NULL;
>> + uid_t caller_uid;
>> + const gchar *problem_dir;
>> + struct passwd *pwd;
>> + int chown_res;
>> + gchar *error_msg;
>> +
>> + g_variant_get(parameters, "(&s)",&problem_dir);
>> +
>> + //FIXME: check if it's problem_dir and refuse to operate on it if it's not
>> + struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
>> + if (!dd)
>> + {
>> + error_msg = g_strdup_printf(_("%s is not a valid problem dir"), problem_dir);
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.InvalidProblemDir",
>> + error_msg);
>> + free(error_msg);
>> + return;
>> + }
>> + dd_close(dd);
>> +
>> + caller_uid = get_caller_uid(connection, caller, error);
>> +
>> + g_print("out\n");
>> +
>> + if (error)
>> + {
>> + g_dbus_method_invocation_return_gerror(invocation, error);
>> + g_error_free(error);
>> + }
>> +
>> + if (caller_uid == 99)
>> + {
>> + error_msg = g_strdup_printf("Could not get unix user for caller %s", caller);
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.InvalidProblemDir",
>> + error_msg);
>> + free(error_msg);
>> + return;
>> + }
>> +
>> + struct stat statbuf;
>> + errno = 0;
>> + if (stat(problem_dir,&statbuf) == 0&& S_ISDIR(statbuf.st_mode))
>> + {
>> + if (caller_uid == 0 || uid_in_group(caller_uid, statbuf.st_gid)) //caller seems to be in group with access to this dir, so no action needed
>> + {
>> + //return ok
>> + VERB1 log("caller has access to the requested directory %s\n", problem_dir);
>> + g_dbus_method_invocation_return_value(invocation, NULL);
>> + return;
>> + //free something?
>> + }
>> +
>> + }
>> + else
>> + {
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.StatFailure",
>> + strerror(errno));
>> + return;
>> + }
>> +
>> + if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
>> + {
>> + VERB1 log("not authorized");
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.AuthFailure",
>> + "Not Authorized");
>> + return;
>> + }
>> +
>> + pwd = getpwuid(caller_uid);
>> + if (pwd)
>> + {
>> + errno = 0;
>> + chown_res = chown(problem_dir, statbuf.st_uid, pwd->pw_gid);
>> + if (chown_res != 0)
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.ChownError",
>> + strerror(errno));
>> +
>> + g_dbus_method_invocation_return_value(invocation, NULL);
>> + return;
>> + }
>> + }
>> +
>> + else if (g_strcmp0(method_name, "GetInfo") == 0)
>> + {
>> + VERB1 log("GetInfo\n");
>> +
>> + const gchar *problem_dir;
>> + g_variant_get(parameters, "(&s)",&problem_dir);
>> + gchar *response = g_strdup_printf("You've requested dir: '%s'. ", problem_dir);
>> +
>> + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", response));
>> + }
>> +
>> + else if (g_strcmp0(method_name, "Quit") == 0)
>> + {
>> + VERB1 log("Quit\n");
>> +
>> + g_dbus_method_invocation_return_value(invocation, NULL);
>> +
>> + g_main_loop_quit(loop);
>> +
>> + }
>> +}
>> +
>> +static gboolean
>> +on_timeout_cb(gpointer user_data)
>> +{
>> + g_print("timeout, would die, but we're still in debug mode\n");
>> + //g_main_loop_quit(loop);
>> + return TRUE;
>> +}
>> +
>> +/* for now */
>> +static const GDBusInterfaceVTable interface_vtable =
>> +{
>> + handle_method_call,
>> + NULL,
>> + NULL,
>> +};
>> +
>> +static void
>> +on_bus_acquired(GDBusConnection *connection,
>> + const gchar *name,
>> + gpointer user_data)
>> +{
>> + guint registration_id;
>> +
>> + registration_id = g_dbus_connection_register_object(connection,
>> + "/org/freedesktop/problems",
>> + introspection_data->interfaces[0],
>> +&interface_vtable,
>> + NULL, /* user_data */
>> + NULL, /* user_data_free_func */
>> + NULL); /* GError** */
>> + g_assert(registration_id> 0);
>> +
>> + reset_timeout();
>> +}
>> +
>> +static void
>> +on_name_acquired (GDBusConnection *connection,
>> + const gchar *name,
>> + gpointer user_data)
>> +{
>> +}
>> +
>> +static void
>> +on_name_lost (GDBusConnection *connection,
>> + const gchar *name,
>> + gpointer user_data)
>> +{
>> + exit (1);
>> +}
>> +
>> +int
>> +main (int argc, char *argv[])
>> +{
>> + guint owner_id;
>> +
>> + g_type_init();
>> +
>> + /* We are lazy here - we don't want to manually provide
>> + * the introspection data structures - so we just build
>> + * them from XML.
>> + */
>> + introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
>> + g_assert(introspection_data != NULL);
>> +
>> + owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
>> + "org.freedesktop.problems",
>> + G_BUS_NAME_OWNER_FLAGS_NONE,
>> + on_bus_acquired,
>> + on_name_acquired,
>> + on_name_lost,
>> + NULL,
>> + NULL);
>> +
>> + loop = g_main_loop_new(NULL, FALSE);
>> + g_main_loop_run(loop);
>> +
>> + g_print("Finishing server\n");
>> +
>> + g_bus_unown_name(owner_id);
>> +
>> + g_dbus_node_info_unref(introspection_data);
>> +
>> + return 0;
>> +}
>> +
>> diff --git a/src/dbus/abrt-polkit.c b/src/dbus/abrt-polkit.c
>> new file mode 100644
>> index 0000000..d90baf4
>> --- /dev/null
>> +++ b/src/dbus/abrt-polkit.c
>> @@ -0,0 +1,102 @@
>> +/*
>> + Copyright (C) 2012 ABRT team
>> +
>> + This program is free software; you can redistribute it and/or modify
>> + it under the terms of the GNU General Public License as published by
>> + the Free Software Foundation; either version 2 of the License, or
>> + (at your option) any later version.
>> +
>> + This program is distributed in the hope that it will be useful,
>> + but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + GNU General Public License for more details.
>> +
>> + You should have received a copy of the GNU General Public License along
>> + with this program; if not, write to the Free Software Foundation, Inc.,
>> + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>> +*/
>> +
>> +#include<polkit/polkit.h>
>> +#include<glib-object.h>
>> +#include<sys/types.h>
>> +#include<unistd.h>
>> +
>> +#include "libabrt.h"
>> +#include "abrt-polkit.h"
>> +
>> +/*number of seconds: timeout for the authorization*/
>> +#define POLKIT_TIMEOUT 20
>> +
>> +static gboolean do_cancel(GCancellable* cancellable)
>> +{
>> + log("Timer has expired; cancelling authorization check\n");
>> + g_cancellable_cancel(cancellable);
>> + return FALSE;
>> +}
>> +
>> +
>> +static PolkitResult do_check(PolkitSubject *subject, const char *action_id)
>> +{
>> + if (result)
>> + {
>> + if (polkit_authorization_result_get_is_challenge(result))
>> + {
>> + /* Can't happen (happens only with
>> + * POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE flag) */
>> + g_object_unref(result);
>> + return PolkitChallenge;
>> + }
>> + if (polkit_authorization_result_get_is_authorized(result))
>> + {
>> + g_object_unref(result);
>> + return PolkitYes;
>> + }
>> + g_object_unref(result);
>> + return PolkitNo;
>> + }
>> +
>> + return PolkitUnknown;
>> +}
>
> this function has a lot exit points, so let's simplify this
>
- done
> if (!result)
> return PolkitUnknown;
>
>
> here is the point that you always unref result
>
> if (polkit_authorization_result_get_is_challenge(result))
> {
> /* Can't happen (happens only with
> * POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE flag) */
> g_object_unref(result);
> return PolkitChallenge;
> }
> if (polkit_authorization_result_get_is_authorized(result))
> {
> g_object_unref(result);
> return PolkitYes;
> }
>
> and use *goto*
>
- argh goto... http://xkcd.com/292/ (but I did it since we use on other
places and so far no T-Rex ;))
>> +
>> +PolkitResult polkit_check_authorization_dname(const char *dbus_name, const char *action_id)
>> +{
>> + g_type_init();
>> + PolkitSubject *subject = polkit_system_bus_name_new(dbus_name);
>> + return do_check(subject, action_id);
>> +}
>> +
>> +PolkitResult polkit_check_authorization_pid(pid_t pid, const char *action_id)
>> +{
>> + g_type_init();
>> + PolkitSubject *subject = polkit_unix_process_new(pid);
>> + return do_check(subject, action_id);
>> +}
>> diff --git a/src/dbus/abrt-polkit.h b/src/dbus/abrt-polkit.h
>> new file mode 100644
>> index 0000000..0f6eb1e
>> --- /dev/null
>> +++ b/src/dbus/abrt-polkit.h
>> @@ -0,0 +1,39 @@
>> +/*
>> + Copyright (C) 2012 ABRT team
>> +
>> + This program is free software; you can redistribute it and/or modify
>> + it under the terms of the GNU General Public License as published by
>> + the Free Software Foundation; either version 2 of the License, or
>> + (at your option) any later version.
>> +
>> + This program is distributed in the hope that it will be useful,
>> + but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + GNU General Public License for more details.
>> +
>> + You should have received a copy of the GNU General Public License along
>> + with this program; if not, write to the Free Software Foundation, Inc.,
>> + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>> +*/
>> +#ifndef ABRT_POLKIT_H
>> +#define ABRT_POLKIT_H
>> +
>> +#include<sys/types.h>
>> +#include<unistd.h>
>> +
>> +typedef enum {
>> +/* Authorization status is unknown */
>> + PolkitUnknown = 0x0,
>> + /* Subject is authorized for the action */
>> + PolkitYes = 0x01,
>> + /* Subject is not authorized for the action */
>> + PolkitNo = 0x02,
>> + /* Challenge is needed for this action, only when flag is
>> + * POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE */
>> + PolkitChallenge = 0x03
>> +} PolkitResult;
>> +
>> +PolkitResult polkit_check_authorization_dname(const char *dbus_name, const char *action_id);
>> +PolkitResult polkit_check_authorization_pid(pid_t pid, const char *action_id);
>> +
>> +#endif
>> diff --git a/src/dbus/abrt_polkit.policy b/src/dbus/abrt_polkit.policy
>> new file mode 100644
>> index 0000000..7e7af94
>> --- /dev/null
>> +++ b/src/dbus/abrt_polkit.policy
>> @@ -0,0 +1,28 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<!DOCTYPE policyconfig PUBLIC
>> + "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
>> + "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
>> +
>> +<!--
>> +PolicyKit policy definitions for ABRT
>> +
>> +Copyright (c) 2012 ABRT Team<crash-catcher(a)fedorahosted.com>
>> +
>> +-->
>> +
>> +<policyconfig>
>> +<vendor>The ABRT Team</vendor>
>> +<vendor_url>https://fedorahosted.org/abrt/</vendor_url>
>> +
>> +<!-- install-debuginfos: default yes, administrator can change this -->
>> +<action id="org.freedesktop.problems.getall">
>> +<description>Get problems from all users</description>
>> +<message>Reading others problems requires authentication</message>
>> +<defaults>
>> +<allow_any>no</allow_any>
>> +<allow_active>auth_admin_keep</allow_active>
>> +<allow_inactive>no</allow_inactive>
>> +</defaults>
>> +</action>
>> +
>> +</policyconfig>
>> diff --git a/src/dbus/dbus-abrt.conf b/src/dbus/dbus-abrt.conf
>> new file mode 100644
>> index 0000000..ba09762
>> --- /dev/null
>> +++ b/src/dbus/dbus-abrt.conf
>> @@ -0,0 +1,25 @@
>> +<!-- This configuration file specifies the required security policies
>> + for abrt core daemon to work. -->
>> +
>> +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
>> + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
>> +<busconfig>
>> +
>> +<!-- ../system.conf have denied everything, so we just punch some holes -->
>> +
>> +<policy user="root">
>> +<allow own="org.freedesktop.problems"/>
>> +<allow send_destination="org.freedesktop.problems"/>
>> +<allow send_interface="org.freedesktop.problems"/>
>> +</policy>
>> +
>> +<policy at_console="true">
>> +<allow send_destination="org.freedesktop.org"/>
>> +</policy>
>> +
>> +<!-- Allow anyone to invoke methods on abrt server -->
>> +<policy context="default">
>> +<allow send_destination="org.freedesktop.problems"/>
>> +</policy>
>> +
>> +</busconfig>
>> diff --git a/src/dbus/org.freedesktop.problems.service b/src/dbus/org.freedesktop.problems.service
>> new file mode 100644
>> index 0000000..2b855c0
>> --- /dev/null
>> +++ b/src/dbus/org.freedesktop.problems.service
>> @@ -0,0 +1,7 @@
>> +[D-BUS Service]
>> +Name=org.freedesktop.problems
>> +# For testing, you may use -t5 to use small timeout of 5 seconds.
>> +# This will make "abrtd exited while clients existed but were idle"
>> +# situations easier to trigger
>> +Exec=/usr/sbin/abrt-dbus -ds -t133
>> +User=root
>> --
>> 1.7.7.6
>>
>> From 80ecee1c2fb64ca85ca3997645ecf323d13049b6 Mon Sep 17 00:00:00 2001
>> From: Jiri<moskovcak(a)gmail.com>
>> Date: Tue, 20 Mar 2012 13:47:42 +0100
>> Subject: [PATCH 2/3] abrt-dbus code cleanup, fixed some error paths
>>
>> - use VERBX log() instead of g_print
>> - properly close dump_dir
>> - use define for the dbus api names
>> - ignore abrt-dbus
>> ---
>> .gitignore | 1 +
>> src/dbus/Makefile.am | 2 +
>> src/dbus/abrt-dbus.c | 317 ++++++++++++++++++++++++++++++++++------------
>> src/include/Makefile.am | 3 +-
>> src/include/abrt-dbus.h | 8 ++
>> 5 files changed, 247 insertions(+), 84 deletions(-)
>> create mode 100644 src/include/abrt-dbus.h
>>
>> diff --git a/.gitignore b/.gitignore
>> index 1388141..e354997 100644
>> --- a/.gitignore
>> +++ b/.gitignore
>> @@ -14,6 +14,7 @@ src/daemon/abrt-server
>> src/daemon/abrtd
>> src/daemon/abrt-handle-event
>> src/daemon/abrt-dbus
>> +src/dbus/abrt-dbus
>> src/gui-gtk/abrt-gui
>> src/plugins/abrt-action-analyze-backtrace
>> src/plugins/abrt-action-analyze-c
>> diff --git a/src/dbus/Makefile.am b/src/dbus/Makefile.am
>> index 095df7c..5f29c71 100644
>> --- a/src/dbus/Makefile.am
>> +++ b/src/dbus/Makefile.am
>> @@ -23,6 +23,8 @@ abrt_dbus_LDADD = \
>> $(POLKIT_LIBS) \
>> -labrt_dbus
>>
>> +DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
>> +
>> polkitconfdir = ${datadir}/polkit-1/actions
>> dist_polkitconf_DATA = abrt_polkit.policy
>>
>> diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c
>> index a8e3690..4899285 100644
>> --- a/src/dbus/abrt-dbus.c
>> +++ b/src/dbus/abrt-dbus.c
>> @@ -5,12 +5,11 @@
>> #include<grp.h>
>> #include "libabrt.h"
>> #include "abrt-polkit.h"
>> -
>> -/* how long should we wait from the last request */
>> -#define TIME_TO_DIE 5
>> +#include "abrt-dbus.h"
>>
>> GMainLoop *loop;
>> guint g_timeout;
>> +static unsigned s_timeout;
>>
>> /* ---------------------------------------------------------------------------------------------------- */
>>
>> @@ -19,16 +18,18 @@ static GDBusNodeInfo *introspection_data = NULL;
>> /* Introspection data for the service we are exporting */
>> static const gchar introspection_xml[] =
>> "<node>"
>> - "<interface name='org.freedesktop.problems'>"
>> + "<interface name='"ABRT_DBUS_IFACE"'>"
>> "<method name='GetProblems'>"
>> + "<arg type='s' name='directory' direction='in'/>"
>> "<arg type='as' name='response' direction='out'/>"
>> "</method>"
>> "<method name='GetAllProblems'>"
>> + "<arg type='s' name='directory' direction='in'/>"
>> "<arg type='as' name='response' direction='out'/>"
>> "</method>"
>> "<method name='GetInfo'>"
>> "<arg type='s' name='problem_dir' direction='in'/>"
>> - "<arg type='s' name='response' direction='out'/>"
>> + "<arg type='a{ss}' name='response' direction='out'/>"
>> "</method>"
>> "<method name='ChownProblemDir'>"
>> "<arg type='s' name='problem_dir' direction='in'/>"
>> @@ -47,11 +48,11 @@ static void reset_timeout()
>> //FIXME: reset timer on every call
>> if (g_timeout> 0)
>> {
>> - VERB2 log("Removing timeout\n");
>> + VERB2 log("Removing timeout");
>> g_source_remove(g_timeout);
>> }
>> - VERB2 log("Setting a new timeout\n");
>> - g_timeout = g_timeout_add_seconds(TIME_TO_DIE, on_timeout_cb, NULL);
>> + VERB2 log("Setting a new timeout");
>> + g_timeout = g_timeout_add_seconds(s_timeout, on_timeout_cb, NULL);
>> }
>>
>> uid_t get_caller_uid(GDBusConnection *connection, const char *caller, GError *error)
>> @@ -85,13 +86,12 @@ uid_t get_caller_uid(GDBusConnection *connection, const char *caller, GError *er
>> g_variant_get(result, "(u)",&caller_uid);
>> g_variant_unref(result);
>>
>> - VERB2 log("Caller uid: %i\n", caller_uid);
>> + VERB2 log("Caller uid: %i", caller_uid);
>> return caller_uid;
>> }
>>
>> bool uid_in_group(uid_t uid, gid_t gid)
>> {
>> - g_print("uid_in_group\n");
>> char **tmp;
>> struct passwd *pwd = getpwuid(uid);
>> if (pwd&& (pwd->pw_gid == gid))
>> @@ -104,13 +104,12 @@ bool uid_in_group(uid_t uid, gid_t gid)
>> {
>> if (g_strcmp0(*tmp, pwd->pw_name) == 0)
>> {
>> - VERB3 log("user %s belongs to group: %s\n", pwd->pw_name, grp->gr_name);
>> + VERB3 log("user %s belongs to group: %s", pwd->pw_name, grp->gr_name);
>> return TRUE;
>> }
>> }
>> }
>> - g_print("uid_in_gourp out\n");
>> - VERB2 log("WARN: user %s DOESN'T belong to group: %s\n", pwd->pw_name, grp->gr_name);
>> + VERB2 log("WARN: user %s DOESN'T belong to group: %s", pwd->pw_name, grp->gr_name);
>> return FALSE;
>> }
>>
>> @@ -147,7 +146,7 @@ static GList* scan_directory(const char *path, uid_t caller_uid)
>> /* or we could just setuid?
>> - but it would require locking, because we want to setuid back before we server another request..
>> */
>> - if (dd&& (uid_in_group(caller_uid, statbuf.st_gid) || caller_uid == 0))
>> + if (dd&& (caller_uid == 0 || statbuf.st_mode& S_IROTH || uid_in_group(caller_uid, statbuf.st_gid)))
>> {
>> list = g_list_prepend(list, full_name);
>> full_name = NULL;
>> @@ -164,12 +163,12 @@ static GList* scan_directory(const char *path, uid_t caller_uid)
>> return g_list_reverse(list);
>> }
>>
>> -GVariant *get_problem_dirs_for_uid(uid_t uid)
>> +GVariant *get_problem_dirs_for_uid(uid_t uid, const char *dump_location)
>> {
>> - GList *dirs = scan_directory(g_settings_dump_location, uid);
>> + GList *dirs = scan_directory(dump_location, uid);
>>
>> GVariantBuilder *builder;
>> - builder = g_variant_builder_new(G_VARIANT_TYPE ("as"));
>> + builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
>> while (dirs)
>> {
>> g_variant_builder_add(builder, "s", (char*)dirs->data);
>> @@ -183,15 +182,14 @@ GVariant *get_problem_dirs_for_uid(uid_t uid)
>> return response;
>> }
>>
>> -static void
>> -handle_method_call(GDBusConnection *connection,
>> - const gchar *caller,
>> - const gchar *object_path,
>> - const gchar *interface_name,
>> - const gchar *method_name,
>> - GVariant *parameters,
>> - GDBusMethodInvocation *invocation,
>> - gpointer user_data)
>> +static void handle_method_call(GDBusConnection *connection,
>> + const gchar *caller,
>> + const gchar *object_path,
>> + const gchar *interface_name,
>> + const gchar *method_name,
>> + GVariant *parameters,
>> + GDBusMethodInvocation *invocation,
>> + gpointer user_data)
>> {
>> reset_timeout();
>> if (g_strcmp0(method_name, "GetProblems") == 0)
>> @@ -204,17 +202,30 @@ handle_method_call(GDBusConnection *connection,
>> caller_uid = get_caller_uid(connection, caller, error);
>>
>> if (error)
>> - g_warning("Could not get unix user: %s", error->message);
>> - //die!
>> + {
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.InvalidUser",
>> + error->message);
>> + g_error_free(error);
>> + return;
>> + }
>> else if (caller_uid == 99)
>> - //die
>> - g_warning("Could not get unix user, using 99 - nobody");
>> + {
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.InvalidUser",
>> + "Unknown error");
>> + return;
>> + }
>> +
>> + //TODO: change the API to not accept the dumpdir from user, but read it from config file?
>>
>> - //read config here!
>> - if (!g_settings_dump_location)
>> - g_settings_dump_location = (char*)"/var/spool/abrt";
>> + const gchar *dump_location;
>> + g_variant_get(parameters, "(&s)",&dump_location);
>>
>> - response = get_problem_dirs_for_uid(caller_uid);
>> + //if (!g_settings_dump_location)
>> + // g_settings_dump_location = (char*)"/var/spool/abrt";
>> +
>> + response = get_problem_dirs_for_uid(caller_uid, dump_location);
>>
>> g_dbus_method_invocation_return_value(invocation, response);
>> //I was told that g_dbus_method frees the response
>> @@ -227,18 +238,26 @@ handle_method_call(GDBusConnection *connection,
>> GError *error = NULL;
>> uid_t caller_uid;
>>
>> + const gchar *dump_location;
>> + g_variant_get(parameters, "(&s)",&dump_location);
>>
>> caller_uid = get_caller_uid(connection, caller, error);
>>
>> if (error)
>> {
>> - g_warning("Could not get unix user: %s", error->message);
>> - //die!
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.InvalidUser",
>> + error->message);
>> g_error_free(error);
>> + return;
>> }
>> else if (caller_uid == 99)
>> - //die
>> - g_warning("Could not get unix user, using 99 - nobody");
>> + {
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.InvalidUser",
>> + "Unknown error");
>> + return;
>> + }
>>
>> /*
>> - so, we have UID,
>> @@ -252,14 +271,14 @@ handle_method_call(GDBusConnection *connection,
>> caller_uid = 0;
>> }
>>
>> - response = get_problem_dirs_for_uid(caller_uid);
>> + response = get_problem_dirs_for_uid(caller_uid, dump_location);
>>
>> g_dbus_method_invocation_return_value(invocation, response);
>> }
>>
>> else if (g_strcmp0(method_name, "ChownProblemDir") == 0)
>> {
>> - VERB2 log("ChownProblemDir");
>> + VERB1 log("ChownProblemDir");
>>
>> GError *error = NULL;
>> uid_t caller_uid;
>> @@ -277,29 +296,29 @@ handle_method_call(GDBusConnection *connection,
>> error_msg = g_strdup_printf(_("%s is not a valid problem dir"), problem_dir);
>> g_dbus_method_invocation_return_dbus_error(invocation,
>> "org.freedesktop.problems.InvalidProblemDir",
>> - error_msg);
>> + error_msg);
>> free(error_msg);
>> return;
>> }
>> - dd_close(dd);
>>
>> caller_uid = get_caller_uid(connection, caller, error);
>>
>> - g_print("out\n");
>> -
>> if (error)
>> {
>> g_dbus_method_invocation_return_gerror(invocation, error);
>> g_error_free(error);
>> + dd_close(dd);
>> + return;
>> }
>>
>> if (caller_uid == 99)
>> {
>> error_msg = g_strdup_printf("Could not get unix user for caller %s", caller);
>> g_dbus_method_invocation_return_dbus_error(invocation,
>> - "org.freedesktop.problems.InvalidProblemDir",
>> - error_msg);
>> + "org.freedesktop.problems.InvalidUser",
>> + error_msg);
>> free(error_msg);
>> + dd_close(dd);
>> return;
>> }
>>
>> @@ -310,8 +329,9 @@ handle_method_call(GDBusConnection *connection,
>> if (caller_uid == 0 || uid_in_group(caller_uid, statbuf.st_gid)) //caller seems to be in group with access to this dir, so no action needed
>> {
>> //return ok
>> - VERB1 log("caller has access to the requested directory %s\n", problem_dir);
>> + VERB1 log("caller has access to the requested directory %s", problem_dir);
>> g_dbus_method_invocation_return_value(invocation, NULL);
>> + dd_close(dd);
>> return;
>> //free something?
>> }
>> @@ -322,6 +342,7 @@ handle_method_call(GDBusConnection *connection,
>> g_dbus_method_invocation_return_dbus_error(invocation,
>> "org.freedesktop.problems.StatFailure",
>> strerror(errno));
>> + dd_close(dd);
>> return;
>> }
>>
>> @@ -331,6 +352,7 @@ handle_method_call(GDBusConnection *connection,
>> g_dbus_method_invocation_return_dbus_error(invocation,
>> "org.freedesktop.problems.AuthFailure",
>> "Not Authorized");
>> + dd_close(dd);
>> return;
>> }
>>
>> @@ -339,30 +361,121 @@ handle_method_call(GDBusConnection *connection,
>> {
>> errno = 0;
>> chown_res = chown(problem_dir, statbuf.st_uid, pwd->pw_gid);
>> + dd_init_next_file(dd);
>> + char *short_name, *full_name;
>> + while (chown_res == 0&& dd_get_next_file(dd,&short_name,&full_name))
>> + {
>> + VERB3 log("chowning %s", full_name);
>> + chown_res = chown(full_name, statbuf.st_uid, pwd->pw_gid);
>> + }
>> +
>> if (chown_res != 0)
>> g_dbus_method_invocation_return_dbus_error(invocation,
>> "org.freedesktop.problems.ChownError",
>> strerror(errno));
>>
>> g_dbus_method_invocation_return_value(invocation, NULL);
>> + dd_close(dd);
>> return;
>> }
>> + VERB3 log("shouldn't get here");
>> + dd_close(dd);
>> }
>>
>> else if (g_strcmp0(method_name, "GetInfo") == 0)
>> {
>> - VERB1 log("GetInfo\n");
>> + VERB1 log("GetInfo");
>> + GError *error = NULL;
>>
>> const gchar *problem_dir;
>> g_variant_get(parameters, "(&s)",&problem_dir);
>> - gchar *response = g_strdup_printf("You've requested dir: '%s'. ", problem_dir);
>>
>> - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", response));
>> + GVariantBuilder *builder;
>> +
>> + struct stat statbuf;
>> + errno = 0;
>> + if (stat(problem_dir,&statbuf) != 0)
>> + {
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.GetInfoError",
>> + strerror(errno));
>> + return;
>> + }
>> +
>> +
>> + uid_t caller_uid = get_caller_uid(connection, caller, error);
>> + if (!uid_in_group(caller_uid, statbuf.st_gid))
>> + {
>> + if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
>> + {
>> + VERB1 log("not authorized");
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.AuthFailure",
>> + "Not Authorized");
>> + return;
>> + }
>> + }
>> +
>> + struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
>> + if (!dd)
>> + {
>> + char *error_msg = g_strdup_printf(_("%s is not a valid problem directory"), problem_dir);
>> + g_dbus_method_invocation_return_dbus_error(invocation,
>> + "org.freedesktop.problems.GetInfo",
>> + error_msg);
>> + free(error_msg);
>> + }
>> +
>> + builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
>> + g_variant_builder_add (builder, "{ss}", g_strdup(FILENAME_TIME), dd_load_text(dd, FILENAME_TIME));
>> + g_variant_builder_add (builder, "{ss}", g_strdup(FILENAME_REASON), dd_load_text(dd, FILENAME_REASON));
>> + char *not_reportable_reason = dd_load_text_ext(dd, FILENAME_NOT_REPORTABLE, 0
>> + | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> + | DD_FAIL_QUIETLY_ENOENT
>> + | DD_FAIL_QUIETLY_EACCES);
>> + if (not_reportable_reason)
>> + g_variant_builder_add (builder, "{ss}", g_strdup(FILENAME_NOT_REPORTABLE), dd_load_text_ext(dd, FILENAME_NOT_REPORTABLE, 0
>> + | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> + | DD_FAIL_QUIETLY_ENOENT
>> + | DD_FAIL_QUIETLY_EACCES));
>> + /* the source of the problem:
>> + * - first we try to load component, as we use it on Fedora
>> + */
>> + char *source = dd_load_text_ext(dd, FILENAME_COMPONENT, 0
>> + | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> + | DD_FAIL_QUIETLY_ENOENT
>> + | DD_FAIL_QUIETLY_EACCES
>> + );
>> + /* if we don't have component, we fallback to executable */
>> + if (!source)
>> + {
>> + source = dd_load_text_ext(dd, FILENAME_EXECUTABLE, 0
>> + | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> + | DD_FAIL_QUIETLY_ENOENT
>> + | DD_FAIL_QUIETLY_EACCES
>> + );
>> + }
>> +
>> + g_variant_builder_add (builder, "{ss}", g_strdup("source"), source);
>> + char *msg = dd_load_text_ext(dd, FILENAME_REPORTED_TO, 0
>> + | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> + | DD_FAIL_QUIETLY_ENOENT
>> + | DD_FAIL_QUIETLY_EACCES
>> + );
>> + if (msg)
>> + g_variant_builder_add (builder, "{ss}", g_strdup(FILENAME_REPORTED_TO), msg);
>> +
>> + dd_close(dd);
>> +
>> + GVariant *response = g_variant_new("(a{ss})", builder);
>> + g_variant_builder_unref(builder);
>> +
>> + g_dbus_method_invocation_return_value(invocation, response);
>> }
>>
>> else if (g_strcmp0(method_name, "Quit") == 0)
>> {
>> - VERB1 log("Quit\n");
>> + VERB1 log("Quit");
>>
>> g_dbus_method_invocation_return_value(invocation, NULL);
>>
>> @@ -371,11 +484,9 @@ handle_method_call(GDBusConnection *connection,
>> }
>> }
>>
>> -static gboolean
>> -on_timeout_cb(gpointer user_data)
>> +static gboolean on_timeout_cb(gpointer user_data)
>> {
>> - g_print("timeout, would die, but we're still in debug mode\n");
>> - //g_main_loop_quit(loop);
>> + g_main_loop_quit(loop);
>> return TRUE;
>> }
>>
>> @@ -387,15 +498,14 @@ static const GDBusInterfaceVTable interface_vtable =
>> NULL,
>> };
>>
>> -static void
>> -on_bus_acquired(GDBusConnection *connection,
>> +static void on_bus_acquired(GDBusConnection *connection,
>> const gchar *name,
>> gpointer user_data)
>> {
>> guint registration_id;
>>
>> registration_id = g_dbus_connection_register_object(connection,
>> - "/org/freedesktop/problems",
>> + ABRT_DBUS_OBJECT,
>> introspection_data->interfaces[0],
>> &interface_vtable,
>> NULL, /* user_data */
>> @@ -406,37 +516,78 @@ on_bus_acquired(GDBusConnection *connection,
>> reset_timeout();
>> }
>>
>> -static void
>> -on_name_acquired (GDBusConnection *connection,
>> +static void on_name_acquired (GDBusConnection *connection,
>> const gchar *name,
>> gpointer user_data)
>> {
>> }
>>
>> -static void
>> -on_name_lost (GDBusConnection *connection,
>> - const gchar *name,
>> - gpointer user_data)
>> +static void on_name_lost (GDBusConnection *connection,
>> + const gchar *name,
>> + gpointer user_data)
>> {
>> - exit (1);
>> + g_print(_("The name '%s' has been lost, please check if other "
>> + "service owning the name is not running.\n"), name);
>> + exit(1);
>> }
>>
>> -int
>> -main (int argc, char *argv[])
>> +int main (int argc, char *argv[])
>> {
>> - guint owner_id;
>> + /* I18n */
>> + setlocale(LC_ALL, "");
>> +#if ENABLE_NLS
>> + bindtextdomain(PACKAGE, LOCALEDIR);
>> + textdomain(PACKAGE);
>> +#endif
>> + guint owner_id;
>> +
>> + abrt_init(argv);
>> +
>> + const char *program_usage_string = _(
>> + "& [options]"
>> + );
>> + enum {
>> + OPT_v = 1<< 0,
>> + OPT_t = 1<< 1,
>> + };
>> + /* Keep enum above and order of options below in sync! */
>> + struct options program_options[] = {
>> + OPT__VERBOSE(&g_verbose),
>> + OPT_INTEGER('t', NULL,&s_timeout, _("Exit after NUM seconds of inactivity")),
>> + OPT_END()
>> + };
>> + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
>> +
>> + export_abrt_envvars(0);
>> +
>> + /* When dbus daemon starts us, it doesn't set PATH
>> + * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE).
>> + * In this case, set something sane:
>> + */
>> + const char *env_path = getenv("PATH");
>> + if (!env_path || !env_path[0])
>> + putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin");
>> +
>> + msg_prefix = "abrt-dbus"; /* for log(), error_msg() and such */
>> +
>> + if (!(opts& OPT_t))
>> + s_timeout = 120; //if the timeout is not set we default to 120sec
>> +
>> + if (getuid() != 0)
>> + error_msg_and_die(_("This program must be run as root."));
>> +
>> + g_type_init();
>>
>> - g_type_init();
>>
>> - /* We are lazy here - we don't want to manually provide
>> - * the introspection data structures - so we just build
>> - * them from XML.
>> - */
>> - introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
>> - g_assert(introspection_data != NULL);
>> + /* We are lazy here - we don't want to manually provide
>> + * the introspection data structures - so we just build
>> + * them from XML.
>> + */
>> + introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
>> + g_assert(introspection_data != NULL);
>>
>> - owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
>> - "org.freedesktop.problems",
>> + owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
>> + ABRT_DBUS_NAME,
>> G_BUS_NAME_OWNER_FLAGS_NONE,
>> on_bus_acquired,
>> on_name_acquired,
>> @@ -444,15 +595,15 @@ main (int argc, char *argv[])
>> NULL,
>> NULL);
>>
>> - loop = g_main_loop_new(NULL, FALSE);
>> - g_main_loop_run(loop);
>> + loop = g_main_loop_new(NULL, FALSE);
>> + g_main_loop_run(loop);
>>
>> - g_print("Finishing server\n");
>> + VERB1 log("Cleaning up");
>>
>> - g_bus_unown_name(owner_id);
>> + g_bus_unown_name(owner_id);
>>
>> - g_dbus_node_info_unref(introspection_data);
>> + g_dbus_node_info_unref(introspection_data);
>>
>> - return 0;
>> + return 0;
>> }
>>
>> diff --git a/src/include/Makefile.am b/src/include/Makefile.am
>> index c3317d7..f98e2d5 100644
>> --- a/src/include/Makefile.am
>> +++ b/src/include/Makefile.am
>> @@ -2,4 +2,5 @@ libabrt_includedir = \
>> $(includedir)/abrt
>>
>> libabrt_include_HEADERS = \
>> - libabrt.h
>> + libabrt.h \
>> + abrt-dbus.h
>> diff --git a/src/include/abrt-dbus.h b/src/include/abrt-dbus.h
>> new file mode 100644
>> index 0000000..898dd94
>> --- /dev/null
>> +++ b/src/include/abrt-dbus.h
>> @@ -0,0 +1,8 @@
>> +#ifndef ABRTDBUS_H_
>> +#define ABRTDBUS_H_
>> +
>> +#define ABRT_DBUS_NAME "org.freedesktop.problems"
>> +#define ABRT_DBUS_OBJECT "/org/freedesktop/problems"
>> +#define ABRT_DBUS_IFACE "org.freedesktop.problems"
>> +
>> +#endif /* ABRTDBUS_H_ */
>> --
>> 1.7.7.6
>>
>> From 072f17a615009e538b29286510f47898cc9bd46a Mon Sep 17 00:00:00 2001
>> From: Jiri<moskovcak(a)gmail.com>
>> Date: Tue, 20 Mar 2012 13:59:15 +0100
>> Subject: [PATCH 3/3] teach abrt-gui to use dbus API
>>
>> ---
>> src/dbus/org.freedesktop.problems.service | 2 +-
>> src/gui-gtk/Makefile.am | 6 +-
>> src/gui-gtk/main.c | 206 ++++++++++++++++++++--------
>> 3 files changed, 152 insertions(+), 62 deletions(-)
>>
>> diff --git a/src/dbus/org.freedesktop.problems.service b/src/dbus/org.freedesktop.problems.service
>> index 2b855c0..e8e3bf1 100644
>> --- a/src/dbus/org.freedesktop.problems.service
>> +++ b/src/dbus/org.freedesktop.problems.service
>> @@ -3,5 +3,5 @@ Name=org.freedesktop.problems
>> # For testing, you may use -t5 to use small timeout of 5 seconds.
>> # This will make "abrtd exited while clients existed but were idle"
>> # situations easier to trigger
>> -Exec=/usr/sbin/abrt-dbus -ds -t133
>> +Exec=/usr/sbin/abrt-dbus -t133
>> User=root
>> diff --git a/src/gui-gtk/Makefile.am b/src/gui-gtk/Makefile.am
>> index 734899e..2ce69c5 100644
>> --- a/src/gui-gtk/Makefile.am
>> +++ b/src/gui-gtk/Makefile.am
>> @@ -10,6 +10,7 @@ abrt_gui_CFLAGS = \
>> $(GTK_CFLAGS) \
>> $(LIBREPORT_GTK_CFLAGS) \
>> -D_GNU_SOURCE \
>> + $(GIO_CFLAGS) \
>> -Wall -Wwrite-strings -Werror
>> # -I/usr/include/glib-2.0
>> # -I/usr/lib/glib-2.0/include
>> @@ -18,9 +19,10 @@ abrt_gui_CFLAGS = \
>> abrt_gui_LDADD = \
>> -lglib-2.0 \
>> -lgthread-2.0 \
>> - $(GTK_LIBS) \
>> + $(GIO_LIBS) \
>> $(LIBREPORT_GTK_LIBS) \
>> - ../lib/libabrt.la
>> + ../lib/libabrt.la \
>> + $(GTK_LIBS)
>> # $(LIBNOTIFY_LIBS)
>>
>> #test_report_SOURCES = \
>> diff --git a/src/gui-gtk/main.c b/src/gui-gtk/main.c
>> index f34ff3f..777d9df 100644
>> --- a/src/gui-gtk/main.c
>> +++ b/src/gui-gtk/main.c
>> @@ -19,11 +19,13 @@
>> #include<gtk/gtk.h>
>> #include<gdk/gdkkeysyms.h>
>> #include<sys/inotify.h>
>> +#include<gio/gio.h> //dbus
>> #if HAVE_LOCALE_H
>> # include<locale.h>
>> #endif
>> #include<internal_libreport_gtk.h>
>> #include "libabrt.h"
>> +#include "abrt-dbus.h"
>>
>> #if GTK_MAJOR_VERSION == 2&& GTK_MINOR_VERSION< 22
>> # define GDK_KEY_Delete GDK_Delete
>> @@ -31,6 +33,7 @@
>> #endif
>>
>> static void scan_dirs_and_add_to_dirlist(void);
>> +static void rescan_and_refresh(void);
>>
>>
>> static const char help_uri[] = "http://docs.fedoraproject.org/en-US/"
>> @@ -59,6 +62,8 @@ enum
>> NUM_COLUMNS
>> };
>>
>> +gint g_authorize; /* wheter to try to authorize when getting list of problems */
>> +
>> //FIXME: maybe we can use strrchr and make this faster...
>> static char *get_last_line(const char* msg)
>> {
>> @@ -84,22 +89,60 @@ static char *get_last_line(const char* msg)
>> return xstrndup(start, end - start);
>> }
>>
>> -static void add_directory_to_dirlist(const char *dirname)
>> +static problem_data_t* get_problem_data_dbus(const char *problem_dir_path, GError *error)
>> +{
>> + problem_data_t *pd;
>> + char *key, *val;
>> +
>> + GDBusProxy *proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
>> + G_DBUS_PROXY_FLAGS_NONE,
>> + NULL,
>> + ABRT_DBUS_NAME,
>> + ABRT_DBUS_OBJECT,
>> + ABRT_DBUS_IFACE,
>> + NULL,
>> +&error);
>> +
>> + GVariant *result = g_dbus_proxy_call_sync(proxy,
>> + "GetInfo",
>> + g_variant_new("(s)", problem_dir_path),
>> + G_DBUS_CALL_FLAGS_NONE,
>> + -1,
>> + NULL,
>> +&error);
>> +
>> + pd = new_problem_data();
>> +
>> + GVariantIter *iter;
>> + g_variant_get(result, "(a{ss})",&iter);
>> + while (g_variant_iter_loop(iter, "{ss}",&key,&val))
>> + {
>> + add_to_problem_data(pd, key, val);
>> + }
>> + return pd;
>> +}
>> +
>> +static void add_directory_to_dirlist(gpointer dir, gpointer data)
>> {
>> + const char *dirname = (const char *)dir;
>> /* Silently ignore *any* errors, not only EACCES.
>> * We saw "lock file is locked by process PID" error
>> * when we raced with wizard.
>> */
>> int sv_logmode = logmode;
>> logmode = 0;
>> - struct dump_dir *dd = dd_opendir(dirname, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
>> logmode = sv_logmode;
>> + /*
>> + struct dump_dir *dd = dd_opendir(dirname, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
>> +
>> if (!dd)
>> return;
>> + */
>>
>> + problem_data_t *pd = get_problem_data_dbus(dir, NULL);
>> char time_buf[sizeof("YYYY-MM-DD hh:mm:ss")];
>> time_buf[0] = '\0';
>> - char *time_str = dd_load_text(dd, FILENAME_TIME);
>> + const char *time_str = get_problem_item_content_or_NULL(pd, FILENAME_TIME);
>> time_t t = 0;
>> if (time_str&& time_str[0])
>> {
>> @@ -108,40 +151,18 @@ static void add_directory_to_dirlist(const char *dirname)
>> size_t time_len = strftime(time_buf, sizeof(time_buf)-1, "%Y-%m-%d %H:%M", ptm);
>> time_buf[time_len] = '\0';
>> }
>> - free(time_str);
>> -
>>
>> - char *not_reportable_reason = dd_load_text_ext(dd, FILENAME_NOT_REPORTABLE, 0
>> - | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> - | DD_FAIL_QUIETLY_ENOENT
>> - | DD_FAIL_QUIETLY_EACCES);
>> - char *reason = NULL;
>> - if (!not_reportable_reason)
>> - reason = dd_load_text(dd, FILENAME_REASON);
>> + const char *not_reportable_reason = get_problem_item_content_or_NULL(pd, FILENAME_NOT_REPORTABLE);
>> + const char *reason = get_problem_item_content_or_NULL(pd, FILENAME_REASON);
>> + //if (!not_reportable_reason)
>> + // reason = get_problem_item_content_or_NULL(pd, FILENAME_REASON);
>>
>> /* the source of the problem:
>> * - first we try to load component, as we use it on Fedora
>> */
>> - char *source = dd_load_text_ext(dd, FILENAME_COMPONENT, 0
>> - | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> - | DD_FAIL_QUIETLY_ENOENT
>> - | DD_FAIL_QUIETLY_EACCES
>> - );
>> - /* if we don't have component, we fallback to executable */
>> - if (!source)
>> - {
>> - source = dd_load_text_ext(dd, FILENAME_EXECUTABLE, 0
>> - | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> - | DD_FAIL_QUIETLY_ENOENT
>> - | DD_FAIL_QUIETLY_EACCES
>> - );
>> - }
>> + const char *source = get_problem_item_content_or_NULL(pd, "source");
>>
>> - char *msg = dd_load_text_ext(dd, FILENAME_REPORTED_TO, 0
>> - | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
>> - | DD_FAIL_QUIETLY_ENOENT
>> - | DD_FAIL_QUIETLY_EACCES
>> - );
>> + const char *msg = get_problem_item_content_or_NULL(pd, FILENAME_REPORTED_TO);
>>
>>
>> GtkListStore *list_store;
>> @@ -166,16 +187,55 @@ static void add_directory_to_dirlist(const char *dirname)
>> COLUMN_DUMP_DIR, dirname,
>> COLUMN_REPORTED_TO, msg ? subm_status : NULL,
>> -1);
>> - /* this is safe, subm_status is either null or malloced string from get_last_line */
>> - free(not_reportable_reason);
>> - free(subm_status);
>> - free(msg);
>> - free(reason);
>>
>> - dd_close(dd);
>> + free_problem_data(pd);
>> +
>> VERB1 log("added: %s", dirname);
>> }
>>
>> +GList *get_problems_over_dbus(const char *dump_location, GError *error)
>> +{
>> + GDBusProxy * proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
>> + G_DBUS_PROXY_FLAGS_NONE,
>> + NULL,
>> + ABRT_DBUS_NAME,
>> + ABRT_DBUS_OBJECT,
>> + ABRT_DBUS_IFACE,
>> + NULL,
>> +&error);
>> +
>> +/*
>> + GDBusProxy * proxy = g_dbus_proxy_new_sync(connection,
>> + G_DBUS_PROXY_FLAGS_NONE,
>> + NULL,
>> + "org.freedesktop.problems",
>> + "/org/freedesktop/problems",
>> + "org.freedesktop.problems",
>> + NULL,
>> +&error);
>> +*/
>> +
>> + GVariant *result = g_dbus_proxy_call_sync(proxy,
>> + g_authorize ? "GetAllProblems" : "GetProblems",
>> + g_variant_new("(s)", dump_location),
>> + G_DBUS_CALL_FLAGS_NONE,
>> + -1,
>> + NULL,
>> +&error);
>> + GList *list = NULL;
>> + GVariantIter *iter;
>> + gchar *str;
>> + g_variant_get(result, "(as)",&iter);
>> + while (g_variant_iter_loop(iter, "s",&str))
>> + {
>> + VERB1 log("adding: %s\n", str);
>> + list = g_list_prepend(list, xstrdup(str));
>> + }
>> + g_variant_iter_free(iter);
>> +
>> + return list;
>> +}
>> +
>> static void rescan_dirs_and_add_to_dirlist(void)
>> {
>> gtk_list_store_clear(s_dumps_list_store);
>> @@ -344,6 +404,35 @@ static gboolean on_focus_cb(
>> return false; /* propagate the event further */
>> }
>>
>> +static int chown_dir_over_dbus(const char *problem_dir_path)
>> +{
>> + GError *error;
>> + GDBusProxy * proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
>> + G_DBUS_PROXY_FLAGS_NONE,
>> + NULL,
>> + ABRT_DBUS_NAME,
>> + ABRT_DBUS_OBJECT,
>> + ABRT_DBUS_IFACE,
>> + NULL,
>> +&error);
>> +
>> + g_dbus_proxy_call_sync(proxy,
>> + "ChownProblemDir",
>> + g_variant_new("(s)", problem_dir_path),
>> + G_DBUS_CALL_FLAGS_NONE,
>> + -1,
>> + NULL,
>> +&error);
>> +
>> + if (error)
>> + {
>> + //TODO show a warning dialog here or on the higher level?
>> + error_msg(_("Can't chown '%s': %s"),problem_dir_path, error->message);
>> + return 1;
>> + }
>> + return 0;
>> +}
>> +
>> static void on_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
>> {
>> GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
>> @@ -358,8 +447,13 @@ static void on_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTre
>>
>> const char *dirname = g_value_get_string(&d_dir);
>>
>> - report_problem_in_dir(dirname,
>> + if (chown_dir_over_dbus(dirname) == 0)
>> + {
>> + report_problem_in_dir(dirname,
>> LIBREPORT_ANALYZE | LIBREPORT_NOWAIT | LIBREPORT_GETPID);
>> + }
>> + //else
>> + // TODO: show a warning dialog
>> }
>> }
>> }
>> @@ -392,6 +486,12 @@ static void on_column_change_cb(GtkTreeSortable *sortable, gpointer user_data)
>> free(value);
>> }
>>
>> +static void on_show_all_cb(GtkToggleButton *togglebutton, gpointer data)
>> +{
>> + g_authorize = gtk_toggle_button_get_active(togglebutton);
>> + rescan_and_refresh();
>> +}
>> +
>> static void load_sort_setting(GtkTreeSortable *sortable)
>> {
>> const char *name, *value;
>> @@ -754,10 +854,14 @@ static GtkWidget *create_main_window(void)
>> gtk_misc_set_alignment(GTK_MISC(not_subm_lbl), 0, 0);
>> gtk_label_set_markup(GTK_LABEL(not_subm_lbl), _("<b>Not submitted reports</b>"));
>>
>> + GtkWidget *show_all_btn = gtk_check_button_new_with_label(_("Show all problems"));
>> + g_signal_connect(show_all_btn, "toggled", G_CALLBACK(on_show_all_cb), NULL);
>> +
>> /* add label for not submitted tree view */
>> gtk_box_pack_start(GTK_BOX(not_subm_vbox), not_subm_lbl, false, false, 0);
>> gtk_box_pack_start(GTK_BOX(not_subm_vbox), new_problems_scroll_win, true, true, 0);
>> gtk_box_pack_start(GTK_BOX(main_vbox), not_subm_vbox, true, true, 0);
>> + gtk_box_pack_start(GTK_BOX(main_vbox), show_all_btn, false, false, 0);
>>
>> /* Two tree views */
>> s_treeview = gtk_tree_view_new();
>> @@ -988,27 +1092,11 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin
>>
>> static void scan_directory_and_add_to_dirlist(const char *path)
>> {
>> - DIR *dp = opendir(path);
>> - if (!dp)
>> - {
>> - /* We don't want to yell if, say, $HOME/.abrt/spool doesn't exist */
>> - //perror_msg("Can't open directory '%s'", path);
>> - return;
>> - }
>> -
>> - struct dirent *dent;
>> - while ((dent = readdir(dp)) != NULL)
>> - {
>> - if (dot_or_dotdot(dent->d_name))
>> - continue; /* skip "." and ".." */
>> -
>> - char *full_name = concat_path_file(path, dent->d_name);
>> - struct stat statbuf;
>> - if (stat(full_name,&statbuf) == 0&& S_ISDIR(statbuf.st_mode))
>> - add_directory_to_dirlist(full_name);
>> - free(full_name);
>> - }
>> - closedir(dp);
>> + GList *problem_dirs = get_problems_over_dbus(path, NULL);
>> + if (problem_dirs)
>> + g_list_foreach(problem_dirs, (GFunc)add_directory_to_dirlist, NULL);
>> + else
>> + error_msg_and_die(_("Can't get problem list from abrt-dbus"));
>>
>> if (inotify_fd>= 0&& inotify_add_watch(inotify_fd, path, 0
>> // | IN_ATTRIB // Metadata changed
>
12 years, 1 month
[PATCH 1/2] initial abrt-dbus API rewrite using glib
by Jiri Moskovcak
---
.gitignore | 1 +
abrt.spec.in | 22 +-
configure.ac | 3 +
po/POTFILES.in | 2 +-
src/Makefile.am | 2 +-
src/daemon/Makefile.am | 26 +--
src/daemon/abrt-dbus.c | 536 -------------------------
src/daemon/com.redhat.abrt.service | 7 -
src/daemon/dbus-abrt.conf | 25 --
src/dbus/Makefile.am | 35 ++
src/dbus/abrt-dbus.c | 609 +++++++++++++++++++++++++++++
src/dbus/abrt-polkit.c | 102 +++++
src/dbus/abrt-polkit.h | 39 ++
src/dbus/abrt_polkit.policy | 28 ++
src/dbus/dbus-abrt.conf | 25 ++
src/dbus/org.freedesktop.problems.service | 7 +
src/include/Makefile.am | 3 +-
src/include/abrt-dbus.h | 8 +
18 files changed, 881 insertions(+), 599 deletions(-)
delete mode 100644 src/daemon/abrt-dbus.c
delete mode 100644 src/daemon/com.redhat.abrt.service
delete mode 100644 src/daemon/dbus-abrt.conf
create mode 100644 src/dbus/Makefile.am
create mode 100644 src/dbus/abrt-dbus.c
create mode 100644 src/dbus/abrt-polkit.c
create mode 100644 src/dbus/abrt-polkit.h
create mode 100644 src/dbus/abrt_polkit.policy
create mode 100644 src/dbus/dbus-abrt.conf
create mode 100644 src/dbus/org.freedesktop.problems.service
create mode 100644 src/include/abrt-dbus.h
diff --git a/.gitignore b/.gitignore
index 1388141..e354997 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ src/daemon/abrt-server
src/daemon/abrtd
src/daemon/abrt-handle-event
src/daemon/abrt-dbus
+src/dbus/abrt-dbus
src/gui-gtk/abrt-gui
src/plugins/abrt-action-analyze-backtrace
src/plugins/abrt-action-analyze-c
diff --git a/abrt.spec.in b/abrt.spec.in
index 5cdf644..d619c19 100644
--- a/abrt.spec.in
+++ b/abrt.spec.in
@@ -198,6 +198,18 @@ Provides: bug-buddy
%description desktop
Virtual package to make easy default installation on desktop environments.
+%package dbus
+Summary: ABRT DBus service
+Group: Application/System
+Requires: %{name} = %{version}-%{release}
+Requires: libreport
+BuildRequires: polkit-devel
+
+%description dbus
+ABRT DBus service which provides org.freedesktop.problems API on dbus and
+uses PolicyKit to authorize to access the problem data.
+
+
%prep
%setup -q
@@ -438,7 +450,6 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%{_initrddir}/abrtd
%endif
%{_sbindir}/abrtd
-%{_sbindir}/abrt-dbus
%{_sbindir}/abrt-server
%{_libexecdir}/abrt-handle-event
%{_bindir}/abrt-handle-upload
@@ -448,7 +459,6 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%config(noreplace) %{_sysconfdir}/%{name}/abrt-action-save-package-data.conf
%config(noreplace) %{_sysconfdir}/%{name}/gpg_keys
%config(noreplace) %{_sysconfdir}/libreport/events.d/abrt_event.conf
-%config(noreplace) %{_sysconfdir}/dbus-1/system.d/dbus-abrt.conf
%config(noreplace) %{_sysconfdir}/libreport/events.d/smart_event.conf
%config(noreplace) %{_sysconfdir}/libreport/events.d/smolt_event.conf
%dir %attr(0755, abrt, abrt) %{_localstatedir}/spool/%{name}
@@ -469,7 +479,6 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%{_mandir}/man5/abrt.conf.5.gz
%{_mandir}/man5/abrt-action-save-package-data.conf.5.gz
# {_mandir}/man5/pyhook.conf.5.gz
-%{_datadir}/dbus-1/system-services/com.redhat.abrt.service
%files libs
%defattr(-,root,root,-)
@@ -594,6 +603,13 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%files desktop
%defattr(-,root,root,-)
+%files dbus
+%defattr(-,root,root,-)
+%{_sbindir}/abrt-dbus
+%config(noreplace) %{_sysconfdir}/dbus-1/system.d/dbus-abrt.conf
+%{_datadir}/dbus-1/system-services/org.freedesktop.problems.service
+%{_datadir}/polkit-1/actions/abrt_polkit.policy
+
%changelog
* Wed Mar 16 2011 Jiri Moskovcak <jmoskovc(a)redhat.com> 2.0.0-1
- update to the latest upstream version
diff --git a/configure.ac b/configure.ac
index 4391239..987cacd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,12 +71,14 @@ PKG_CHECK_MODULES([NSS], [nss])
PKG_CHECK_MODULES([BTPARSER], [btparser])
PKG_CHECK_MODULES([LIBREPORT], [libreport])
PKG_CHECK_MODULES([LIBREPORT_GTK], [libreport-gtk])
+PKG_CHECK_MODULES([POLKIT], [polkit-gobject-1])
# Just PKG_CHECK_MODULES([PYTHON], [python]) works only with python2.7+
# Below, if python is not found, we set up for python2.6 w/o checking:
PKG_CHECK_MODULES([PYTHON], [python],,[
PYTHON_LIBS='-L/usr/lib64 -lpython2.6'
PYTHON_CFLAGS='-I/usr/include/python2.6'
])
+PKG_CHECK_MODULES([GIO], [gio-2.0])
AC_ARG_ENABLE([dupcheck-fingerprint],
AS_HELP_STRING([--enable-dupcheck-fingerprint], [enable function fingerprinting for duplicate checking (x86_64 only)]),
@@ -129,6 +131,7 @@ AC_CONFIG_FILES([
src/applet/Makefile
src/gui-gtk/Makefile
src/cli/Makefile
+ src/dbus/Makefile
src/plugins/abrt-action-install-debuginfo
src/plugins/abrt-action-analyze-vmcore
po/Makefile.in
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1e9e5cd..254518a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -5,7 +5,7 @@ src/applet/abrt-applet.desktop.in
src/applet/applet.c
src/daemon/abrt-action-save-package-data.c
src/daemon/abrt-server.c
-src/daemon/abrt-dbus.c
+src/dbus/abrt-dbus.c
src/daemon/abrtd.c
src/daemon/abrt-handle-event.c
src/gui-gtk/abrt.desktop.in
diff --git a/src/Makefile.am b/src/Makefile.am
index ab95ef7..2198f3c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1 +1 @@
-SUBDIRS = include lib hooks daemon applet gui-gtk plugins cli
+SUBDIRS = include lib hooks daemon applet gui-gtk plugins cli dbus
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index bed3c44..46a4517 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -11,8 +11,7 @@ bin_PROGRAMS = \
sbin_PROGRAMS = \
abrtd \
- abrt-server \
- abrt-dbus
+ abrt-server
libexec_PROGRAMS = abrt-handle-event
@@ -44,24 +43,6 @@ abrt_server_LDADD = \
../lib/libabrt.la \
$(LIBREPORT_LIBS)
-abrt_dbus_SOURCES = \
- abrt-dbus.c
-abrt_dbus_CPPFLAGS = \
- -I$(srcdir)/../include \
- -I$(srcdir)/../lib \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- $(GLIB_CFLAGS) \
- $(DBUS_CFLAGS) \
- $(LIBREPORT_CFLAGS) \
- -D_GNU_SOURCE \
- -Wall -Wwrite-strings \
- -Werror
-abrt_dbus_LDADD = \
- $(DBUS_LIBS) \
- ../lib/libabrt.la \
- $(LIBREPORT_LIBS) \
- -labrt_dbus
-
abrt_handle_event_SOURCES = \
abrt-handle-event.c
abrt_handle_event_CPPFLAGS = \
@@ -93,17 +74,12 @@ abrt_action_save_package_data_LDADD = \
$(LIBREPORT_LIBS) \
../lib/libabrt.la
-dbusabrtconfdir = ${sysconfdir}/dbus-1/system.d/
-dist_dbusabrtconf_DATA = dbus-abrt.conf
-
daemonconfdir = $(CONF_DIR)
dist_daemonconf_DATA = \
abrt.conf \
abrt-action-save-package-data.conf \
gpg_keys
-comredhatabrtservicedir = ${datadir}/dbus-1/system-services
-dist_comredhatabrtservice_DATA = com.redhat.abrt.service
EXTRA_DIST = abrt-handle-upload
DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
diff --git a/src/daemon/abrt-dbus.c b/src/daemon/abrt-dbus.c
deleted file mode 100644
index ee53ba9..0000000
--- a/src/daemon/abrt-dbus.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2011 RedHat Inc
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#include <syslog.h>
-#include <dbus/dbus.h>
-#include <internal_abrt_dbus.h>
-#include "libabrt.h"
-
-/* I want to use -Werror, but gcc-4.4 throws a curveball:
- * "warning: ignoring return value of 'ftruncate', declared with attribute warn_unused_result"
- * and (void) cast is not enough to shut it up! Oh God...
- */
-#define IGNORE_RESULT(func_call) do { if (func_call) /* nothing */; } while (0)
-
-
-#define ABRTD_DBUS_NAME "com.redhat.abrt"
-#define ABRTD_DBUS_PATH "/com/redhat/abrt"
-#define ABRTD_DBUS_IFACE "com.redhat.abrt"
-
-
-static volatile sig_atomic_t s_sig_caught;
-static int s_signal_pipe[2];
-static int s_signal_pipe_write = -1;
-static unsigned s_timeout;
-static bool s_exiting;
-
-
-static void send_flush_and_unref(DBusMessage* msg)
-{
- if (!g_dbus_conn)
- {
- /* Not logging this, it may recurse */
- return;
- }
- if (!dbus_connection_send(g_dbus_conn, msg, NULL /* &serial */))
- error_msg_and_die("Error sending DBus message");
- dbus_connection_flush(g_dbus_conn);
- VERB3 log("DBus message sent");
- dbus_message_unref(msg);
-}
-
-/*
- * DBus call handlers
- */
-
-static GList* scan_directory(const char *path)
-{
- GList *list = NULL;
-
- DIR *dp = opendir(path);
- if (!dp)
- {
- /* We don't want to yell if, say, $HOME/.abrt/spool doesn't exist */
- //perror_msg("Can't open directory '%s'", path);
- return list;
- }
-
- struct dirent *dent;
- while ((dent = readdir(dp)) != NULL)
- {
- if (dot_or_dotdot(dent->d_name))
- continue; /* skip "." and ".." */
-
- char *full_name = concat_path_file(path, dent->d_name);
- struct stat statbuf;
- if (stat(full_name, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
- {
- /* Silently ignore *any* errors, not only EACCES.
- * We saw "lock file is locked by process PID" error
- * when we raced with wizard.
- */
- int sv_logmode = logmode;
- logmode = 0;
- struct dump_dir *dd = dd_opendir(full_name, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
- logmode = sv_logmode;
- if (dd)
- {
- list = g_list_prepend(list, full_name);
- full_name = NULL;
- dd_close(dd);
- }
- }
- free(full_name);
- }
- closedir(dp);
-
- /* Why reverse?
- * Because N*prepend+reverse is faster than N*append
- */
- return g_list_reverse(list);
-}
-
-/* To test from command line:
- * dbus-send --system --type=method_call --print-reply --dest=com.redhat.abrt \
- * /com/redhat/abrt com.redhat.abrt.GetListOfProblems
- */
-static int handle_GetListOfProblems(DBusMessage* call, DBusMessage* reply)
-{
- DBusMessageIter out_iter;
- dbus_message_iter_init_append(reply, &out_iter);
-
- GList *list = scan_directory(g_settings_dump_location);
-
- /* Store the array */
- DBusMessageIter sub_iter;
- if (!dbus_message_iter_open_container(&out_iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
- die_out_of_memory();
- while (list)
- {
- store_string(&sub_iter, (char*)list->data);
- free(list->data);
- list = g_list_delete_link(list, list);
- }
- if (!dbus_message_iter_close_container(&out_iter, &sub_iter))
- die_out_of_memory();
-
- /* Send reply */
- send_flush_and_unref(reply);
- return 0;
-}
-
-/*
- * Glib integration machinery
- */
-
-/* Callback: "a message is received to a registered object path" */
-static DBusHandlerResult message_received(DBusConnection* conn, DBusMessage* msg, void* data)
-{
- const char* member = dbus_message_get_member(msg);
- VERB1 log("%s(method:'%s')", __func__, member);
-
- //set_client_name(dbus_message_get_sender(msg));
-
- DBusMessage* reply = dbus_message_new_method_return(msg);
- int r = -1;
- if (strcmp(member, "GetListOfProblems") == 0)
- r = handle_GetListOfProblems(msg, reply);
-// NB: C++ binding also handles "Introspect" method, which returns a string.
-// It was sending "dummy" introspection answer whick looks like this:
-// "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
-// "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
-// "<node>\n"
-// "</node>\n"
-// Apart from a warning from abrt-gui, just sending error back works as well.
-// NB2: we may want to handle "Disconnected" here too.
-
- if (r < 0)
- {
- /* handle_XXX experienced an error (and did not send any reply) */
- dbus_message_unref(reply);
- if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL)
- {
- /* Create and send error reply */
- reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "not supported");
- if (!reply)
- die_out_of_memory();
- send_flush_and_unref(reply);
- }
- }
-
- //set_client_name(NULL);
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static void handle_dbus_err(bool error_flag, DBusError *err)
-{
- if (dbus_error_is_set(err))
- {
- error_msg("dbus error: %s", err->message);
- /* dbus_error_free(&err); */
- error_flag = true;
- }
- if (!error_flag)
- return;
- error_msg_and_die(
- "Error requesting DBus name %s, possible reasons: "
- "abrt run by non-root; dbus config is incorrect; "
- "or dbus daemon needs to be restarted to reload dbus config",
- ABRTD_DBUS_NAME);
-}
-
-static int init_dbus(void)
-{
- DBusConnection* conn;
- DBusError err;
-
- dbus_error_init(&err);
- VERB3 log("dbus_bus_get");
- conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
- handle_dbus_err(conn == NULL, &err);
- // dbus api says:
- // "If dbus_bus_get obtains a new connection object never before returned
- // from dbus_bus_get(), it will call dbus_connection_set_exit_on_disconnect(),
- // so the application will exit if the connection closes. You can undo this
- // by calling dbus_connection_set_exit_on_disconnect() yourself after you get
- // the connection."
- // ...
- // "When a connection is disconnected, you are guaranteed to get a signal
- // "Disconnected" from the interface DBUS_INTERFACE_LOCAL, path DBUS_PATH_LOCAL"
- //
- // dbus-daemon drops connections if it recvs a malformed message
- // (we actually observed this when we sent bad UTF-8 string).
- // Currently, in this case abrtd just exits with exit code 1.
- // (symptom: last two log messages are "abrtd: remove_watch()")
- // If we want to have better logging or other nontrivial handling,
- // here we need to do:
- //
- //dbus_connection_set_exit_on_disconnect(conn, FALSE);
- //dbus_connection_add_filter(conn, handle_message, NULL, NULL);
- //
- // and need to code up handle_message to check for "Disconnected" dbus signal
-
- /* Also sets g_dbus_conn to conn. */
- attach_dbus_conn_to_glib_main_loop(conn, "/com/redhat/abrt", message_received);
-
- VERB3 log("dbus_bus_request_name");
- int rc = dbus_bus_request_name(conn, ABRTD_DBUS_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
-//maybe check that r == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER instead?
- handle_dbus_err(rc < 0, &err);
- VERB3 log("dbus init done");
-
- /* dbus_bus_request_name can already read some data. For example,
- * if we were autostarted, the call which caused autostart arrives
- * at this moment. Thus while dbus fd hasn't any data anymore,
- * dbus library can buffer a message or two.
- * If we don't do this, the data won't be processed
- * until next dbus data arrives.
- */
- int cnt = 10;
- while (dbus_connection_dispatch(conn) != DBUS_DISPATCH_COMPLETE && --cnt)
- VERB3 log("processed initial buffered dbus message");
-
- return 0;
-}
-
-static void deinit_dbus(void)
-{
- if (g_dbus_conn != NULL)
- {
- dbus_connection_unref(g_dbus_conn);
- g_dbus_conn = NULL;
- }
-}
-
-/*
- * Signal pipe handling
- */
-
-static void handle_signal(int signo)
-{
- int save_errno = errno;
-
- // Enable for debugging only, malloc/printf are unsafe in signal handlers
- //VERB3 log("Got signal %d", signo);
-
- uint8_t sig_caught;
- s_sig_caught = sig_caught = signo;
- /* Using local copy of s_sig_caught so that concurrent signal
- * won't change it under us */
- if (s_signal_pipe_write >= 0)
- IGNORE_RESULT(write(s_signal_pipe_write, &sig_caught, 1));
-
- errno = save_errno;
-}
-
-/* Signal pipe handler */
-static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
-{
- uint8_t signo;
- gsize len = 0;
- g_io_channel_read_chars(gio, (void*) &signo, 1, &len, NULL);
- if (len == 1)
- {
- /* we did receive a signal */
- VERB3 log("Got signal %d through signal pipe", signo);
- s_exiting = 1;
- }
- return TRUE; /* "please don't remove this event" */
-}
-
-
-static void start_syslog_logging(void)
-{
- /* Open stdin to /dev/null */
- xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO);
- /* We must not leave fds 0,1,2 closed.
- * Otherwise fprintf(stderr) dumps messages into random fds, etc. */
- xdup2(STDIN_FILENO, STDOUT_FILENO);
- xdup2(STDIN_FILENO, STDERR_FILENO);
- openlog(g_progname, 0, LOG_DAEMON);
- logmode = LOGMODE_SYSLOG;
- putenv((char*)"ABRT_SYSLOG=1");
-}
-
-/* Run main loop with idle timeout.
- * Basically, almost like glib's g_main_run(loop)
- */
-static void run_main_loop(GMainLoop *loop)
-{
- time_t cur_time = time(NULL);
- GMainContext *context = g_main_loop_get_context(loop);
- int fds_size = 0;
- GPollFD *fds = NULL;
-
- while (!s_exiting)
- {
- gboolean some_ready;
- gint max_priority;
- gint timeout;
- gint nfds;
-
- some_ready = g_main_context_prepare(context, &max_priority);
- if (some_ready)
- g_main_context_dispatch(context);
-
- while (1)
- {
- nfds = g_main_context_query(context, max_priority, &timeout, fds, fds_size);
- if (nfds <= fds_size)
- break;
- fds_size = nfds + 16; /* +16: optimizing realloc frequency */
- fds = (GPollFD *)xrealloc(fds, fds_size * sizeof(fds[0]));
- }
-
- if (s_timeout != 0)
- alarm(s_timeout);
- g_poll(fds, nfds, timeout);
- if (s_timeout != 0)
- alarm(0);
-
- time_t new_time = time(NULL);
- if (cur_time != new_time)
- {
- cur_time = new_time;
- load_abrt_conf();
-//TODO: react to changes in g_settings_sWatchCrashdumpArchiveDir
- }
-
- some_ready = g_main_context_check(context, max_priority, fds, nfds);
- if (some_ready)
- g_main_context_dispatch(context);
- }
-
- free(fds);
- g_main_context_unref(context);
-}
-
-int main(int argc, char** argv)
-{
- /* I18n */
- setlocale(LC_ALL, "");
-#if ENABLE_NLS
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
-#endif
-
- abrt_init(argv);
-
- int parent_pid = getpid();
-
- const char *program_usage_string = _(
- "& [options]"
- );
- enum {
- OPT_v = 1 << 0,
- OPT_d = 1 << 1,
- OPT_s = 1 << 2,
- OPT_t = 1 << 3,
- };
- /* Keep enum above and order of options below in sync! */
- struct options program_options[] = {
- OPT__VERBOSE(&g_verbose),
- OPT_BOOL( 'd', NULL, NULL , _("Do not daemonize")),
- OPT_BOOL( 's', NULL, NULL , _("Log to syslog even with -d")),
- OPT_INTEGER('t', NULL, &s_timeout, _("Exit after NUM seconds of inactivity")),
- OPT_END()
- };
- unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
-
- export_abrt_envvars(0);
-
- /* When dbus daemon starts us, it doesn't set PATH
- * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE).
- * In this case, set something sane:
- */
- const char *env_path = getenv("PATH");
- if (!env_path || !env_path[0])
- putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin");
-
- unsetenv("ABRT_SYSLOG");
- msg_prefix = g_progname; /* for log(), error_msg() and such */
-
- if (getuid() != 0)
- error_msg_and_die("Must be run as root");
-
- if (opts & OPT_s)
- start_syslog_logging();
-
- xpipe(s_signal_pipe);
- close_on_exec_on(s_signal_pipe[0]);
- close_on_exec_on(s_signal_pipe[1]);
- ndelay_on(s_signal_pipe[0]); /* I/O should not block - */
- ndelay_on(s_signal_pipe[1]); /* especially writes! they happen in signal handler! */
- signal(SIGTERM, handle_signal);
- signal(SIGINT, handle_signal);
- if (s_timeout != 0)
- signal(SIGALRM, handle_signal);
-
- /* Daemonize unless -d */
- if (!(opts & OPT_d))
- {
- /* forking to background */
- pid_t pid = fork();
- if (pid < 0)
- {
- perror_msg_and_die("fork");
- }
- if (pid > 0)
- {
- /* Parent */
- /* Wait for child to notify us via SIGTERM that it feels ok */
- int i = 20; /* 2 sec */
- while (s_sig_caught == 0 && --i)
- {
- usleep(100 * 1000);
- }
- if (s_sig_caught == SIGTERM)
- {
- exit(0);
- }
- if (s_sig_caught)
- {
- error_msg_and_die("Failed to start: got sig %d", s_sig_caught);
- }
- error_msg_and_die("Failed to start: timeout waiting for child");
- }
- /* Child (daemon) continues */
- setsid(); /* never fails */
- if (g_verbose == 0 && logmode != LOGMODE_SYSLOG)
- start_syslog_logging();
- }
-
- GMainLoop *pMainloop = NULL;
- GIOChannel *channel_signal = NULL;
- guint channel_signal_event_id = 0;
-
- /* Initialization */
-
- VERB1 log("Loading settings");
- if (load_abrt_conf() != 0)
- goto init_error;
-
- VERB1 log("Creating glib main loop");
- pMainloop = g_main_loop_new(NULL, FALSE);
-
- /* Add an event source which waits for INT/TERM signal */
- VERB1 log("Adding signal pipe watch to glib main loop");
- channel_signal = g_io_channel_unix_new(s_signal_pipe[0]);
- channel_signal_event_id = g_io_add_watch(channel_signal,
- G_IO_IN,
- handle_signal_cb,
- NULL);
-
- /* Note: this already may process a few dbus messages,
- * therefore it should be the last thing to initialize.
- */
- VERB1 log("Initializing dbus");
- if (init_dbus() != 0)
- goto init_error;
-
- /* Inform parent that we initialized ok */
- if (!(opts & OPT_d))
- {
- VERB1 log("Signalling parent");
- kill(parent_pid, SIGTERM);
- if (logmode != LOGMODE_SYSLOG)
- start_syslog_logging();
- }
-
- /* Only now we want signal pipe to work */
- s_signal_pipe_write = s_signal_pipe[1];
-
- /* Enter the event loop */
- log("Init complete, entering main loop");
- run_main_loop(pMainloop);
-
- cleanup:
- /* Error or INT/TERM. Clean up, in reverse order.
- * Take care to not undo things we did not do.
- */
-
- if (channel_signal_event_id > 0)
- g_source_remove(channel_signal_event_id);
- if (channel_signal)
- g_io_channel_unref(channel_signal);
-
- deinit_dbus();
-
- if (pMainloop)
- g_main_loop_unref(pMainloop);
-
- free_abrt_conf_data();
-
- /* Exiting */
- if (s_sig_caught && s_sig_caught != SIGALRM)
- {
- error_msg("Got signal %d, exiting", s_sig_caught);
- signal(s_sig_caught, SIG_DFL);
- raise(s_sig_caught);
- }
- error_msg_and_die("Exiting");
-
- init_error:
- /* Initialization error */
- error_msg("Error while initializing daemon");
- /* Inform parent that initialization failed */
- if (!(opts & OPT_d))
- kill(parent_pid, SIGINT);
- goto cleanup;
-}
diff --git a/src/daemon/com.redhat.abrt.service b/src/daemon/com.redhat.abrt.service
deleted file mode 100644
index afcb9a2..0000000
--- a/src/daemon/com.redhat.abrt.service
+++ /dev/null
@@ -1,7 +0,0 @@
-[D-BUS Service]
-Name=com.redhat.abrt
-# For testing, you may use -t5 to use small timeout of 5 seconds.
-# This will make "abrtd exited while clients existed but were idle"
-# situations easier to trigger
-Exec=/usr/sbin/abrt-dbus -ds -t133
-User=root
diff --git a/src/daemon/dbus-abrt.conf b/src/daemon/dbus-abrt.conf
deleted file mode 100644
index 11b2a11..0000000
--- a/src/daemon/dbus-abrt.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-<!-- This configuration file specifies the required security policies
- for abrt core daemon to work. -->
-
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-
- <!-- ../system.conf have denied everything, so we just punch some holes -->
-
- <policy user="root">
- <allow own="com.redhat.abrt"/>
- <allow send_destination="com.redhat.abrt"/>
- <allow send_interface="com.redhat.abrt"/>
- </policy>
-
- <policy at_console="true">
- <allow send_destination="com.redhat.abrt"/>
- </policy>
-
- <!-- Allow anyone to invoke methods on abrt server -->
- <policy context="default">
- <allow send_destination="com.redhat.abrt"/>
- </policy>
-
-</busconfig>
diff --git a/src/dbus/Makefile.am b/src/dbus/Makefile.am
new file mode 100644
index 0000000..5f29c71
--- /dev/null
+++ b/src/dbus/Makefile.am
@@ -0,0 +1,35 @@
+sbin_PROGRAMS = \
+ abrt-dbus
+
+abrt_dbus_SOURCES = \
+ abrt-dbus.c \
+ abrt-polkit.c \
+ abrt-polkit.h
+abrt_dbus_CPPFLAGS = \
+ -I$(srcdir)/../include \
+ -I$(srcdir)/../lib \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ $(GIO_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(LIBREPORT_CFLAGS) \
+ $(POLKIT_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Wwrite-strings \
+ -Werror
+abrt_dbus_LDADD = \
+ $(GIO_LIBS) \
+ ../lib/libabrt.la \
+ $(LIBREPORT_LIBS) \
+ $(POLKIT_LIBS) \
+ -labrt_dbus
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
+
+polkitconfdir = ${datadir}/polkit-1/actions
+dist_polkitconf_DATA = abrt_polkit.policy
+
+dbusabrtconfdir = ${sysconfdir}/dbus-1/system.d/
+dist_dbusabrtconf_DATA = dbus-abrt.conf
+
+orgfreedesktopproblemsservicedir = ${datadir}/dbus-1/system-services
+dist_orgfreedesktopproblemsservice_DATA = org.freedesktop.problems.service
diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c
new file mode 100644
index 0000000..4899285
--- /dev/null
+++ b/src/dbus/abrt-dbus.c
@@ -0,0 +1,609 @@
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include "libabrt.h"
+#include "abrt-polkit.h"
+#include "abrt-dbus.h"
+
+GMainLoop *loop;
+guint g_timeout;
+static unsigned s_timeout;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GDBusNodeInfo *introspection_data = NULL;
+
+/* Introspection data for the service we are exporting */
+static const gchar introspection_xml[] =
+ "<node>"
+ " <interface name='"ABRT_DBUS_IFACE"'>"
+ " <method name='GetProblems'>"
+ " <arg type='s' name='directory' direction='in'/>"
+ " <arg type='as' name='response' direction='out'/>"
+ " </method>"
+ " <method name='GetAllProblems'>"
+ " <arg type='s' name='directory' direction='in'/>"
+ " <arg type='as' name='response' direction='out'/>"
+ " </method>"
+ " <method name='GetInfo'>"
+ " <arg type='s' name='problem_dir' direction='in'/>"
+ " <arg type='a{ss}' name='response' direction='out'/>"
+ " </method>"
+ " <method name='ChownProblemDir'>"
+ " <arg type='s' name='problem_dir' direction='in'/>"
+ " </method>"
+ " <method name='Quit' />"
+ " </interface>"
+ "</node>";
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* forward */
+static gboolean on_timeout_cb(gpointer user_data);
+
+static void reset_timeout()
+{
+ //FIXME: reset timer on every call
+ if (g_timeout > 0)
+ {
+ VERB2 log("Removing timeout");
+ g_source_remove(g_timeout);
+ }
+ VERB2 log("Setting a new timeout");
+ g_timeout = g_timeout_add_seconds(s_timeout, on_timeout_cb, NULL);
+}
+
+uid_t get_caller_uid(GDBusConnection *connection, const char *caller, GError *error)
+{
+ guint caller_uid;
+
+ GDBusProxy * proxy = g_dbus_proxy_new_sync(connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ NULL,
+ &error);
+
+ GVariant *result = g_dbus_proxy_call_sync(proxy,
+ "GetConnectionUnixUser",
+ g_variant_new ("(s)", caller),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (result == NULL) {
+ /* this value shouldn't be used, beacuse error is set,
+ * but return 99 -> nobody just to be sure
+ */
+ return 99;
+ }
+
+ g_variant_get(result, "(u)", &caller_uid);
+ g_variant_unref(result);
+
+ VERB2 log("Caller uid: %i", caller_uid);
+ return caller_uid;
+}
+
+bool uid_in_group(uid_t uid, gid_t gid)
+{
+ char **tmp;
+ struct passwd *pwd = getpwuid(uid);
+ if (pwd && (pwd->pw_gid == gid))
+ return TRUE;
+
+ struct group *grp = getgrgid(gid);
+ if (pwd && grp && grp->gr_mem)
+ {
+ for (tmp = grp->gr_mem; *tmp != NULL; tmp++)
+ {
+ if (g_strcmp0(*tmp, pwd->pw_name) == 0)
+ {
+ VERB3 log("user %s belongs to group: %s", pwd->pw_name, grp->gr_name);
+ return TRUE;
+ }
+ }
+ }
+ VERB2 log("WARN: user %s DOESN'T belong to group: %s", pwd->pw_name, grp->gr_name);
+ return FALSE;
+}
+
+static GList* scan_directory(const char *path, uid_t caller_uid)
+{
+ GList *list = NULL;
+
+ DIR *dp = opendir(path);
+ if (!dp)
+ {
+ /* We don't want to yell if, say, $HOME/.abrt/spool doesn't exist */
+ //perror_msg("Can't open directory '%s'", path);
+ return list;
+ }
+
+ struct dirent *dent;
+ while ((dent = readdir(dp)) != NULL)
+ {
+ if (dot_or_dotdot(dent->d_name))
+ continue; /* skip "." and ".." */
+
+ char *full_name = concat_path_file(path, dent->d_name);
+ struct stat statbuf;
+ if (stat(full_name, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
+ {
+ /* Silently ignore *any* errors, not only EACCES.
+ * We saw "lock file is locked by process PID" error
+ * when we raced with wizard.
+ */
+ int sv_logmode = logmode;
+ logmode = 0;
+ struct dump_dir *dd = dd_opendir(full_name, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
+ logmode = sv_logmode;
+ /* or we could just setuid?
+ - but it would require locking, because we want to setuid back before we server another request..
+ */
+ if (dd && (caller_uid == 0 || statbuf.st_mode & S_IROTH || uid_in_group(caller_uid, statbuf.st_gid)))
+ {
+ list = g_list_prepend(list, full_name);
+ full_name = NULL;
+ }
+ dd_close(dd); //doesn't fail even if dd == NULL
+ }
+ free(full_name);
+ }
+ closedir(dp);
+
+ /* Why reverse?
+ * Because N*prepend+reverse is faster than N*append
+ */
+ return g_list_reverse(list);
+}
+
+GVariant *get_problem_dirs_for_uid(uid_t uid, const char *dump_location)
+{
+ GList *dirs = scan_directory(dump_location, uid);
+
+ GVariantBuilder *builder;
+ builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+ while (dirs)
+ {
+ g_variant_builder_add(builder, "s", (char*)dirs->data);
+ free(dirs->data);
+ dirs = g_list_delete_link(dirs, dirs);
+ }
+
+ GVariant *response = g_variant_new("(as)", builder);
+ g_variant_builder_unref(builder);
+
+ return response;
+}
+
+static void handle_method_call(GDBusConnection *connection,
+ const gchar *caller,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ reset_timeout();
+ if (g_strcmp0(method_name, "GetProblems") == 0)
+ {
+ GError *error = NULL;
+ GVariant *response;
+ uid_t caller_uid;
+
+
+ caller_uid = get_caller_uid(connection, caller, error);
+
+ if (error)
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.InvalidUser",
+ error->message);
+ g_error_free(error);
+ return;
+ }
+ else if (caller_uid == 99)
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.InvalidUser",
+ "Unknown error");
+ return;
+ }
+
+ //TODO: change the API to not accept the dumpdir from user, but read it from config file?
+
+ const gchar *dump_location;
+ g_variant_get(parameters, "(&s)", &dump_location);
+
+ //if (!g_settings_dump_location)
+ // g_settings_dump_location = (char*)"/var/spool/abrt";
+
+ response = get_problem_dirs_for_uid(caller_uid, dump_location);
+
+ g_dbus_method_invocation_return_value(invocation, response);
+ //I was told that g_dbus_method frees the response
+ //g_variant_unref(response);
+ }
+
+ else if (g_strcmp0(method_name, "GetAllProblems") == 0)
+ {
+ GVariant *response;
+ GError *error = NULL;
+ uid_t caller_uid;
+
+ const gchar *dump_location;
+ g_variant_get(parameters, "(&s)", &dump_location);
+
+ caller_uid = get_caller_uid(connection, caller, error);
+
+ if (error)
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.InvalidUser",
+ error->message);
+ g_error_free(error);
+ return;
+ }
+ else if (caller_uid == 99)
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.InvalidUser",
+ "Unknown error");
+ return;
+ }
+
+ /*
+ - so, we have UID,
+ - if it's 0, then we don't have to check anything and just return all directories
+ - if uid != 0 then we want to ask for authorization
+ */
+
+ if (caller_uid != 0)
+ {
+ if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") == PolkitYes)
+ caller_uid = 0;
+ }
+
+ response = get_problem_dirs_for_uid(caller_uid, dump_location);
+
+ g_dbus_method_invocation_return_value(invocation, response);
+ }
+
+ else if (g_strcmp0(method_name, "ChownProblemDir") == 0)
+ {
+ VERB1 log("ChownProblemDir");
+
+ GError *error = NULL;
+ uid_t caller_uid;
+ const gchar *problem_dir;
+ struct passwd *pwd;
+ int chown_res;
+ gchar *error_msg;
+
+ g_variant_get(parameters, "(&s)", &problem_dir);
+
+ //FIXME: check if it's problem_dir and refuse to operate on it if it's not
+ struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
+ if (!dd)
+ {
+ error_msg = g_strdup_printf(_("%s is not a valid problem dir"), problem_dir);
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.InvalidProblemDir",
+ error_msg);
+ free(error_msg);
+ return;
+ }
+
+ caller_uid = get_caller_uid(connection, caller, error);
+
+ if (error)
+ {
+ g_dbus_method_invocation_return_gerror(invocation, error);
+ g_error_free(error);
+ dd_close(dd);
+ return;
+ }
+
+ if (caller_uid == 99)
+ {
+ error_msg = g_strdup_printf("Could not get unix user for caller %s", caller);
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.InvalidUser",
+ error_msg);
+ free(error_msg);
+ dd_close(dd);
+ return;
+ }
+
+ struct stat statbuf;
+ errno = 0;
+ if (stat(problem_dir, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
+ {
+ if (caller_uid == 0 || uid_in_group(caller_uid, statbuf.st_gid)) //caller seems to be in group with access to this dir, so no action needed
+ {
+ //return ok
+ VERB1 log("caller has access to the requested directory %s", problem_dir);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ dd_close(dd);
+ return;
+ //free something?
+ }
+
+ }
+ else
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.StatFailure",
+ strerror(errno));
+ dd_close(dd);
+ return;
+ }
+
+ if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
+ {
+ VERB1 log("not authorized");
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.AuthFailure",
+ "Not Authorized");
+ dd_close(dd);
+ return;
+ }
+
+ pwd = getpwuid(caller_uid);
+ if (pwd)
+ {
+ errno = 0;
+ chown_res = chown(problem_dir, statbuf.st_uid, pwd->pw_gid);
+ dd_init_next_file(dd);
+ char *short_name, *full_name;
+ while (chown_res == 0 && dd_get_next_file(dd, &short_name, &full_name))
+ {
+ VERB3 log("chowning %s", full_name);
+ chown_res = chown(full_name, statbuf.st_uid, pwd->pw_gid);
+ }
+
+ if (chown_res != 0)
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.ChownError",
+ strerror(errno));
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ dd_close(dd);
+ return;
+ }
+ VERB3 log("shouldn't get here");
+ dd_close(dd);
+ }
+
+ else if (g_strcmp0(method_name, "GetInfo") == 0)
+ {
+ VERB1 log("GetInfo");
+ GError *error = NULL;
+
+ const gchar *problem_dir;
+ g_variant_get(parameters, "(&s)", &problem_dir);
+
+ GVariantBuilder *builder;
+
+ struct stat statbuf;
+ errno = 0;
+ if (stat(problem_dir, &statbuf) != 0)
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.GetInfoError",
+ strerror(errno));
+ return;
+ }
+
+
+ uid_t caller_uid = get_caller_uid(connection, caller, error);
+ if (!uid_in_group(caller_uid, statbuf.st_gid))
+ {
+ if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
+ {
+ VERB1 log("not authorized");
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.AuthFailure",
+ "Not Authorized");
+ return;
+ }
+ }
+
+ struct dump_dir *dd = dd_opendir(problem_dir, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
+ if (!dd)
+ {
+ char *error_msg = g_strdup_printf(_("%s is not a valid problem directory"), problem_dir);
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.GetInfo",
+ error_msg);
+ free(error_msg);
+ }
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add (builder, "{ss}", g_strdup(FILENAME_TIME), dd_load_text(dd, FILENAME_TIME));
+ g_variant_builder_add (builder, "{ss}", g_strdup(FILENAME_REASON), dd_load_text(dd, FILENAME_REASON));
+ char *not_reportable_reason = dd_load_text_ext(dd, FILENAME_NOT_REPORTABLE, 0
+ | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
+ | DD_FAIL_QUIETLY_ENOENT
+ | DD_FAIL_QUIETLY_EACCES);
+ if (not_reportable_reason)
+ g_variant_builder_add (builder, "{ss}", g_strdup(FILENAME_NOT_REPORTABLE), dd_load_text_ext(dd, FILENAME_NOT_REPORTABLE, 0
+ | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
+ | DD_FAIL_QUIETLY_ENOENT
+ | DD_FAIL_QUIETLY_EACCES));
+ /* the source of the problem:
+ * - first we try to load component, as we use it on Fedora
+ */
+ char *source = dd_load_text_ext(dd, FILENAME_COMPONENT, 0
+ | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
+ | DD_FAIL_QUIETLY_ENOENT
+ | DD_FAIL_QUIETLY_EACCES
+ );
+ /* if we don't have component, we fallback to executable */
+ if (!source)
+ {
+ source = dd_load_text_ext(dd, FILENAME_EXECUTABLE, 0
+ | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
+ | DD_FAIL_QUIETLY_ENOENT
+ | DD_FAIL_QUIETLY_EACCES
+ );
+ }
+
+ g_variant_builder_add (builder, "{ss}", g_strdup("source"), source);
+ char *msg = dd_load_text_ext(dd, FILENAME_REPORTED_TO, 0
+ | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
+ | DD_FAIL_QUIETLY_ENOENT
+ | DD_FAIL_QUIETLY_EACCES
+ );
+ if (msg)
+ g_variant_builder_add (builder, "{ss}", g_strdup(FILENAME_REPORTED_TO), msg);
+
+ dd_close(dd);
+
+ GVariant *response = g_variant_new("(a{ss})", builder);
+ g_variant_builder_unref(builder);
+
+ g_dbus_method_invocation_return_value(invocation, response);
+ }
+
+ else if (g_strcmp0(method_name, "Quit") == 0)
+ {
+ VERB1 log("Quit");
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+
+ g_main_loop_quit(loop);
+
+ }
+}
+
+static gboolean on_timeout_cb(gpointer user_data)
+{
+ g_main_loop_quit(loop);
+ return TRUE;
+}
+
+/* for now */
+static const GDBusInterfaceVTable interface_vtable =
+{
+ handle_method_call,
+ NULL,
+ NULL,
+};
+
+static void on_bus_acquired(GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ guint registration_id;
+
+ registration_id = g_dbus_connection_register_object(connection,
+ ABRT_DBUS_OBJECT,
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ NULL, /* user_data */
+ NULL, /* user_data_free_func */
+ NULL); /* GError** */
+ g_assert(registration_id > 0);
+
+ reset_timeout();
+}
+
+static void on_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+}
+
+static void on_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_print(_("The name '%s' has been lost, please check if other "
+ "service owning the name is not running.\n"), name);
+ exit(1);
+}
+
+int main (int argc, char *argv[])
+{
+ /* I18n */
+ setlocale(LC_ALL, "");
+#if ENABLE_NLS
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+#endif
+ guint owner_id;
+
+ abrt_init(argv);
+
+ const char *program_usage_string = _(
+ "& [options]"
+ );
+ enum {
+ OPT_v = 1 << 0,
+ OPT_t = 1 << 1,
+ };
+ /* Keep enum above and order of options below in sync! */
+ struct options program_options[] = {
+ OPT__VERBOSE(&g_verbose),
+ OPT_INTEGER('t', NULL, &s_timeout, _("Exit after NUM seconds of inactivity")),
+ OPT_END()
+ };
+ unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
+
+ export_abrt_envvars(0);
+
+ /* When dbus daemon starts us, it doesn't set PATH
+ * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE).
+ * In this case, set something sane:
+ */
+ const char *env_path = getenv("PATH");
+ if (!env_path || !env_path[0])
+ putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin");
+
+ msg_prefix = "abrt-dbus"; /* for log(), error_msg() and such */
+
+ if (!(opts & OPT_t))
+ s_timeout = 120; //if the timeout is not set we default to 120sec
+
+ if (getuid() != 0)
+ error_msg_and_die(_("This program must be run as root."));
+
+ g_type_init();
+
+
+ /* We are lazy here - we don't want to manually provide
+ * the introspection data structures - so we just build
+ * them from XML.
+ */
+ introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
+ g_assert(introspection_data != NULL);
+
+ owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
+ ABRT_DBUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ NULL,
+ NULL);
+
+ loop = g_main_loop_new(NULL, FALSE);
+ g_main_loop_run(loop);
+
+ VERB1 log("Cleaning up");
+
+ g_bus_unown_name(owner_id);
+
+ g_dbus_node_info_unref(introspection_data);
+
+ return 0;
+}
+
diff --git a/src/dbus/abrt-polkit.c b/src/dbus/abrt-polkit.c
new file mode 100644
index 0000000..d90baf4
--- /dev/null
+++ b/src/dbus/abrt-polkit.c
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2012 ABRT team
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <polkit/polkit.h>
+#include <glib-object.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "libabrt.h"
+#include "abrt-polkit.h"
+
+/*number of seconds: timeout for the authorization*/
+#define POLKIT_TIMEOUT 20
+
+static gboolean do_cancel(GCancellable* cancellable)
+{
+ log("Timer has expired; cancelling authorization check\n");
+ g_cancellable_cancel(cancellable);
+ return FALSE;
+}
+
+
+static PolkitResult do_check(PolkitSubject *subject, const char *action_id)
+{
+ PolkitAuthority *authority;
+ PolkitAuthorizationResult *result;
+ GError *error = NULL;
+ GCancellable * cancellable;
+
+ cancellable = g_cancellable_new();
+
+ /* we ignore the error for now .. */
+ authority = polkit_authority_get_sync(cancellable, NULL);
+
+ guint cancel_timeout = g_timeout_add(POLKIT_TIMEOUT * 1000,
+ (GSourceFunc) do_cancel,
+ cancellable);
+
+ result = polkit_authority_check_authorization_sync(authority,
+ subject,
+ action_id,
+ NULL,
+ POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
+ cancellable,
+ &error);
+ g_object_unref(authority);
+ g_source_remove(cancel_timeout);
+ if (error)
+ {
+ g_error_free(error);
+ return PolkitUnknown;
+ }
+
+ if (result)
+ {
+ if (polkit_authorization_result_get_is_challenge(result))
+ {
+ /* Can't happen (happens only with
+ * POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE flag) */
+ g_object_unref(result);
+ return PolkitChallenge;
+ }
+ if (polkit_authorization_result_get_is_authorized(result))
+ {
+ g_object_unref(result);
+ return PolkitYes;
+ }
+ g_object_unref(result);
+ return PolkitNo;
+ }
+
+ return PolkitUnknown;
+}
+
+PolkitResult polkit_check_authorization_dname(const char *dbus_name, const char *action_id)
+{
+ g_type_init();
+ PolkitSubject *subject = polkit_system_bus_name_new(dbus_name);
+ return do_check(subject, action_id);
+}
+
+PolkitResult polkit_check_authorization_pid(pid_t pid, const char *action_id)
+{
+ g_type_init();
+ PolkitSubject *subject = polkit_unix_process_new(pid);
+ return do_check(subject, action_id);
+}
diff --git a/src/dbus/abrt-polkit.h b/src/dbus/abrt-polkit.h
new file mode 100644
index 0000000..0f6eb1e
--- /dev/null
+++ b/src/dbus/abrt-polkit.h
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2012 ABRT team
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifndef ABRT_POLKIT_H
+#define ABRT_POLKIT_H
+
+#include <sys/types.h>
+#include <unistd.h>
+
+typedef enum {
+/* Authorization status is unknown */
+ PolkitUnknown = 0x0,
+ /* Subject is authorized for the action */
+ PolkitYes = 0x01,
+ /* Subject is not authorized for the action */
+ PolkitNo = 0x02,
+ /* Challenge is needed for this action, only when flag is
+ * POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE */
+ PolkitChallenge = 0x03
+} PolkitResult;
+
+PolkitResult polkit_check_authorization_dname(const char *dbus_name, const char *action_id);
+PolkitResult polkit_check_authorization_pid(pid_t pid, const char *action_id);
+
+#endif
diff --git a/src/dbus/abrt_polkit.policy b/src/dbus/abrt_polkit.policy
new file mode 100644
index 0000000..7e7af94
--- /dev/null
+++ b/src/dbus/abrt_polkit.policy
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+
+<!--
+PolicyKit policy definitions for ABRT
+
+Copyright (c) 2012 ABRT Team <crash-catcher(a)fedorahosted.com>
+
+-->
+
+<policyconfig>
+ <vendor>The ABRT Team</vendor>
+ <vendor_url>https://fedorahosted.org/abrt/</vendor_url>
+
+ <!-- install-debuginfos: default yes, administrator can change this -->
+ <action id="org.freedesktop.problems.getall">
+ <description>Get problems from all users</description>
+ <message>Reading others problems requires authentication</message>
+ <defaults>
+ <allow_any>no</allow_any>
+ <allow_active>auth_admin_keep</allow_active>
+ <allow_inactive>no</allow_inactive>
+ </defaults>
+ </action>
+
+</policyconfig>
diff --git a/src/dbus/dbus-abrt.conf b/src/dbus/dbus-abrt.conf
new file mode 100644
index 0000000..ba09762
--- /dev/null
+++ b/src/dbus/dbus-abrt.conf
@@ -0,0 +1,25 @@
+<!-- This configuration file specifies the required security policies
+ for abrt core daemon to work. -->
+
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+ <!-- ../system.conf have denied everything, so we just punch some holes -->
+
+ <policy user="root">
+ <allow own="org.freedesktop.problems"/>
+ <allow send_destination="org.freedesktop.problems"/>
+ <allow send_interface="org.freedesktop.problems"/>
+ </policy>
+
+ <policy at_console="true">
+ <allow send_destination="org.freedesktop.org"/>
+ </policy>
+
+ <!-- Allow anyone to invoke methods on abrt server -->
+ <policy context="default">
+ <allow send_destination="org.freedesktop.problems"/>
+ </policy>
+
+</busconfig>
diff --git a/src/dbus/org.freedesktop.problems.service b/src/dbus/org.freedesktop.problems.service
new file mode 100644
index 0000000..e8e3bf1
--- /dev/null
+++ b/src/dbus/org.freedesktop.problems.service
@@ -0,0 +1,7 @@
+[D-BUS Service]
+Name=org.freedesktop.problems
+# For testing, you may use -t5 to use small timeout of 5 seconds.
+# This will make "abrtd exited while clients existed but were idle"
+# situations easier to trigger
+Exec=/usr/sbin/abrt-dbus -t133
+User=root
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index c3317d7..f98e2d5 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -2,4 +2,5 @@ libabrt_includedir = \
$(includedir)/abrt
libabrt_include_HEADERS = \
- libabrt.h
+ libabrt.h \
+ abrt-dbus.h
diff --git a/src/include/abrt-dbus.h b/src/include/abrt-dbus.h
new file mode 100644
index 0000000..898dd94
--- /dev/null
+++ b/src/include/abrt-dbus.h
@@ -0,0 +1,8 @@
+#ifndef ABRTDBUS_H_
+#define ABRTDBUS_H_
+
+#define ABRT_DBUS_NAME "org.freedesktop.problems"
+#define ABRT_DBUS_OBJECT "/org/freedesktop/problems"
+#define ABRT_DBUS_IFACE "org.freedesktop.problems"
+
+#endif /* ABRTDBUS_H_ */
--
1.7.7.6
12 years, 1 month
[PATCH] Add cgroup information filename
by Richard Marko
---
src/include/internal_libreport.h | 1 +
src/lib/problem_data.c | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h
index 95b600b..d99d84c 100644
--- a/src/include/internal_libreport.h
+++ b/src/include/internal_libreport.h
@@ -662,6 +662,7 @@ bool make_dir_recursive(char *dir, mode_t dir_mode);
#define FILENAME_BINARY "binary"
#define FILENAME_CMDLINE "cmdline"
#define FILENAME_COREDUMP "coredump"
+#define FILENAME_CGROUP "cgroup"
#define FILENAME_BACKTRACE "backtrace"
#define FILENAME_MAPS "maps"
#define FILENAME_SMAPS "smaps"
diff --git a/src/lib/problem_data.c b/src/lib/problem_data.c
index 2a7835a..536f7a1 100644
--- a/src/lib/problem_data.c
+++ b/src/lib/problem_data.c
@@ -187,6 +187,7 @@ static const char *const editable_files[] = {
FILENAME_OPEN_FDS , /* user might want to hide sensitive file names */
//FILENAME_LIMITS ,
FILENAME_CMDLINE ,
+ //FILENAME_CGROUP ,
//FILENAME_COREDUMP ,
FILENAME_BACKTRACE ,
FILENAME_MAPS ,
--
1.7.7.6
12 years, 1 month
[PATCH] Save cgroup information for crashing process
by Richard Marko
Stored in /proc/<pid>/cgroup
---
src/hooks/abrt-hook-ccpp.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
index 83dbf9f..e9838d2 100644
--- a/src/hooks/abrt-hook-ccpp.c
+++ b/src/hooks/abrt-hook-ccpp.c
@@ -713,6 +713,13 @@ int main(int argc, char** argv)
copy_file(source_filename, dest_filename, 0640);
IGNORE_RESULT(chown(dest_filename, dd->dd_uid, dd->dd_gid));
+ strcpy(source_filename + source_base_ofs, "cgroup");
+ strcpy(dest_base, FILENAME_CGROUP);
+ if (access(source_filename, F_OK) != -1) {
+ copy_file(source_filename, dest_filename, 0640);
+ IGNORE_RESULT(chown(dest_filename, dd->dd_uid, dd->dd_gid));
+ }
+
strcpy(dest_base, FILENAME_OPEN_FDS);
if (dump_fd_info(dest_filename, source_filename, source_base_ofs))
IGNORE_RESULT(chown(dest_filename, dd->dd_uid, dd->dd_gid));
--
1.7.7.6
12 years, 1 month
[PATCH] abrt-watch-log
by Denys Vlasenko
Hi,
This patch splits abrt-dump-oops into a generic log watcher tool,
abrt-watch-log, and oops finder, which retains the name
abrt-dump-oops:
$ abrt-watch-log --help
Usage: abrt-watch-log [-vsw] FILE PROG [ARGS]
Watch log file FILE, run PROG when it grows or is replaced
-v, --verbose Be verbose
-s Log to syslog
-w Do not exit, watch FILE for changes
$ abrt-dump-oops --help
Usage: abrt-dump-oops [-vsox] [-d DIR]/[-D]
Extract oops from standard input
-v, --verbose Be verbose
-s Log to syslog
-o Print found oopses on standard output
-d DIR Create ABRT dump in DIR for every oops found
-D Same as -d DumpLocation, DumpLocation is specified in abrt.conf
-x Make the problem directory world readable
Instead of running
abrt-dump-oops -rwxD /var/log/messages
about the same effect is achieved by
abrt-watch-log -w /var/log/messages -- abrt-dump-oops -xD
This opens up a possibility to have other log files watched,
with different processing apps.
Problems:
* How to kill a log watcher which watches particular file?
Ideas:
* Add --match='STR' and --match-regex='REGEX' switches to limit the frequency
of executions of the helper.
* Remove -w switch as redundant?
* Retain optional FILE parameter of abrt-dump-oops?
1.patch is preparatory, it removes old abrt-dump-oops.c -
otherwise it's hard to read the changes.
2.patch is the gist of the change.
Please review.
--
vda
12 years, 1 month
[PATCH (abrt+libreport)] store cgroup file for each crash
by Richard Marko
[PATCH] Save cgroup information for crashing process
Stored in /proc/<pid>/cgroup
---
src/hooks/abrt-hook-ccpp.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/src/hooks/abrt-hook-ccpp.c b/src/hooks/abrt-hook-ccpp.c
index 83dbf9f..1a918c8 100644
--- a/src/hooks/abrt-hook-ccpp.c
+++ b/src/hooks/abrt-hook-ccpp.c
@@ -713,6 +713,11 @@ int main(int argc, char** argv)
copy_file(source_filename, dest_filename, 0640);
IGNORE_RESULT(chown(dest_filename, dd->dd_uid, dd->dd_gid));
+ strcpy(source_filename + source_base_ofs, "cgroup");
+ strcpy(dest_base, FILENAME_CGROUP);
+ copy_file(source_filename, dest_filename, 0640);
+ IGNORE_RESULT(chown(dest_filename, dd->dd_uid, dd->dd_gid));
+
strcpy(dest_base, FILENAME_OPEN_FDS);
if (dump_fd_info(dest_filename, source_filename, source_base_ofs))
IGNORE_RESULT(chown(dest_filename, dd->dd_uid, dd->dd_gid));
--
1.7.7.6
[PATCH] Add cgroup information filename
---
src/include/internal_libreport.h | 1 +
src/lib/problem_data.c | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/src/include/internal_libreport.h
b/src/include/internal_libreport.h
index 95b600b..d99d84c 100644
--- a/src/include/internal_libreport.h
+++ b/src/include/internal_libreport.h
@@ -662,6 +662,7 @@ bool make_dir_recursive(char *dir, mode_t dir_mode);
#define FILENAME_BINARY "binary"
#define FILENAME_CMDLINE "cmdline"
#define FILENAME_COREDUMP "coredump"
+#define FILENAME_CGROUP "cgroup"
#define FILENAME_BACKTRACE "backtrace"
#define FILENAME_MAPS "maps"
#define FILENAME_SMAPS "smaps"
diff --git a/src/lib/problem_data.c b/src/lib/problem_data.c
index 2a7835a..536f7a1 100644
--- a/src/lib/problem_data.c
+++ b/src/lib/problem_data.c
@@ -187,6 +187,7 @@ static const char *const editable_files[] = {
FILENAME_OPEN_FDS , /* user might want to hide sensitive file
names */
//FILENAME_LIMITS ,
FILENAME_CMDLINE ,
+ //FILENAME_CGROUP ,
//FILENAME_COREDUMP ,
FILENAME_BACKTRACE ,
FILENAME_MAPS ,
--
1.7.7.6
--
Richard Marko
12 years, 1 month
[PATCH] Replace exitcodes by messages
by Michal Toman
Patch replaces the "{Analyzing,Reporting,Collecting} finished with
exitcode 0" message by a more user-friendly one. If a better text comes
to anybody's mind, I'm free to use that one.
Run-tested, please review.
Michal
12 years, 1 month