1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 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/>.
23 #include "journald-audit.h"
25 typedef struct MapField {
26 const char *audit_field;
27 const char *journal_field;
28 int (*map)(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov);
31 static int map_simple_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
32 _cleanup_free_ char *c = NULL;
33 size_t l = 0, allocated = 0;
43 c = malloc(allocated);
48 for (e = *p; *e != ' ' && *e != 0; e++) {
49 if (!GREEDY_REALLOC(c, allocated, l+2))
57 if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
60 (*iov)[*n_iov].iov_base = c;
61 (*iov)[*n_iov].iov_len = l;
70 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) {
71 _cleanup_free_ char *c = NULL;
80 /* The kernel formats string fields in one of two formats. */
83 /* Normal quoted syntax */
89 l = strlen(field) + (e - s);
94 *((char*) mempcpy(stpcpy(c, field), s, e - s)) = 0;
98 } else if (unhexchar(**p) >= 0) {
99 /* Hexadecimal escaping */
100 size_t allocated = 0;
104 c = malloc(allocated);
109 for (e = *p; *e != ' ' && *e != 0; e += 2) {
121 x = ((uint8_t) a << 4 | (uint8_t) b);
123 if (filter_printable && x < (uint8_t) ' ')
126 if (!GREEDY_REALLOC(c, allocated, l+2))
136 if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
139 (*iov)[*n_iov].iov_base = c;
140 (*iov)[*n_iov].iov_len = l;
149 static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
150 return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, false);
153 static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
154 return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, true);
157 static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
162 /* Implements fallback mappings for all fields we don't know */
164 for (e = *p; e < *p + 16; e++) {
166 if (*e == 0 || *e == ' ')
172 if (!((*e >= 'a' && *e <= 'z') ||
173 (*e >= 'A' && *e <= 'Z') ||
174 (*e >= '0' && *e <= '9') ||
179 if (e <= *p || e >= *p + 16)
182 c = alloca(strlen(prefix) + (e - *p) + 2);
184 t = stpcpy(c, prefix);
185 for (f = *p; f < e; f++)
186 *(t++) = *f >= 'a' && *f <= 'z' ? ((*f - 'a') + 'A') : *f;
191 r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov);
199 /* Kernel fields are those occuring in the audit string before
200 * msg='. All of these fields are trusted, hence carry the "_" prefix.
201 * We try to translate the fields we know into our native names. The
202 * other's are generically mapped to _AUDIT_FIELD_XYZ= */
203 static const MapField map_fields_kernel[] = {
205 /* First, we map certain well-known audit fields into native
206 * well-known fields */
207 { "pid=", "_PID=", map_simple_field },
208 { "ppid=", "_PPID=", map_simple_field },
209 { "uid=", "_UID=", map_simple_field },
210 { "euid=", "_EUID=", map_simple_field },
211 { "fsuid=", "_FSUID=", map_simple_field },
212 { "gid=", "_GID=", map_simple_field },
213 { "egid=", "_EGID=", map_simple_field },
214 { "fsgid=", "_FSGID=", map_simple_field },
215 { "tty=", "_TTY=", map_simple_field },
216 { "ses=", "_AUDIT_SESSION=", map_simple_field },
217 { "auid=", "_AUDIT_LOGINUID=", map_simple_field },
218 { "subj=", "_SELINUX_CONTEXT=", map_simple_field },
219 { "comm=", "_COMM=", map_string_field },
220 { "exe=", "_EXE=", map_string_field },
221 { "proctitle=", "_CMDLINE=", map_string_field_printable },
223 /* Some fields don't map to native well-known fields. However,
224 * we know that they are string fields, hence let's undo
225 * string field escaping for them, though we stick to the
226 * generic field names. */
227 { "path=", "_AUDIT_FIELD_PATH=", map_string_field },
228 { "dev=", "_AUDIT_FIELD_DEV=", map_string_field },
229 { "name=", "_AUDIT_FIELD_NAME=", map_string_field },
233 /* Userspace fields are thos occuring in the audit string after
234 * msg='. All of these fields are untrusted, hence carry no "_"
235 * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
236 static const MapField map_fields_userspace[] = {
237 { "cwd=", "AUDIT_FIELD_CWD=", map_string_field },
238 { "cmd=", "AUDIT_FIELD_CMD=", map_string_field },
239 { "acct=", "AUDIT_FIELD_ACCT=", map_string_field },
240 { "exe=", "AUDIT_FIELD_EXE=", map_string_field },
241 { "comm=", "AUDIT_FIELD_COMM=", map_string_field },
245 static int map_all_fields(
247 const MapField map_fields[],
251 size_t *n_iov_allocated,
258 assert(n_iov_allocated);
266 p += strspn(p, WHITESPACE);
272 v = startswith(p, "msg='");
277 /* Userspace message. It's enclosed in
278 simple quotation marks, is not
279 escaped, but the last field in the
280 line, hence let's remove the
281 quotation mark, and apply the
282 userspace mapping instead of the
285 e = endswith(v, "'");
287 return 0; /* don't continue splitting up if the final quotation mark is missing */
289 c = strndupa(v, e - v);
290 return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iov, n_iov_allocated, n_iov);
294 /* Try to map the kernel fields to our own names */
295 for (m = map_fields; m->audit_field; m++) {
296 v = startswith(p, m->audit_field);
300 r = m->map(m->journal_field, &v, iov, n_iov_allocated, n_iov);
302 log_debug("Failed to parse audit array: %s", strerror(-r));
314 r = map_generic_field(prefix, &p, iov, n_iov_allocated, n_iov);
316 log_debug("Failed to parse audit array: %s", strerror(-r));
321 /* Couldn't process as generic field, let's just skip over it */
322 p += strcspn(p, WHITESPACE);
328 static void process_audit_string(Server *s, int type, const char *data, size_t size, const struct timeval *tv) {
329 _cleanup_free_ struct iovec *iov = NULL;
330 size_t n_iov_allocated = 0;
331 unsigned n_iov = 0, k;
332 uint64_t seconds, msec, id;
335 char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
336 type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
337 source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
348 /* Note that the input buffer is NUL terminated, but let's
349 * check whether there is a spurious NUL byte */
350 if (memchr(data, 0, size))
353 p = startswith(data, "audit");
357 if (sscanf(p, "(%" PRIi64 ".%" PRIi64 ":%" PRIi64 "):%n",
365 p += strspn(p, WHITESPACE);
370 n_iov_allocated = N_IOVEC_META_FIELDS + 5;
371 iov = new(struct iovec, n_iov_allocated);
377 IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
379 sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64,
380 (usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC);
381 IOVEC_SET_STRING(iov[n_iov++], source_time_field);
383 sprintf(type_field, "_AUDIT_TYPE=%i", type);
384 IOVEC_SET_STRING(iov[n_iov++], type_field);
386 sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
387 IOVEC_SET_STRING(iov[n_iov++], id_field);
389 m = strappenda("MESSAGE=audit: ", p);
390 IOVEC_SET_STRING(iov[n_iov++], m);
394 map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov_allocated, &n_iov);
396 if (!GREEDY_REALLOC(iov, n_iov_allocated, n_iov + N_IOVEC_META_FIELDS)) {
401 server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, tv, NULL, 0, NULL, LOG_NOTICE, 0);
404 /* free() all entries that map_all_fields() added. All others
405 * are allocated on the stack or are constant. */
407 for (; z < n_iov; z++)
408 free(iov[z].iov_base);
411 void server_process_audit_message(
415 const struct ucred *ucred,
416 const struct timeval *tv,
417 const union sockaddr_union *sa,
420 const struct nlmsghdr *nl = buffer;
424 if (buffer_size < ALIGN(sizeof(struct nlmsghdr)))
429 /* Filter out fake data */
431 salen != sizeof(struct sockaddr_nl) ||
432 sa->nl.nl_family != AF_NETLINK ||
433 sa->nl.nl_pid != 0) {
434 log_debug("Audit netlink message from invalid sender.");
438 if (!ucred || ucred->pid != 0) {
439 log_debug("Audit netlink message with invalid credentials.");
443 if (!NLMSG_OK(nl, buffer_size)) {
444 log_error("Audit netlink message truncated.");
448 /* Ignore special Netlink messages */
449 if (IN_SET(nl->nlmsg_type, NLMSG_NOOP, NLMSG_ERROR))
452 /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
453 if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG)
456 process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)), tv);
459 static int enable_audit(int fd, bool b) {
462 struct nlmsghdr header;
463 uint8_t header_space[NLMSG_HDRLEN];
465 struct audit_status body;
466 } _packed_ request = {
467 .header.nlmsg_len = NLMSG_LENGTH(sizeof(struct audit_status)),
468 .header.nlmsg_type = AUDIT_SET,
469 .header.nlmsg_flags = NLM_F_REQUEST,
470 .header.nlmsg_seq = 1,
471 .header.nlmsg_pid = 0,
472 .body.mask = AUDIT_STATUS_ENABLED,
475 union sockaddr_union sa = {
476 .nl.nl_family = AF_NETLINK,
479 struct iovec iovec = {
480 .iov_base = &request,
481 .iov_len = NLMSG_LENGTH(sizeof(struct audit_status)),
487 .msg_namelen = sizeof(sa.nl),
492 n = sendmsg(fd, &mh, MSG_NOSIGNAL);
495 if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
498 /* We don't wait for the result here, we can't do anything
504 int server_open_audit(Server *s) {
505 static const int one = 1;
508 if (s->audit_fd < 0) {
509 static const union sockaddr_union sa = {
510 .nl.nl_family = AF_NETLINK,
512 .nl.nl_groups = AUDIT_NLGRP_READLOG,
515 s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
516 if (s->audit_fd < 0) {
517 if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
518 log_debug("Audit not supported in the kernel.");
520 log_warning("Failed to create audit socket, ignoring: %m");
525 r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl));
527 log_error("Failed to join audit multicast group: %m");
531 fd_nonblock(s->audit_fd, 1);
533 r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
535 log_error("Failed to set SO_PASSCRED on audit socket: %m");
539 r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, process_datagram, s);
541 log_error("Failed to add audit fd to event loop: %s", strerror(-r));
545 /* We are listening now, try to enable audit */
546 r = enable_audit(s->audit_fd, true);
548 log_warning("Failed to issue audit enable call: %s", strerror(-r));