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 static bool allow_object_pid(struct ucred *ucred) {
75 return ucred && ucred->uid == 0;
78 void server_process_native_message(
80 const void *buffer, size_t buffer_size,
83 const char *label, size_t label_len) {
85 struct iovec *iovec = NULL;
86 unsigned n = 0, j, tn = (unsigned) -1;
88 size_t remaining, m = 0;
89 int priority = LOG_INFO;
90 char *identifier = NULL, *message = NULL;
94 assert(buffer || buffer_size == 0);
97 remaining = buffer_size;
99 while (remaining > 0) {
102 e = memchr(p, '\n', remaining);
105 /* Trailing noise, let's ignore it, and flush what we collected */
106 log_debug("Received message with trailing noise, ignoring.");
111 /* Entry separator */
112 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
121 if (*p == '.' || *p == '#') {
122 /* Ignore control commands for now, and
124 remaining -= (e - p) + 1;
129 /* A property follows */
131 /* n received properties, +1 for _TRANSPORT */
132 if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS +
133 !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
138 q = memchr(p, '=', e - p);
140 if (valid_user_field(p, q - p)) {
145 /* If the field name starts with an
146 * underscore, skip the variable,
147 * since that indidates a trusted
149 iovec[n].iov_base = (char*) p;
150 iovec[n].iov_len = l;
153 /* We need to determine the priority
154 * of this entry for the rate limiting
157 startswith(p, "PRIORITY=") &&
158 p[9] >= '0' && p[9] <= '9')
159 priority = (priority & LOG_FACMASK) | (p[9] - '0');
162 startswith(p, "SYSLOG_FACILITY=") &&
163 p[16] >= '0' && p[16] <= '9')
164 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
167 startswith(p, "SYSLOG_FACILITY=") &&
168 p[16] >= '0' && p[16] <= '9' &&
169 p[17] >= '0' && p[17] <= '9')
170 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
173 startswith(p, "SYSLOG_IDENTIFIER=")) {
176 t = strndup(p + 18, l - 18);
182 startswith(p, "MESSAGE=")) {
185 t = strndup(p + 8, l - 8);
190 } else if (l > strlen("OBJECT_PID=") &&
191 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
192 startswith(p, "OBJECT_PID=") &&
193 allow_object_pid(ucred)) {
194 char buf[DECIMAL_STR_MAX(pid_t)];
195 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
199 parse_pid(buf, &object_pid);
203 remaining -= (e - p) + 1;
211 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
212 log_debug("Failed to parse message, ignoring.");
216 memcpy(&l_le, e + 1, sizeof(uint64_t));
219 if (l > DATA_SIZE_MAX) {
220 log_debug("Received binary data block too large, ignoring.");
224 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
225 e[1+sizeof(uint64_t)+l] != '\n') {
226 log_debug("Failed to parse message, ignoring.");
230 k = malloc((e - p) + 1 + l);
238 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
240 if (valid_user_field(p, e - p)) {
241 iovec[n].iov_base = k;
242 iovec[n].iov_len = (e - p) + 1 + l;
247 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
248 p = e + 1 + sizeof(uint64_t) + l + 1;
256 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
259 if (s->forward_to_syslog)
260 server_forward_syslog(s, priority, identifier, message, ucred, tv);
262 if (s->forward_to_kmsg)
263 server_forward_kmsg(s, priority, identifier, message, ucred);
265 if (s->forward_to_console)
266 server_forward_console(s, priority, identifier, message, ucred);
269 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
272 for (j = 0; j < n; j++) {
276 if (iovec[j].iov_base < buffer ||
277 (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
278 free(iovec[j].iov_base);
286 void server_process_native_file(
291 const char *label, size_t label_len) {
294 _cleanup_free_ void *p = NULL;
301 if (!ucred || ucred->uid != 0) {
302 _cleanup_free_ char *sl = NULL, *k = NULL;
305 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
310 r = readlink_malloc(sl, &k);
312 log_error("readlink(%s) failed: %m", sl);
316 e = path_startswith(k, "/dev/shm/");
318 e = path_startswith(k, "/tmp/");
320 e = path_startswith(k, "/var/tmp/");
322 log_error("Received file outside of allowed directories. Refusing.");
326 if (!filename_is_safe(e)) {
327 log_error("Received file in subdirectory of allowed directories. Refusing.");
332 /* Data is in the passed file, since it didn't fit in a
333 * datagram. We can't map the file here, since clients might
334 * then truncate it and trigger a SIGBUS for us. So let's
335 * stupidly read it */
337 if (fstat(fd, &st) < 0) {
338 log_error("Failed to stat passed file, ignoring: %m");
342 if (!S_ISREG(st.st_mode)) {
343 log_error("File passed is not regular. Ignoring.");
350 if (st.st_size > ENTRY_SIZE_MAX) {
351 log_error("File passed too large. Ignoring.");
355 p = malloc(st.st_size);
361 n = pread(fd, p, st.st_size, 0);
363 log_error("Failed to read file, ignoring: %s", strerror(-n));
365 server_process_native_message(s, p, n, ucred, tv, label, label_len);
368 int server_open_native_socket(Server*s) {
369 union sockaddr_union sa;
371 struct epoll_event ev;
375 if (s->native_fd < 0) {
377 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
378 if (s->native_fd < 0) {
379 log_error("socket() failed: %m");
384 sa.un.sun_family = AF_UNIX;
385 strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
387 unlink(sa.un.sun_path);
389 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
391 log_error("bind() failed: %m");
395 chmod(sa.un.sun_path, 0666);
397 fd_nonblock(s->native_fd, 1);
400 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
402 log_error("SO_PASSCRED failed: %m");
408 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
410 log_warning("SO_PASSSEC failed: %m");
414 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
416 log_error("SO_TIMESTAMP failed: %m");
422 ev.data.fd = s->native_fd;
423 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->native_fd, &ev) < 0) {
424 log_error("Failed to add native server fd to epoll object: %m");