---
.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 | 584 +++++++++++++++++++++++++++++
src/dbus/abrt-polkit.c | 104 +++++
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, 858 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..465b77e
--- /dev/null
+++ b/src/dbus/abrt-dbus.c
@@ -0,0 +1,584 @@
+#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);
+}
+
+static uid_t get_caller_uid(GDBusConnection *connection, GDBusMethodInvocation
*invocation, const char *caller)
+{
+ GError *error = NULL;
+ 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)
+ {
+ /* we failed to get the uid, so return (uid_t) -1 to indicate the error
+ */
+ if (error)
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.InvalidUser",
+ error->message);
+ g_error_free(error);
+ }
+ else
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.freedesktop.problems.InvalidUser",
+ "Unknown error");
+ }
+ return (uid_t) -1;
+ }
+
+ g_variant_get(result, "(u)", &caller_uid);
+ g_variant_unref(result);
+
+ VERB2 log("Caller uid: %i", caller_uid);
+ return caller_uid;
+}
+
+static bool uid_in_group(uid_t uid, gid_t gid)
+{
+ char **tmp;
+ struct passwd *pwd = getpwuid(uid);
+
+ if (!pwd)
+ return FALSE;
+
+ if (pwd->pw_gid == gid)
+ return TRUE;
+
+ struct group *grp = getgrgid(gid);
+ if (!(grp && grp->gr_mem))
+ return FALSE;
+
+ 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("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);
+}
+
+static 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();
+ uid_t caller_uid;
+ GVariant *response;
+
+ if (g_strcmp0(method_name, "GetProblems") == 0)
+ {
+
+ caller_uid = get_caller_uid(connection, invocation, caller);
+
+ if (caller_uid == (uid_t) -1)
+ 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)
+ {
+
+ const gchar *dump_location;
+ g_variant_get(parameters, "(&s)", &dump_location);
+
+ caller_uid = get_caller_uid(connection, invocation, caller);
+
+ if (caller_uid == (uid_t) -1)
+ 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);
+ return;
+ }
+
+ else if (g_strcmp0(method_name, "ChownProblemDir") == 0)
+ {
+ VERB1 log("ChownProblemDir");
+
+ 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, invocation, caller);
+
+ if (caller_uid == (uid_t) -1)
+ 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");
+
+ 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;
+ }
+
+
+ caller_uid = get_caller_uid(connection, invocation, caller);
+
+ if (caller_uid == (uid_t) -1)
+ return;
+
+ 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..29973e5
--- /dev/null
+++ b/src/dbus/abrt-polkit.c
@@ -0,0 +1,104 @@
+/*
+ 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 *auth_result;
+ PolkitResult result = PolkitNo;
+ 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);
+
+ auth_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 (!auth_result)
+ return PolkitUnknown;
+
+ if (polkit_authorization_result_get_is_challenge(auth_result))
+ {
+ /* Can't happen (happens only with
+ * POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE flag) */
+ result = PolkitChallenge;
+ goto out;
+ }
+
+ if (polkit_authorization_result_get_is_authorized(auth_result))
+ {
+ result = PolkitYes;
+ goto out;
+ }
+
+out:
+ g_object_unref(auth_result);
+ return result;
+}
+
+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