1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
6 #include "audit-type.h"
7 #include "errno-util.h"
10 #include "iovec-util.h"
11 #include "journal-internal.h"
12 #include "journald-audit.h"
13 #include "missing_audit.h"
14 #include "string-util.h"
16 typedef struct MapField
{
17 const char *audit_field
;
18 const char *journal_field
;
19 int (*map
)(const char *field
, const char **p
, struct iovec
*iovec
, size_t *n
);
22 static int map_simple_field(
28 _cleanup_free_
char *c
= NULL
;
43 for (e
= *p
; !IN_SET(*e
, 0, ' '); e
++) {
44 if (!GREEDY_REALLOC(c
, l
+2))
52 iovec
[(*n
)++] = IOVEC_MAKE(c
, l
);
60 static int map_string_field_internal(
65 bool filter_printable
) {
67 _cleanup_free_
char *c
= NULL
;
76 /* The kernel formats string fields in one of two formats. */
79 /* Normal quoted syntax */
85 l
= strlen(field
) + (e
- s
);
90 *((char*) mempcpy(stpcpy(c
, field
), s
, e
- s
)) = 0;
94 } else if (unhexchar(**p
) >= 0) {
95 /* Hexadecimal escaping */
102 for (e
= *p
; !IN_SET(*e
, 0, ' '); e
+= 2) {
114 x
= ((uint8_t) a
<< 4 | (uint8_t) b
);
116 if (filter_printable
&& x
< (uint8_t) ' ')
119 if (!GREEDY_REALLOC(c
, l
+2))
129 iovec
[(*n
)++] = IOVEC_MAKE(c
, l
);
137 static int map_string_field(const char *field
, const char **p
, struct iovec
*iovec
, size_t *n
) {
138 return map_string_field_internal(field
, p
, iovec
, n
, false);
141 static int map_string_field_printable(const char *field
, const char **p
, struct iovec
*iovec
, size_t *n
) {
142 return map_string_field_internal(field
, p
, iovec
, n
, true);
145 static int map_generic_field(
155 /* Implements fallback mappings for all fields we don't know */
157 for (e
= *p
; e
< *p
+ 16; e
++) {
159 if (IN_SET(*e
, 0, ' '))
165 if (!(ascii_isalpha(*e
) ||
167 IN_SET(*e
, '_', '-')))
171 if (e
<= *p
|| e
>= *p
+ 16)
174 c
= newa(char, strlen(prefix
) + (e
- *p
) + 2);
176 t
= stpcpy(c
, prefix
);
177 for (f
= *p
; f
< e
; f
++) {
180 if (*f
>= 'a' && *f
<= 'z')
181 x
= (*f
- 'a') + 'A'; /* uppercase */
183 x
= '_'; /* dashes → underscores */
193 r
= map_simple_field(c
, &e
, iovec
, n
);
201 /* Kernel fields are those occurring in the audit string before
202 * msg='. All of these fields are trusted, hence carry the "_" prefix.
203 * We try to translate the fields we know into our native names. The
204 * other's are generically mapped to _AUDIT_FIELD_XYZ= */
205 static const MapField map_fields_kernel
[] = {
207 /* First, we map certain well-known audit fields into native
208 * well-known fields */
209 { "pid=", "_PID=", map_simple_field
},
210 { "ppid=", "_PPID=", map_simple_field
},
211 { "uid=", "_UID=", map_simple_field
},
212 { "euid=", "_EUID=", map_simple_field
},
213 { "fsuid=", "_FSUID=", map_simple_field
},
214 { "gid=", "_GID=", map_simple_field
},
215 { "egid=", "_EGID=", map_simple_field
},
216 { "fsgid=", "_FSGID=", map_simple_field
},
217 { "tty=", "_TTY=", map_simple_field
},
218 { "ses=", "_AUDIT_SESSION=", map_simple_field
},
219 { "auid=", "_AUDIT_LOGINUID=", map_simple_field
},
220 { "subj=", "_SELINUX_CONTEXT=", map_simple_field
},
221 { "comm=", "_COMM=", map_string_field
},
222 { "exe=", "_EXE=", map_string_field
},
223 { "proctitle=", "_CMDLINE=", map_string_field_printable
},
225 /* Some fields don't map to native well-known fields. However,
226 * we know that they are string fields, hence let's undo
227 * string field escaping for them, though we stick to the
228 * generic field names. */
229 { "path=", "_AUDIT_FIELD_PATH=", map_string_field
},
230 { "dev=", "_AUDIT_FIELD_DEV=", map_string_field
},
231 { "name=", "_AUDIT_FIELD_NAME=", map_string_field
},
235 /* Userspace fields are those occurring in the audit string after
236 * msg='. All of these fields are untrusted, hence carry no "_"
237 * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
238 static const MapField map_fields_userspace
[] = {
239 { "cwd=", "AUDIT_FIELD_CWD=", map_string_field
},
240 { "cmd=", "AUDIT_FIELD_CMD=", map_string_field
},
241 { "acct=", "AUDIT_FIELD_ACCT=", map_string_field
},
242 { "exe=", "AUDIT_FIELD_EXE=", map_string_field
},
243 { "comm=", "AUDIT_FIELD_COMM=", map_string_field
},
247 static int map_all_fields(
249 const MapField map_fields
[],
269 "More fields in audit message than audit field limit (%i), skipping remaining fields",
270 N_IOVEC_AUDIT_FIELDS
);
274 p
+= strspn(p
, WHITESPACE
);
280 v
= startswith(p
, "msg='");
282 _cleanup_free_
char *c
= NULL
;
285 /* Userspace message. It's enclosed in
286 simple quotation marks, is not
287 escaped, but the last field in the
288 line, hence let's remove the
289 quotation mark, and apply the
290 userspace mapping instead of the
293 e
= endswith(v
, "'");
295 return 0; /* don't continue splitting up if the final quotation mark is missing */
297 c
= strndup(v
, e
- v
);
301 return map_all_fields(c
, map_fields_userspace
, "AUDIT_FIELD_", false, iovec
, n
, m
);
305 /* Try to map the kernel fields to our own names */
306 for (mf
= map_fields
; mf
->audit_field
; mf
++) {
307 v
= startswith(p
, mf
->audit_field
);
311 r
= mf
->map(mf
->journal_field
, &v
, iovec
, n
);
313 return log_debug_errno(r
, "Failed to parse audit array: %m");
323 r
= map_generic_field(prefix
, &p
, iovec
, n
);
325 return log_debug_errno(r
, "Failed to parse audit array: %m");
328 /* Couldn't process as generic field, let's just skip over it */
329 p
+= strcspn(p
, WHITESPACE
);
334 void process_audit_string(Server
*s
, int type
, const char *data
, size_t size
) {
336 uint64_t seconds
, msec
, id
;
337 const char *p
, *type_name
;
338 char id_field
[STRLEN("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
339 type_field
[STRLEN("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)];
340 struct iovec iovec
[N_IOVEC_META_FIELDS
+ 7 + N_IOVEC_AUDIT_FIELDS
];
341 char *m
, *type_field_name
;
352 /* Note that the input buffer is NUL terminated, but let's
353 * check whether there is a spurious NUL byte */
354 if (memchr(data
, 0, size
))
357 p
= startswith(data
, "audit");
362 if (sscanf(p
, "(%" PRIu64
".%" PRIu64
":%" PRIu64
"):%n",
370 p
+= strspn(p
, WHITESPACE
);
375 iovec
[n
++] = IOVEC_MAKE_STRING("_TRANSPORT=audit");
377 xsprintf(type_field
, "_AUDIT_TYPE=%i", type
);
378 iovec
[n
++] = IOVEC_MAKE_STRING(type_field
);
380 xsprintf(id_field
, "_AUDIT_ID=%" PRIu64
, id
);
381 iovec
[n
++] = IOVEC_MAKE_STRING(id_field
);
383 assert_cc(4 == LOG_FAC(LOG_AUTH
));
384 iovec
[n
++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=4");
385 iovec
[n
++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=audit");
387 type_name
= audit_type_name_alloca(type
);
389 type_field_name
= strjoina("_AUDIT_TYPE_NAME=", type_name
);
390 iovec
[n
++] = IOVEC_MAKE_STRING(type_field_name
);
392 m
= strjoina("MESSAGE=", type_name
, " ", p
);
393 iovec
[n
++] = IOVEC_MAKE_STRING(m
);
397 map_all_fields(p
, map_fields_kernel
, "_AUDIT_FIELD_", true, iovec
, &n
, n
+ N_IOVEC_AUDIT_FIELDS
);
399 server_dispatch_message(s
, iovec
, n
, ELEMENTSOF(iovec
), NULL
,
400 TIMEVAL_STORE((usec_t
) seconds
* USEC_PER_SEC
+ (usec_t
) msec
* USEC_PER_MSEC
),
403 /* free() all entries that map_all_fields() added. All others
404 * are allocated on the stack or are constant. */
407 free(iovec
[z
].iov_base
);
410 void server_process_audit_message(
414 const struct ucred
*ucred
,
415 const union sockaddr_union
*sa
,
418 const struct nlmsghdr
*nl
= buffer
;
422 if (buffer_size
< ALIGN(sizeof(struct nlmsghdr
)))
427 /* Filter out fake data */
429 salen
!= sizeof(struct sockaddr_nl
) ||
430 sa
->nl
.nl_family
!= AF_NETLINK
||
431 sa
->nl
.nl_pid
!= 0) {
432 log_debug("Audit netlink message from invalid sender.");
436 if (!ucred
|| ucred
->pid
!= 0) {
437 log_debug("Audit netlink message with invalid credentials.");
441 if (!NLMSG_OK(nl
, buffer_size
)) {
442 log_ratelimit_error(JOURNAL_LOG_RATELIMIT
, "Audit netlink message truncated.");
446 /* Ignore special Netlink messages */
447 if (IN_SET(nl
->nlmsg_type
, NLMSG_NOOP
, NLMSG_ERROR
))
450 /* Except AUDIT_USER, all messages below AUDIT_FIRST_USER_MSG are control messages, let's ignore those */
451 if (nl
->nlmsg_type
< AUDIT_FIRST_USER_MSG
&& nl
->nlmsg_type
!= AUDIT_USER
)
454 process_audit_string(s
, nl
->nlmsg_type
, NLMSG_DATA(nl
), nl
->nlmsg_len
- ALIGN(sizeof(struct nlmsghdr
)));
457 static int enable_audit(int fd
, bool b
) {
460 struct nlmsghdr header
;
461 uint8_t header_space
[NLMSG_HDRLEN
];
463 struct audit_status body
;
464 } _packed_ request
= {
465 .header
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
466 .header
.nlmsg_type
= AUDIT_SET
,
467 .header
.nlmsg_flags
= NLM_F_REQUEST
,
468 .header
.nlmsg_seq
= 1,
469 .header
.nlmsg_pid
= 0,
470 .body
.mask
= AUDIT_STATUS_ENABLED
,
473 union sockaddr_union sa
= {
474 .nl
.nl_family
= AF_NETLINK
,
477 struct iovec iovec
= {
478 .iov_base
= &request
,
479 .iov_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
485 .msg_namelen
= sizeof(sa
.nl
),
490 n
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
493 if (n
!= NLMSG_LENGTH(sizeof(struct audit_status
)))
496 /* We don't wait for the result here, we can't do anything
502 int server_open_audit(Server
*s
) {
505 if (s
->audit_fd
< 0) {
506 static const union sockaddr_union sa
= {
507 .nl
.nl_family
= AF_NETLINK
,
509 .nl
.nl_groups
= AUDIT_NLGRP_READLOG
,
512 s
->audit_fd
= socket(AF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, NETLINK_AUDIT
);
513 if (s
->audit_fd
< 0) {
514 if (ERRNO_IS_NOT_SUPPORTED(errno
))
515 log_debug("Audit not supported in the kernel.");
517 log_warning_errno(errno
, "Failed to create audit socket, ignoring: %m");
522 if (bind(s
->audit_fd
, &sa
.sa
, sizeof(sa
.nl
)) < 0) {
523 log_warning_errno(errno
,
524 "Failed to join audit multicast group. "
525 "The kernel is probably too old or multicast reading is not supported. "
527 s
->audit_fd
= safe_close(s
->audit_fd
);
531 (void) fd_nonblock(s
->audit_fd
, true);
533 r
= setsockopt_int(s
->audit_fd
, SOL_SOCKET
, SO_PASSCRED
, true);
535 return log_error_errno(r
, "Failed to set SO_PASSCRED on audit socket: %m");
537 r
= sd_event_add_io(s
->event
, &s
->audit_event_source
, s
->audit_fd
, EPOLLIN
, server_process_datagram
, s
);
539 return log_error_errno(r
, "Failed to add audit fd to event loop: %m");
541 if (s
->set_audit
>= 0) {
542 /* We are listening now, try to enable audit if configured so */
543 r
= enable_audit(s
->audit_fd
, s
->set_audit
);
545 log_warning_errno(r
, "Failed to issue audit enable call: %m");
546 else if (s
->set_audit
> 0)
547 log_debug("Auditing in kernel turned on.");
549 log_debug("Auditing in kernel turned off.");