summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-03-22 17:44:15 +0100
committerLennart Poettering <lennart@poettering.net>2013-03-22 17:44:19 +0100
commit4468addca6d01a0d2d154371dd72f54307a9c786 (patch)
tree01d5a809da50ccdf1621a5e5cb7813b262519ae4
parent8e70580bb07ae46dc0b0bf377de6333540668acc (diff)
journalctl: give a nice hint about group membership based on ACLs of /var/log/journal
If we notice that we unprivileged and not in any of the groups which have access to /var/log/journal, print a nice message about which groups do. This checks and prints all groups that are in the default ACL for /var/log/journal, which is not necessarily correct for all journal files, but pretty close.
-rw-r--r--src/journal/journalctl.c91
-rw-r--r--src/shared/strv.c31
-rw-r--r--src/shared/strv.h1
-rw-r--r--src/shared/util.c36
-rw-r--r--src/shared/util.h2
5 files changed, 143 insertions, 18 deletions
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index ddadc21338..4c288f3334 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -35,6 +35,10 @@
#include <sys/ioctl.h>
#include <linux/fs.h>
+#ifdef HAVE_ACL
+#include <sys/acl.h>
+#endif
+
#include <systemd/sd-journal.h>
#include "log.h"
@@ -881,13 +885,96 @@ static int verify(sd_journal *j) {
static int access_check(void) {
#ifdef HAVE_ACL
+ /* If /var/log/journal doesn't even exist, unprivileged users have no access at all */
if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("systemd-journal") <= 0) {
log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'systemd-journal' can always see messages.");
return -EACCES;
}
- if (!arg_quiet && geteuid() != 0 && in_group("systemd-journal") <= 0)
- log_warning("Showing user generated messages only. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off.");
+ /* If /var/log/journal exists, try to pring a nice notice if the user lacks access to it */
+ if (!arg_quiet && geteuid() != 0) {
+ _cleanup_strv_free_ char **g = NULL;
+ bool have_access;
+ acl_t acl;
+ int r;
+
+ have_access = in_group("systemd-journal") > 0;
+ if (!have_access) {
+
+ /* Let's enumerate all groups from the default
+ * ACL of the directory, which generally
+ * should allow access to most journal
+ * files too */
+
+ acl = acl_get_file("/var/log/journal/", ACL_TYPE_DEFAULT);
+ if (acl) {
+ acl_entry_t entry;
+
+ r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+ while (r > 0) {
+ acl_tag_t tag;
+ gid_t *gid;
+ char *name;
+
+ r = acl_get_tag_type(entry, &tag);
+ if (r < 0)
+ break;
+
+ if (tag != ACL_GROUP)
+ goto next;
+
+ gid = acl_get_qualifier(entry);
+ if (!gid)
+ break;
+
+ if (in_gid(*gid) > 0) {
+ have_access = true;
+ break;
+ }
+
+ name = gid_to_name(*gid);
+ if (!name) {
+ acl_free(acl);
+ return log_oom();
+ }
+
+ r = strv_push(&g, name);
+ if (r < 0) {
+ free(name);
+ acl_free(acl);
+ return log_oom();
+ }
+
+ next:
+ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
+ }
+
+ acl_free(acl);
+ }
+ }
+
+ if (!have_access) {
+
+ if (strv_isempty(g))
+ log_notice("Hint: You are currently not seeing messages from other users and the system. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off.");
+ else {
+ _cleanup_free_ char *s = NULL;
+
+ r = strv_extend(&g, "systemd-journal");
+ if (r < 0)
+ return log_oom();
+
+ strv_sort(g);
+ strv_uniq(g);
+
+ s = strv_join(g, "', '");
+ if (!s)
+ return log_oom();
+
+ log_notice("Hint: You are currently not seeing messages from other users and the system. Users in the groups '%s' can see all messages. Pass -q to turn this notice off.", s);
+ }
+ }
+ }
#else
if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
log_error("No access to messages. Only users in the group 'systemd-journal' can see messages.");
diff --git a/src/shared/strv.c b/src/shared/strv.c
index 7bcfabbf1a..e57e0ee7bf 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -387,32 +387,43 @@ fail:
return NULL;
}
-int strv_extend(char ***l, const char *value) {
+int strv_push(char ***l, char *value) {
char **c;
- char *v;
unsigned n;
if (!value)
return 0;
- v = strdup(value);
- if (!v)
- return -ENOMEM;
-
n = strv_length(*l);
c = realloc(*l, sizeof(char*) * (n + 2));
- if (!c) {
- free(v);
+ if (!c)
return -ENOMEM;
- }
- c[n] = v;
+ c[n] = value;
c[n+1] = NULL;
*l = c;
return 0;
}
+int strv_extend(char ***l, const char *value) {
+ char *v;
+ int r;
+
+ if (!value)
+ return 0;
+
+ v = strdup(value);
+ if (!v)
+ return -ENOMEM;
+
+ r = strv_push(l, v);
+ if (r < 0)
+ free(v);
+
+ return r;
+}
+
char **strv_uniq(char **l) {
char **i;
diff --git a/src/shared/strv.h b/src/shared/strv.h
index 49058f8df8..910d15337f 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -41,6 +41,7 @@ char **strv_merge(char **a, char **b);
char **strv_merge_concat(char **a, char **b, const char *suffix);
char **strv_append(char **l, const char *s);
int strv_extend(char ***l, const char *value);
+int strv_push(char ***l, char *value);
char **strv_remove(char **l, const char *s);
char **strv_remove_prefix(char **l, const char *s);
diff --git a/src/shared/util.c b/src/shared/util.c
index 872f6f7371..020b75d0f2 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -4190,6 +4190,23 @@ char* uid_to_name(uid_t uid) {
return r;
}
+char* gid_to_name(gid_t gid) {
+ struct group *p;
+ char *r;
+
+ if (gid == 0)
+ return strdup("root");
+
+ p = getgrgid(gid);
+ if (p)
+ return strdup(p->gr_name);
+
+ if (asprintf(&r, "%lu", (unsigned long) gid) < 0)
+ return NULL;
+
+ return r;
+}
+
int get_group_creds(const char **groupname, gid_t *gid) {
struct group *g;
gid_t id;
@@ -4228,14 +4245,10 @@ int get_group_creds(const char **groupname, gid_t *gid) {
return 0;
}
-int in_group(const char *name) {
- gid_t gid, *gids;
+int in_gid(gid_t gid) {
+ gid_t *gids;
int ngroups_max, r, i;
- r = get_group_creds(&name, &gid);
- if (r < 0)
- return r;
-
if (getgid() == gid)
return 1;
@@ -4258,6 +4271,17 @@ int in_group(const char *name) {
return 0;
}
+int in_group(const char *name) {
+ int r;
+ gid_t gid;
+
+ r = get_group_creds(&name, &gid);
+ if (r < 0)
+ return r;
+
+ return in_gid(gid);
+}
+
int glob_exists(const char *path) {
glob_t g;
int r, k;
diff --git a/src/shared/util.h b/src/shared/util.h
index f75c66bb83..7a38421007 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -429,9 +429,11 @@ int socket_from_display(const char *display, char **path);
int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
int get_group_creds(const char **groupname, gid_t *gid);
+int in_gid(gid_t gid);
int in_group(const char *name);
char* uid_to_name(uid_t uid);
+char* gid_to_name(gid_t gid);
int glob_exists(const char *path);