Administrators should be able to report, modify and delete reports
for other users. But we still want users for which the crashes occurred
to be able to report them themselves.
So add READ and WRITE ACLs to the dump directory.
The ACL 'patching' is based upon systemd helper code.
Closes #915
---
configure.ac | 15 +++++++
src/lib/Makefile.am | 6 ++-
src/lib/acl_util.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/lib/acl_util.h | 23 ++++++++++
src/lib/dump_dir.c | 29 +++++++++++++
5 files changed, 189 insertions(+), 2 deletions(-)
create mode 100644 src/lib/acl_util.c
create mode 100644 src/lib/acl_util.h
diff --git a/configure.ac b/configure.ac
index c9f07bd..43e905e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -86,6 +86,21 @@ AC_PATH_PROG([XMLTO], [xmlto], [no])
[exit 1]
[fi]
+AC_CHECK_HEADERS(
+ [sys/acl.h acl/libacl.h],
+ [have_acl=yes],
+ [AC_MSG_ERROR([*** ACL headers not found.])
+ ])
+
+AC_CHECK_LIB(
+ [acl],
+ [acl_get_file],
+ [have_acl=yes],
+ [AC_MSG_ERROR([*** libacl not found.])
+ ])
+
+ACL_LIBS="-lacl"
+
AC_ARG_WITH(bugzilla,
AS_HELP_STRING([--with-bugzilla],[use Bugzilla plugin (default is YES)]),
LIBREPORT_PARSE_WITH([bugzilla]))
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index b5de38e..d393d3d 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -66,7 +66,8 @@ libreport_la_SOURCES = \
xml_parser.c \
libreport_init.c \
reporters.c \
- global_configuration.c
+ global_configuration.c \
+ acl_util.c acl_util.h
libreport_la_CPPFLAGS = \
-I$(srcdir)/../include \
@@ -97,7 +98,8 @@ libreport_la_LIBADD = \
$(JOURNAL_LIBS) \
$(GOBJECT_LIBS) \
$(AUGEAS_LIBS) \
- $(SATYR_LIBS)
+ $(SATYR_LIBS) \
+ $(ACL_LIBS)
libreportconfdir = $(CONF_DIR)
dist_libreportconf_DATA = \
diff --git a/src/lib/acl_util.c b/src/lib/acl_util.c
new file mode 100644
index 0000000..fefbe1c
--- /dev/null
+++ b/src/lib/acl_util.c
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 2015 Bastien Nocera <hadess(a)hadess.net>
+ Copyright (C) 2011, 2013 Lennart Poettering•
+ Copyright (C) 2015 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 <acl/libacl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "internal_libreport.h"
+
+#define IN_SET(x, y, ...) \
+ ({ \
+ const typeof(y) _y = (y); \
+ const typeof(_y) _x = (x); \
+ unsigned _i; \
+ bool _found = false; \
+ for (_i = 0; _i < 1 + sizeof((const typeof(_x)[]) { __VA_ARGS__
})/sizeof(const typeof(_x)); _i++) \
+ if (((const typeof(_x)[]) { _y, __VA_ARGS__ })[_i] == _x) { \
+ _found = true; \
+ break; \
+ } \
+ _found; \
+ })
+
+
+int calc_acl_mask_if_needed(acl_t *acl_p) {
+ acl_entry_t i;
+ int r;
+
+ assert(acl_p);
+
+ for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
+ r > 0;
+ r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
+ acl_tag_t tag;
+
+ if (acl_get_tag_type(i, &tag) < 0)
+ return -errno;
+
+ if (tag == ACL_MASK)
+ return 0;
+ if (IN_SET(tag, ACL_USER, ACL_GROUP))
+ goto calc;
+ }
+ if (r < 0)
+ return -errno;
+ return 0;
+
+calc:
+ if (acl_calc_mask(acl_p) < 0)
+ return -errno;
+ return 1;
+}
+
+int add_group_acl(int fd, gid_t gid)
+{
+ acl_t acl = NULL;
+ acl_entry_t entry;
+ acl_permset_t permset;
+
+ assert(fd >= 0);
+
+ acl = acl_get_fd(fd);
+ if (!acl)
+ {
+ perror_msg("Failed to get ACL: %s", strerror(errno));
+ return -errno;
+ }
+
+ if (acl_create_entry(&acl, &entry) < 0 ||
+ acl_set_tag_type(entry, ACL_GROUP) < 0 ||
+ acl_set_qualifier(entry, &gid) < 0) {
+ perror_msg("Failed to patch ACL: %s", strerror(errno));
+ acl_free(&acl);
+ return -errno;
+ }
+
+ if (acl_get_permset(entry, &permset) < 0 ||
+ acl_add_perm(permset, ACL_READ) < 0 ||
+ acl_add_perm(permset, ACL_WRITE) < 0 ||
+ calc_acl_mask_if_needed(&acl) < 0) {
+ perror_msg("Failed to patch ACL: %s", strerror(errno));
+ acl_free(&acl);
+ return -errno;
+ }
+
+ if (acl_set_fd(fd, acl) < 0) {
+ acl_free(&acl);
+ perror_msg("Failed to apply ACL: %s", strerror(errno));
+ return -errno;
+ }
+
+ acl_free(&acl);
+ return 0;
+}
diff --git a/src/lib/acl_util.h b/src/lib/acl_util.h
new file mode 100644
index 0000000..7d8684d
--- /dev/null
+++ b/src/lib/acl_util.h
@@ -0,0 +1,23 @@
+/*
+ Copyright (C) 2015 Bastien Nocera <hadess(a)hadess.net>
+ Copyright (C) 2011, 2013 Lennart Poettering•
+ Copyright (C) 2015 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 <grp.h>
+
+int add_group_acl(int fd, gid_t gid);
diff --git a/src/lib/dump_dir.c b/src/lib/dump_dir.c
index d50ebf7..49dc8ca 100644
--- a/src/lib/dump_dir.c
+++ b/src/lib/dump_dir.c
@@ -18,6 +18,7 @@
*/
#include <sys/utsname.h>
#include "internal_libreport.h"
+#include "acl_util.h"
// Locking logic:
//
@@ -621,6 +622,34 @@ struct dump_dir *dd_create(const char *dir, uid_t uid, mode_t mode)
}
}
+ /* Allow 'wheel' users (admins) to modify dump dirs */
+ {
+ /* Get wheel's group gid */
+ struct group *gr = getgrnam("wheel");
+ if (!gr)
+ {
+ error_msg("Group 'wheel' does not exist, not adding
ACLs");
+ }
+ else
+ {
+ DIR *d;
+
+ d = opendir(dir);
+ if (!d)
+ {
+ error_msg("Can't open '%s' to add ACLs", dir);
+ }
+ else
+ {
+ int fd;
+
+ fd = dirfd(d);
+ add_group_acl(fd, gr->gr_gid);
+ closedir(d);
+ }
+ }
+ }
+
return dd;
}
--
2.1.0