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(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
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) {
120 if (!GREEDY_REALLOC(c, allocated, l+2))
123 c[l++] = (char) ((uint8_t) a << 4 | (uint8_t) b);
130 if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
133 (*iov)[*n_iov].iov_base = c;
134 (*iov)[*n_iov].iov_len = l;
143 static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
148 /* Implements fallback mappings for all fields we don't know */
150 for (e = *p; e < *p + 16; e++) {
152 if (*e == 0 || *e == ' ')
158 if (!((*e >= 'a' && *e <= 'z') ||
159 (*e >= 'A' && *e <= 'Z') ||
160 (*e >= '0' && *e <= '9') ||
165 if (e <= *p || e >= *p + 16)
168 c = alloca(strlen(prefix) + (e - *p) + 2);
170 t = stpcpy(c, prefix);
171 for (f = *p; f < e; f++)
172 *(t++) = *f >= 'a' && *f <= 'z' ? ((*f - 'a') + 'A') : *f;
177 r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov);
185 /* Kernel fields are those occuring in the audit string before
186 * msg='. All of these fields are trusted, hence carry the "_" prefix.
187 * We try to translate the fields we know into our native names. The
188 * other's are generically mapped to _AUDIT_FIELD_XYZ= */
189 static const MapField map_fields_kernel[] = {
191 /* First, we map certain well-known audit fields into native
192 * well-known fields */
193 { "pid=", "_PID=", map_simple_field },
194 { "ppid=", "_PPID=", map_simple_field },
195 { "uid=", "_UID=", map_simple_field },
196 { "euid=", "_EUID=", map_simple_field },
197 { "fsuid=", "_FSUID=", map_simple_field },
198 { "gid=", "_GID=", map_simple_field },
199 { "egid=", "_EGID=", map_simple_field },
200 { "fsgid=", "_FSGID=", map_simple_field },
201 { "tty=", "_TTY=", map_simple_field },
202 { "ses=", "_AUDIT_SESSION=", map_simple_field },
203 { "auid=", "_AUDIT_LOGINUID=", map_simple_field },
204 { "subj=", "_SELINUX_CONTEXT=", map_simple_field },
205 { "comm=", "_COMM=", map_string_field },
206 { "exe=", "_EXE=", map_string_field },
207 { "proctitle=", "_CMDLINE=", map_string_field },
209 /* Some fields don't map to native well-known fields. However,
210 * we know that they are string fields, hence let's undo
211 * string field escaping for them, though we stick to the
212 * generic field names. */
213 { "path=", "_AUDIT_FIELD_PATH=", map_string_field },
214 { "dev=", "_AUDIT_FIELD_DEV=", map_string_field },
215 { "name=", "_AUDIT_FIELD_NAME=", map_string_field },
219 /* Userspace fields are thos occuring in the audit string after
220 * msg='. All of these fields are untrusted, hence carry no "_"
221 * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
222 static const MapField map_fields_userspace[] = {
223 { "cwd=", "AUDIT_FIELD_CWD=", map_string_field },
224 { "cmd=", "AUDIT_FIELD_CMD=", map_string_field },
225 { "acct=", "AUDIT_FIELD_ACCT=", map_string_field },
226 { "exe=", "AUDIT_FIELD_EXE=", map_string_field },
227 { "comm=", "AUDIT_FIELD_COMM=", map_string_field },
231 static int map_all_fields(
233 const MapField map_fields[],
237 size_t *n_iov_allocated,
244 assert(n_iov_allocated);
252 p += strspn(p, WHITESPACE);
258 v = startswith(p, "msg='");
263 /* Userspace message. It's enclosed in
264 simple quotation marks, is not
265 escaped, but the last field in the
266 line, hence let's remove the
267 quotation mark, and apply the
268 userspace mapping instead of the
271 e = endswith(v, "'");
273 return 0; /* don't continue splitting up if the final quotation mark is missing */
275 c = strndupa(v, e - v);
276 return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iov, n_iov_allocated, n_iov);
280 /* Try to map the kernel fields to our own names */
281 for (m = map_fields; m->audit_field; m++) {
282 v = startswith(p, m->audit_field);
286 r = m->map(m->journal_field, &v, iov, n_iov_allocated, n_iov);
288 log_debug("Failed to parse audit array: %s", strerror(-r));
300 r = map_generic_field(prefix, &p, iov, n_iov_allocated, n_iov);
302 log_debug("Failed to parse audit array: %s", strerror(-r));
307 /* Couldn't process as generic field, let's just skip over it */
308 p += strcspn(p, WHITESPACE);
314 static void process_audit_string(Server *s, int type, const char *data, size_t size, const struct timeval *tv) {
315 _cleanup_free_ struct iovec *iov = NULL;
316 size_t n_iov_allocated = 0;
317 unsigned n_iov = 0, k;
318 uint64_t seconds, msec, id;
321 char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
322 type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
323 source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
334 /* Note that the input buffer is NUL terminated, but let's
335 * check whether there is a spurious NUL byte */
336 if (memchr(data, 0, size))
339 p = startswith(data, "audit");
343 if (sscanf(p, "(%" PRIi64 ".%" PRIi64 ":%" PRIi64 "): %n",
352 n_iov_allocated = N_IOVEC_META_FIELDS + 5;
353 iov = new(struct iovec, n_iov_allocated);
359 IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
361 sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64,
362 (usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC);
363 IOVEC_SET_STRING(iov[n_iov++], source_time_field);
365 sprintf(type_field, "_AUDIT_TYPE=%i", type);
366 IOVEC_SET_STRING(iov[n_iov++], type_field);
368 sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
369 IOVEC_SET_STRING(iov[n_iov++], id_field);
371 m = strappenda("MESSAGE=", data);
372 IOVEC_SET_STRING(iov[n_iov++], m);
376 map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov_allocated, &n_iov);
378 if (!GREEDY_REALLOC(iov, n_iov_allocated, n_iov + N_IOVEC_META_FIELDS)) {
383 server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, tv, NULL, 0, NULL, LOG_NOTICE, 0);
386 /* free() all entries that map_all_fields() added. All others
387 * are allocated on the stack or are constant. */
389 for (; z < n_iov; z++)
390 free(iov[z].iov_base);
393 void server_process_audit_message(
397 const struct ucred *ucred,
398 const struct timeval *tv,
399 const union sockaddr_union *sa,
402 const struct nlmsghdr *nl = buffer;
406 if (buffer_size < ALIGN(sizeof(struct nlmsghdr)))
411 /* Filter out fake data */
413 salen != sizeof(struct sockaddr_nl) ||
414 sa->nl.nl_family != AF_NETLINK ||
415 sa->nl.nl_pid != 0) {
416 log_debug("Audit netlink message from invalid sender.");
420 if (!ucred || ucred->pid != 0) {
421 log_debug("Audit netlink message with invalid credentials.");
425 if (!NLMSG_OK(nl, buffer_size)) {
426 log_error("Audit netlink message truncated.");
430 /* Ignore special Netlink messages */
431 if (IN_SET(nl->nlmsg_type, NLMSG_NOOP, NLMSG_ERROR))
434 /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
435 if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG)
438 process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)), tv);
441 static int enable_audit(int fd, bool b) {
444 struct nlmsghdr header;
445 uint8_t header_space[NLMSG_HDRLEN];
447 struct audit_status body;
448 } _packed_ request = {
449 .header.nlmsg_len = NLMSG_LENGTH(sizeof(struct audit_status)),
450 .header.nlmsg_type = AUDIT_SET,
451 .header.nlmsg_flags = NLM_F_REQUEST,
452 .header.nlmsg_seq = 1,
453 .header.nlmsg_pid = 0,
454 .body.mask = AUDIT_STATUS_ENABLED,
457 union sockaddr_union sa = {
458 .nl.nl_family = AF_NETLINK,
461 struct iovec iovec = {
462 .iov_base = &request,
463 .iov_len = NLMSG_LENGTH(sizeof(struct audit_status)),
469 .msg_namelen = sizeof(sa.nl),
474 n = sendmsg(fd, &mh, MSG_NOSIGNAL);
477 if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
480 /* We don't wait for the result here, we can't do anything
486 int server_open_audit(Server *s) {
487 static const int one = 1;
490 if (s->audit_fd < 0) {
491 static const union sockaddr_union sa = {
492 .nl.nl_family = AF_NETLINK,
494 .nl.nl_groups = AUDIT_NLGRP_READLOG,
497 s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
498 if (s->audit_fd < 0) {
499 if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
500 log_debug("Audit not supported in the kernel.");
502 log_warning("Failed to create audit socket, ignoring: %m");
507 r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl));
509 log_error("Failed to join audit multicast group: %m");
513 fd_nonblock(s->audit_fd, 1);
515 r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
517 log_error("Failed to set SO_PASSCRED on audit socket: %m");
521 r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, process_datagram, s);
523 log_error("Failed to add audit fd to event loop: %s", strerror(-r));
527 /* We are listening now, try to enable audit */
528 r = enable_audit(s->audit_fd, true);
530 log_warning("Failed to issue audit enable call: %s", strerror(-r));