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 "journald-server.h"
29 #include "journald-native.h"
30 #include "journald-kmsg.h"
31 #include "journald-console.h"
32 #include "journald-syslog.h"
34 /* Make sure not to make this smaller than the maximum coredump
35 * size. See COREDUMP_MAX in coredump.c */
36 #define ENTRY_SIZE_MAX (1024*1024*768)
37 #define DATA_SIZE_MAX (1024*1024*768)
39 static bool valid_user_field(const char *p, size_t l) {
42 /* We kinda enforce POSIX syntax recommendations for
43 environment variables here, but make a couple of additional
46 http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
48 /* No empty field names */
52 /* Don't allow names longer than 64 chars */
56 /* Variables starting with an underscore are protected */
60 /* Don't allow digits as first character */
61 if (p[0] >= '0' && p[0] <= '9')
64 /* Only allow A-Z0-9 and '_' */
65 for (a = p; a < p + l; a++)
66 if (!((*a >= 'A' && *a <= 'Z') ||
67 (*a >= '0' && *a <= '9') ||
74 void server_process_native_message(
76 const void *buffer, size_t buffer_size,
79 const char *label, size_t label_len) {
81 struct iovec *iovec = NULL;
82 unsigned n = 0, m = 0, j, tn = (unsigned) -1;
85 int priority = LOG_INFO;
86 char *identifier = NULL, *message = NULL;
89 assert(buffer || buffer_size == 0);
92 remaining = buffer_size;
94 while (remaining > 0) {
97 e = memchr(p, '\n', remaining);
100 /* Trailing noise, let's ignore it, and flush what we collected */
101 log_debug("Received message with trailing noise, ignoring.");
106 /* Entry separator */
107 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
116 if (*p == '.' || *p == '#') {
117 /* Ignore control commands for now, and
119 remaining -= (e - p) + 1;
124 /* A property follows */
126 if (n+N_IOVEC_META_FIELDS >= m) {
130 u = MAX((n+N_IOVEC_META_FIELDS+1) * 2U, 4U);
131 c = realloc(iovec, u * sizeof(struct iovec));
141 q = memchr(p, '=', e - p);
143 if (valid_user_field(p, q - p)) {
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;
156 /* We need to determine the priority
157 * of this entry for the rate limiting
160 memcmp(p, "PRIORITY=", 9) == 0 &&
161 p[9] >= '0' && p[9] <= '9')
162 priority = (priority & LOG_FACMASK) | (p[9] - '0');
165 memcmp(p, "SYSLOG_FACILITY=", 16) == 0 &&
166 p[16] >= '0' && p[16] <= '9')
167 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
170 memcmp(p, "SYSLOG_FACILITY=", 16) == 0 &&
171 p[16] >= '0' && p[16] <= '9' &&
172 p[17] >= '0' && p[17] <= '9')
173 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
176 memcmp(p, "SYSLOG_IDENTIFIER=", 18) == 0) {
179 t = strndup(p + 18, l - 18);
185 memcmp(p, "MESSAGE=", 8) == 0) {
188 t = strndup(p + 8, l - 8);
196 remaining -= (e - p) + 1;
204 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
205 log_debug("Failed to parse message, ignoring.");
209 memcpy(&l_le, e + 1, sizeof(uint64_t));
212 if (l > DATA_SIZE_MAX) {
213 log_debug("Received binary data block too large, ignoring.");
217 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
218 e[1+sizeof(uint64_t)+l] != '\n') {
219 log_debug("Failed to parse message, ignoring.");
223 k = malloc((e - p) + 1 + l);
231 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
233 if (valid_user_field(p, e - p)) {
234 iovec[n].iov_base = k;
235 iovec[n].iov_len = (e - p) + 1 + l;
240 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
241 p = e + 1 + sizeof(uint64_t) + l + 1;
249 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
252 if (s->forward_to_syslog)
253 server_forward_syslog(s, priority, identifier, message, ucred, tv);
255 if (s->forward_to_kmsg)
256 server_forward_kmsg(s, priority, identifier, message, ucred);
258 if (s->forward_to_console)
259 server_forward_console(s, priority, identifier, message, ucred);
262 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
265 for (j = 0; j < n; j++) {
269 if (iovec[j].iov_base < buffer ||
270 (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
271 free(iovec[j].iov_base);
279 void server_process_native_file(
284 const char *label, size_t label_len) {
287 _cleanup_free_ void *p = NULL;
294 if (!ucred || ucred->uid != 0) {
295 _cleanup_free_ char *sl = NULL, *k = NULL;
298 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
303 r = readlink_malloc(sl, &k);
305 log_error("readlink(%s) failed: %m", sl);
309 e = path_startswith(k, "/dev/shm/");
311 e = path_startswith(k, "/tmp/");
313 e = path_startswith(k, "/var/tmp/");
315 log_error("Received file outside of allowed directories. Refusing.");
319 if (!filename_is_safe(e)) {
320 log_error("Received file in subdirectory of allowed directories. Refusing.");
325 /* Data is in the passed file, since it didn't fit in a
326 * datagram. We can't map the file here, since clients might
327 * then truncate it and trigger a SIGBUS for us. So let's
328 * stupidly read it */
330 if (fstat(fd, &st) < 0) {
331 log_error("Failed to stat passed file, ignoring: %m");
335 if (!S_ISREG(st.st_mode)) {
336 log_error("File passed is not regular. Ignoring.");
343 if (st.st_size > ENTRY_SIZE_MAX) {
344 log_error("File passed too large. Ignoring.");
348 p = malloc(st.st_size);
354 n = pread(fd, p, st.st_size, 0);
356 log_error("Failed to read file, ignoring: %s", strerror(-n));
358 server_process_native_message(s, p, n, ucred, tv, label, label_len);
361 int server_open_native_socket(Server*s) {
362 union sockaddr_union sa;
364 struct epoll_event ev;
368 if (s->native_fd < 0) {
370 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
371 if (s->native_fd < 0) {
372 log_error("socket() failed: %m");
377 sa.un.sun_family = AF_UNIX;
378 strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
380 unlink(sa.un.sun_path);
382 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
384 log_error("bind() failed: %m");
388 chmod(sa.un.sun_path, 0666);
390 fd_nonblock(s->native_fd, 1);
393 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
395 log_error("SO_PASSCRED failed: %m");
401 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
403 log_warning("SO_PASSSEC failed: %m");
407 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
409 log_error("SO_TIMESTAMP failed: %m");
415 ev.data.fd = s->native_fd;
416 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->native_fd, &ev) < 0) {
417 log_error("Failed to add native server fd to epoll object: %m");