]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journald-audit.c
tree-wide: drop {} from one-line if blocks
[thirdparty/systemd.git] / src / journal / journald-audit.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include "missing.h"
23 #include "journald-audit.h"
24 #include "audit-type.h"
25
26 typedef struct MapField {
27 const char *audit_field;
28 const char *journal_field;
29 int (*map)(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov);
30 } MapField;
31
32 static int map_simple_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
33 _cleanup_free_ char *c = NULL;
34 size_t l = 0, allocated = 0;
35 const char *e;
36
37 assert(field);
38 assert(p);
39 assert(iov);
40 assert(n_iov);
41
42 l = strlen(field);
43 allocated = l + 1;
44 c = malloc(allocated);
45 if (!c)
46 return -ENOMEM;
47
48 memcpy(c, field, l);
49 for (e = *p; *e != ' ' && *e != 0; e++) {
50 if (!GREEDY_REALLOC(c, allocated, l+2))
51 return -ENOMEM;
52
53 c[l++] = *e;
54 }
55
56 c[l] = 0;
57
58 if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
59 return -ENOMEM;
60
61 (*iov)[*n_iov].iov_base = c;
62 (*iov)[*n_iov].iov_len = l;
63 (*n_iov) ++;
64
65 *p = e;
66 c = NULL;
67
68 return 1;
69 }
70
71 static int map_string_field_internal(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov, bool filter_printable) {
72 _cleanup_free_ char *c = NULL;
73 const char *s, *e;
74 size_t l;
75
76 assert(field);
77 assert(p);
78 assert(iov);
79 assert(n_iov);
80
81 /* The kernel formats string fields in one of two formats. */
82
83 if (**p == '"') {
84 /* Normal quoted syntax */
85 s = *p + 1;
86 e = strchr(s, '"');
87 if (!e)
88 return 0;
89
90 l = strlen(field) + (e - s);
91 c = malloc(l+1);
92 if (!c)
93 return -ENOMEM;
94
95 *((char*) mempcpy(stpcpy(c, field), s, e - s)) = 0;
96
97 e += 1;
98
99 } else if (unhexchar(**p) >= 0) {
100 /* Hexadecimal escaping */
101 size_t allocated = 0;
102
103 l = strlen(field);
104 allocated = l + 2;
105 c = malloc(allocated);
106 if (!c)
107 return -ENOMEM;
108
109 memcpy(c, field, l);
110 for (e = *p; *e != ' ' && *e != 0; e += 2) {
111 int a, b;
112 uint8_t x;
113
114 a = unhexchar(e[0]);
115 if (a < 0)
116 return 0;
117
118 b = unhexchar(e[1]);
119 if (b < 0)
120 return 0;
121
122 x = ((uint8_t) a << 4 | (uint8_t) b);
123
124 if (filter_printable && x < (uint8_t) ' ')
125 x = (uint8_t) ' ';
126
127 if (!GREEDY_REALLOC(c, allocated, l+2))
128 return -ENOMEM;
129
130 c[l++] = (char) x;
131 }
132
133 c[l] = 0;
134 } else
135 return 0;
136
137 if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
138 return -ENOMEM;
139
140 (*iov)[*n_iov].iov_base = c;
141 (*iov)[*n_iov].iov_len = l;
142 (*n_iov) ++;
143
144 *p = e;
145 c = NULL;
146
147 return 1;
148 }
149
150 static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
151 return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, false);
152 }
153
154 static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
155 return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, true);
156 }
157
158 static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
159 const char *e, *f;
160 char *c, *t;
161 int r;
162
163 /* Implements fallback mappings for all fields we don't know */
164
165 for (e = *p; e < *p + 16; e++) {
166
167 if (*e == 0 || *e == ' ')
168 return 0;
169
170 if (*e == '=')
171 break;
172
173 if (!((*e >= 'a' && *e <= 'z') ||
174 (*e >= 'A' && *e <= 'Z') ||
175 (*e >= '0' && *e <= '9') ||
176 *e == '_' || *e == '-'))
177 return 0;
178 }
179
180 if (e <= *p || e >= *p + 16)
181 return 0;
182
183 c = alloca(strlen(prefix) + (e - *p) + 2);
184
185 t = stpcpy(c, prefix);
186 for (f = *p; f < e; f++) {
187 char x;
188
189 if (*f >= 'a' && *f <= 'z')
190 x = (*f - 'a') + 'A'; /* uppercase */
191 else if (*f == '-')
192 x = '_'; /* dashes → underscores */
193 else
194 x = *f;
195
196 *(t++) = x;
197 }
198 strcpy(t, "=");
199
200 e ++;
201
202 r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov);
203 if (r < 0)
204 return r;
205
206 *p = e;
207 return r;
208 }
209
210 /* Kernel fields are those occurring in the audit string before
211 * msg='. All of these fields are trusted, hence carry the "_" prefix.
212 * We try to translate the fields we know into our native names. The
213 * other's are generically mapped to _AUDIT_FIELD_XYZ= */
214 static const MapField map_fields_kernel[] = {
215
216 /* First, we map certain well-known audit fields into native
217 * well-known fields */
218 { "pid=", "_PID=", map_simple_field },
219 { "ppid=", "_PPID=", map_simple_field },
220 { "uid=", "_UID=", map_simple_field },
221 { "euid=", "_EUID=", map_simple_field },
222 { "fsuid=", "_FSUID=", map_simple_field },
223 { "gid=", "_GID=", map_simple_field },
224 { "egid=", "_EGID=", map_simple_field },
225 { "fsgid=", "_FSGID=", map_simple_field },
226 { "tty=", "_TTY=", map_simple_field },
227 { "ses=", "_AUDIT_SESSION=", map_simple_field },
228 { "auid=", "_AUDIT_LOGINUID=", map_simple_field },
229 { "subj=", "_SELINUX_CONTEXT=", map_simple_field },
230 { "comm=", "_COMM=", map_string_field },
231 { "exe=", "_EXE=", map_string_field },
232 { "proctitle=", "_CMDLINE=", map_string_field_printable },
233
234 /* Some fields don't map to native well-known fields. However,
235 * we know that they are string fields, hence let's undo
236 * string field escaping for them, though we stick to the
237 * generic field names. */
238 { "path=", "_AUDIT_FIELD_PATH=", map_string_field },
239 { "dev=", "_AUDIT_FIELD_DEV=", map_string_field },
240 { "name=", "_AUDIT_FIELD_NAME=", map_string_field },
241 {}
242 };
243
244 /* Userspace fields are those occurring in the audit string after
245 * msg='. All of these fields are untrusted, hence carry no "_"
246 * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
247 static const MapField map_fields_userspace[] = {
248 { "cwd=", "AUDIT_FIELD_CWD=", map_string_field },
249 { "cmd=", "AUDIT_FIELD_CMD=", map_string_field },
250 { "acct=", "AUDIT_FIELD_ACCT=", map_string_field },
251 { "exe=", "AUDIT_FIELD_EXE=", map_string_field },
252 { "comm=", "AUDIT_FIELD_COMM=", map_string_field },
253 {}
254 };
255
256 static int map_all_fields(
257 const char *p,
258 const MapField map_fields[],
259 const char *prefix,
260 bool handle_msg,
261 struct iovec **iov,
262 size_t *n_iov_allocated,
263 unsigned *n_iov) {
264
265 int r;
266
267 assert(p);
268 assert(iov);
269 assert(n_iov_allocated);
270 assert(n_iov);
271
272 for (;;) {
273 bool mapped = false;
274 const MapField *m;
275 const char *v;
276
277 p += strspn(p, WHITESPACE);
278
279 if (*p == 0)
280 return 0;
281
282 if (handle_msg) {
283 v = startswith(p, "msg='");
284 if (v) {
285 const char *e;
286 char *c;
287
288 /* Userspace message. It's enclosed in
289 simple quotation marks, is not
290 escaped, but the last field in the
291 line, hence let's remove the
292 quotation mark, and apply the
293 userspace mapping instead of the
294 kernel mapping. */
295
296 e = endswith(v, "'");
297 if (!e)
298 return 0; /* don't continue splitting up if the final quotation mark is missing */
299
300 c = strndupa(v, e - v);
301 return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iov, n_iov_allocated, n_iov);
302 }
303 }
304
305 /* Try to map the kernel fields to our own names */
306 for (m = map_fields; m->audit_field; m++) {
307 v = startswith(p, m->audit_field);
308 if (!v)
309 continue;
310
311 r = m->map(m->journal_field, &v, iov, n_iov_allocated, n_iov);
312 if (r < 0)
313 return log_debug_errno(r, "Failed to parse audit array: %m");
314
315 if (r > 0) {
316 mapped = true;
317 p = v;
318 break;
319 }
320 }
321
322 if (!mapped) {
323 r = map_generic_field(prefix, &p, iov, n_iov_allocated, n_iov);
324 if (r < 0)
325 return log_debug_errno(r, "Failed to parse audit array: %m");
326
327 if (r == 0)
328 /* Couldn't process as generic field, let's just skip over it */
329 p += strcspn(p, WHITESPACE);
330 }
331 }
332 }
333
334 static void process_audit_string(Server *s, int type, const char *data, size_t size) {
335 _cleanup_free_ struct iovec *iov = NULL;
336 size_t n_iov_allocated = 0;
337 unsigned n_iov = 0, k;
338 uint64_t seconds, msec, id;
339 const char *p, *type_name;
340 unsigned z;
341 char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
342 type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
343 source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
344 char *m;
345
346 assert(s);
347
348 if (size <= 0)
349 return;
350
351 if (!data)
352 return;
353
354 /* Note that the input buffer is NUL terminated, but let's
355 * check whether there is a spurious NUL byte */
356 if (memchr(data, 0, size))
357 return;
358
359 p = startswith(data, "audit");
360 if (!p)
361 return;
362
363 if (sscanf(p, "(%" PRIu64 ".%" PRIu64 ":%" PRIu64 "):%n",
364 &seconds,
365 &msec,
366 &id,
367 &k) != 3)
368 return;
369
370 p += k;
371 p += strspn(p, WHITESPACE);
372
373 if (isempty(p))
374 return;
375
376 n_iov_allocated = N_IOVEC_META_FIELDS + 7;
377 iov = new(struct iovec, n_iov_allocated);
378 if (!iov) {
379 log_oom();
380 return;
381 }
382
383 IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
384
385 sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64,
386 (usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC);
387 IOVEC_SET_STRING(iov[n_iov++], source_time_field);
388
389 sprintf(type_field, "_AUDIT_TYPE=%i", type);
390 IOVEC_SET_STRING(iov[n_iov++], type_field);
391
392 sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
393 IOVEC_SET_STRING(iov[n_iov++], id_field);
394
395 assert_cc(32 == LOG_AUTH);
396 IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=32");
397 IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_IDENTIFIER=audit");
398
399 type_name = audit_type_name_alloca(type);
400
401 m = strjoina("MESSAGE=", type_name, " ", p);
402 IOVEC_SET_STRING(iov[n_iov++], m);
403
404 z = n_iov;
405
406 map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov_allocated, &n_iov);
407
408 if (!GREEDY_REALLOC(iov, n_iov_allocated, n_iov + N_IOVEC_META_FIELDS)) {
409 log_oom();
410 goto finish;
411 }
412
413 server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, NULL, NULL, 0, NULL, LOG_NOTICE, 0);
414
415 finish:
416 /* free() all entries that map_all_fields() added. All others
417 * are allocated on the stack or are constant. */
418
419 for (; z < n_iov; z++)
420 free(iov[z].iov_base);
421 }
422
423 void server_process_audit_message(
424 Server *s,
425 const void *buffer,
426 size_t buffer_size,
427 const struct ucred *ucred,
428 const union sockaddr_union *sa,
429 socklen_t salen) {
430
431 const struct nlmsghdr *nl = buffer;
432
433 assert(s);
434
435 if (buffer_size < ALIGN(sizeof(struct nlmsghdr)))
436 return;
437
438 assert(buffer);
439
440 /* Filter out fake data */
441 if (!sa ||
442 salen != sizeof(struct sockaddr_nl) ||
443 sa->nl.nl_family != AF_NETLINK ||
444 sa->nl.nl_pid != 0) {
445 log_debug("Audit netlink message from invalid sender.");
446 return;
447 }
448
449 if (!ucred || ucred->pid != 0) {
450 log_debug("Audit netlink message with invalid credentials.");
451 return;
452 }
453
454 if (!NLMSG_OK(nl, buffer_size)) {
455 log_error("Audit netlink message truncated.");
456 return;
457 }
458
459 /* Ignore special Netlink messages */
460 if (IN_SET(nl->nlmsg_type, NLMSG_NOOP, NLMSG_ERROR))
461 return;
462
463 /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
464 if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG)
465 return;
466
467 process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)));
468 }
469
470 static int enable_audit(int fd, bool b) {
471 struct {
472 union {
473 struct nlmsghdr header;
474 uint8_t header_space[NLMSG_HDRLEN];
475 };
476 struct audit_status body;
477 } _packed_ request = {
478 .header.nlmsg_len = NLMSG_LENGTH(sizeof(struct audit_status)),
479 .header.nlmsg_type = AUDIT_SET,
480 .header.nlmsg_flags = NLM_F_REQUEST,
481 .header.nlmsg_seq = 1,
482 .header.nlmsg_pid = 0,
483 .body.mask = AUDIT_STATUS_ENABLED,
484 .body.enabled = b,
485 };
486 union sockaddr_union sa = {
487 .nl.nl_family = AF_NETLINK,
488 .nl.nl_pid = 0,
489 };
490 struct iovec iovec = {
491 .iov_base = &request,
492 .iov_len = NLMSG_LENGTH(sizeof(struct audit_status)),
493 };
494 struct msghdr mh = {
495 .msg_iov = &iovec,
496 .msg_iovlen = 1,
497 .msg_name = &sa.sa,
498 .msg_namelen = sizeof(sa.nl),
499 };
500
501 ssize_t n;
502
503 n = sendmsg(fd, &mh, MSG_NOSIGNAL);
504 if (n < 0)
505 return -errno;
506 if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
507 return -EIO;
508
509 /* We don't wait for the result here, we can't do anything
510 * about it anyway */
511
512 return 0;
513 }
514
515 int server_open_audit(Server *s) {
516 static const int one = 1;
517 int r;
518
519 if (s->audit_fd < 0) {
520 static const union sockaddr_union sa = {
521 .nl.nl_family = AF_NETLINK,
522 .nl.nl_pid = 0,
523 .nl.nl_groups = AUDIT_NLGRP_READLOG,
524 };
525
526 s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
527 if (s->audit_fd < 0) {
528 if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
529 log_debug("Audit not supported in the kernel.");
530 else
531 log_warning_errno(errno, "Failed to create audit socket, ignoring: %m");
532
533 return 0;
534 }
535
536 if (bind(s->audit_fd, &sa.sa, sizeof(sa.nl)) < 0) {
537 log_warning_errno(errno,
538 "Failed to join audit multicast group. "
539 "The kernel is probably too old or multicast reading is not supported. "
540 "Ignoring: %m");
541 s->audit_fd = safe_close(s->audit_fd);
542 return 0;
543 }
544 } else
545 fd_nonblock(s->audit_fd, 1);
546
547 r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
548 if (r < 0)
549 return log_error_errno(errno, "Failed to set SO_PASSCRED on audit socket: %m");
550
551 r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, server_process_datagram, s);
552 if (r < 0)
553 return log_error_errno(r, "Failed to add audit fd to event loop: %m");
554
555 /* We are listening now, try to enable audit */
556 r = enable_audit(s->audit_fd, true);
557 if (r < 0)
558 log_warning_errno(r, "Failed to issue audit enable call: %m");
559
560 return 0;
561 }