journald-native.c revision 1dfa7e79a60de680086b1d93fcc3629b463f58bd
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen This file is part of systemd.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Copyright 2011 Lennart Poettering
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is free software; you can redistribute it and/or modify it
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen under the terms of the GNU Lesser General Public License as published by
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen (at your option) any later version.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is distributed in the hope that it will be useful, but
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Lesser General Public License for more details.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen You should have received a copy of the GNU Lesser General Public License
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic bool valid_user_field(const char *p, size_t l) {
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen const char *a;
3aeb37bc4f32b5edc334f2ac7c5d3c7b0a121328Tom Gundersen /* We kinda enforce POSIX syntax recommendations for
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen environment variables here, but make a couple of additional
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* No empty field names */
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersen return false;
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen /* Don't allow names longer than 64 chars */
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen return false;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* Variables starting with an underscore are protected */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (p[0] == '_')
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek /* Don't allow digits as first character */
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek if (p[0] >= '0' && p[0] <= '9')
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek /* Only allow A-Z0-9 and '_' */
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek for (a = p; a < p + l; a++)
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek if (!((*a >= 'A' && *a <= 'Z') ||
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen return false;
977085794d2996320e345433403de75f662b0622Tom Gundersen const char *p;
977085794d2996320e345433403de75f662b0622Tom Gundersen const char *e, *q;
977085794d2996320e345433403de75f662b0622Tom Gundersen /* Trailing noise, let's ignore it, and flush what we collected */
977085794d2996320e345433403de75f662b0622Tom Gundersen log_debug("Received message with trailing noise, ignoring.");
977085794d2996320e345433403de75f662b0622Tom Gundersen if (e == p) {
977085794d2996320e345433403de75f662b0622Tom Gundersen /* Entry separator */
977085794d2996320e345433403de75f662b0622Tom Gundersen server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* Ignore control commands for now, and
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen * comments too. */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* A property follows */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (valid_user_field(p, q - p)) {
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen /* If the field name starts with an
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen * underscore, skip the variable,
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen * since that indidates a trusted
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* We need to determine the priority
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen * of this entry for the rate limiting
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (l == 10 &&
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen priority = (priority & LOG_FACMASK) | (p[9] - '0');
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen else if (l == 17 &&
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen else if (l == 18 &&
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
98a375f6d5cac24eb80d6d4e00699851324afdecTom Gundersen else if (l >= 19 &&
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen } else if (l >= 8 &&
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen log_debug("Failed to parse message, ignoring.");
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen log_debug("Received binary data block too large, ignoring.");
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek log_debug("Failed to parse message, ignoring.");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen memcpy(k, p, e - p);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen k[e - p] = '=';
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (valid_user_field(p, e - p)) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
b3e013148603aa670bc2c060ac63d48e54d76fc2Tom Gundersen IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen server_forward_syslog(s, priority, identifier, message, ucred, tv);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen server_forward_kmsg(s, priority, identifier, message, ucred);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen server_forward_console(s, priority, identifier, message, ucred);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen for (j = 0; j < n; j++) {
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen const char *e;
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen log_error("Received file outside of allowed directories. Refusing.");
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering log_error("Received file in subdirectory of allowed directories. Refusing.");
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen /* Data is in the passed file, since it didn't fit in a
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering * datagram. We can't map the file here, since clients might
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen * then truncate it and trigger a SIGBUS for us. So let's
55428d84f31b52da1c50b7469f14e15740547f20Tom Gundersen * stupidly read it */
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering log_error("Failed to stat passed file, ignoring: %m");
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering log_error("File passed is not regular. Ignoring.");
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen log_error("File passed too large. Ignoring.");
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen log_error("Failed to read file, ignoring: %s", strerror(-n));
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen else if (n > 0)
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen server_process_native_message(s, p, n, ucred, tv, label, label_len);
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->native_fd, &ev) < 0) {
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen log_error("Failed to add native server fd to epoll object: %m");