|
|
1abbee |
From e9bef2f8146ccf152459248775eec8e8ce123865 Mon Sep 17 00:00:00 2001
|
|
|
1abbee |
From: Lennart Poettering <lennart@poettering.net>
|
|
|
1abbee |
Date: Wed, 22 Apr 2015 22:54:23 +0200
|
|
|
1abbee |
Subject: [PATCH] journalctl: rework code that checks whether we have access to
|
|
|
1abbee |
/var/log/journal
|
|
|
1abbee |
|
|
|
1abbee |
- fix some memory leaks on error conditions
|
|
|
1abbee |
|
|
|
1abbee |
- handle all error cases properly, and log about failures
|
|
|
1abbee |
|
|
|
1abbee |
- move HAVE_ACL and no-HAVE_ACL code closer to each other
|
|
|
1abbee |
|
|
|
1abbee |
Cherry-picked from: e346512c684e9efae84c6442f7e6a5781564ecde
|
|
|
1abbee |
Related: #1318994
|
|
|
1abbee |
---
|
|
|
23b3cf |
src/journal/journalctl.c | 120 ++++++++++++++++++++-------------------
|
|
|
23b3cf |
src/shared/acl-util.c | 102 ++++++++++++++++++---------------
|
|
|
1abbee |
src/shared/acl-util.h | 2 +-
|
|
|
1abbee |
3 files changed, 119 insertions(+), 105 deletions(-)
|
|
|
1abbee |
|
|
|
1abbee |
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
|
|
|
c62b8e |
index 6ba8847798..f60e6415f8 100644
|
|
|
1abbee |
--- a/src/journal/journalctl.c
|
|
|
1abbee |
+++ b/src/journal/journalctl.c
|
|
|
1abbee |
@@ -1680,61 +1680,76 @@ static int verify(sd_journal *j) {
|
|
|
1abbee |
return r;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
-#ifdef HAVE_ACL
|
|
|
1abbee |
static int access_check_var_log_journal(sd_journal *j) {
|
|
|
1abbee |
+#ifdef HAVE_ACL
|
|
|
1abbee |
_cleanup_strv_free_ char **g = NULL;
|
|
|
1abbee |
- bool have_access;
|
|
|
1abbee |
+ const char* dir;
|
|
|
1abbee |
+#endif
|
|
|
1abbee |
int r;
|
|
|
1abbee |
|
|
|
1abbee |
assert(j);
|
|
|
1abbee |
|
|
|
1abbee |
- have_access = in_group("systemd-journal") > 0;
|
|
|
1abbee |
+ if (arg_quiet)
|
|
|
1abbee |
+ return 0;
|
|
|
1abbee |
|
|
|
1abbee |
- if (!have_access) {
|
|
|
1abbee |
- const char* dir;
|
|
|
1abbee |
+ /* If we are root, we should have access, don't warn. */
|
|
|
1abbee |
+ if (getuid() == 0)
|
|
|
1abbee |
+ return 0;
|
|
|
1abbee |
|
|
|
1abbee |
- if (access("/run/log/journal", F_OK) >= 0)
|
|
|
1abbee |
- dir = "/run/log/journal";
|
|
|
1abbee |
- else
|
|
|
1abbee |
- dir = "/var/log/journal";
|
|
|
1abbee |
+ /* If we are in the 'systemd-journal' group, we should have
|
|
|
1abbee |
+ * access too. */
|
|
|
1abbee |
+ r = in_group("systemd-journal");
|
|
|
1abbee |
+ if (r < 0)
|
|
|
1abbee |
+ return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m");
|
|
|
1abbee |
+ if (r > 0)
|
|
|
1abbee |
+ return 0;
|
|
|
1abbee |
|
|
|
1abbee |
- /* Let's enumerate all groups from the default ACL of
|
|
|
1abbee |
- * the directory, which generally should allow access
|
|
|
1abbee |
- * to most journal files too */
|
|
|
1abbee |
- r = search_acl_groups(&g, dir, &have_access);
|
|
|
1abbee |
- if (r < 0)
|
|
|
1abbee |
- return r;
|
|
|
1abbee |
- }
|
|
|
1abbee |
+#ifdef HAVE_ACL
|
|
|
1abbee |
+ if (laccess("/run/log/journal", F_OK) >= 0)
|
|
|
1abbee |
+ dir = "/run/log/journal";
|
|
|
1abbee |
+ else
|
|
|
1abbee |
+ dir = "/var/log/journal";
|
|
|
1abbee |
|
|
|
1abbee |
- if (!have_access) {
|
|
|
1abbee |
+ /* If we are in any of the groups listed in the journal ACLs,
|
|
|
1abbee |
+ * then all is good, too. Let's enumerate all groups from the
|
|
|
1abbee |
+ * default ACL of the directory, which generally should allow
|
|
|
1abbee |
+ * access to most journal files too. */
|
|
|
1abbee |
+ r = acl_search_groups(dir, &g);
|
|
|
1abbee |
+ if (r < 0)
|
|
|
1abbee |
+ return log_error_errno(r, "Failed to search journal ACL: %m");
|
|
|
1abbee |
+ if (r > 0)
|
|
|
1abbee |
+ return 0;
|
|
|
1abbee |
|
|
|
1abbee |
- if (strv_isempty(g))
|
|
|
1abbee |
- log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
|
|
|
1abbee |
- " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
|
|
|
1abbee |
- " turn off this notice.");
|
|
|
1abbee |
- else {
|
|
|
1abbee |
- _cleanup_free_ char *s = NULL;
|
|
|
1abbee |
+ /* Print a pretty list, if there were ACLs set. */
|
|
|
1abbee |
+ if (!strv_isempty(g)) {
|
|
|
1abbee |
+ _cleanup_free_ char *s = NULL;
|
|
|
1abbee |
|
|
|
1abbee |
- r = strv_extend(&g, "systemd-journal");
|
|
|
1abbee |
- if (r < 0)
|
|
|
1abbee |
- return log_oom();
|
|
|
1abbee |
+ /* Thre are groups in the ACL, let's list them */
|
|
|
1abbee |
+ r = strv_extend(&g, "systemd-journal");
|
|
|
1abbee |
+ if (r < 0)
|
|
|
1abbee |
+ return log_oom();
|
|
|
1abbee |
|
|
|
1abbee |
- strv_sort(g);
|
|
|
1abbee |
- strv_uniq(g);
|
|
|
1abbee |
+ strv_sort(g);
|
|
|
1abbee |
+ strv_uniq(g);
|
|
|
1abbee |
|
|
|
1abbee |
- s = strv_join(g, "', '");
|
|
|
1abbee |
- if (!s)
|
|
|
1abbee |
- return log_oom();
|
|
|
1abbee |
+ s = strv_join(g, "', '");
|
|
|
1abbee |
+ if (!s)
|
|
|
1abbee |
+ return log_oom();
|
|
|
1abbee |
|
|
|
1abbee |
- log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
|
|
|
1abbee |
- " Users in groups '%s' can see all messages.\n"
|
|
|
1abbee |
- " Pass -q to turn off this notice.", s);
|
|
|
1abbee |
- }
|
|
|
1abbee |
+ log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
|
|
|
1abbee |
+ " Users in groups '%s' can see all messages.\n"
|
|
|
1abbee |
+ " Pass -q to turn off this notice.", s);
|
|
|
1abbee |
+ return 1;
|
|
|
1abbee |
}
|
|
|
1abbee |
+#endif
|
|
|
1abbee |
|
|
|
1abbee |
- return 0;
|
|
|
1abbee |
+ /* If no ACLs were found, print a short version of the message. */
|
|
|
1abbee |
+ log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
|
|
|
1abbee |
+ " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
|
|
|
1abbee |
+ " turn off this notice.");
|
|
|
1abbee |
+
|
|
|
1abbee |
+ return 1;
|
|
|
1abbee |
}
|
|
|
1abbee |
-#endif
|
|
|
1abbee |
|
|
|
1abbee |
static int access_check(sd_journal *j) {
|
|
|
1abbee |
Iterator it;
|
|
|
1abbee |
@@ -1746,30 +1761,15 @@ static int access_check(sd_journal *j) {
|
|
|
1abbee |
if (set_isempty(j->errors)) {
|
|
|
1abbee |
if (ordered_hashmap_isempty(j->files))
|
|
|
1abbee |
log_notice("No journal files were found.");
|
|
|
1abbee |
+
|
|
|
1abbee |
return 0;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
|
|
|
1abbee |
-#ifdef HAVE_ACL
|
|
|
1abbee |
- /* If /run/log/journal or /var/log/journal exist, try
|
|
|
1abbee |
- to pring a nice notice if the user lacks access to it. */
|
|
|
1abbee |
- if (!arg_quiet && geteuid() != 0) {
|
|
|
1abbee |
- r = access_check_var_log_journal(j);
|
|
|
1abbee |
- if (r < 0)
|
|
|
1abbee |
- return r;
|
|
|
1abbee |
- }
|
|
|
1abbee |
-#else
|
|
|
1abbee |
- if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
|
|
|
1abbee |
- log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
|
|
|
1abbee |
- "group may access messages.");
|
|
|
1abbee |
- return -EACCES;
|
|
|
1abbee |
- }
|
|
|
1abbee |
-#endif
|
|
|
1abbee |
+ (void) access_check_var_log_journal(j);
|
|
|
1abbee |
|
|
|
1abbee |
- if (ordered_hashmap_isempty(j->files)) {
|
|
|
1abbee |
- log_error("No journal files were opened due to insufficient permissions.");
|
|
|
1abbee |
- r = -EACCES;
|
|
|
1abbee |
- }
|
|
|
1abbee |
+ if (ordered_hashmap_isempty(j->files))
|
|
|
1abbee |
+ r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
SET_FOREACH(code, j->errors, it) {
|
|
|
1abbee |
@@ -1778,8 +1778,12 @@ static int access_check(sd_journal *j) {
|
|
|
1abbee |
err = -PTR_TO_INT(code);
|
|
|
1abbee |
assert(err > 0);
|
|
|
1abbee |
|
|
|
1abbee |
- if (err != EACCES)
|
|
|
1abbee |
- log_warning_errno(err, "Error was encountered while opening journal files: %m");
|
|
|
1abbee |
+ if (err == EACCES)
|
|
|
1abbee |
+ continue;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ log_warning_errno(err, "Error was encountered while opening journal files: %m");
|
|
|
1abbee |
+ if (r == 0)
|
|
|
1abbee |
+ r = -err;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
return r;
|
|
|
1abbee |
diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c
|
|
|
c62b8e |
index e67e9acb6a..d18a02f503 100644
|
|
|
1abbee |
--- a/src/shared/acl-util.c
|
|
|
1abbee |
+++ b/src/shared/acl-util.c
|
|
|
1abbee |
@@ -82,17 +82,18 @@ int calc_acl_mask_if_needed(acl_t *acl_p) {
|
|
|
1abbee |
|
|
|
1abbee |
if (tag == ACL_MASK)
|
|
|
1abbee |
return 0;
|
|
|
1abbee |
- if (IN_SET(tag, ACL_USER, ACL_GROUP))
|
|
|
1abbee |
- goto calc;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ if (IN_SET(tag, ACL_USER, ACL_GROUP)) {
|
|
|
1abbee |
+ if (acl_calc_mask(acl_p) < 0)
|
|
|
1abbee |
+ return -errno;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ return 1;
|
|
|
1abbee |
+ }
|
|
|
1abbee |
}
|
|
|
1abbee |
if (r < 0)
|
|
|
1abbee |
return -errno;
|
|
|
1abbee |
- return 0;
|
|
|
1abbee |
|
|
|
1abbee |
-calc:
|
|
|
1abbee |
- if (acl_calc_mask(acl_p) < 0)
|
|
|
1abbee |
- return -errno;
|
|
|
1abbee |
- return 1;
|
|
|
1abbee |
+ return 0;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
|
|
|
1abbee |
@@ -159,59 +160,68 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
|
|
|
1abbee |
return 0;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
-int search_acl_groups(char*** dst, const char* path, bool* belong) {
|
|
|
1abbee |
- acl_t acl;
|
|
|
1abbee |
+int acl_search_groups(const char *path, char ***ret_groups) {
|
|
|
1abbee |
+ _cleanup_strv_free_ char **g = NULL;
|
|
|
1abbee |
+ _cleanup_(acl_free) acl_t acl = NULL;
|
|
|
1abbee |
+ bool ret = false;
|
|
|
1abbee |
+ acl_entry_t entry;
|
|
|
1abbee |
+ int r;
|
|
|
1abbee |
|
|
|
1abbee |
assert(path);
|
|
|
1abbee |
- assert(belong);
|
|
|
1abbee |
|
|
|
1abbee |
acl = acl_get_file(path, ACL_TYPE_DEFAULT);
|
|
|
1abbee |
- if (acl) {
|
|
|
1abbee |
- acl_entry_t entry;
|
|
|
1abbee |
- int r;
|
|
|
1abbee |
-
|
|
|
1abbee |
- r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
|
|
|
1abbee |
- while (r > 0) {
|
|
|
1abbee |
- acl_tag_t tag;
|
|
|
1abbee |
- gid_t *gid;
|
|
|
1abbee |
- char *name;
|
|
|
1abbee |
+ if (!acl)
|
|
|
1abbee |
+ return -errno;
|
|
|
1abbee |
|
|
|
1abbee |
- r = acl_get_tag_type(entry, &tag;;
|
|
|
1abbee |
- if (r < 0)
|
|
|
1abbee |
- break;
|
|
|
1abbee |
+ r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
|
|
|
1abbee |
+ for (;;) {
|
|
|
1abbee |
+ _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL;
|
|
|
1abbee |
+ acl_tag_t tag;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ if (r < 0)
|
|
|
1abbee |
+ return -errno;
|
|
|
1abbee |
+ if (r == 0)
|
|
|
1abbee |
+ break;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ if (acl_get_tag_type(entry, &tag) < 0)
|
|
|
1abbee |
+ return -errno;
|
|
|
1abbee |
|
|
|
1abbee |
- if (tag != ACL_GROUP)
|
|
|
1abbee |
- goto next;
|
|
|
1abbee |
+ if (tag != ACL_GROUP)
|
|
|
1abbee |
+ goto next;
|
|
|
1abbee |
|
|
|
1abbee |
- gid = acl_get_qualifier(entry);
|
|
|
1abbee |
- if (!gid)
|
|
|
1abbee |
- break;
|
|
|
1abbee |
+ gid = acl_get_qualifier(entry);
|
|
|
1abbee |
+ if (!gid)
|
|
|
1abbee |
+ return -errno;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ if (in_gid(*gid) > 0) {
|
|
|
1abbee |
+ if (!ret_groups)
|
|
|
1abbee |
+ return true;
|
|
|
1abbee |
|
|
|
1abbee |
- if (in_gid(*gid) > 0) {
|
|
|
1abbee |
- *belong = true;
|
|
|
1abbee |
- break;
|
|
|
1abbee |
- }
|
|
|
1abbee |
+ ret = true;
|
|
|
1abbee |
+ }
|
|
|
1abbee |
+
|
|
|
1abbee |
+ if (ret_groups) {
|
|
|
1abbee |
+ char *name;
|
|
|
1abbee |
|
|
|
1abbee |
name = gid_to_name(*gid);
|
|
|
1abbee |
- if (!name) {
|
|
|
1abbee |
- acl_free(acl);
|
|
|
1abbee |
- return log_oom();
|
|
|
1abbee |
- }
|
|
|
1abbee |
-
|
|
|
1abbee |
- r = strv_consume(dst, name);
|
|
|
1abbee |
- if (r < 0) {
|
|
|
1abbee |
- acl_free(acl);
|
|
|
1abbee |
- return log_oom();
|
|
|
1abbee |
- }
|
|
|
1abbee |
-
|
|
|
1abbee |
- next:
|
|
|
1abbee |
- r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
|
|
|
1abbee |
+ if (!name)
|
|
|
1abbee |
+ return -ENOMEM;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ r = strv_consume(&g, name);
|
|
|
1abbee |
+ if (r < 0)
|
|
|
1abbee |
+ return r;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
- acl_free(acl);
|
|
|
1abbee |
+ next:
|
|
|
1abbee |
+ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
- return 0;
|
|
|
1abbee |
+ if (ret_groups) {
|
|
|
1abbee |
+ *ret_groups = g;
|
|
|
1abbee |
+ g = NULL;
|
|
|
1abbee |
+ }
|
|
|
1abbee |
+
|
|
|
1abbee |
+ return ret;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
|
|
|
1abbee |
diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h
|
|
|
c62b8e |
index fdb90063fa..c8bcc266d0 100644
|
|
|
1abbee |
--- a/src/shared/acl-util.h
|
|
|
1abbee |
+++ b/src/shared/acl-util.h
|
|
|
1abbee |
@@ -32,7 +32,7 @@
|
|
|
1abbee |
int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry);
|
|
|
1abbee |
int calc_acl_mask_if_needed(acl_t *acl_p);
|
|
|
1abbee |
int add_base_acls_if_needed(acl_t *acl_p, const char *path);
|
|
|
1abbee |
-int search_acl_groups(char*** dst, const char* path, bool* belong);
|
|
|
1abbee |
+int acl_search_groups(const char* path, char ***ret_groups);
|
|
|
1abbee |
int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask);
|
|
|
1abbee |
int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl);
|
|
|
1abbee |
|