]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journald-syslog.c
resolved: add enablers for DNS-SD
[thirdparty/systemd.git] / src / journal / journald-syslog.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
35e2e347
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
4871690d 21#include <stddef.h>
35e2e347 22#include <sys/epoll.h>
07630cea 23#include <unistd.h>
35e2e347 24
07630cea
LP
25#include "sd-messages.h"
26
b5efdb8a 27#include "alloc-util.h"
3ffd4af2 28#include "fd-util.h"
f97b34a6 29#include "format-util.h"
afc5dbf3 30#include "io-util.h"
3b7124a8 31#include "journald-console.h"
07630cea
LP
32#include "journald-kmsg.h"
33#include "journald-server.h"
3ffd4af2 34#include "journald-syslog.h"
40b71e89 35#include "journald-wall.h"
0b452006 36#include "process-util.h"
07630cea
LP
37#include "selinux-util.h"
38#include "socket-util.h"
15a5e950 39#include "stdio-util.h"
07630cea 40#include "string-util.h"
7ccbd1ae 41#include "syslog-util.h"
35e2e347 42
178cc770
LP
43/* Warn once every 30s if we missed syslog message */
44#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
45
3b3154df 46static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, const struct ucred *ucred, const struct timeval *tv) {
b92bea5d 47
46b13157 48 static const union sockaddr_union sa = {
b92bea5d
ZJS
49 .un.sun_family = AF_UNIX,
50 .un.sun_path = "/run/systemd/journal/syslog",
51 };
52 struct msghdr msghdr = {
53 .msg_iov = (struct iovec *) iovec,
54 .msg_iovlen = n_iovec,
46b13157 55 .msg_name = (struct sockaddr*) &sa.sa,
fc2fffe7 56 .msg_namelen = SOCKADDR_UN_LEN(sa.un),
b92bea5d 57 };
35e2e347
LP
58 struct cmsghdr *cmsg;
59 union {
60 struct cmsghdr cmsghdr;
61 uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
62 } control;
35e2e347
LP
63
64 assert(s);
65 assert(iovec);
66 assert(n_iovec > 0);
67
35e2e347
LP
68 if (ucred) {
69 zero(control);
70 msghdr.msg_control = &control;
71 msghdr.msg_controllen = sizeof(control);
72
73 cmsg = CMSG_FIRSTHDR(&msghdr);
74 cmsg->cmsg_level = SOL_SOCKET;
75 cmsg->cmsg_type = SCM_CREDENTIALS;
76 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
77 memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred));
78 msghdr.msg_controllen = cmsg->cmsg_len;
79 }
80
81 /* Forward the syslog message we received via /dev/log to
82 * /run/systemd/syslog. Unfortunately we currently can't set
83 * the SO_TIMESTAMP auxiliary data, and hence we don't. */
84
85 if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
86 return;
87
88 /* The socket is full? I guess the syslog implementation is
89 * too slow, and we shouldn't wait for that... */
178cc770
LP
90 if (errno == EAGAIN) {
91 s->n_forward_syslog_missed++;
35e2e347 92 return;
178cc770 93 }
35e2e347 94
3742095b 95 if (ucred && IN_SET(errno, ESRCH, EPERM)) {
35e2e347
LP
96 struct ucred u;
97
98 /* Hmm, presumably the sender process vanished
ccf23ad5
CS
99 * by now, or we don't have CAP_SYS_AMDIN, so
100 * let's fix it as good as we can, and retry */
35e2e347
LP
101
102 u = *ucred;
df0ff127 103 u.pid = getpid_cached();
35e2e347
LP
104 memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred));
105
106 if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
107 return;
108
178cc770
LP
109 if (errno == EAGAIN) {
110 s->n_forward_syslog_missed++;
35e2e347 111 return;
178cc770 112 }
35e2e347
LP
113 }
114
115 if (errno != ENOENT)
56f64d95 116 log_debug_errno(errno, "Failed to forward syslog message: %m");
35e2e347
LP
117}
118
3b3154df 119static void forward_syslog_raw(Server *s, int priority, const char *buffer, const struct ucred *ucred, const struct timeval *tv) {
35e2e347
LP
120 struct iovec iovec;
121
122 assert(s);
123 assert(buffer);
124
125 if (LOG_PRI(priority) > s->max_level_syslog)
126 return;
127
e6a7ec4b 128 iovec = IOVEC_MAKE_STRING(buffer);
35e2e347
LP
129 forward_syslog_iovec(s, &iovec, 1, ucred, tv);
130}
131
3b3154df 132void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv) {
35e2e347 133 struct iovec iovec[5];
3b97fcbd 134 char header_priority[DECIMAL_STR_MAX(priority) + 3], header_time[64],
5ffa8c81 135 header_pid[sizeof("[]: ")-1 + DECIMAL_STR_MAX(pid_t) + 1];
35e2e347
LP
136 int n = 0;
137 time_t t;
138 struct tm *tm;
e6a7ec4b 139 _cleanup_free_ char *ident_buf = NULL;
35e2e347
LP
140
141 assert(s);
142 assert(priority >= 0);
143 assert(priority <= 999);
144 assert(message);
145
146 if (LOG_PRI(priority) > s->max_level_syslog)
147 return;
148
149 /* First: priority field */
5ffa8c81 150 xsprintf(header_priority, "<%i>", priority);
e6a7ec4b 151 iovec[n++] = IOVEC_MAKE_STRING(header_priority);
35e2e347
LP
152
153 /* Second: timestamp */
154 t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC));
155 tm = localtime(&t);
156 if (!tm)
157 return;
158 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
159 return;
e6a7ec4b 160 iovec[n++] = IOVEC_MAKE_STRING(header_time);
35e2e347
LP
161
162 /* Third: identifier and PID */
163 if (ucred) {
164 if (!identifier) {
165 get_process_comm(ucred->pid, &ident_buf);
166 identifier = ident_buf;
167 }
168
5ffa8c81 169 xsprintf(header_pid, "["PID_FMT"]: ", ucred->pid);
35e2e347
LP
170
171 if (identifier)
e6a7ec4b 172 iovec[n++] = IOVEC_MAKE_STRING(identifier);
35e2e347 173
e6a7ec4b 174 iovec[n++] = IOVEC_MAKE_STRING(header_pid);
35e2e347 175 } else if (identifier) {
e6a7ec4b
LP
176 iovec[n++] = IOVEC_MAKE_STRING(identifier);
177 iovec[n++] = IOVEC_MAKE_STRING(": ");
35e2e347
LP
178 }
179
180 /* Fourth: message */
e6a7ec4b 181 iovec[n++] = IOVEC_MAKE_STRING(message);
35e2e347
LP
182
183 forward_syslog_iovec(s, iovec, n, ucred, tv);
35e2e347
LP
184}
185
186int syslog_fixup_facility(int priority) {
187
188 if ((priority & LOG_FACMASK) == 0)
189 return (priority & LOG_PRIMASK) | LOG_USER;
190
191 return priority;
192}
193
e88baee8 194size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid) {
35e2e347
LP
195 const char *p;
196 char *t;
197 size_t l, e;
198
199 assert(buf);
200 assert(identifier);
201 assert(pid);
202
203 p = *buf;
204
205 p += strspn(p, WHITESPACE);
206 l = strcspn(p, WHITESPACE);
207
208 if (l <= 0 ||
209 p[l-1] != ':')
e88baee8 210 return 0;
35e2e347
LP
211
212 e = l;
213 l--;
214
215 if (p[l-1] == ']') {
216 size_t k = l-1;
217
218 for (;;) {
219
220 if (p[k] == '[') {
221 t = strndup(p+k+1, l-k-2);
222 if (t)
223 *pid = t;
224
225 l = k;
226 break;
227 }
228
229 if (k == 0)
230 break;
231
232 k--;
233 }
234 }
235
236 t = strndup(p, l);
237 if (t)
238 *identifier = t;
239
ec5ff444
FB
240 if (strchr(WHITESPACE, p[e]))
241 e++;
35e2e347 242 *buf = p + e;
e88baee8 243 return e;
35e2e347
LP
244}
245
5809560d
LP
246static void syslog_skip_date(char **buf) {
247 enum {
248 LETTER,
249 SPACE,
250 NUMBER,
251 SPACE_OR_NUMBER,
252 COLON
253 } sequence[] = {
254 LETTER, LETTER, LETTER,
255 SPACE,
256 SPACE_OR_NUMBER, NUMBER,
257 SPACE,
258 SPACE_OR_NUMBER, NUMBER,
259 COLON,
260 SPACE_OR_NUMBER, NUMBER,
261 COLON,
262 SPACE_OR_NUMBER, NUMBER,
263 SPACE
264 };
265
266 char *p;
267 unsigned i;
268
269 assert(buf);
270 assert(*buf);
271
272 p = *buf;
273
274 for (i = 0; i < ELEMENTSOF(sequence); i++, p++) {
275
276 if (!*p)
277 return;
278
279 switch (sequence[i]) {
280
281 case SPACE:
282 if (*p != ' ')
283 return;
284 break;
285
286 case SPACE_OR_NUMBER:
287 if (*p == ' ')
288 break;
289
4831981d 290 _fallthrough_;
5809560d
LP
291 case NUMBER:
292 if (*p < '0' || *p > '9')
293 return;
294
295 break;
296
297 case LETTER:
298 if (!(*p >= 'A' && *p <= 'Z') &&
299 !(*p >= 'a' && *p <= 'z'))
300 return;
301
302 break;
303
304 case COLON:
305 if (*p != ':')
306 return;
307 break;
308
309 }
310 }
311
312 *buf = p;
313}
314
35e2e347 315void server_process_syslog_message(
23be5709
LP
316 Server *s,
317 const char *buf,
318 const struct ucred *ucred,
319 const struct timeval *tv,
320 const char *label,
321 size_t label_len) {
35e2e347 322
8457f8d6 323 char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
13f5402c 324 syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
8457f8d6 325 const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
8457f8d6 326 _cleanup_free_ char *identifier = NULL, *pid = NULL;
22e3a02b
LP
327 int priority = LOG_USER | LOG_INFO, r;
328 ClientContext *context = NULL;
d3070fbd 329 struct iovec *iovec;
35e2e347 330 const char *orig;
d3070fbd 331 size_t n = 0, m;
35e2e347
LP
332
333 assert(s);
334 assert(buf);
335
d3070fbd
LP
336 if (ucred && pid_is_valid(ucred->pid)) {
337 r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context);
338 if (r < 0)
339 log_warning_errno(r, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", ucred->pid);
340 }
341
35e2e347 342 orig = buf;
e3bfb7be 343 syslog_parse_priority(&buf, &priority, true);
35e2e347 344
d3070fbd
LP
345 if (!client_context_test_priority(context, priority))
346 return;
347
35e2e347
LP
348 if (s->forward_to_syslog)
349 forward_syslog_raw(s, priority, orig, ucred, tv);
350
351 syslog_skip_date((char**) &buf);
5809560d 352 syslog_parse_identifier(&buf, &identifier, &pid);
35e2e347
LP
353
354 if (s->forward_to_kmsg)
355 server_forward_kmsg(s, priority, identifier, buf, ucred);
356
357 if (s->forward_to_console)
358 server_forward_console(s, priority, identifier, buf, ucred);
359
40b71e89
ST
360 if (s->forward_to_wall)
361 server_forward_wall(s, priority, identifier, buf, ucred);
362
d3070fbd
LP
363 m = N_IOVEC_META_FIELDS + 6 + client_context_extra_fields_n_iovec(context);
364 iovec = newa(struct iovec, m);
365
e6a7ec4b 366 iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=syslog");
35e2e347 367
d054f0a4 368 xsprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK);
e6a7ec4b 369 iovec[n++] = IOVEC_MAKE_STRING(syslog_priority);
35e2e347 370
8457f8d6 371 if (priority & LOG_FACMASK) {
d054f0a4 372 xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
e6a7ec4b 373 iovec[n++] = IOVEC_MAKE_STRING(syslog_facility);
8457f8d6 374 }
35e2e347
LP
375
376 if (identifier) {
63c372cb 377 syslog_identifier = strjoina("SYSLOG_IDENTIFIER=", identifier);
e6a7ec4b 378 iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier);
35e2e347
LP
379 }
380
381 if (pid) {
63c372cb 382 syslog_pid = strjoina("SYSLOG_PID=", pid);
e6a7ec4b 383 iovec[n++] = IOVEC_MAKE_STRING(syslog_pid);
35e2e347
LP
384 }
385
63c372cb 386 message = strjoina("MESSAGE=", buf);
35e2e347 387 if (message)
e6a7ec4b 388 iovec[n++] = IOVEC_MAKE_STRING(message);
35e2e347 389
d3070fbd 390 server_dispatch_message(s, iovec, n, m, context, tv, priority, 0);
35e2e347
LP
391}
392
393int server_open_syslog_socket(Server *s) {
fc2fffe7
LP
394
395 static const union sockaddr_union sa = {
396 .un.sun_family = AF_UNIX,
397 .un.sun_path = "/run/systemd/journal/dev-log",
398 };
3b3154df
LP
399 static const int one = 1;
400 int r;
35e2e347
LP
401
402 assert(s);
403
404 if (s->syslog_fd < 0) {
35e2e347 405 s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710
MS
406 if (s->syslog_fd < 0)
407 return log_error_errno(errno, "socket() failed: %m");
35e2e347 408
fc2fffe7 409 (void) unlink(sa.un.sun_path);
35e2e347 410
fc2fffe7 411 r = bind(s->syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
4a62c710
MS
412 if (r < 0)
413 return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
35e2e347 414
4a61c3e5 415 (void) chmod(sa.un.sun_path, 0666);
35e2e347
LP
416 } else
417 fd_nonblock(s->syslog_fd, 1);
418
35e2e347 419 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
4a62c710
MS
420 if (r < 0)
421 return log_error_errno(errno, "SO_PASSCRED failed: %m");
35e2e347 422
349cc4a5 423#if HAVE_SELINUX
6d395665 424 if (mac_selinux_use()) {
d682b3a7
LP
425 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
426 if (r < 0)
56f64d95 427 log_warning_errno(errno, "SO_PASSSEC failed: %m");
d682b3a7 428 }
35e2e347
LP
429#endif
430
35e2e347 431 r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
4a62c710
MS
432 if (r < 0)
433 return log_error_errno(errno, "SO_TIMESTAMP failed: %m");
35e2e347 434
8531ae70 435 r = sd_event_add_io(s->event, &s->syslog_event_source, s->syslog_fd, EPOLLIN, server_process_datagram, s);
23bbb0de
MS
436 if (r < 0)
437 return log_error_errno(r, "Failed to add syslog server fd to event loop: %m");
35e2e347 438
48cef295
VC
439 r = sd_event_source_set_priority(s->syslog_event_source, SD_EVENT_PRIORITY_NORMAL+5);
440 if (r < 0)
441 return log_error_errno(r, "Failed to adjust syslog event source priority: %m");
442
35e2e347
LP
443 return 0;
444}
178cc770
LP
445
446void server_maybe_warn_forward_syslog_missed(Server *s) {
447 usec_t n;
fc2fffe7 448
178cc770
LP
449 assert(s);
450
451 if (s->n_forward_syslog_missed <= 0)
452 return;
453
454 n = now(CLOCK_MONOTONIC);
455 if (s->last_warn_forward_syslog_missed + WARN_FORWARD_SYSLOG_MISSED_USEC > n)
456 return;
457
13181942 458 server_driver_message(s, 0,
2b044526 459 "MESSAGE_ID=" SD_MESSAGE_FORWARD_SYSLOG_MISSED_STR,
8a03c9ef
ZJS
460 LOG_MESSAGE("Forwarding to syslog missed %u messages.",
461 s->n_forward_syslog_missed),
462 NULL);
178cc770
LP
463
464 s->n_forward_syslog_missed = 0;
465 s->last_warn_forward_syslog_missed = n;
466}