1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "acl-util.h"
4 #include "fs-util.h"
5 #include "hashmap.h"
6 #include "journal-internal.h"
7 #include "journal-util.h"
8 #include "log.h"
9 #include "strv.h"
10 #include "user-util.h"
11 
access_check_var_log_journal(sd_journal * j,bool want_other_users)12 static int access_check_var_log_journal(sd_journal *j, bool want_other_users) {
13         int r;
14 
15         assert(j);
16 
17         /* If we are root, we should have access, don't warn. */
18         if (getuid() == 0)
19                 return 0;
20 
21         /* If we are in the 'systemd-journal' group, we should have
22          * access too. */
23         r = in_group("systemd-journal");
24         if (r < 0)
25                 return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m");
26         if (r > 0)
27                 return 0;
28 
29 #if HAVE_ACL
30         _cleanup_strv_free_ char **g = NULL;
31         const char* dir;
32 
33         if (laccess("/run/log/journal", F_OK) >= 0)
34                 dir = "/run/log/journal";
35         else
36                 dir = "/var/log/journal";
37 
38         /* If we are in any of the groups listed in the journal ACLs,
39          * then all is good, too. Let's enumerate all groups from the
40          * default ACL of the directory, which generally should allow
41          * access to most journal files too. */
42         r = acl_search_groups(dir, &g);
43         if (r < 0)
44                 return log_error_errno(r, "Failed to search journal ACL: %m");
45         if (r > 0)
46                 return 0;
47 
48         /* Print a pretty list, if there were ACLs set. */
49         if (!strv_isempty(g)) {
50                 _cleanup_free_ char *s = NULL;
51 
52                 /* There are groups in the ACL, let's list them */
53                 r = strv_extend(&g, "systemd-journal");
54                 if (r < 0)
55                         return log_oom();
56 
57                 strv_sort(g);
58                 strv_uniq(g);
59 
60                 s = strv_join(g, "', '");
61                 if (!s)
62                         return log_oom();
63 
64                 log_notice("Hint: You are currently not seeing messages from %s.\n"
65                            "      Users in groups '%s' can see all messages.\n"
66                            "      Pass -q to turn off this notice.",
67                            want_other_users ? "other users and the system" : "the system",
68                            s);
69                 return 1;
70         }
71 #endif
72 
73         /* If no ACLs were found, print a short version of the message. */
74         log_notice("Hint: You are currently not seeing messages from %s.\n"
75                    "      Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
76                    "      turn off this notice.",
77                    want_other_users ? "other users and the system" : "the system");
78 
79         return 1;
80 }
81 
journal_access_blocked(sd_journal * j)82 int journal_access_blocked(sd_journal *j) {
83         return hashmap_contains(j->errors, INT_TO_PTR(-EACCES));
84 }
85 
journal_access_check_and_warn(sd_journal * j,bool quiet,bool want_other_users)86 int journal_access_check_and_warn(sd_journal *j, bool quiet, bool want_other_users) {
87         void *code;
88         char *path;
89         int r = 0;
90 
91         assert(j);
92 
93         if (hashmap_isempty(j->errors)) {
94                 if (ordered_hashmap_isempty(j->files) && !quiet)
95                         log_notice("No journal files were found.");
96 
97                 return 0;
98         }
99 
100         if (journal_access_blocked(j)) {
101                 if (!quiet)
102                         (void) access_check_var_log_journal(j, want_other_users);
103 
104                 if (ordered_hashmap_isempty(j->files))
105                         r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
106         }
107 
108         HASHMAP_FOREACH_KEY(path, code, j->errors) {
109                 int err;
110 
111                 err = abs(PTR_TO_INT(code));
112 
113                 switch (err) {
114                 case EACCES:
115                         continue;
116 
117                 case ENODATA:
118                         log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path);
119                         break;
120 
121                 case EPROTONOSUPPORT:
122                         log_warning_errno(err, "Journal file %1$s uses an unsupported feature, ignoring file.\n"
123                                                "Use SYSTEMD_LOG_LEVEL=debug journalctl --file=%1$s to see the details.",
124                                                path);
125                         break;
126 
127                 case EBADMSG:
128                         log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path);
129                         break;
130 
131                 default:
132                         log_warning_errno(err, "An error was encountered while opening journal file or directory %s, ignoring file: %m", path);
133                         break;
134                 }
135         }
136 
137         return r;
138 }
139