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"
35 /* Make sure not to make this smaller than the maximum coredump
36 * size. See COREDUMP_MAX in coredump.c */
37 #define ENTRY_SIZE_MAX (1024*1024*768)
38 #define DATA_SIZE_MAX (1024*1024*768)
40 static bool valid_user_field(const char *p, size_t l) {
43 /* We kinda enforce POSIX syntax recommendations for
44 environment variables here, but make a couple of additional
47 http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
49 /* No empty field names */
53 /* Don't allow names longer than 64 chars */
57 /* Variables starting with an underscore are protected */
61 /* Don't allow digits as first character */
62 if (p[0] >= '0' && p[0] <= '9')
65 /* Only allow A-Z0-9 and '_' */
66 for (a = p; a < p + l; a++)
67 if (!((*a >= 'A' && *a <= 'Z') ||
68 (*a >= '0' && *a <= '9') ||
75 static bool allow_object_pid(struct ucred *ucred) {
76 return ucred && ucred->uid == 0;
79 void server_process_native_message(
81 const void *buffer, size_t buffer_size,
84 const char *label, size_t label_len) {
86 struct iovec *iovec = NULL;
87 unsigned n = 0, j, tn = (unsigned) -1;
89 size_t remaining, m = 0;
90 int priority = LOG_INFO;
91 char *identifier = NULL, *message = NULL;
95 assert(buffer || buffer_size == 0);
98 remaining = buffer_size;
100 while (remaining > 0) {
103 e = memchr(p, '\n', remaining);
106 /* Trailing noise, let's ignore it, and flush what we collected */
107 log_debug("Received message with trailing noise, ignoring.");
112 /* Entry separator */
113 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
122 if (*p == '.' || *p == '#') {
123 /* Ignore control commands for now, and
125 remaining -= (e - p) + 1;
130 /* A property follows */
132 /* n received properties, +1 for _TRANSPORT */
133 if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS +
134 !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
139 q = memchr(p, '=', e - p);
141 if (valid_user_field(p, q - p)) {
146 /* If the field name starts with an
147 * underscore, skip the variable,
148 * since that indidates a trusted
150 iovec[n].iov_base = (char*) p;
151 iovec[n].iov_len = l;
154 /* We need to determine the priority
155 * of this entry for the rate limiting
158 startswith(p, "PRIORITY=") &&
159 p[9] >= '0' && p[9] <= '9')
160 priority = (priority & LOG_FACMASK) | (p[9] - '0');
163 startswith(p, "SYSLOG_FACILITY=") &&
164 p[16] >= '0' && p[16] <= '9')
165 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
168 startswith(p, "SYSLOG_FACILITY=") &&
169 p[16] >= '0' && p[16] <= '9' &&
170 p[17] >= '0' && p[17] <= '9')
171 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
174 startswith(p, "SYSLOG_IDENTIFIER=")) {
177 t = strndup(p + 18, l - 18);
183 startswith(p, "MESSAGE=")) {
186 t = strndup(p + 8, l - 8);
191 } else if (l > strlen("OBJECT_PID=") &&
192 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
193 startswith(p, "OBJECT_PID=") &&
194 allow_object_pid(ucred)) {
195 char buf[DECIMAL_STR_MAX(pid_t)];
196 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
200 parse_pid(buf, &object_pid);
204 remaining -= (e - p) + 1;
212 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
213 log_debug("Failed to parse message, ignoring.");
217 memcpy(&l_le, e + 1, sizeof(uint64_t));
220 if (l > DATA_SIZE_MAX) {
221 log_debug("Received binary data block too large, ignoring.");
225 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
226 e[1+sizeof(uint64_t)+l] != '\n') {
227 log_debug("Failed to parse message, ignoring.");
231 k = malloc((e - p) + 1 + l);
239 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
241 if (valid_user_field(p, e - p)) {
242 iovec[n].iov_base = k;
243 iovec[n].iov_len = (e - p) + 1 + l;
248 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
249 p = e + 1 + sizeof(uint64_t) + l + 1;
257 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
260 if (s->forward_to_syslog)
261 server_forward_syslog(s, priority, identifier, message, ucred, tv);
263 if (s->forward_to_kmsg)
264 server_forward_kmsg(s, priority, identifier, message, ucred);
266 if (s->forward_to_console)
267 server_forward_console(s, priority, identifier, message, ucred);
270 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
273 for (j = 0; j < n; j++) {
277 if (iovec[j].iov_base < buffer ||
278 (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
279 free(iovec[j].iov_base);
287 void server_process_native_file(
292 const char *label, size_t label_len) {
295 _cleanup_free_ void *p = NULL;
302 if (!ucred || ucred->uid != 0) {
303 _cleanup_free_ char *sl = NULL, *k = NULL;
306 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
311 r = readlink_malloc(sl, &k);
313 log_error("readlink(%s) failed: %m", sl);
317 e = path_startswith(k, "/dev/shm/");
319 e = path_startswith(k, "/tmp/");
321 e = path_startswith(k, "/var/tmp/");
323 log_error("Received file outside of allowed directories. Refusing.");
327 if (!filename_is_safe(e)) {
328 log_error("Received file in subdirectory of allowed directories. Refusing.");
333 /* Data is in the passed file, since it didn't fit in a
334 * datagram. We can't map the file here, since clients might
335 * then truncate it and trigger a SIGBUS for us. So let's
336 * stupidly read it */
338 if (fstat(fd, &st) < 0) {
339 log_error("Failed to stat passed file, ignoring: %m");
343 if (!S_ISREG(st.st_mode)) {
344 log_error("File passed is not regular. Ignoring.");
351 if (st.st_size > ENTRY_SIZE_MAX) {
352 log_error("File passed too large. Ignoring.");
356 p = malloc(st.st_size);
362 n = pread(fd, p, st.st_size, 0);
364 log_error("Failed to read file, ignoring: %s", strerror(-n));
366 server_process_native_message(s, p, n, ucred, tv, label, label_len);
369 int server_open_native_socket(Server*s) {
370 union sockaddr_union sa;
372 struct epoll_event ev;
376 if (s->native_fd < 0) {
378 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
379 if (s->native_fd < 0) {
380 log_error("socket() failed: %m");
385 sa.un.sun_family = AF_UNIX;
386 strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
388 unlink(sa.un.sun_path);
390 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
392 log_error("bind() failed: %m");
396 chmod(sa.un.sun_path, 0666);
398 fd_nonblock(s->native_fd, 1);
401 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
403 log_error("SO_PASSCRED failed: %m");
410 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
412 log_warning("SO_PASSSEC failed: %m");
417 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
419 log_error("SO_TIMESTAMP failed: %m");
425 ev.data.fd = s->native_fd;
426 if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->native_fd, &ev) < 0) {
427 log_error("Failed to add native server fd to epoll object: %m");