1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
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.
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.
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/>.
24 #include <sys/epoll.h>
26 #include "socket-util.h"
27 #include "path-util.h"
28 #include "selinux-util.h"
29 #include "journald-server.h"
30 #include "journald-native.h"
31 #include "journald-kmsg.h"
32 #include "journald-console.h"
33 #include "journald-syslog.h"
34 #include "journald-wall.h"
36 /* Make sure not to make this smaller than the maximum coredump
37 * size. See COREDUMP_MAX in coredump.c */
38 #define ENTRY_SIZE_MAX (1024*1024*768)
39 #define DATA_SIZE_MAX (1024*1024*768)
41 static bool valid_user_field(const char *p, size_t l) {
44 /* We kinda enforce POSIX syntax recommendations for
45 environment variables here, but make a couple of additional
48 http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
50 /* No empty field names */
54 /* Don't allow names longer than 64 chars */
58 /* Variables starting with an underscore are protected */
62 /* Don't allow digits as first character */
63 if (p[0] >= '0' && p[0] <= '9')
66 /* Only allow A-Z0-9 and '_' */
67 for (a = p; a < p + l; a++)
68 if (!((*a >= 'A' && *a <= 'Z') ||
69 (*a >= '0' && *a <= '9') ||
76 static bool allow_object_pid(struct ucred *ucred) {
77 return ucred && ucred->uid == 0;
80 void server_process_native_message(
82 const void *buffer, size_t buffer_size,
85 const char *label, size_t label_len) {
87 struct iovec *iovec = NULL;
88 unsigned n = 0, j, tn = (unsigned) -1;
90 size_t remaining, m = 0;
91 int priority = LOG_INFO;
92 char *identifier = NULL, *message = NULL;
96 assert(buffer || buffer_size == 0);
99 remaining = buffer_size;
101 while (remaining > 0) {
104 e = memchr(p, '\n', remaining);
107 /* Trailing noise, let's ignore it, and flush what we collected */
108 log_debug("Received message with trailing noise, ignoring.");
113 /* Entry separator */
114 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
123 if (*p == '.' || *p == '#') {
124 /* Ignore control commands for now, and
126 remaining -= (e - p) + 1;
131 /* A property follows */
133 /* n received properties, +1 for _TRANSPORT */
134 if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS +
135 !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
140 q = memchr(p, '=', e - p);
142 if (valid_user_field(p, q - p)) {
147 /* If the field name starts with an
148 * underscore, skip the variable,
149 * since that indidates a trusted
151 iovec[n].iov_base = (char*) p;
152 iovec[n].iov_len = l;
155 /* We need to determine the priority
156 * of this entry for the rate limiting
159 startswith(p, "PRIORITY=") &&
160 p[9] >= '0' && p[9] <= '9')
161 priority = (priority & LOG_FACMASK) | (p[9] - '0');
164 startswith(p, "SYSLOG_FACILITY=") &&
165 p[16] >= '0' && p[16] <= '9')
166 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
169 startswith(p, "SYSLOG_FACILITY=") &&
170 p[16] >= '0' && p[16] <= '9' &&
171 p[17] >= '0' && p[17] <= '9')
172 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
175 startswith(p, "SYSLOG_IDENTIFIER=")) {
178 t = strndup(p + 18, l - 18);
184 startswith(p, "MESSAGE=")) {
187 t = strndup(p + 8, l - 8);
192 } else if (l > strlen("OBJECT_PID=") &&
193 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
194 startswith(p, "OBJECT_PID=") &&
195 allow_object_pid(ucred)) {
196 char buf[DECIMAL_STR_MAX(pid_t)];
197 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
201 parse_pid(buf, &object_pid);
205 remaining -= (e - p) + 1;
213 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
214 log_debug("Failed to parse message, ignoring.");
218 memcpy(&l_le, e + 1, sizeof(uint64_t));
221 if (l > DATA_SIZE_MAX) {
222 log_debug("Received binary data block too large, ignoring.");
226 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
227 e[1+sizeof(uint64_t)+l] != '\n') {
228 log_debug("Failed to parse message, ignoring.");
232 k = malloc((e - p) + 1 + l);
240 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
242 if (valid_user_field(p, e - p)) {
243 iovec[n].iov_base = k;
244 iovec[n].iov_len = (e - p) + 1 + l;
249 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
250 p = e + 1 + sizeof(uint64_t) + l + 1;
258 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
261 if (s->forward_to_syslog)
262 server_forward_syslog(s, priority, identifier, message, ucred, tv);
264 if (s->forward_to_kmsg)
265 server_forward_kmsg(s, priority, identifier, message, ucred);
267 if (s->forward_to_console)
268 server_forward_console(s, priority, identifier, message, ucred);
270 if (s->forward_to_wall)
271 server_forward_wall(s, priority, identifier, message, ucred);
274 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
277 for (j = 0; j < n; j++) {
281 if (iovec[j].iov_base < buffer ||
282 (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
283 free(iovec[j].iov_base);
291 void server_process_native_file(
296 const char *label, size_t label_len) {
299 _cleanup_free_ void *p = NULL;
306 if (!ucred || ucred->uid != 0) {
307 _cleanup_free_ char *sl = NULL, *k = NULL;
310 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
315 r = readlink_malloc(sl, &k);
317 log_error("readlink(%s) failed: %m", sl);
321 e = path_startswith(k, "/dev/shm/");
323 e = path_startswith(k, "/tmp/");
325 e = path_startswith(k, "/var/tmp/");
327 log_error("Received file outside of allowed directories. Refusing.");
331 if (!filename_is_safe(e)) {
332 log_error("Received file in subdirectory of allowed directories. Refusing.");
337 /* Data is in the passed file, since it didn't fit in a
338 * datagram. We can't map the file here, since clients might
339 * then truncate it and trigger a SIGBUS for us. So let's
340 * stupidly read it */
342 if (fstat(fd, &st) < 0) {
343 log_error("Failed to stat passed file, ignoring: %m");
347 if (!S_ISREG(st.st_mode)) {
348 log_error("File passed is not regular. Ignoring.");
355 if (st.st_size > ENTRY_SIZE_MAX) {
356 log_error("File passed too large. Ignoring.");
360 p = malloc(st.st_size);
366 n = pread(fd, p, st.st_size, 0);
368 log_error("Failed to read file, ignoring: %s", strerror(-n));
370 server_process_native_message(s, p, n, ucred, tv, label, label_len);
373 int server_open_native_socket(Server*s) {
374 union sockaddr_union sa;
379 if (s->native_fd < 0) {
381 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
382 if (s->native_fd < 0) {
383 log_error("socket() failed: %m");
388 sa.un.sun_family = AF_UNIX;
389 strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
391 unlink(sa.un.sun_path);
393 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
395 log_error("bind() failed: %m");
399 chmod(sa.un.sun_path, 0666);
401 fd_nonblock(s->native_fd, 1);
404 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
406 log_error("SO_PASSCRED failed: %m");
413 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
415 log_warning("SO_PASSSEC failed: %m");
420 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
422 log_error("SO_TIMESTAMP failed: %m");
426 r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s);
428 log_error("Failed to add native server fd to event loop: %s", strerror(-r));