/src/systemd/src/shared/journal-util.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1+ */ |
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 | | |
12 | 0 | static int access_check_var_log_journal(sd_journal *j, bool want_other_users) { |
13 | | #if HAVE_ACL |
14 | | _cleanup_strv_free_ char **g = NULL; |
15 | | const char* dir; |
16 | | #endif |
17 | | int r; |
18 | 0 |
|
19 | 0 | assert(j); |
20 | 0 |
|
21 | 0 | /* If we are root, we should have access, don't warn. */ |
22 | 0 | if (getuid() == 0) |
23 | 0 | return 0; |
24 | 0 | |
25 | 0 | /* If we are in the 'systemd-journal' group, we should have |
26 | 0 | * access too. */ |
27 | 0 | r = in_group("systemd-journal"); |
28 | 0 | if (r < 0) |
29 | 0 | return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m"); |
30 | 0 | if (r > 0) |
31 | 0 | return 0; |
32 | 0 | |
33 | | #if HAVE_ACL |
34 | | if (laccess("/run/log/journal", F_OK) >= 0) |
35 | | dir = "/run/log/journal"; |
36 | | else |
37 | | dir = "/var/log/journal"; |
38 | | |
39 | | /* If we are in any of the groups listed in the journal ACLs, |
40 | | * then all is good, too. Let's enumerate all groups from the |
41 | | * default ACL of the directory, which generally should allow |
42 | | * access to most journal files too. */ |
43 | | r = acl_search_groups(dir, &g); |
44 | | if (r < 0) |
45 | | return log_error_errno(r, "Failed to search journal ACL: %m"); |
46 | | if (r > 0) |
47 | | return 0; |
48 | | |
49 | | /* Print a pretty list, if there were ACLs set. */ |
50 | | if (!strv_isempty(g)) { |
51 | | _cleanup_free_ char *s = NULL; |
52 | | |
53 | | /* There are groups in the ACL, let's list them */ |
54 | | r = strv_extend(&g, "systemd-journal"); |
55 | | if (r < 0) |
56 | | return log_oom(); |
57 | | |
58 | | strv_sort(g); |
59 | | strv_uniq(g); |
60 | | |
61 | | s = strv_join(g, "', '"); |
62 | | if (!s) |
63 | | return log_oom(); |
64 | | |
65 | | log_notice("Hint: You are currently not seeing messages from %s.\n" |
66 | | " Users in groups '%s' can see all messages.\n" |
67 | | " Pass -q to turn off this notice.", |
68 | | want_other_users ? "other users and the system" : "the system", |
69 | | s); |
70 | | return 1; |
71 | | } |
72 | | #endif |
73 | | |
74 | 0 | /* If no ACLs were found, print a short version of the message. */ |
75 | 0 | log_notice("Hint: You are currently not seeing messages from %s.\n" |
76 | 0 | " Users in the 'systemd-journal' group can see all messages. Pass -q to\n" |
77 | 0 | " turn off this notice.", |
78 | 0 | want_other_users ? "other users and the system" : "the system"); |
79 | 0 |
|
80 | 0 | return 1; |
81 | 0 | } |
82 | | |
83 | 0 | int journal_access_check_and_warn(sd_journal *j, bool quiet, bool want_other_users) { |
84 | 0 | Iterator it; |
85 | 0 | void *code; |
86 | 0 | char *path; |
87 | 0 | int r = 0; |
88 | 0 |
|
89 | 0 | assert(j); |
90 | 0 |
|
91 | 0 | if (hashmap_isempty(j->errors)) { |
92 | 0 | if (ordered_hashmap_isempty(j->files) && !quiet) |
93 | 0 | log_notice("No journal files were found."); |
94 | 0 |
|
95 | 0 | return 0; |
96 | 0 | } |
97 | 0 |
|
98 | 0 | if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) { |
99 | 0 | if (!quiet) |
100 | 0 | (void) access_check_var_log_journal(j, want_other_users); |
101 | 0 |
|
102 | 0 | if (ordered_hashmap_isempty(j->files)) |
103 | 0 | r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions."); |
104 | 0 | } |
105 | 0 |
|
106 | 0 | HASHMAP_FOREACH_KEY(path, code, j->errors, it) { |
107 | 0 | int err; |
108 | 0 |
|
109 | 0 | err = abs(PTR_TO_INT(code)); |
110 | 0 |
|
111 | 0 | switch (err) { |
112 | 0 | case EACCES: |
113 | 0 | continue; |
114 | 0 |
|
115 | 0 | case ENODATA: |
116 | 0 | log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path); |
117 | 0 | break; |
118 | 0 |
|
119 | 0 | case EPROTONOSUPPORT: |
120 | 0 | log_warning_errno(err, "Journal file %1$s uses an unsupported feature, ignoring file.\n" |
121 | 0 | "Use SYSTEMD_LOG_LEVEL=debug journalctl --file=%1$s to see the details.", |
122 | 0 | path); |
123 | 0 | break; |
124 | 0 |
|
125 | 0 | case EBADMSG: |
126 | 0 | log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path); |
127 | 0 | break; |
128 | 0 |
|
129 | 0 | default: |
130 | 0 | log_warning_errno(err, "An error was encountered while opening journal file or directory %s, ignoring file: %m", path); |
131 | 0 | break; |
132 | 0 | } |
133 | 0 | } |
134 | 0 |
|
135 | 0 | return r; |
136 | 0 | } |
137 | | |
138 | 841k | bool journal_field_valid(const char *p, size_t l, bool allow_protected) { |
139 | 841k | const char *a; |
140 | 841k | |
141 | 841k | /* We kinda enforce POSIX syntax recommendations for |
142 | 841k | environment variables here, but make a couple of additional |
143 | 841k | requirements. |
144 | 841k | |
145 | 841k | http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */ |
146 | 841k | |
147 | 841k | if (l == (size_t) -1) |
148 | 0 | l = strlen(p); |
149 | 841k | |
150 | 841k | /* No empty field names */ |
151 | 841k | if (l <= 0) |
152 | 6.20k | return false; |
153 | 835k | |
154 | 835k | /* Don't allow names longer than 64 chars */ |
155 | 835k | if (l > 64) |
156 | 3.53k | return false; |
157 | 831k | |
158 | 831k | /* Variables starting with an underscore are protected */ |
159 | 831k | if (!allow_protected && p[0] == '_') |
160 | 621 | return false; |
161 | 830k | |
162 | 830k | /* Don't allow digits as first character */ |
163 | 830k | if (p[0] >= '0' && p[0] <= '9') |
164 | 2.86k | return false; |
165 | 828k | |
166 | 828k | /* Only allow A-Z0-9 and '_' */ |
167 | 4.80M | for (a = p; a < p + l; a++) |
168 | 4.01M | if ((*a < 'A' || *a > 'Z') && |
169 | 4.01M | (*a < '0' || *a > '9') && |
170 | 4.01M | *a != '_') |
171 | 41.2k | return false; |
172 | 828k | |
173 | 828k | return true; |
174 | 828k | } |