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;
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 */
109 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
118 if (*p == '.' || *p == '#') {
119 /* Ignore control commands for now, and
121 remaining -= (e - p) + 1;
126 /* A property follows */
128 /* n received properties, +1 for _TRANSPORT */
129 if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS +
130 !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
135 q = memchr(p, '=', e - p);
137 if (valid_user_field(p, q - p, false)) {
142 /* If the field name starts with an
143 * underscore, skip the variable,
144 * since that indidates a trusted
146 iovec[n].iov_base = (char*) p;
147 iovec[n].iov_len = l;
150 /* We need to determine the priority
151 * of this entry for the rate limiting
154 startswith(p, "PRIORITY=") &&
155 p[9] >= '0' && p[9] <= '9')
156 priority = (priority & LOG_FACMASK) | (p[9] - '0');
159 startswith(p, "SYSLOG_FACILITY=") &&
160 p[16] >= '0' && p[16] <= '9')
161 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
164 startswith(p, "SYSLOG_FACILITY=") &&
165 p[16] >= '0' && p[16] <= '9' &&
166 p[17] >= '0' && p[17] <= '9')
167 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
170 startswith(p, "SYSLOG_IDENTIFIER=")) {
173 t = strndup(p + 18, l - 18);
179 startswith(p, "MESSAGE=")) {
182 t = strndup(p + 8, l - 8);
187 } else if (l > strlen("OBJECT_PID=") &&
188 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
189 startswith(p, "OBJECT_PID=") &&
190 allow_object_pid(ucred)) {
191 char buf[DECIMAL_STR_MAX(pid_t)];
192 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
196 parse_pid(buf, &object_pid);
200 remaining -= (e - p) + 1;
208 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
209 log_debug("Failed to parse message, ignoring.");
213 memcpy(&l_le, e + 1, sizeof(uint64_t));
216 if (l > DATA_SIZE_MAX) {
217 log_debug("Received binary data block too large, ignoring.");
221 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
222 e[1+sizeof(uint64_t)+l] != '\n') {
223 log_debug("Failed to parse message, ignoring.");
227 k = malloc((e - p) + 1 + l);
235 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
237 if (valid_user_field(p, e - p, false)) {
238 iovec[n].iov_base = k;
239 iovec[n].iov_len = (e - p) + 1 + l;
244 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
245 p = e + 1 + sizeof(uint64_t) + l + 1;
253 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
256 if (s->forward_to_syslog)
257 server_forward_syslog(s, priority, identifier, message, ucred, tv);
259 if (s->forward_to_kmsg)
260 server_forward_kmsg(s, priority, identifier, message, ucred);
262 if (s->forward_to_console)
263 server_forward_console(s, priority, identifier, message, ucred);
265 if (s->forward_to_wall)
266 server_forward_wall(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;
374 if (s->native_fd < 0) {
376 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
377 if (s->native_fd < 0) {
378 log_error("socket() failed: %m");
383 sa.un.sun_family = AF_UNIX;
384 strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
386 unlink(sa.un.sun_path);
388 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
390 log_error("bind() failed: %m");
394 chmod(sa.un.sun_path, 0666);
396 fd_nonblock(s->native_fd, 1);
399 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
401 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");
415 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
417 log_error("SO_TIMESTAMP failed: %m");
421 r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s);
423 log_error("Failed to add native server fd to event loop: %s", strerror(-r));