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