chiark / gitweb /
journalctl: give a nice hint about group membership based on ACLs of /var/log/journal
authorLennart Poettering <lennart@poettering.net>
Fri, 22 Mar 2013 16:44:15 +0000 (17:44 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 22 Mar 2013 16:44:19 +0000 (17:44 +0100)
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.

src/journal/journalctl.c
src/shared/strv.c
src/shared/strv.h
src/shared/util.c
src/shared/util.h

index ddadc21..4c288f3 100644 (file)
 #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.");
index 7bcfabb..e57e0ee 100644 (file)
@@ -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;
 
index 49058f8..910d153 100644 (file)
@@ -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);
index 872f6f7..020b75d 100644 (file)
@@ -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;
index f75c66b..7a38421 100644 (file)
@@ -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);