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/>.
22 #include "alloc-util.h"
23 #include "audit-type.h"
25 #include "hexdecoct.h"
27 #include "journald-audit.h"
29 #include "string-util.h"
31 typedef struct MapField
{
32 const char *audit_field
;
33 const char *journal_field
;
34 int (*map
)(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
);
37 static int map_simple_field(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
) {
38 _cleanup_free_
char *c
= NULL
;
39 size_t l
= 0, allocated
= 0;
49 c
= malloc(allocated
);
54 for (e
= *p
; *e
!= ' ' && *e
!= 0; e
++) {
55 if (!GREEDY_REALLOC(c
, allocated
, l
+2))
63 if (!GREEDY_REALLOC(*iov
, *n_iov_allocated
, *n_iov
+ 1))
66 (*iov
)[*n_iov
].iov_base
= c
;
67 (*iov
)[*n_iov
].iov_len
= l
;
76 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
) {
77 _cleanup_free_
char *c
= NULL
;
86 /* The kernel formats string fields in one of two formats. */
89 /* Normal quoted syntax */
95 l
= strlen(field
) + (e
- s
);
100 *((char*) mempcpy(stpcpy(c
, field
), s
, e
- s
)) = 0;
104 } else if (unhexchar(**p
) >= 0) {
105 /* Hexadecimal escaping */
106 size_t allocated
= 0;
110 c
= malloc(allocated
);
115 for (e
= *p
; *e
!= ' ' && *e
!= 0; e
+= 2) {
127 x
= ((uint8_t) a
<< 4 | (uint8_t) b
);
129 if (filter_printable
&& x
< (uint8_t) ' ')
132 if (!GREEDY_REALLOC(c
, allocated
, l
+2))
142 if (!GREEDY_REALLOC(*iov
, *n_iov_allocated
, *n_iov
+ 1))
145 (*iov
)[*n_iov
].iov_base
= c
;
146 (*iov
)[*n_iov
].iov_len
= l
;
155 static int map_string_field(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
) {
156 return map_string_field_internal(field
, p
, iov
, n_iov_allocated
, n_iov
, false);
159 static int map_string_field_printable(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
) {
160 return map_string_field_internal(field
, p
, iov
, n_iov_allocated
, n_iov
, true);
163 static int map_generic_field(const char *prefix
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
) {
168 /* Implements fallback mappings for all fields we don't know */
170 for (e
= *p
; e
< *p
+ 16; e
++) {
172 if (*e
== 0 || *e
== ' ')
178 if (!((*e
>= 'a' && *e
<= 'z') ||
179 (*e
>= 'A' && *e
<= 'Z') ||
180 (*e
>= '0' && *e
<= '9') ||
181 *e
== '_' || *e
== '-'))
185 if (e
<= *p
|| e
>= *p
+ 16)
188 c
= alloca(strlen(prefix
) + (e
- *p
) + 2);
190 t
= stpcpy(c
, prefix
);
191 for (f
= *p
; f
< e
; f
++) {
194 if (*f
>= 'a' && *f
<= 'z')
195 x
= (*f
- 'a') + 'A'; /* uppercase */
197 x
= '_'; /* dashes → underscores */
207 r
= map_simple_field(c
, &e
, iov
, n_iov_allocated
, n_iov
);
215 /* Kernel fields are those occurring in the audit string before
216 * msg='. All of these fields are trusted, hence carry the "_" prefix.
217 * We try to translate the fields we know into our native names. The
218 * other's are generically mapped to _AUDIT_FIELD_XYZ= */
219 static const MapField map_fields_kernel
[] = {
221 /* First, we map certain well-known audit fields into native
222 * well-known fields */
223 { "pid=", "_PID=", map_simple_field
},
224 { "ppid=", "_PPID=", map_simple_field
},
225 { "uid=", "_UID=", map_simple_field
},
226 { "euid=", "_EUID=", map_simple_field
},
227 { "fsuid=", "_FSUID=", map_simple_field
},
228 { "gid=", "_GID=", map_simple_field
},
229 { "egid=", "_EGID=", map_simple_field
},
230 { "fsgid=", "_FSGID=", map_simple_field
},
231 { "tty=", "_TTY=", map_simple_field
},
232 { "ses=", "_AUDIT_SESSION=", map_simple_field
},
233 { "auid=", "_AUDIT_LOGINUID=", map_simple_field
},
234 { "subj=", "_SELINUX_CONTEXT=", map_simple_field
},
235 { "comm=", "_COMM=", map_string_field
},
236 { "exe=", "_EXE=", map_string_field
},
237 { "proctitle=", "_CMDLINE=", map_string_field_printable
},
239 /* Some fields don't map to native well-known fields. However,
240 * we know that they are string fields, hence let's undo
241 * string field escaping for them, though we stick to the
242 * generic field names. */
243 { "path=", "_AUDIT_FIELD_PATH=", map_string_field
},
244 { "dev=", "_AUDIT_FIELD_DEV=", map_string_field
},
245 { "name=", "_AUDIT_FIELD_NAME=", map_string_field
},
249 /* Userspace fields are those occurring in the audit string after
250 * msg='. All of these fields are untrusted, hence carry no "_"
251 * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
252 static const MapField map_fields_userspace
[] = {
253 { "cwd=", "AUDIT_FIELD_CWD=", map_string_field
},
254 { "cmd=", "AUDIT_FIELD_CMD=", map_string_field
},
255 { "acct=", "AUDIT_FIELD_ACCT=", map_string_field
},
256 { "exe=", "AUDIT_FIELD_EXE=", map_string_field
},
257 { "comm=", "AUDIT_FIELD_COMM=", map_string_field
},
261 static int map_all_fields(
263 const MapField map_fields
[],
267 size_t *n_iov_allocated
,
274 assert(n_iov_allocated
);
282 p
+= strspn(p
, WHITESPACE
);
288 v
= startswith(p
, "msg='");
293 /* Userspace message. It's enclosed in
294 simple quotation marks, is not
295 escaped, but the last field in the
296 line, hence let's remove the
297 quotation mark, and apply the
298 userspace mapping instead of the
301 e
= endswith(v
, "'");
303 return 0; /* don't continue splitting up if the final quotation mark is missing */
305 c
= strndupa(v
, e
- v
);
306 return map_all_fields(c
, map_fields_userspace
, "AUDIT_FIELD_", false, iov
, n_iov_allocated
, n_iov
);
310 /* Try to map the kernel fields to our own names */
311 for (m
= map_fields
; m
->audit_field
; m
++) {
312 v
= startswith(p
, m
->audit_field
);
316 r
= m
->map(m
->journal_field
, &v
, iov
, n_iov_allocated
, n_iov
);
318 return log_debug_errno(r
, "Failed to parse audit array: %m");
328 r
= map_generic_field(prefix
, &p
, iov
, n_iov_allocated
, n_iov
);
330 return log_debug_errno(r
, "Failed to parse audit array: %m");
333 /* Couldn't process as generic field, let's just skip over it */
334 p
+= strcspn(p
, WHITESPACE
);
339 static void process_audit_string(Server
*s
, int type
, const char *data
, size_t size
) {
340 _cleanup_free_
struct iovec
*iov
= NULL
;
341 size_t n_iov_allocated
= 0;
342 unsigned n_iov
= 0, k
;
343 uint64_t seconds
, msec
, id
;
344 const char *p
, *type_name
;
346 char id_field
[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
347 type_field
[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
348 source_time_field
[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t
)];
359 /* Note that the input buffer is NUL terminated, but let's
360 * check whether there is a spurious NUL byte */
361 if (memchr(data
, 0, size
))
364 p
= startswith(data
, "audit");
368 if (sscanf(p
, "(%" PRIu64
".%" PRIu64
":%" PRIu64
"):%n",
376 p
+= strspn(p
, WHITESPACE
);
381 n_iov_allocated
= N_IOVEC_META_FIELDS
+ 7;
382 iov
= new(struct iovec
, n_iov_allocated
);
388 IOVEC_SET_STRING(iov
[n_iov
++], "_TRANSPORT=audit");
390 sprintf(source_time_field
, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64
,
391 (usec_t
) seconds
* USEC_PER_SEC
+ (usec_t
) msec
* USEC_PER_MSEC
);
392 IOVEC_SET_STRING(iov
[n_iov
++], source_time_field
);
394 sprintf(type_field
, "_AUDIT_TYPE=%i", type
);
395 IOVEC_SET_STRING(iov
[n_iov
++], type_field
);
397 sprintf(id_field
, "_AUDIT_ID=%" PRIu64
, id
);
398 IOVEC_SET_STRING(iov
[n_iov
++], id_field
);
400 assert_cc(32 == LOG_AUTH
);
401 IOVEC_SET_STRING(iov
[n_iov
++], "SYSLOG_FACILITY=32");
402 IOVEC_SET_STRING(iov
[n_iov
++], "SYSLOG_IDENTIFIER=audit");
404 type_name
= audit_type_name_alloca(type
);
406 m
= strjoina("MESSAGE=", type_name
, " ", p
);
407 IOVEC_SET_STRING(iov
[n_iov
++], m
);
411 map_all_fields(p
, map_fields_kernel
, "_AUDIT_FIELD_", true, &iov
, &n_iov_allocated
, &n_iov
);
413 if (!GREEDY_REALLOC(iov
, n_iov_allocated
, n_iov
+ N_IOVEC_META_FIELDS
)) {
418 server_dispatch_message(s
, iov
, n_iov
, n_iov_allocated
, NULL
, NULL
, NULL
, 0, NULL
, LOG_NOTICE
, 0);
421 /* free() all entries that map_all_fields() added. All others
422 * are allocated on the stack or are constant. */
424 for (; z
< n_iov
; z
++)
425 free(iov
[z
].iov_base
);
428 void server_process_audit_message(
432 const struct ucred
*ucred
,
433 const union sockaddr_union
*sa
,
436 const struct nlmsghdr
*nl
= buffer
;
440 if (buffer_size
< ALIGN(sizeof(struct nlmsghdr
)))
445 /* Filter out fake data */
447 salen
!= sizeof(struct sockaddr_nl
) ||
448 sa
->nl
.nl_family
!= AF_NETLINK
||
449 sa
->nl
.nl_pid
!= 0) {
450 log_debug("Audit netlink message from invalid sender.");
454 if (!ucred
|| ucred
->pid
!= 0) {
455 log_debug("Audit netlink message with invalid credentials.");
459 if (!NLMSG_OK(nl
, buffer_size
)) {
460 log_error("Audit netlink message truncated.");
464 /* Ignore special Netlink messages */
465 if (IN_SET(nl
->nlmsg_type
, NLMSG_NOOP
, NLMSG_ERROR
))
468 /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
469 if (nl
->nlmsg_type
< AUDIT_FIRST_USER_MSG
)
472 process_audit_string(s
, nl
->nlmsg_type
, NLMSG_DATA(nl
), nl
->nlmsg_len
- ALIGN(sizeof(struct nlmsghdr
)));
475 static int enable_audit(int fd
, bool b
) {
478 struct nlmsghdr header
;
479 uint8_t header_space
[NLMSG_HDRLEN
];
481 struct audit_status body
;
482 } _packed_ request
= {
483 .header
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
484 .header
.nlmsg_type
= AUDIT_SET
,
485 .header
.nlmsg_flags
= NLM_F_REQUEST
,
486 .header
.nlmsg_seq
= 1,
487 .header
.nlmsg_pid
= 0,
488 .body
.mask
= AUDIT_STATUS_ENABLED
,
491 union sockaddr_union sa
= {
492 .nl
.nl_family
= AF_NETLINK
,
495 struct iovec iovec
= {
496 .iov_base
= &request
,
497 .iov_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
503 .msg_namelen
= sizeof(sa
.nl
),
508 n
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
511 if (n
!= NLMSG_LENGTH(sizeof(struct audit_status
)))
514 /* We don't wait for the result here, we can't do anything
520 int server_open_audit(Server
*s
) {
521 static const int one
= 1;
524 if (s
->audit_fd
< 0) {
525 static const union sockaddr_union sa
= {
526 .nl
.nl_family
= AF_NETLINK
,
528 .nl
.nl_groups
= AUDIT_NLGRP_READLOG
,
531 s
->audit_fd
= socket(AF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, NETLINK_AUDIT
);
532 if (s
->audit_fd
< 0) {
533 if (errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
)
534 log_debug("Audit not supported in the kernel.");
536 log_warning_errno(errno
, "Failed to create audit socket, ignoring: %m");
541 if (bind(s
->audit_fd
, &sa
.sa
, sizeof(sa
.nl
)) < 0) {
542 log_warning_errno(errno
,
543 "Failed to join audit multicast group. "
544 "The kernel is probably too old or multicast reading is not supported. "
546 s
->audit_fd
= safe_close(s
->audit_fd
);
550 fd_nonblock(s
->audit_fd
, 1);
552 r
= setsockopt(s
->audit_fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
));
554 return log_error_errno(errno
, "Failed to set SO_PASSCRED on audit socket: %m");
556 r
= sd_event_add_io(s
->event
, &s
->audit_event_source
, s
->audit_fd
, EPOLLIN
, server_process_datagram
, s
);
558 return log_error_errno(r
, "Failed to add audit fd to event loop: %m");
560 /* We are listening now, try to enable audit */
561 r
= enable_audit(s
->audit_fd
, true);
563 log_warning_errno(r
, "Failed to issue audit enable call: %m");