]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journald-audit.c
Merge pull request #4 from systemd-mailing-devs/1431989131-25145-1-git-send-email...
[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
335 static void process_audit_string(Server *s, int type, const char *data, size_t size) {
336 _cleanup_free_ struct iovec *iov = NULL;
337 size_t n_iov_allocated = 0;
338 unsigned n_iov = 0, k;
339 uint64_t seconds, msec, id;
340 const char *p, *type_name;
341 unsigned z;
342 char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
343 type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
344 source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
345 char *m;
346
347 assert(s);
348
349 if (size <= 0)
350 return;
351
352 if (!data)
353 return;
354
355 /* Note that the input buffer is NUL terminated, but let's
356 * check whether there is a spurious NUL byte */
357 if (memchr(data, 0, size))
358 return;
359
360 p = startswith(data, "audit");
361 if (!p)
362 return;
363
364 if (sscanf(p, "(%" PRIu64 ".%" PRIu64 ":%" PRIu64 "):%n",
365 &seconds,
366 &msec,
367 &id,
368 &k) != 3)
369 return;
370
371 p += k;
372 p += strspn(p, WHITESPACE);
373
374 if (isempty(p))
375 return;
376
377 n_iov_allocated = N_IOVEC_META_FIELDS + 7;
378 iov = new(struct iovec, n_iov_allocated);
379 if (!iov) {
380 log_oom();
381 return;
382 }
383
384 IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
385
386 sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64,
387 (usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC);
388 IOVEC_SET_STRING(iov[n_iov++], source_time_field);
389
390 sprintf(type_field, "_AUDIT_TYPE=%i", type);
391 IOVEC_SET_STRING(iov[n_iov++], type_field);
392
393 sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
394 IOVEC_SET_STRING(iov[n_iov++], id_field);
395
396 assert_cc(32 == LOG_AUTH);
397 IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=32");
398 IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_IDENTIFIER=audit");
399
400 type_name = audit_type_name_alloca(type);
401
402 m = strjoina("MESSAGE=", type_name, " ", p);
403 IOVEC_SET_STRING(iov[n_iov++], m);
404
405 z = n_iov;
406
407 map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov_allocated, &n_iov);
408
409 if (!GREEDY_REALLOC(iov, n_iov_allocated, n_iov + N_IOVEC_META_FIELDS)) {
410 log_oom();
411 goto finish;
412 }
413
414 server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, NULL, NULL, 0, NULL, LOG_NOTICE, 0);
415
416 finish:
417 /* free() all entries that map_all_fields() added. All others
418 * are allocated on the stack or are constant. */
419
420 for (; z < n_iov; z++)
421 free(iov[z].iov_base);
422 }
423
424 void server_process_audit_message(
425 Server *s,
426 const void *buffer,
427 size_t buffer_size,
428 const struct ucred *ucred,
429 const union sockaddr_union *sa,
430 socklen_t salen) {
431
432 const struct nlmsghdr *nl = buffer;
433
434 assert(s);
435
436 if (buffer_size < ALIGN(sizeof(struct nlmsghdr)))
437 return;
438
439 assert(buffer);
440
441 /* Filter out fake data */
442 if (!sa ||
443 salen != sizeof(struct sockaddr_nl) ||
444 sa->nl.nl_family != AF_NETLINK ||
445 sa->nl.nl_pid != 0) {
446 log_debug("Audit netlink message from invalid sender.");
447 return;
448 }
449
450 if (!ucred || ucred->pid != 0) {
451 log_debug("Audit netlink message with invalid credentials.");
452 return;
453 }
454
455 if (!NLMSG_OK(nl, buffer_size)) {
456 log_error("Audit netlink message truncated.");
457 return;
458 }
459
460 /* Ignore special Netlink messages */
461 if (IN_SET(nl->nlmsg_type, NLMSG_NOOP, NLMSG_ERROR))
462 return;
463
464 /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
465 if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG)
466 return;
467
468 process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)));
469 }
470
471 static int enable_audit(int fd, bool b) {
472 struct {
473 union {
474 struct nlmsghdr header;
475 uint8_t header_space[NLMSG_HDRLEN];
476 };
477 struct audit_status body;
478 } _packed_ request = {
479 .header.nlmsg_len = NLMSG_LENGTH(sizeof(struct audit_status)),
480 .header.nlmsg_type = AUDIT_SET,
481 .header.nlmsg_flags = NLM_F_REQUEST,
482 .header.nlmsg_seq = 1,
483 .header.nlmsg_pid = 0,
484 .body.mask = AUDIT_STATUS_ENABLED,
485 .body.enabled = b,
486 };
487 union sockaddr_union sa = {
488 .nl.nl_family = AF_NETLINK,
489 .nl.nl_pid = 0,
490 };
491 struct iovec iovec = {
492 .iov_base = &request,
493 .iov_len = NLMSG_LENGTH(sizeof(struct audit_status)),
494 };
495 struct msghdr mh = {
496 .msg_iov = &iovec,
497 .msg_iovlen = 1,
498 .msg_name = &sa.sa,
499 .msg_namelen = sizeof(sa.nl),
500 };
501
502 ssize_t n;
503
504 n = sendmsg(fd, &mh, MSG_NOSIGNAL);
505 if (n < 0)
506 return -errno;
507 if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
508 return -EIO;
509
510 /* We don't wait for the result here, we can't do anything
511 * about it anyway */
512
513 return 0;
514 }
515
516 int server_open_audit(Server *s) {
517 static const int one = 1;
518 int r;
519
520 if (s->audit_fd < 0) {
521 static const union sockaddr_union sa = {
522 .nl.nl_family = AF_NETLINK,
523 .nl.nl_pid = 0,
524 .nl.nl_groups = AUDIT_NLGRP_READLOG,
525 };
526
527 s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
528 if (s->audit_fd < 0) {
529 if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
530 log_debug("Audit not supported in the kernel.");
531 else
532 log_warning_errno(errno, "Failed to create audit socket, ignoring: %m");
533
534 return 0;
535 }
536
537 if (bind(s->audit_fd, &sa.sa, sizeof(sa.nl)) < 0) {
538 log_warning_errno(errno,
539 "Failed to join audit multicast group. "
540 "The kernel is probably too old or multicast reading is not supported. "
541 "Ignoring: %m");
542 s->audit_fd = safe_close(s->audit_fd);
543 return 0;
544 }
545 } else
546 fd_nonblock(s->audit_fd, 1);
547
548 r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
549 if (r < 0)
550 return log_error_errno(errno, "Failed to set SO_PASSCRED on audit socket: %m");
551
552 r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, server_process_datagram, s);
553 if (r < 0)
554 return log_error_errno(r, "Failed to add audit fd to event loop: %m");
555
556 /* We are listening now, try to enable audit */
557 r = enable_audit(s->audit_fd, true);
558 if (r < 0)
559 log_warning_errno(r, "Failed to issue audit enable call: %m");
560
561 return 0;
562 }