new version of abrt-server.c
by Vratislav Podzimek
This set of patches introduce a new version of abrt-server.c that can parse more messages and thus save more
information about the crashes handled by Python exception handler (and in future, hopefully, python-meh).
I've tested it and it seems to be working well. I know the changes are not ideal as they cannot be applied
separately (abrt-server.c is not compilable if they are), but I really do not see any reason why I should
remove printable_str() function in one commit and add it back in the following one. If you really need the
commits to change the code from one compilable and working state to another, I can squash all these patches
to one for you. :)
--
Vratislav Podzimek
12 years
[PATCH] rhbz#795548 - opt kernel out of showing smolt information in abrt bug reports
by Nikola Pajkovsky
Signed-off-by: Nikola Pajkovsky <npajkovs(a)redhat.com>
---
src/include/internal_libreport.h | 5 ++++-
src/lib/is_in_string_list.c | 14 +++++++++++---
src/lib/make_descr.c | 36 +++++++++++++++++++++++++++---------
src/lib/problem_data.c | 8 ++++----
src/plugins/rhbz.c | 7 ++++++-
5 files changed, 52 insertions(+), 18 deletions(-)
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h
index 95b600b..9011d2a 100644
--- a/src/include/internal_libreport.h
+++ b/src/include/internal_libreport.h
@@ -251,7 +251,7 @@ char *run_in_shell_and_save_output(int flags,
/* Random utility functions */
#define is_in_string_list libreport_is_in_string_list
-bool is_in_string_list(const char *name, char **v);
+bool is_in_string_list(const char *name, char **v, int flags);
#define is_in_comma_separated_list libreport_is_in_comma_separated_list
bool is_in_comma_separated_list(const char *value, const char *list);
@@ -572,6 +572,7 @@ enum {
MAKEDESC_SHOW_FILES = (1 << 0),
MAKEDESC_SHOW_MULTILINE = (1 << 1),
MAKEDESC_SHOW_ONLY_LIST = (1 << 2),
+ MAKEDESC_WHITELIST = (1 << 3),
};
#define make_description libreport_make_description
char *make_description(problem_data_t *problem_data, char **names_to_skip, unsigned max_text_size, unsigned desc_flags);
@@ -579,6 +580,8 @@ char *make_description(problem_data_t *problem_data, char **names_to_skip, unsig
char* make_description_bz(problem_data_t *problem_data, unsigned max_text_size);
#define make_description_logger libreport_make_description_logger
char* make_description_logger(problem_data_t *problem_data, unsigned max_text_size);
+#define make_description_koops libreport_make_description_koops
+char* make_description_koops(problem_data_t *problem_data, unsigned max_text_size);
//UNUSED
//#define make_description_mailx libreport_make_description_mailx
//char* make_description_mailx(problem_data_t *problem_data);
diff --git a/src/lib/is_in_string_list.c b/src/lib/is_in_string_list.c
index 663edff..b347b2b 100644
--- a/src/lib/is_in_string_list.c
+++ b/src/lib/is_in_string_list.c
@@ -18,13 +18,21 @@
*/
#include "internal_libreport.h"
-bool is_in_string_list(const char *name, char **v)
+bool is_in_string_list(const char *name, char **v, int flags)
{
+ bool ret = false;
while (*v)
{
if (strcmp(*v, name) == 0)
- return true;
+ {
+ ret = true;
+ break;
+ }
v++;
}
- return false;
+
+ if (flags & MAKEDESC_WHITELIST)
+ ret = !ret;
+
+ return ret;
}
diff --git a/src/lib/make_descr.c b/src/lib/make_descr.c
index a1a9234..f7ac058 100644
--- a/src/lib/make_descr.c
+++ b/src/lib/make_descr.c
@@ -18,7 +18,8 @@
*/
#include "internal_libreport.h"
-char *make_description(problem_data_t *problem_data, char **names_to_skip, unsigned max_text_size, unsigned desc_flags)
+char *make_description(problem_data_t *problem_data, char **names_to_skip,
+ unsigned max_text_size, unsigned desc_flags)
{
struct strbuf *buf_dsc = strbuf_new();
@@ -42,7 +43,8 @@ char *make_description(problem_data_t *problem_data, char **names_to_skip, unsig
/* Skip items we are not interested in */
//TODO: optimize by doing this once, not 3 times:
- if (names_to_skip && is_in_string_list(key, names_to_skip))
+ if (names_to_skip
+ && is_in_string_list(key, names_to_skip, desc_flags))
continue;
struct problem_item *item = g_hash_table_lookup(problem_data, key);
@@ -87,7 +89,8 @@ char *make_description(problem_data_t *problem_data, char **names_to_skip, unsig
l = l->next;
/* Skip items we are not interested in */
- if (names_to_skip && is_in_string_list(key, names_to_skip))
+ if (names_to_skip
+ && is_in_string_list(key, names_to_skip, desc_flags))
continue;
struct problem_item *item = g_hash_table_lookup(problem_data, key);
@@ -144,7 +147,8 @@ char *make_description(problem_data_t *problem_data, char **names_to_skip, unsig
l = l->next;
/* Skip items we are not interested in */
- if (names_to_skip && is_in_string_list(key, names_to_skip))
+ if (names_to_skip
+ && is_in_string_list(key, names_to_skip, desc_flags))
continue;
struct problem_item *item = g_hash_table_lookup(problem_data, key);
@@ -251,11 +255,6 @@ static const char *const blacklisted_items[] = {
NULL
};
-/*
- * npajkovs: implement second part of problem (not so important)
- * https://bugzilla.redhat.com/show_bug.cgi?id=711591
- */
-
char* make_description_bz(problem_data_t *problem_data, unsigned max_text_size)
{
return make_description(
@@ -275,3 +274,22 @@ char* make_description_logger(problem_data_t *problem_data, unsigned max_text_si
MAKEDESC_SHOW_FILES | MAKEDESC_SHOW_MULTILINE
);
}
+
+/* Items we want to include to bz */
+static const char *const whitelisted_items[] = {
+ FILENAME_CMDLINE,
+ FILENAME_BACKTRACE,
+ NULL
+};
+
+char* make_description_koops(problem_data_t *problem_data, unsigned max_text_size)
+{
+ return make_description(
+ problem_data,
+ (char**)whitelisted_items,
+ max_text_size,
+ MAKEDESC_SHOW_FILES
+ | MAKEDESC_SHOW_MULTILINE
+ | MAKEDESC_WHITELIST
+ );
+}
diff --git a/src/lib/problem_data.c b/src/lib/problem_data.c
index 2a7835a..06098de 100644
--- a/src/lib/problem_data.c
+++ b/src/lib/problem_data.c
@@ -213,7 +213,7 @@ static const char *const editable_files[] = {
};
static bool is_editable_file(const char *file_name)
{
- return is_in_string_list(file_name, (char**)editable_files);
+ return is_in_string_list(file_name, (char**)editable_files, /* flags */ 0);
}
static const char *const always_text_files[] = {
@@ -257,7 +257,7 @@ static char* is_text_file(const char *name, ssize_t *sz)
if (base)
{
base++;
- if (is_in_string_list(base, (char**)always_text_files))
+ if (is_in_string_list(base, (char**)always_text_files, /* flags */ 0))
return buf;
}
@@ -298,7 +298,7 @@ void load_problem_data_from_dump_dir(problem_data_t *problem_data, struct dump_d
dd_init_next_file(dd);
while (dd_get_next_file(dd, &short_name, &full_name))
{
- if (excluding && is_in_string_list(short_name, excluding))
+ if (excluding && is_in_string_list(short_name, excluding, /* flags */ 0))
{
//log("Excluded:'%s'", short_name);
goto next;
@@ -373,7 +373,7 @@ void load_problem_data_from_dump_dir(problem_data_t *problem_data, struct dump_d
FILENAME_COUNT ,
NULL
};
- if (is_in_string_list(short_name, (char**)list_files))
+ if (is_in_string_list(short_name, (char**)list_files, /* flags */ 0))
flags |= CD_FLAG_LIST;
if (strcmp(short_name, FILENAME_TIME) == 0)
diff --git a/src/plugins/rhbz.c b/src/plugins/rhbz.c
index 9ed3154..a3aa2ef 100644
--- a/src/plugins/rhbz.c
+++ b/src/plugins/rhbz.c
@@ -438,7 +438,12 @@ int rhbz_new_bug(struct abrt_xmlrpc *ax, problem_data_t *problem_data,
}
char *status_whiteboard = xasprintf("abrt_hash:%s", duphash);
- char *bz_dsc = make_description_bz(problem_data, CD_TEXT_ATT_SIZE_BZ);
+ char *bz_dsc;
+ if (analyzer && !strcmp(analyzer, "Kerneloops"))
+ bz_dsc = make_description_koops(problem_data, CD_TEXT_ATT_SIZE_BZ);
+ else
+ bz_dsc = make_description_bz(problem_data, CD_TEXT_ATT_SIZE_BZ);
+
char *full_dsc = xasprintf("libreport version: "VERSION"\n%s", bz_dsc);
free(bz_dsc);
--
1.7.7.2
12 years
[PATCH 1/2] added DeleteProblem call to dbus api
by Jiri Moskovcak
- + minor refactoring
---
src/dbus/abrt-dbus.c | 71 +++++++++++++++++++++++++++++++++-------------
src/include/abrt-dbus.h | 4 ++
src/lib/Makefile.am | 3 +-
src/lib/abrt_glib.c | 54 +++++++++++++++++++++++++++++++++++
4 files changed, 111 insertions(+), 21 deletions(-)
create mode 100644 src/lib/abrt_glib.c
diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c
index cf04a0d..abeadaf 100644
--- a/src/dbus/abrt-dbus.c
+++ b/src/dbus/abrt-dbus.c
@@ -6,6 +6,7 @@
#include "libabrt.h"
#include "abrt-polkit.h"
#include "abrt-dbus.h"
+#include "dump_dir.h"
GMainLoop *loop;
guint g_timeout;
@@ -34,6 +35,9 @@ static const gchar introspection_xml[] =
" <method name='ChownProblemDir'>"
" <arg type='s' name='problem_dir' direction='in'/>"
" </method>"
+ " <method name='DeleteProblem'>"
+ " <arg type='as' name='problem_dir' direction='in'/>"
+ " </method>"
" <method name='Quit' />"
" </interface>"
"</node>";
@@ -131,6 +135,25 @@ static bool uid_in_group(uid_t uid, gid_t gid)
return FALSE;
}
+/*
+ 0 - user doesn't have access
+ 1 - user has access
+*/
+static int dir_accessible_by_uid(const char* dir_path, uid_t uid)
+{
+ struct stat statbuf;
+ if (stat(dir_path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
+ {
+ if (uid == 0 || uid_in_group(uid, statbuf.st_gid))
+ {
+ VERB1 log("caller has access to the requested directory %s", dir_path);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static GList* scan_directory(const char *path, uid_t caller_uid)
{
GList *list = NULL;
@@ -185,19 +208,7 @@ 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;
+ return variant_from_string_list(dirs);
}
static void handle_method_call(GDBusConnection *connection,
@@ -331,8 +342,9 @@ static void handle_method_call(GDBusConnection *connection,
g_dbus_method_invocation_return_dbus_error(invocation,
"org.freedesktop.problems.ChownError",
strerror(errno));
+ else
+ g_dbus_method_invocation_return_value(invocation, NULL);
- g_dbus_method_invocation_return_value(invocation, NULL);
dd_close(dd);
return;
}
@@ -390,10 +402,7 @@ static void handle_method_call(GDBusConnection *connection,
| DD_FAIL_QUIETLY_ENOENT
| DD_FAIL_QUIETLY_EACCES);
if (not_reportable_reason)
- g_variant_builder_add (builder, "{ss}", xstrdup(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));
+ g_variant_builder_add (builder, "{ss}", xstrdup(FILENAME_NOT_REPORTABLE), not_reportable_reason);
/* the source of the problem:
* - first we try to load component, as we use it on Fedora
*/
@@ -406,7 +415,6 @@ static void handle_method_call(GDBusConnection *connection,
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
);
@@ -434,6 +442,30 @@ static void handle_method_call(GDBusConnection *connection,
return;
}
+ else if (g_strcmp0(method_name, "DeleteProblem") == 0)
+ {
+ VERB1 log("DeleteProblem");
+
+ GList *problem_dirs = string_list_from_variant(parameters);
+
+ while (problem_dirs)
+ {
+ if (!dir_accessible_by_uid((const char*)problem_dirs->data, caller_uid))
+ {
+ if (polkit_check_authorization_dname(caller, "org.freedesktop.problems.getall") != PolkitYes)
+ { // if user didn't provide correct credentials, just move to the next dir
+ problem_dirs = g_list_next((const char*)problem_dirs->data);
+ continue;
+ }
+ }
+ delete_dump_dir((const char*)problem_dirs->data);
+ problem_dirs = g_list_next(problem_dirs);
+ }
+
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ return;
+ }
+
else if (g_strcmp0(method_name, "Quit") == 0)
{
VERB1 log("Quit");
@@ -441,7 +473,6 @@ static void handle_method_call(GDBusConnection *connection,
g_dbus_method_invocation_return_value(invocation, NULL);
g_main_loop_quit(loop);
-
}
}
diff --git a/src/include/abrt-dbus.h b/src/include/abrt-dbus.h
index 898dd94..dfc5b80 100644
--- a/src/include/abrt-dbus.h
+++ b/src/include/abrt-dbus.h
@@ -5,4 +5,8 @@
#define ABRT_DBUS_OBJECT "/org/freedesktop/problems"
#define ABRT_DBUS_IFACE "org.freedesktop.problems"
+GList *string_list_from_variant(GVariant *variant);
+
+GVariant *variant_from_string_list(GList *strings);
+
#endif /* ABRTDBUS_H_ */
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index bbeb687..4ea19ef 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -8,7 +8,8 @@ libabrt_la_SOURCES = \
abrt_conf.c \
hooklib.c \
daemon_is_ok.c \
- kernel.c
+ kernel.c \
+ abrt_glib.c
libabrt_la_CPPFLAGS = \
-Wall -Wwrite-strings -Werror \
diff --git a/src/lib/abrt_glib.c b/src/lib/abrt_glib.c
new file mode 100644
index 0000000..c54a33a
--- /dev/null
+++ b/src/lib/abrt_glib.c
@@ -0,0 +1,54 @@
+/*
+ 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 <glib-2.0/glib.h>
+#include "libabrt.h"
+
+GList *string_list_from_variant(GVariant *variant)
+{
+ GList *list = NULL;
+ GVariantIter *iter;
+ gchar *str;
+ g_variant_get(variant, "(as)", &iter);
+ while (g_variant_iter_loop(iter, "s", &str))
+ {
+ VERB1 log("adding: %s", str);
+ list = g_list_prepend(list, xstrdup(str));
+ }
+ g_variant_unref(variant);
+
+ return list;
+}
+
+GVariant *variant_from_string_list(GList *strings)
+{
+ GVariantBuilder *builder;
+ builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+
+ while (strings)
+ {
+ g_variant_builder_add(builder, "s", (char*)strings->data);
+ free(strings->data);
+ strings = g_list_delete_link(strings, strings);
+ }
+
+ GVariant *variant = g_variant_new("(as)", builder);
+ g_variant_builder_unref(builder);
+
+ return variant;
+}
\ No newline at end of file
--
1.7.7.6
12 years
[PATCH] Save cgroup information for crashing process
by Richard Marko
Stored in /proc/<pid>/cgroup
Signed-off-by: Richard Marko <rmarko(a)redhat.com>
---
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
12 years, 1 month
[PATCH] Add cgroup information filename
by Richard Marko
Signed-off-by: Richard Marko <rmarko(a)redhat.com>
---
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
Signed-off-by: Richard Marko <rmarko(a)redhat.com>
---
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-libreport] Add cgroup information filename
by Richard Marko
Signed-off-by: Richard Marko <rmarko(a)redhat.com>
---
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
abrt configuration question
by Kuzeja, William
I have a question about configuration of abrt that is not apparent (at
least to me) from the reading the documentation. The question is
concerning how to handle dumps from third party applications (developed
by Stratus).
What I'm trying to do is configure abrt to not delete crashes of these
applications, but also to not allow the user to send these dumps off to
Redhat (which would not be appropriate).
For the first part of this: initially, I was getting complaints about
"invalid key" after an application crash had occurred (abrt would
automatically then delete the dump). I can fix this either by adding
our key to "gpg_keys" or by changing "OpenGPGCheck = no" in
/etc/abrt/abrt-action-save-package-data.conf. I have chosen to do the
latter.
Now, I can get the dumps to not be deleted.
However, I'm concerned that the user can send these dumps to Redhat
through the abrt-gui. Is there a way (configuration settings, etc) to
prevent certain dumps from being sent to Redhat?
The documentation does not cover if abrt can be configured to do this.
Hopefully it can.
Any insight would be greatly appreciated! Thanks in advance,
Regards
-Bill Kuzeja
Stratus Technologies
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 | 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
12 years, 1 month
[PATCH] 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 | 571 +++++++++++++++++++++++++++++
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, 845 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..cf04a0d
--- /dev/null
+++ b/src/dbus/abrt-dbus.c
@@ -0,0 +1,571 @@
+#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()
+{
+ 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;
+
+ caller_uid = get_caller_uid(connection, invocation, caller);
+
+ if (caller_uid == (uid_t) -1)
+ return;
+
+ if (g_strcmp0(method_name, "GetProblems") == 0)
+ {
+ //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);
+
+ /*
+ - 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;
+ }
+
+ 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
+ {
+ VERB1 log("caller has access to the requested directory %s", problem_dir);
+ g_dbus_method_invocation_return_value(invocation, NULL);
+ dd_close(dd);
+ return;
+ }
+
+ }
+ 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;
+ }
+
+ 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);
+ return;
+ }
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add (builder, "{ss}", xstrdup(FILENAME_TIME), dd_load_text(dd, FILENAME_TIME));
+ g_variant_builder_add (builder, "{ss}", xstrdup(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}", xstrdup(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}", xstrdup("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}", xstrdup(FILENAME_REPORTED_TO), msg);
+
+ dd_close(dd);
+
+ GVariant *response = g_variant_new("(a{ss})", builder);
+ g_variant_builder_unref(builder);
+
+ free(msg);
+ free(source);
+ free(not_reportable_reason);
+
+ g_dbus_method_invocation_return_value(invocation, response);
+ return;
+ }
+
+ 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;
+}
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+ .method_call = handle_method_call,
+ .get_property = NULL,
+ .set_property = 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();
+}
+
+/* not used
+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,
+ NULL,
+ 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
12 years, 1 month