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 bool valid_user_field(const char *p, size_t l, bool allow_protected) {
39 /* We kinda enforce POSIX syntax recommendations for
40 environment variables here, but make a couple of additional
43 http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
45 /* No empty field names */
49 /* Don't allow names longer than 64 chars */
53 /* Variables starting with an underscore are protected */
54 if (!allow_protected && p[0] == '_')
57 /* Don't allow digits as first character */
58 if (p[0] >= '0' && p[0] <= '9')
61 /* Only allow A-Z0-9 and '_' */
62 for (a = p; a < p + l; a++)
63 if ((*a < 'A' || *a > 'Z') &&
64 (*a < '0' || *a > '9') &&
71 static bool allow_object_pid(struct ucred *ucred) {
72 return ucred && ucred->uid == 0;
75 void server_process_native_message(
77 const void *buffer, size_t buffer_size,
80 const char *label, size_t label_len) {
82 struct iovec *iovec = NULL;
83 unsigned n = 0, j, tn = (unsigned) -1;
85 size_t remaining, m = 0, entry_size = 0;
86 int priority = LOG_INFO;
87 char *identifier = NULL, *message = NULL;
91 assert(buffer || buffer_size == 0);
94 remaining = buffer_size;
96 while (remaining > 0) {
99 e = memchr(p, '\n', remaining);
102 /* Trailing noise, let's ignore it, and flush what we collected */
103 log_debug("Received message with trailing noise, ignoring.");
108 /* Entry separator */
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.", n, entry_size);
115 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
125 if (*p == '.' || *p == '#') {
126 /* Ignore control commands for now, and
128 remaining -= (e - p) + 1;
133 /* A property follows */
135 /* n received properties, +1 for _TRANSPORT */
136 if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS + !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
141 q = memchr(p, '=', e - p);
143 if (valid_user_field(p, q - p, false)) {
148 /* If the field name starts with an
149 * underscore, skip the variable,
150 * since that indidates a trusted
152 iovec[n].iov_base = (char*) p;
153 iovec[n].iov_len = l;
154 entry_size += iovec[n].iov_len;
157 /* We need to determine the priority
158 * of this entry for the rate limiting
161 startswith(p, "PRIORITY=") &&
162 p[9] >= '0' && p[9] <= '9')
163 priority = (priority & LOG_FACMASK) | (p[9] - '0');
166 startswith(p, "SYSLOG_FACILITY=") &&
167 p[16] >= '0' && p[16] <= '9')
168 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
171 startswith(p, "SYSLOG_FACILITY=") &&
172 p[16] >= '0' && p[16] <= '9' &&
173 p[17] >= '0' && p[17] <= '9')
174 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
177 startswith(p, "SYSLOG_IDENTIFIER=")) {
180 t = strndup(p + 18, l - 18);
186 startswith(p, "MESSAGE=")) {
189 t = strndup(p + 8, l - 8);
194 } else if (l > strlen("OBJECT_PID=") &&
195 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
196 startswith(p, "OBJECT_PID=") &&
197 allow_object_pid(ucred)) {
198 char buf[DECIMAL_STR_MAX(pid_t)];
199 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
203 parse_pid(buf, &object_pid);
207 remaining -= (e - p) + 1;
215 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
216 log_debug("Failed to parse message, ignoring.");
220 memcpy(&l_le, e + 1, sizeof(uint64_t));
223 if (l > DATA_SIZE_MAX) {
224 log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
228 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
229 e[1+sizeof(uint64_t)+l] != '\n') {
230 log_debug("Failed to parse message, ignoring.");
234 k = malloc((e - p) + 1 + l);
242 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
244 if (valid_user_field(p, e - p, false)) {
245 iovec[n].iov_base = k;
246 iovec[n].iov_len = (e - p) + 1 + l;
247 entry_size += iovec[n].iov_len;
252 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
253 p = e + 1 + sizeof(uint64_t) + l + 1;
261 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
262 entry_size += strlen("_TRANSPORT=journal");
264 if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
265 log_debug("Entry is too big with %u properties and %zu bytes, ignoring.",
271 if (s->forward_to_syslog)
272 server_forward_syslog(s, priority, identifier, message, ucred, tv);
274 if (s->forward_to_kmsg)
275 server_forward_kmsg(s, priority, identifier, message, ucred);
277 if (s->forward_to_console)
278 server_forward_console(s, priority, identifier, message, ucred);
280 if (s->forward_to_wall)
281 server_forward_wall(s, priority, identifier, message, ucred);
284 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
287 for (j = 0; j < n; j++) {
291 if (iovec[j].iov_base < buffer ||
292 (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
293 free(iovec[j].iov_base);
301 void server_process_native_file(
306 const char *label, size_t label_len) {
309 _cleanup_free_ void *p = NULL;
316 if (!ucred || ucred->uid != 0) {
317 _cleanup_free_ char *sl = NULL, *k = NULL;
320 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
325 r = readlink_malloc(sl, &k);
327 log_error("readlink(%s) failed: %m", sl);
331 e = path_startswith(k, "/dev/shm/");
333 e = path_startswith(k, "/tmp/");
335 e = path_startswith(k, "/var/tmp/");
337 log_error("Received file outside of allowed directories. Refusing.");
341 if (!filename_is_safe(e)) {
342 log_error("Received file in subdirectory of allowed directories. Refusing.");
347 /* Data is in the passed file, since it didn't fit in a
348 * datagram. We can't map the file here, since clients might
349 * then truncate it and trigger a SIGBUS for us. So let's
350 * stupidly read it */
352 if (fstat(fd, &st) < 0) {
353 log_error("Failed to stat passed file, ignoring: %m");
357 if (!S_ISREG(st.st_mode)) {
358 log_error("File passed is not regular. Ignoring.");
365 if (st.st_size > ENTRY_SIZE_MAX) {
366 log_error("File passed too large. Ignoring.");
370 p = malloc(st.st_size);
376 n = pread(fd, p, st.st_size, 0);
378 log_error("Failed to read file, ignoring: %s", strerror(-n));
380 server_process_native_message(s, p, n, ucred, tv, label, label_len);
383 int server_open_native_socket(Server*s) {
388 if (s->native_fd < 0) {
389 union sockaddr_union sa = {
390 .un.sun_family = AF_UNIX,
391 .un.sun_path = "/run/systemd/journal/socket",
394 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
395 if (s->native_fd < 0) {
396 log_error("socket() failed: %m");
400 unlink(sa.un.sun_path);
402 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
404 log_error("bind(%s) failed: %m", sa.un.sun_path);
408 chmod(sa.un.sun_path, 0666);
410 fd_nonblock(s->native_fd, 1);
413 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
415 log_error("SO_PASSCRED failed: %m");
422 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
424 log_warning("SO_PASSSEC failed: %m");
429 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
431 log_error("SO_TIMESTAMP failed: %m");
435 r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s);
437 log_error("Failed to add native server fd to event loop: %s", strerror(-r));