1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
6 #include "audit-type.h"
7 #include "errno-util.h"
11 #include "journald-audit.h"
12 #include "missing_audit.h"
13 #include "string-util.h"
15 typedef struct MapField
{
16 const char *audit_field
;
17 const char *journal_field
;
18 int (*map
)(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov
);
21 static int map_simple_field(
27 _cleanup_free_
char *c
= NULL
;
42 for (e
= *p
; !IN_SET(*e
, 0, ' '); e
++) {
43 if (!GREEDY_REALLOC(c
, l
+2))
51 if (!GREEDY_REALLOC(*iov
, *n_iov
+ 1))
54 (*iov
)[(*n_iov
)++] = IOVEC_MAKE(c
, l
);
62 static int map_string_field_internal(
67 bool filter_printable
) {
69 _cleanup_free_
char *c
= NULL
;
78 /* The kernel formats string fields in one of two formats. */
81 /* Normal quoted syntax */
87 l
= strlen(field
) + (e
- s
);
92 *((char*) mempcpy(stpcpy(c
, field
), s
, e
- s
)) = 0;
96 } else if (unhexchar(**p
) >= 0) {
97 /* Hexadecimal escaping */
104 for (e
= *p
; !IN_SET(*e
, 0, ' '); e
+= 2) {
116 x
= ((uint8_t) a
<< 4 | (uint8_t) b
);
118 if (filter_printable
&& x
< (uint8_t) ' ')
121 if (!GREEDY_REALLOC(c
, l
+2))
131 if (!GREEDY_REALLOC(*iov
, *n_iov
+ 1))
134 (*iov
)[(*n_iov
)++] = IOVEC_MAKE(c
, l
);
142 static int map_string_field(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov
) {
143 return map_string_field_internal(field
, p
, iov
, n_iov
, false);
146 static int map_string_field_printable(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov
) {
147 return map_string_field_internal(field
, p
, iov
, n_iov
, true);
150 static int map_generic_field(
160 /* Implements fallback mappings for all fields we don't know */
162 for (e
= *p
; e
< *p
+ 16; e
++) {
164 if (IN_SET(*e
, 0, ' '))
170 if (!((*e
>= 'a' && *e
<= 'z') ||
171 (*e
>= 'A' && *e
<= 'Z') ||
172 (*e
>= '0' && *e
<= '9') ||
173 IN_SET(*e
, '_', '-')))
177 if (e
<= *p
|| e
>= *p
+ 16)
180 c
= newa(char, strlen(prefix
) + (e
- *p
) + 2);
182 t
= stpcpy(c
, prefix
);
183 for (f
= *p
; f
< e
; f
++) {
186 if (*f
>= 'a' && *f
<= 'z')
187 x
= (*f
- 'a') + 'A'; /* uppercase */
189 x
= '_'; /* dashes → underscores */
199 r
= map_simple_field(c
, &e
, iov
, n_iov
);
207 /* Kernel fields are those occurring in the audit string before
208 * msg='. All of these fields are trusted, hence carry the "_" prefix.
209 * We try to translate the fields we know into our native names. The
210 * other's are generically mapped to _AUDIT_FIELD_XYZ= */
211 static const MapField map_fields_kernel
[] = {
213 /* First, we map certain well-known audit fields into native
214 * well-known fields */
215 { "pid=", "_PID=", map_simple_field
},
216 { "ppid=", "_PPID=", map_simple_field
},
217 { "uid=", "_UID=", map_simple_field
},
218 { "euid=", "_EUID=", map_simple_field
},
219 { "fsuid=", "_FSUID=", map_simple_field
},
220 { "gid=", "_GID=", map_simple_field
},
221 { "egid=", "_EGID=", map_simple_field
},
222 { "fsgid=", "_FSGID=", map_simple_field
},
223 { "tty=", "_TTY=", map_simple_field
},
224 { "ses=", "_AUDIT_SESSION=", map_simple_field
},
225 { "auid=", "_AUDIT_LOGINUID=", map_simple_field
},
226 { "subj=", "_SELINUX_CONTEXT=", map_simple_field
},
227 { "comm=", "_COMM=", map_string_field
},
228 { "exe=", "_EXE=", map_string_field
},
229 { "proctitle=", "_CMDLINE=", map_string_field_printable
},
231 /* Some fields don't map to native well-known fields. However,
232 * we know that they are string fields, hence let's undo
233 * string field escaping for them, though we stick to the
234 * generic field names. */
235 { "path=", "_AUDIT_FIELD_PATH=", map_string_field
},
236 { "dev=", "_AUDIT_FIELD_DEV=", map_string_field
},
237 { "name=", "_AUDIT_FIELD_NAME=", map_string_field
},
241 /* Userspace fields are those occurring in the audit string after
242 * msg='. All of these fields are untrusted, hence carry no "_"
243 * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
244 static const MapField map_fields_userspace
[] = {
245 { "cwd=", "AUDIT_FIELD_CWD=", map_string_field
},
246 { "cmd=", "AUDIT_FIELD_CMD=", map_string_field
},
247 { "acct=", "AUDIT_FIELD_ACCT=", map_string_field
},
248 { "exe=", "AUDIT_FIELD_EXE=", map_string_field
},
249 { "comm=", "AUDIT_FIELD_COMM=", map_string_field
},
253 static int map_all_fields(
255 const MapField map_fields
[],
272 p
+= strspn(p
, WHITESPACE
);
278 v
= startswith(p
, "msg='");
280 _cleanup_free_
char *c
= NULL
;
283 /* Userspace message. It's enclosed in
284 simple quotation marks, is not
285 escaped, but the last field in the
286 line, hence let's remove the
287 quotation mark, and apply the
288 userspace mapping instead of the
291 e
= endswith(v
, "'");
293 return 0; /* don't continue splitting up if the final quotation mark is missing */
295 c
= strndup(v
, e
- v
);
299 return map_all_fields(c
, map_fields_userspace
, "AUDIT_FIELD_", false, iov
, n_iov
);
303 /* Try to map the kernel fields to our own names */
304 for (m
= map_fields
; m
->audit_field
; m
++) {
305 v
= startswith(p
, m
->audit_field
);
309 r
= m
->map(m
->journal_field
, &v
, iov
, n_iov
);
311 return log_debug_errno(r
, "Failed to parse audit array: %m");
321 r
= map_generic_field(prefix
, &p
, iov
, n_iov
);
323 return log_debug_errno(r
, "Failed to parse audit array: %m");
326 /* Couldn't process as generic field, let's just skip over it */
327 p
+= strcspn(p
, WHITESPACE
);
332 void process_audit_string(Server
*s
, int type
, const char *data
, size_t size
) {
334 _cleanup_free_
struct iovec
*iov
= NULL
;
335 uint64_t seconds
, msec
, id
;
336 const char *p
, *type_name
;
337 char id_field
[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
338 type_field
[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
339 source_time_field
[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t
)];
340 char *m
, *type_field_name
;
351 /* Note that the input buffer is NUL terminated, but let's
352 * check whether there is a spurious NUL byte */
353 if (memchr(data
, 0, size
))
356 p
= startswith(data
, "audit");
361 if (sscanf(p
, "(%" PRIu64
".%" PRIu64
":%" PRIu64
"):%n",
369 p
+= strspn(p
, WHITESPACE
);
374 iov
= new(struct iovec
, N_IOVEC_META_FIELDS
+ 8);
380 iov
[n_iov
++] = IOVEC_MAKE_STRING("_TRANSPORT=audit");
382 sprintf(source_time_field
, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64
,
383 (usec_t
) seconds
* USEC_PER_SEC
+ (usec_t
) msec
* USEC_PER_MSEC
);
384 iov
[n_iov
++] = IOVEC_MAKE_STRING(source_time_field
);
386 sprintf(type_field
, "_AUDIT_TYPE=%i", type
);
387 iov
[n_iov
++] = IOVEC_MAKE_STRING(type_field
);
389 sprintf(id_field
, "_AUDIT_ID=%" PRIu64
, id
);
390 iov
[n_iov
++] = IOVEC_MAKE_STRING(id_field
);
392 assert_cc(4 == LOG_FAC(LOG_AUTH
));
393 iov
[n_iov
++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=4");
394 iov
[n_iov
++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=audit");
396 type_name
= audit_type_name_alloca(type
);
398 type_field_name
= strjoina("_AUDIT_TYPE_NAME=", type_name
);
399 iov
[n_iov
++] = IOVEC_MAKE_STRING(type_field_name
);
401 m
= strjoina("MESSAGE=", type_name
, " ", p
);
402 iov
[n_iov
++] = IOVEC_MAKE_STRING(m
);
406 map_all_fields(p
, map_fields_kernel
, "_AUDIT_FIELD_", true, &iov
, &n_iov
);
408 if (!GREEDY_REALLOC(iov
, n_iov
+ N_IOVEC_META_FIELDS
)) {
413 server_dispatch_message(s
, iov
, n_iov
, MALLOC_ELEMENTSOF(iov
), NULL
, NULL
, LOG_NOTICE
, 0);
416 /* free() all entries that map_all_fields() added. All others
417 * are allocated on the stack or are constant. */
419 for (; z
< n_iov
; z
++)
420 free(iov
[z
].iov_base
);
423 void server_process_audit_message(
427 const struct ucred
*ucred
,
428 const union sockaddr_union
*sa
,
431 const struct nlmsghdr
*nl
= buffer
;
435 if (buffer_size
< ALIGN(sizeof(struct nlmsghdr
)))
440 /* Filter out fake data */
442 salen
!= sizeof(struct sockaddr_nl
) ||
443 sa
->nl
.nl_family
!= AF_NETLINK
||
444 sa
->nl
.nl_pid
!= 0) {
445 log_debug("Audit netlink message from invalid sender.");
449 if (!ucred
|| ucred
->pid
!= 0) {
450 log_debug("Audit netlink message with invalid credentials.");
454 if (!NLMSG_OK(nl
, buffer_size
)) {
455 log_error("Audit netlink message truncated.");
459 /* Ignore special Netlink messages */
460 if (IN_SET(nl
->nlmsg_type
, NLMSG_NOOP
, NLMSG_ERROR
))
463 /* Except AUDIT_USER, all messages below AUDIT_FIRST_USER_MSG are control messages, let's ignore those */
464 if (nl
->nlmsg_type
< AUDIT_FIRST_USER_MSG
&& nl
->nlmsg_type
!= AUDIT_USER
)
467 process_audit_string(s
, nl
->nlmsg_type
, NLMSG_DATA(nl
), nl
->nlmsg_len
- ALIGN(sizeof(struct nlmsghdr
)));
470 static int enable_audit(int fd
, bool b
) {
473 struct nlmsghdr header
;
474 uint8_t header_space
[NLMSG_HDRLEN
];
476 struct audit_status body
;
477 } _packed_ request
= {
478 .header
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
479 .header
.nlmsg_type
= AUDIT_SET
,
480 .header
.nlmsg_flags
= NLM_F_REQUEST
,
481 .header
.nlmsg_seq
= 1,
482 .header
.nlmsg_pid
= 0,
483 .body
.mask
= AUDIT_STATUS_ENABLED
,
486 union sockaddr_union sa
= {
487 .nl
.nl_family
= AF_NETLINK
,
490 struct iovec iovec
= {
491 .iov_base
= &request
,
492 .iov_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
498 .msg_namelen
= sizeof(sa
.nl
),
503 n
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
506 if (n
!= NLMSG_LENGTH(sizeof(struct audit_status
)))
509 /* We don't wait for the result here, we can't do anything
515 int server_open_audit(Server
*s
) {
518 if (s
->audit_fd
< 0) {
519 static const union sockaddr_union sa
= {
520 .nl
.nl_family
= AF_NETLINK
,
522 .nl
.nl_groups
= AUDIT_NLGRP_READLOG
,
525 s
->audit_fd
= socket(AF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, NETLINK_AUDIT
);
526 if (s
->audit_fd
< 0) {
527 if (ERRNO_IS_NOT_SUPPORTED(errno
))
528 log_debug("Audit not supported in the kernel.");
530 log_warning_errno(errno
, "Failed to create audit socket, ignoring: %m");
535 if (bind(s
->audit_fd
, &sa
.sa
, sizeof(sa
.nl
)) < 0) {
536 log_warning_errno(errno
,
537 "Failed to join audit multicast group. "
538 "The kernel is probably too old or multicast reading is not supported. "
540 s
->audit_fd
= safe_close(s
->audit_fd
);
544 (void) fd_nonblock(s
->audit_fd
, true);
546 r
= setsockopt_int(s
->audit_fd
, SOL_SOCKET
, SO_PASSCRED
, true);
548 return log_error_errno(r
, "Failed to set SO_PASSCRED on audit socket: %m");
550 r
= sd_event_add_io(s
->event
, &s
->audit_event_source
, s
->audit_fd
, EPOLLIN
, server_process_datagram
, s
);
552 return log_error_errno(r
, "Failed to add audit fd to event loop: %m");
554 if (s
->set_audit
>= 0) {
555 /* We are listening now, try to enable audit if configured so */
556 r
= enable_audit(s
->audit_fd
, s
->set_audit
);
558 log_warning_errno(r
, "Failed to issue audit enable call: %m");
559 else if (s
->set_audit
> 0)
560 log_debug("Auditing in kernel turned on.");
562 log_debug("Auditing in kernel turned off.");