]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journald-native.c
man: bring resolved.conf up-to-date
[thirdparty/systemd.git] / src / journal / journald-native.c
CommitLineData
0153028a
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <unistd.h>
4871690d 23#include <stddef.h>
0153028a
LP
24#include <sys/epoll.h>
25
26#include "socket-util.h"
1dfa7e79 27#include "path-util.h"
d682b3a7 28#include "selinux-util.h"
d025f1e4 29#include "journald-server.h"
0153028a
LP
30#include "journald-native.h"
31#include "journald-kmsg.h"
32#include "journald-console.h"
33#include "journald-syslog.h"
40b71e89 34#include "journald-wall.h"
0153028a 35
d18d46ec 36bool valid_user_field(const char *p, size_t l, bool allow_protected) {
0153028a
LP
37 const char *a;
38
39 /* We kinda enforce POSIX syntax recommendations for
40 environment variables here, but make a couple of additional
41 requirements.
42
43 http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
44
45 /* No empty field names */
46 if (l <= 0)
47 return false;
48
49 /* Don't allow names longer than 64 chars */
50 if (l > 64)
51 return false;
52
53 /* Variables starting with an underscore are protected */
d18d46ec 54 if (!allow_protected && p[0] == '_')
0153028a
LP
55 return false;
56
57 /* Don't allow digits as first character */
58 if (p[0] >= '0' && p[0] <= '9')
59 return false;
60
61 /* Only allow A-Z0-9 and '_' */
62 for (a = p; a < p + l; a++)
d18d46ec
ZJS
63 if ((*a < 'A' || *a > 'Z') &&
64 (*a < '0' || *a > '9') &&
65 *a != '_')
0153028a
LP
66 return false;
67
68 return true;
69}
70
968f3196
ZJS
71static bool allow_object_pid(struct ucred *ucred) {
72 return ucred && ucred->uid == 0;
73}
74
0153028a
LP
75void server_process_native_message(
76 Server *s,
77 const void *buffer, size_t buffer_size,
78 struct ucred *ucred,
79 struct timeval *tv,
80 const char *label, size_t label_len) {
81
82 struct iovec *iovec = NULL;
968f3196 83 unsigned n = 0, j, tn = (unsigned) -1;
0153028a 84 const char *p;
874bc134 85 size_t remaining, m = 0, entry_size = 0;
0153028a
LP
86 int priority = LOG_INFO;
87 char *identifier = NULL, *message = NULL;
968f3196 88 pid_t object_pid = 0;
0153028a
LP
89
90 assert(s);
91 assert(buffer || buffer_size == 0);
92
93 p = buffer;
94 remaining = buffer_size;
95
96 while (remaining > 0) {
97 const char *e, *q;
98
99 e = memchr(p, '\n', remaining);
100
101 if (!e) {
102 /* Trailing noise, let's ignore it, and flush what we collected */
103 log_debug("Received message with trailing noise, ignoring.");
104 break;
105 }
106
107 if (e == p) {
108 /* Entry separator */
874bc134
ZJS
109
110 if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
111 log_debug("Entry is too big with %u properties and %zu bytes, ignoring.",
112 n, entry_size);
113 continue;
114 }
115
968f3196 116 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
0153028a
LP
117 n = 0;
118 priority = LOG_INFO;
874bc134 119 entry_size = 0;
0153028a
LP
120
121 p++;
122 remaining--;
123 continue;
124 }
125
126 if (*p == '.' || *p == '#') {
127 /* Ignore control commands for now, and
128 * comments too. */
129 remaining -= (e - p) + 1;
130 p = e + 1;
131 continue;
132 }
133
134 /* A property follows */
135
f6422def 136 /* n received properties, +1 for _TRANSPORT */
968f3196
ZJS
137 if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS +
138 !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
139 log_oom();
140 break;
0153028a
LP
141 }
142
143 q = memchr(p, '=', e - p);
144 if (q) {
d18d46ec 145 if (valid_user_field(p, q - p, false)) {
0153028a
LP
146 size_t l;
147
148 l = e - p;
149
150 /* If the field name starts with an
151 * underscore, skip the variable,
152 * since that indidates a trusted
153 * field */
154 iovec[n].iov_base = (char*) p;
155 iovec[n].iov_len = l;
156 n++;
874bc134 157 entry_size += iovec[n].iov_len;
0153028a
LP
158
159 /* We need to determine the priority
160 * of this entry for the rate limiting
161 * logic */
162 if (l == 10 &&
2a0e0692 163 startswith(p, "PRIORITY=") &&
0153028a
LP
164 p[9] >= '0' && p[9] <= '9')
165 priority = (priority & LOG_FACMASK) | (p[9] - '0');
166
167 else if (l == 17 &&
2a0e0692 168 startswith(p, "SYSLOG_FACILITY=") &&
0153028a
LP
169 p[16] >= '0' && p[16] <= '9')
170 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
171
172 else if (l == 18 &&
2a0e0692 173 startswith(p, "SYSLOG_FACILITY=") &&
0153028a
LP
174 p[16] >= '0' && p[16] <= '9' &&
175 p[17] >= '0' && p[17] <= '9')
176 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
177
178 else if (l >= 19 &&
2a0e0692 179 startswith(p, "SYSLOG_IDENTIFIER=")) {
0153028a
LP
180 char *t;
181
182 t = strndup(p + 18, l - 18);
183 if (t) {
184 free(identifier);
185 identifier = t;
186 }
187 } else if (l >= 8 &&
2a0e0692 188 startswith(p, "MESSAGE=")) {
0153028a
LP
189 char *t;
190
191 t = strndup(p + 8, l - 8);
192 if (t) {
193 free(message);
194 message = t;
195 }
968f3196
ZJS
196 } else if (l > strlen("OBJECT_PID=") &&
197 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
2a0e0692 198 startswith(p, "OBJECT_PID=") &&
968f3196
ZJS
199 allow_object_pid(ucred)) {
200 char buf[DECIMAL_STR_MAX(pid_t)];
201 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
202 char_array_0(buf);
203
204 /* ignore error */
205 parse_pid(buf, &object_pid);
0153028a
LP
206 }
207 }
208
209 remaining -= (e - p) + 1;
210 p = e + 1;
211 continue;
212 } else {
213 le64_t l_le;
214 uint64_t l;
215 char *k;
216
217 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
218 log_debug("Failed to parse message, ignoring.");
219 break;
220 }
221
222 memcpy(&l_le, e + 1, sizeof(uint64_t));
223 l = le64toh(l_le);
224
505b6a61 225 if (l > DATA_SIZE_MAX) {
fa1c4b51 226 log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
505b6a61
LP
227 break;
228 }
229
230 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
0153028a
LP
231 e[1+sizeof(uint64_t)+l] != '\n') {
232 log_debug("Failed to parse message, ignoring.");
233 break;
234 }
235
236 k = malloc((e - p) + 1 + l);
237 if (!k) {
238 log_oom();
239 break;
240 }
241
242 memcpy(k, p, e - p);
243 k[e - p] = '=';
244 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
245
d18d46ec 246 if (valid_user_field(p, e - p, false)) {
0153028a
LP
247 iovec[n].iov_base = k;
248 iovec[n].iov_len = (e - p) + 1 + l;
249 n++;
874bc134 250 entry_size += iovec[n].iov_len;
0153028a
LP
251 } else
252 free(k);
253
254 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
255 p = e + 1 + sizeof(uint64_t) + l + 1;
256 }
257 }
258
259 if (n <= 0)
260 goto finish;
261
262 tn = n++;
263 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
874bc134
ZJS
264 entry_size += strlen("_TRANSPORT=journal");
265
266 if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
267 log_debug("Entry is too big with %u properties and %zu bytes, ignoring.",
268 n, entry_size);
269 goto finish;
270 }
0153028a
LP
271
272 if (message) {
273 if (s->forward_to_syslog)
274 server_forward_syslog(s, priority, identifier, message, ucred, tv);
275
276 if (s->forward_to_kmsg)
277 server_forward_kmsg(s, priority, identifier, message, ucred);
278
279 if (s->forward_to_console)
280 server_forward_console(s, priority, identifier, message, ucred);
40b71e89
ST
281
282 if (s->forward_to_wall)
283 server_forward_wall(s, priority, identifier, message, ucred);
0153028a
LP
284 }
285
968f3196 286 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
0153028a
LP
287
288finish:
289 for (j = 0; j < n; j++) {
290 if (j == tn)
291 continue;
292
293 if (iovec[j].iov_base < buffer ||
294 (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
295 free(iovec[j].iov_base);
296 }
297
298 free(iovec);
299 free(identifier);
300 free(message);
301}
302
303void server_process_native_file(
304 Server *s,
305 int fd,
306 struct ucred *ucred,
307 struct timeval *tv,
308 const char *label, size_t label_len) {
309
310 struct stat st;
1dfa7e79 311 _cleanup_free_ void *p = NULL;
0153028a 312 ssize_t n;
1dfa7e79 313 int r;
0153028a
LP
314
315 assert(s);
316 assert(fd >= 0);
317
1dfa7e79
LP
318 if (!ucred || ucred->uid != 0) {
319 _cleanup_free_ char *sl = NULL, *k = NULL;
320 const char *e;
321
322 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
323 log_oom();
324 return;
325 }
326
327 r = readlink_malloc(sl, &k);
328 if (r < 0) {
329 log_error("readlink(%s) failed: %m", sl);
330 return;
331 }
332
333 e = path_startswith(k, "/dev/shm/");
334 if (!e)
335 e = path_startswith(k, "/tmp/");
336 if (!e)
337 e = path_startswith(k, "/var/tmp/");
338 if (!e) {
339 log_error("Received file outside of allowed directories. Refusing.");
340 return;
341 }
342
0b507b17 343 if (!filename_is_safe(e)) {
1dfa7e79
LP
344 log_error("Received file in subdirectory of allowed directories. Refusing.");
345 return;
346 }
347 }
348
0153028a
LP
349 /* Data is in the passed file, since it didn't fit in a
350 * datagram. We can't map the file here, since clients might
351 * then truncate it and trigger a SIGBUS for us. So let's
352 * stupidly read it */
353
354 if (fstat(fd, &st) < 0) {
355 log_error("Failed to stat passed file, ignoring: %m");
356 return;
357 }
358
359 if (!S_ISREG(st.st_mode)) {
360 log_error("File passed is not regular. Ignoring.");
361 return;
362 }
363
364 if (st.st_size <= 0)
365 return;
366
367 if (st.st_size > ENTRY_SIZE_MAX) {
368 log_error("File passed too large. Ignoring.");
369 return;
370 }
371
372 p = malloc(st.st_size);
373 if (!p) {
374 log_oom();
375 return;
376 }
377
378 n = pread(fd, p, st.st_size, 0);
379 if (n < 0)
380 log_error("Failed to read file, ignoring: %s", strerror(-n));
381 else if (n > 0)
382 server_process_native_message(s, p, n, ucred, tv, label, label_len);
0153028a
LP
383}
384
385int server_open_native_socket(Server*s) {
0153028a 386 int one, r;
0153028a
LP
387
388 assert(s);
389
390 if (s->native_fd < 0) {
f7a5bb28
ZJS
391 union sockaddr_union sa = {
392 .un.sun_family = AF_UNIX,
393 .un.sun_path = "/run/systemd/journal/socket",
394 };
0153028a
LP
395
396 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
397 if (s->native_fd < 0) {
398 log_error("socket() failed: %m");
399 return -errno;
400 }
401
0153028a
LP
402 unlink(sa.un.sun_path);
403
404 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
405 if (r < 0) {
6b9732b2 406 log_error("bind(%s) failed: %m", sa.un.sun_path);
0153028a
LP
407 return -errno;
408 }
409
410 chmod(sa.un.sun_path, 0666);
411 } else
412 fd_nonblock(s->native_fd, 1);
413
414 one = 1;
415 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
416 if (r < 0) {
417 log_error("SO_PASSCRED failed: %m");
418 return -errno;
419 }
420
421#ifdef HAVE_SELINUX
d682b3a7
LP
422 if (use_selinux()) {
423 one = 1;
424 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
425 if (r < 0)
426 log_warning("SO_PASSSEC failed: %m");
427 }
0153028a
LP
428#endif
429
430 one = 1;
431 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
432 if (r < 0) {
433 log_error("SO_TIMESTAMP failed: %m");
434 return -errno;
435 }
436
151b9b96 437 r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s);
f9a810be
LP
438 if (r < 0) {
439 log_error("Failed to add native server fd to event loop: %s", strerror(-r));
440 return r;
0153028a
LP
441 }
442
443 return 0;
444}