]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journald-audit.c
journald: don't pass around SO_TIMESTAMP timestamp for audit, which we don't have...
[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
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);
29 } MapField;
30
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;
34 const char *e;
35
36 assert(field);
37 assert(p);
38 assert(iov);
39 assert(n_iov);
40
41 l = strlen(field);
42 allocated = l + 1;
43 c = malloc(allocated);
44 if (!c)
45 return -ENOMEM;
46
47 memcpy(c, field, l);
48 for (e = *p; *e != ' ' && *e != 0; e++) {
49 if (!GREEDY_REALLOC(c, allocated, l+2))
50 return -ENOMEM;
51
52 c[l++] = *e;
53 }
54
55 c[l] = 0;
56
57 if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
58 return -ENOMEM;
59
60 (*iov)[*n_iov].iov_base = c;
61 (*iov)[*n_iov].iov_len = l;
62 (*n_iov) ++;
63
64 *p = e;
65 c = NULL;
66
67 return 1;
68 }
69
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;
72 const char *s, *e;
73 size_t l;
74
75 assert(field);
76 assert(p);
77 assert(iov);
78 assert(n_iov);
79
80 /* The kernel formats string fields in one of two formats. */
81
82 if (**p == '"') {
83 /* Normal quoted syntax */
84 s = *p + 1;
85 e = strchr(s, '"');
86 if (!e)
87 return 0;
88
89 l = strlen(field) + (e - s);
90 c = malloc(l+1);
91 if (!c)
92 return -ENOMEM;
93
94 *((char*) mempcpy(stpcpy(c, field), s, e - s)) = 0;
95
96 e += 1;
97
98 } else if (unhexchar(**p) >= 0) {
99 /* Hexadecimal escaping */
100 size_t allocated = 0;
101
102 l = strlen(field);
103 allocated = l + 2;
104 c = malloc(allocated);
105 if (!c)
106 return -ENOMEM;
107
108 memcpy(c, field, l);
109 for (e = *p; *e != ' ' && *e != 0; e += 2) {
110 int a, b;
111 uint8_t x;
112
113 a = unhexchar(e[0]);
114 if (a < 0)
115 return 0;
116
117 b = unhexchar(e[1]);
118 if (b < 0)
119 return 0;
120
121 x = ((uint8_t) a << 4 | (uint8_t) b);
122
123 if (filter_printable && x < (uint8_t) ' ')
124 x = (uint8_t) ' ';
125
126 if (!GREEDY_REALLOC(c, allocated, l+2))
127 return -ENOMEM;
128
129 c[l++] = (char) x;
130 }
131
132 c[l] = 0;
133 } else
134 return 0;
135
136 if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
137 return -ENOMEM;
138
139 (*iov)[*n_iov].iov_base = c;
140 (*iov)[*n_iov].iov_len = l;
141 (*n_iov) ++;
142
143 *p = e;
144 c = NULL;
145
146 return 1;
147 }
148
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);
151 }
152
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);
155 }
156
157 static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
158 const char *e, *f;
159 char *c, *t;
160 int r;
161
162 /* Implements fallback mappings for all fields we don't know */
163
164 for (e = *p; e < *p + 16; e++) {
165
166 if (*e == 0 || *e == ' ')
167 return 0;
168
169 if (*e == '=')
170 break;
171
172 if (!((*e >= 'a' && *e <= 'z') ||
173 (*e >= 'A' && *e <= 'Z') ||
174 (*e >= '0' && *e <= '9') ||
175 (*e == '_')))
176 return 0;
177 }
178
179 if (e <= *p || e >= *p + 16)
180 return 0;
181
182 c = alloca(strlen(prefix) + (e - *p) + 2);
183
184 t = stpcpy(c, prefix);
185 for (f = *p; f < e; f++)
186 *(t++) = *f >= 'a' && *f <= 'z' ? ((*f - 'a') + 'A') : *f;
187 strcpy(t, "=");
188
189 e ++;
190
191 r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov);
192 if (r < 0)
193 return r;
194
195 *p = e;
196 return r;
197 }
198
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[] = {
204
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 },
222
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 },
230 {}
231 };
232
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 },
242 {}
243 };
244
245 static int map_all_fields(
246 const char *p,
247 const MapField map_fields[],
248 const char *prefix,
249 bool handle_msg,
250 struct iovec **iov,
251 size_t *n_iov_allocated,
252 unsigned *n_iov) {
253
254 int r;
255
256 assert(p);
257 assert(iov);
258 assert(n_iov_allocated);
259 assert(n_iov);
260
261 for (;;) {
262 bool mapped = false;
263 const MapField *m;
264 const char *v;
265
266 p += strspn(p, WHITESPACE);
267
268 if (*p == 0)
269 return 0;
270
271 if (handle_msg) {
272 v = startswith(p, "msg='");
273 if (v) {
274 const char *e;
275 char *c;
276
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
283 kernel mapping. */
284
285 e = endswith(v, "'");
286 if (!e)
287 return 0; /* don't continue splitting up if the final quotation mark is missing */
288
289 c = strndupa(v, e - v);
290 return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iov, n_iov_allocated, n_iov);
291 }
292 }
293
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);
297 if (!v)
298 continue;
299
300 r = m->map(m->journal_field, &v, iov, n_iov_allocated, n_iov);
301 if (r < 0) {
302 log_debug("Failed to parse audit array: %s", strerror(-r));
303 return r;
304 }
305
306 if (r > 0) {
307 mapped = true;
308 p = v;
309 break;
310 }
311 }
312
313 if (!mapped) {
314 r = map_generic_field(prefix, &p, iov, n_iov_allocated, n_iov);
315 if (r < 0) {
316 log_debug("Failed to parse audit array: %s", strerror(-r));
317 return r;
318 }
319
320 if (r == 0) {
321 /* Couldn't process as generic field, let's just skip over it */
322 p += strcspn(p, WHITESPACE);
323 }
324 }
325 }
326 }
327
328 static void process_audit_string(Server *s, int type, const char *data, size_t size) {
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;
333 const char *p;
334 unsigned z;
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)];
338 const char *m;
339
340 assert(s);
341
342 if (size <= 0)
343 return;
344
345 if (!data)
346 return;
347
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))
351 return;
352
353 p = startswith(data, "audit");
354 if (!p)
355 return;
356
357 if (sscanf(p, "(%" PRIi64 ".%" PRIi64 ":%" PRIi64 "):%n",
358 &seconds,
359 &msec,
360 &id,
361 &k) != 3)
362 return;
363
364 p += k;
365 p += strspn(p, WHITESPACE);
366
367 if (isempty(p))
368 return;
369
370 n_iov_allocated = N_IOVEC_META_FIELDS + 5;
371 iov = new(struct iovec, n_iov_allocated);
372 if (!iov) {
373 log_oom();
374 return;
375 }
376
377 IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
378
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);
382
383 sprintf(type_field, "_AUDIT_TYPE=%i", type);
384 IOVEC_SET_STRING(iov[n_iov++], type_field);
385
386 sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
387 IOVEC_SET_STRING(iov[n_iov++], id_field);
388
389 m = strappenda("MESSAGE=audit: ", p);
390 IOVEC_SET_STRING(iov[n_iov++], m);
391
392 z = n_iov;
393
394 map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov_allocated, &n_iov);
395
396 if (!GREEDY_REALLOC(iov, n_iov_allocated, n_iov + N_IOVEC_META_FIELDS)) {
397 log_oom();
398 goto finish;
399 }
400
401 server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, NULL, NULL, 0, NULL, LOG_NOTICE, 0);
402
403 finish:
404 /* free() all entries that map_all_fields() added. All others
405 * are allocated on the stack or are constant. */
406
407 for (; z < n_iov; z++)
408 free(iov[z].iov_base);
409 }
410
411 void server_process_audit_message(
412 Server *s,
413 const void *buffer,
414 size_t buffer_size,
415 const struct ucred *ucred,
416 const union sockaddr_union *sa,
417 socklen_t salen) {
418
419 const struct nlmsghdr *nl = buffer;
420
421 assert(s);
422
423 if (buffer_size < ALIGN(sizeof(struct nlmsghdr)))
424 return;
425
426 assert(buffer);
427
428 /* Filter out fake data */
429 if (!sa ||
430 salen != sizeof(struct sockaddr_nl) ||
431 sa->nl.nl_family != AF_NETLINK ||
432 sa->nl.nl_pid != 0) {
433 log_debug("Audit netlink message from invalid sender.");
434 return;
435 }
436
437 if (!ucred || ucred->pid != 0) {
438 log_debug("Audit netlink message with invalid credentials.");
439 return;
440 }
441
442 if (!NLMSG_OK(nl, buffer_size)) {
443 log_error("Audit netlink message truncated.");
444 return;
445 }
446
447 /* Ignore special Netlink messages */
448 if (IN_SET(nl->nlmsg_type, NLMSG_NOOP, NLMSG_ERROR))
449 return;
450
451 /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
452 if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG)
453 return;
454
455 process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)));
456 }
457
458 static int enable_audit(int fd, bool b) {
459 struct {
460 union {
461 struct nlmsghdr header;
462 uint8_t header_space[NLMSG_HDRLEN];
463 };
464 struct audit_status body;
465 } _packed_ request = {
466 .header.nlmsg_len = NLMSG_LENGTH(sizeof(struct audit_status)),
467 .header.nlmsg_type = AUDIT_SET,
468 .header.nlmsg_flags = NLM_F_REQUEST,
469 .header.nlmsg_seq = 1,
470 .header.nlmsg_pid = 0,
471 .body.mask = AUDIT_STATUS_ENABLED,
472 .body.enabled = b,
473 };
474 union sockaddr_union sa = {
475 .nl.nl_family = AF_NETLINK,
476 .nl.nl_pid = 0,
477 };
478 struct iovec iovec = {
479 .iov_base = &request,
480 .iov_len = NLMSG_LENGTH(sizeof(struct audit_status)),
481 };
482 struct msghdr mh = {
483 .msg_iov = &iovec,
484 .msg_iovlen = 1,
485 .msg_name = &sa.sa,
486 .msg_namelen = sizeof(sa.nl),
487 };
488
489 ssize_t n;
490
491 n = sendmsg(fd, &mh, MSG_NOSIGNAL);
492 if (n < 0)
493 return -errno;
494 if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
495 return -EIO;
496
497 /* We don't wait for the result here, we can't do anything
498 * about it anyway */
499
500 return 0;
501 }
502
503 int server_open_audit(Server *s) {
504 static const int one = 1;
505 int r;
506
507 if (s->audit_fd < 0) {
508 static const union sockaddr_union sa = {
509 .nl.nl_family = AF_NETLINK,
510 .nl.nl_pid = 0,
511 .nl.nl_groups = AUDIT_NLGRP_READLOG,
512 };
513
514 s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
515 if (s->audit_fd < 0) {
516 if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
517 log_debug("Audit not supported in the kernel.");
518 else
519 log_warning("Failed to create audit socket, ignoring: %m");
520
521 return 0;
522 }
523
524 r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl));
525 if (r < 0) {
526 log_error("Failed to join audit multicast group: %m");
527 return -errno;
528 }
529 } else
530 fd_nonblock(s->audit_fd, 1);
531
532 r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
533 if (r < 0) {
534 log_error("Failed to set SO_PASSCRED on audit socket: %m");
535 return -errno;
536 }
537
538 r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, process_datagram, s);
539 if (r < 0) {
540 log_error("Failed to add audit fd to event loop: %s", strerror(-r));
541 return r;
542 }
543
544 /* We are listening now, try to enable audit */
545 r = enable_audit(s->audit_fd, true);
546 if (r < 0)
547 log_warning("Failed to issue audit enable call: %s", strerror(-r));
548
549 return 0;
550 }