Line data Source code
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 0 : static int map_simple_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
33 0 : _cleanup_free_ char *c = NULL;
34 0 : size_t l = 0, allocated = 0;
35 : const char *e;
36 :
37 0 : assert(field);
38 0 : assert(p);
39 0 : assert(iov);
40 0 : assert(n_iov);
41 :
42 0 : l = strlen(field);
43 0 : allocated = l + 1;
44 0 : c = malloc(allocated);
45 0 : if (!c)
46 0 : return -ENOMEM;
47 :
48 0 : memcpy(c, field, l);
49 0 : for (e = *p; *e != ' ' && *e != 0; e++) {
50 0 : if (!GREEDY_REALLOC(c, allocated, l+2))
51 0 : return -ENOMEM;
52 :
53 0 : c[l++] = *e;
54 : }
55 :
56 0 : c[l] = 0;
57 :
58 0 : if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
59 0 : return -ENOMEM;
60 :
61 0 : (*iov)[*n_iov].iov_base = c;
62 0 : (*iov)[*n_iov].iov_len = l;
63 0 : (*n_iov) ++;
64 :
65 0 : *p = e;
66 0 : c = NULL;
67 :
68 0 : return 1;
69 : }
70 :
71 0 : 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 0 : _cleanup_free_ char *c = NULL;
73 : const char *s, *e;
74 : size_t l;
75 :
76 0 : assert(field);
77 0 : assert(p);
78 0 : assert(iov);
79 0 : assert(n_iov);
80 :
81 : /* The kernel formats string fields in one of two formats. */
82 :
83 0 : if (**p == '"') {
84 : /* Normal quoted syntax */
85 0 : s = *p + 1;
86 0 : e = strchr(s, '"');
87 0 : if (!e)
88 0 : return 0;
89 :
90 0 : l = strlen(field) + (e - s);
91 0 : c = malloc(l+1);
92 0 : if (!c)
93 0 : return -ENOMEM;
94 :
95 0 : *((char*) mempcpy(stpcpy(c, field), s, e - s)) = 0;
96 :
97 0 : e += 1;
98 :
99 0 : } else if (unhexchar(**p) >= 0) {
100 : /* Hexadecimal escaping */
101 0 : size_t allocated = 0;
102 :
103 0 : l = strlen(field);
104 0 : allocated = l + 2;
105 0 : c = malloc(allocated);
106 0 : if (!c)
107 0 : return -ENOMEM;
108 :
109 0 : memcpy(c, field, l);
110 0 : for (e = *p; *e != ' ' && *e != 0; e += 2) {
111 : int a, b;
112 : uint8_t x;
113 :
114 0 : a = unhexchar(e[0]);
115 0 : if (a < 0)
116 0 : return 0;
117 :
118 0 : b = unhexchar(e[1]);
119 0 : if (b < 0)
120 0 : return 0;
121 :
122 0 : x = ((uint8_t) a << 4 | (uint8_t) b);
123 :
124 0 : if (filter_printable && x < (uint8_t) ' ')
125 0 : x = (uint8_t) ' ';
126 :
127 0 : if (!GREEDY_REALLOC(c, allocated, l+2))
128 0 : return -ENOMEM;
129 :
130 0 : c[l++] = (char) x;
131 : }
132 :
133 0 : c[l] = 0;
134 : } else
135 0 : return 0;
136 :
137 0 : if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
138 0 : return -ENOMEM;
139 :
140 0 : (*iov)[*n_iov].iov_base = c;
141 0 : (*iov)[*n_iov].iov_len = l;
142 0 : (*n_iov) ++;
143 :
144 0 : *p = e;
145 0 : c = NULL;
146 :
147 0 : return 1;
148 : }
149 :
150 0 : static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
151 0 : return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, false);
152 : }
153 :
154 0 : static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
155 0 : return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, true);
156 : }
157 :
158 0 : 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 0 : for (e = *p; e < *p + 16; e++) {
166 :
167 0 : if (*e == 0 || *e == ' ')
168 0 : return 0;
169 :
170 0 : if (*e == '=')
171 0 : break;
172 :
173 0 : if (!((*e >= 'a' && *e <= 'z') ||
174 0 : (*e >= 'A' && *e <= 'Z') ||
175 0 : (*e >= '0' && *e <= '9') ||
176 0 : *e == '_' || *e == '-'))
177 0 : return 0;
178 : }
179 :
180 0 : if (e <= *p || e >= *p + 16)
181 0 : return 0;
182 :
183 0 : c = alloca(strlen(prefix) + (e - *p) + 2);
184 :
185 0 : t = stpcpy(c, prefix);
186 0 : for (f = *p; f < e; f++) {
187 : char x;
188 :
189 0 : if (*f >= 'a' && *f <= 'z')
190 0 : x = (*f - 'a') + 'A'; /* uppercase */
191 0 : else if (*f == '-')
192 0 : x = '_'; /* dashes → underscores */
193 : else
194 0 : x = *f;
195 :
196 0 : *(t++) = x;
197 : }
198 0 : strcpy(t, "=");
199 :
200 0 : e ++;
201 :
202 0 : r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov);
203 0 : if (r < 0)
204 0 : return r;
205 :
206 0 : *p = e;
207 0 : 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 0 : 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 0 : assert(p);
268 0 : assert(iov);
269 0 : assert(n_iov_allocated);
270 0 : assert(n_iov);
271 :
272 : for (;;) {
273 0 : bool mapped = false;
274 : const MapField *m;
275 : const char *v;
276 :
277 0 : p += strspn(p, WHITESPACE);
278 :
279 0 : if (*p == 0)
280 0 : return 0;
281 :
282 0 : if (handle_msg) {
283 0 : v = startswith(p, "msg='");
284 0 : 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 0 : e = endswith(v, "'");
297 0 : if (!e)
298 0 : return 0; /* don't continue splitting up if the final quotation mark is missing */
299 :
300 0 : c = strndupa(v, e - v);
301 0 : 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 0 : for (m = map_fields; m->audit_field; m++) {
307 0 : v = startswith(p, m->audit_field);
308 0 : if (!v)
309 0 : continue;
310 :
311 0 : r = m->map(m->journal_field, &v, iov, n_iov_allocated, n_iov);
312 0 : if (r < 0)
313 0 : return log_debug_errno(r, "Failed to parse audit array: %m");
314 :
315 0 : if (r > 0) {
316 0 : mapped = true;
317 0 : p = v;
318 0 : break;
319 : }
320 : }
321 :
322 0 : if (!mapped) {
323 0 : r = map_generic_field(prefix, &p, iov, n_iov_allocated, n_iov);
324 0 : if (r < 0)
325 0 : return log_debug_errno(r, "Failed to parse audit array: %m");
326 :
327 0 : if (r == 0) {
328 : /* Couldn't process as generic field, let's just skip over it */
329 0 : p += strcspn(p, WHITESPACE);
330 : }
331 : }
332 0 : }
333 : }
334 :
335 0 : static void process_audit_string(Server *s, int type, const char *data, size_t size) {
336 0 : _cleanup_free_ struct iovec *iov = NULL;
337 0 : size_t n_iov_allocated = 0;
338 0 : 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 0 : assert(s);
348 :
349 0 : if (size <= 0)
350 0 : return;
351 :
352 0 : if (!data)
353 0 : return;
354 :
355 : /* Note that the input buffer is NUL terminated, but let's
356 : * check whether there is a spurious NUL byte */
357 0 : if (memchr(data, 0, size))
358 0 : return;
359 :
360 0 : p = startswith(data, "audit");
361 0 : if (!p)
362 0 : return;
363 :
364 0 : if (sscanf(p, "(%" PRIu64 ".%" PRIu64 ":%" PRIu64 "):%n",
365 : &seconds,
366 : &msec,
367 : &id,
368 : &k) != 3)
369 0 : return;
370 :
371 0 : p += k;
372 0 : p += strspn(p, WHITESPACE);
373 :
374 0 : if (isempty(p))
375 0 : return;
376 :
377 0 : n_iov_allocated = N_IOVEC_META_FIELDS + 7;
378 0 : iov = new(struct iovec, n_iov_allocated);
379 0 : if (!iov) {
380 0 : log_oom();
381 0 : return;
382 : }
383 :
384 0 : IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
385 :
386 0 : sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64,
387 0 : (usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC);
388 0 : IOVEC_SET_STRING(iov[n_iov++], source_time_field);
389 :
390 0 : sprintf(type_field, "_AUDIT_TYPE=%i", type);
391 0 : IOVEC_SET_STRING(iov[n_iov++], type_field);
392 :
393 0 : sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
394 0 : IOVEC_SET_STRING(iov[n_iov++], id_field);
395 :
396 : assert_cc(32 == LOG_AUTH);
397 0 : IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=32");
398 0 : IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_IDENTIFIER=audit");
399 :
400 0 : type_name = audit_type_name_alloca(type);
401 :
402 0 : m = strjoina("MESSAGE=", type_name, " ", p);
403 0 : IOVEC_SET_STRING(iov[n_iov++], m);
404 :
405 0 : z = n_iov;
406 :
407 0 : map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov_allocated, &n_iov);
408 :
409 0 : if (!GREEDY_REALLOC(iov, n_iov_allocated, n_iov + N_IOVEC_META_FIELDS)) {
410 0 : log_oom();
411 0 : goto finish;
412 : }
413 :
414 0 : 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 0 : for (; z < n_iov; z++)
421 0 : free(iov[z].iov_base);
422 : }
423 :
424 0 : 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 0 : const struct nlmsghdr *nl = buffer;
433 :
434 0 : assert(s);
435 :
436 0 : if (buffer_size < ALIGN(sizeof(struct nlmsghdr)))
437 0 : return;
438 :
439 0 : assert(buffer);
440 :
441 : /* Filter out fake data */
442 0 : if (!sa ||
443 0 : salen != sizeof(struct sockaddr_nl) ||
444 0 : sa->nl.nl_family != AF_NETLINK ||
445 0 : sa->nl.nl_pid != 0) {
446 0 : log_debug("Audit netlink message from invalid sender.");
447 0 : return;
448 : }
449 :
450 0 : if (!ucred || ucred->pid != 0) {
451 0 : log_debug("Audit netlink message with invalid credentials.");
452 0 : return;
453 : }
454 :
455 0 : if (!NLMSG_OK(nl, buffer_size)) {
456 0 : log_error("Audit netlink message truncated.");
457 0 : return;
458 : }
459 :
460 : /* Ignore special Netlink messages */
461 0 : if (IN_SET(nl->nlmsg_type, NLMSG_NOOP, NLMSG_ERROR))
462 0 : return;
463 :
464 : /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
465 0 : if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG)
466 0 : return;
467 :
468 0 : process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)));
469 : }
470 :
471 0 : 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 0 : } _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 0 : union sockaddr_union sa = {
488 : .nl.nl_family = AF_NETLINK,
489 : .nl.nl_pid = 0,
490 : };
491 0 : struct iovec iovec = {
492 : .iov_base = &request,
493 : .iov_len = NLMSG_LENGTH(sizeof(struct audit_status)),
494 : };
495 0 : 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 0 : n = sendmsg(fd, &mh, MSG_NOSIGNAL);
505 0 : if (n < 0)
506 0 : return -errno;
507 0 : if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
508 0 : return -EIO;
509 :
510 : /* We don't wait for the result here, we can't do anything
511 : * about it anyway */
512 :
513 0 : return 0;
514 : }
515 :
516 0 : int server_open_audit(Server *s) {
517 : static const int one = 1;
518 : int r;
519 :
520 0 : 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 0 : s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
528 0 : if (s->audit_fd < 0) {
529 0 : if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
530 0 : log_debug("Audit not supported in the kernel.");
531 : else
532 0 : log_warning_errno(errno, "Failed to create audit socket, ignoring: %m");
533 :
534 0 : return 0;
535 : }
536 :
537 0 : if (bind(s->audit_fd, &sa.sa, sizeof(sa.nl)) < 0) {
538 0 : 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 0 : s->audit_fd = safe_close(s->audit_fd);
543 0 : return 0;
544 : }
545 : } else
546 0 : fd_nonblock(s->audit_fd, 1);
547 :
548 0 : r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
549 0 : if (r < 0)
550 0 : return log_error_errno(errno, "Failed to set SO_PASSCRED on audit socket: %m");
551 :
552 0 : r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, server_process_datagram, s);
553 0 : if (r < 0)
554 0 : 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 0 : r = enable_audit(s->audit_fd, true);
558 0 : if (r < 0)
559 0 : log_warning_errno(r, "Failed to issue audit enable call: %m");
560 :
561 0 : return 0;
562 : }
|