1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
4 #include "audit-type.h"
5 #include "errno-util.h"
9 #include "journald-audit.h"
10 #include "missing_audit.h"
11 #include "string-util.h"
13 typedef struct MapField
{
14 const char *audit_field
;
15 const char *journal_field
;
16 int (*map
)(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, size_t *n_iov
);
19 static int map_simple_field(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, size_t *n_iov
) {
20 _cleanup_free_
char *c
= NULL
;
21 size_t l
= 0, allocated
= 0;
31 c
= malloc(allocated
);
36 for (e
= *p
; !IN_SET(*e
, 0, ' '); e
++) {
37 if (!GREEDY_REALLOC(c
, allocated
, l
+2))
45 if (!GREEDY_REALLOC(*iov
, *n_iov_allocated
, *n_iov
+ 1))
48 (*iov
)[(*n_iov
)++] = IOVEC_MAKE(c
, l
);
56 static int map_string_field_internal(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, size_t *n_iov
, bool filter_printable
) {
57 _cleanup_free_
char *c
= NULL
;
66 /* The kernel formats string fields in one of two formats. */
69 /* Normal quoted syntax */
75 l
= strlen(field
) + (e
- s
);
80 *((char*) mempcpy(stpcpy(c
, field
), s
, e
- s
)) = 0;
84 } else if (unhexchar(**p
) >= 0) {
85 /* Hexadecimal escaping */
90 c
= malloc(allocated
);
95 for (e
= *p
; !IN_SET(*e
, 0, ' '); e
+= 2) {
107 x
= ((uint8_t) a
<< 4 | (uint8_t) b
);
109 if (filter_printable
&& x
< (uint8_t) ' ')
112 if (!GREEDY_REALLOC(c
, allocated
, l
+2))
122 if (!GREEDY_REALLOC(*iov
, *n_iov_allocated
, *n_iov
+ 1))
125 (*iov
)[(*n_iov
)++] = IOVEC_MAKE(c
, l
);
133 static int map_string_field(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, size_t *n_iov
) {
134 return map_string_field_internal(field
, p
, iov
, n_iov_allocated
, n_iov
, false);
137 static int map_string_field_printable(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, size_t *n_iov
) {
138 return map_string_field_internal(field
, p
, iov
, n_iov_allocated
, n_iov
, true);
141 static int map_generic_field(const char *prefix
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, size_t *n_iov
) {
146 /* Implements fallback mappings for all fields we don't know */
148 for (e
= *p
; e
< *p
+ 16; e
++) {
150 if (IN_SET(*e
, 0, ' '))
156 if (!((*e
>= 'a' && *e
<= 'z') ||
157 (*e
>= 'A' && *e
<= 'Z') ||
158 (*e
>= '0' && *e
<= '9') ||
159 IN_SET(*e
, '_', '-')))
163 if (e
<= *p
|| e
>= *p
+ 16)
166 c
= newa(char, strlen(prefix
) + (e
- *p
) + 2);
168 t
= stpcpy(c
, prefix
);
169 for (f
= *p
; f
< e
; f
++) {
172 if (*f
>= 'a' && *f
<= 'z')
173 x
= (*f
- 'a') + 'A'; /* uppercase */
175 x
= '_'; /* dashes → underscores */
185 r
= map_simple_field(c
, &e
, iov
, n_iov_allocated
, n_iov
);
193 /* Kernel fields are those occurring in the audit string before
194 * msg='. All of these fields are trusted, hence carry the "_" prefix.
195 * We try to translate the fields we know into our native names. The
196 * other's are generically mapped to _AUDIT_FIELD_XYZ= */
197 static const MapField map_fields_kernel
[] = {
199 /* First, we map certain well-known audit fields into native
200 * well-known fields */
201 { "pid=", "_PID=", map_simple_field
},
202 { "ppid=", "_PPID=", map_simple_field
},
203 { "uid=", "_UID=", map_simple_field
},
204 { "euid=", "_EUID=", map_simple_field
},
205 { "fsuid=", "_FSUID=", map_simple_field
},
206 { "gid=", "_GID=", map_simple_field
},
207 { "egid=", "_EGID=", map_simple_field
},
208 { "fsgid=", "_FSGID=", map_simple_field
},
209 { "tty=", "_TTY=", map_simple_field
},
210 { "ses=", "_AUDIT_SESSION=", map_simple_field
},
211 { "auid=", "_AUDIT_LOGINUID=", map_simple_field
},
212 { "subj=", "_SELINUX_CONTEXT=", map_simple_field
},
213 { "comm=", "_COMM=", map_string_field
},
214 { "exe=", "_EXE=", map_string_field
},
215 { "proctitle=", "_CMDLINE=", map_string_field_printable
},
217 /* Some fields don't map to native well-known fields. However,
218 * we know that they are string fields, hence let's undo
219 * string field escaping for them, though we stick to the
220 * generic field names. */
221 { "path=", "_AUDIT_FIELD_PATH=", map_string_field
},
222 { "dev=", "_AUDIT_FIELD_DEV=", map_string_field
},
223 { "name=", "_AUDIT_FIELD_NAME=", map_string_field
},
227 /* Userspace fields are those occurring in the audit string after
228 * msg='. All of these fields are untrusted, hence carry no "_"
229 * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
230 static const MapField map_fields_userspace
[] = {
231 { "cwd=", "AUDIT_FIELD_CWD=", map_string_field
},
232 { "cmd=", "AUDIT_FIELD_CMD=", map_string_field
},
233 { "acct=", "AUDIT_FIELD_ACCT=", map_string_field
},
234 { "exe=", "AUDIT_FIELD_EXE=", map_string_field
},
235 { "comm=", "AUDIT_FIELD_COMM=", map_string_field
},
239 static int map_all_fields(
241 const MapField map_fields
[],
245 size_t *n_iov_allocated
,
252 assert(n_iov_allocated
);
260 p
+= strspn(p
, WHITESPACE
);
266 v
= startswith(p
, "msg='");
268 _cleanup_free_
char *c
= NULL
;
271 /* Userspace message. It's enclosed in
272 simple quotation marks, is not
273 escaped, but the last field in the
274 line, hence let's remove the
275 quotation mark, and apply the
276 userspace mapping instead of the
279 e
= endswith(v
, "'");
281 return 0; /* don't continue splitting up if the final quotation mark is missing */
283 c
= strndup(v
, e
- v
);
287 return map_all_fields(c
, map_fields_userspace
, "AUDIT_FIELD_", false, iov
, n_iov_allocated
, n_iov
);
291 /* Try to map the kernel fields to our own names */
292 for (m
= map_fields
; m
->audit_field
; m
++) {
293 v
= startswith(p
, m
->audit_field
);
297 r
= m
->map(m
->journal_field
, &v
, iov
, n_iov_allocated
, n_iov
);
299 return log_debug_errno(r
, "Failed to parse audit array: %m");
309 r
= map_generic_field(prefix
, &p
, iov
, n_iov_allocated
, n_iov
);
311 return log_debug_errno(r
, "Failed to parse audit array: %m");
314 /* Couldn't process as generic field, let's just skip over it */
315 p
+= strcspn(p
, WHITESPACE
);
320 void process_audit_string(Server
*s
, int type
, const char *data
, size_t size
) {
321 size_t n_iov_allocated
= 0, n_iov
= 0, z
;
322 _cleanup_free_
struct iovec
*iov
= NULL
;
323 uint64_t seconds
, msec
, id
;
324 const char *p
, *type_name
;
325 char id_field
[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
326 type_field
[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
327 source_time_field
[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t
)];
328 char *m
, *type_field_name
;
339 /* Note that the input buffer is NUL terminated, but let's
340 * check whether there is a spurious NUL byte */
341 if (memchr(data
, 0, size
))
344 p
= startswith(data
, "audit");
349 if (sscanf(p
, "(%" PRIu64
".%" PRIu64
":%" PRIu64
"):%n",
357 p
+= strspn(p
, WHITESPACE
);
362 n_iov_allocated
= N_IOVEC_META_FIELDS
+ 8;
363 iov
= new(struct iovec
, n_iov_allocated
);
369 iov
[n_iov
++] = IOVEC_MAKE_STRING("_TRANSPORT=audit");
371 sprintf(source_time_field
, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64
,
372 (usec_t
) seconds
* USEC_PER_SEC
+ (usec_t
) msec
* USEC_PER_MSEC
);
373 iov
[n_iov
++] = IOVEC_MAKE_STRING(source_time_field
);
375 sprintf(type_field
, "_AUDIT_TYPE=%i", type
);
376 iov
[n_iov
++] = IOVEC_MAKE_STRING(type_field
);
378 sprintf(id_field
, "_AUDIT_ID=%" PRIu64
, id
);
379 iov
[n_iov
++] = IOVEC_MAKE_STRING(id_field
);
381 assert_cc(4 == LOG_FAC(LOG_AUTH
));
382 iov
[n_iov
++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=4");
383 iov
[n_iov
++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=audit");
385 type_name
= audit_type_name_alloca(type
);
387 type_field_name
= strjoina("_AUDIT_TYPE_NAME=", type_name
);
388 iov
[n_iov
++] = IOVEC_MAKE_STRING(type_field_name
);
390 m
= strjoina("MESSAGE=", type_name
, " ", p
);
391 iov
[n_iov
++] = IOVEC_MAKE_STRING(m
);
395 map_all_fields(p
, map_fields_kernel
, "_AUDIT_FIELD_", true, &iov
, &n_iov_allocated
, &n_iov
);
397 if (!GREEDY_REALLOC(iov
, n_iov_allocated
, n_iov
+ N_IOVEC_META_FIELDS
)) {
402 server_dispatch_message(s
, iov
, n_iov
, n_iov_allocated
, NULL
, NULL
, LOG_NOTICE
, 0);
405 /* free() all entries that map_all_fields() added. All others
406 * are allocated on the stack or are constant. */
408 for (; z
< n_iov
; z
++)
409 free(iov
[z
].iov_base
);
412 void server_process_audit_message(
416 const struct ucred
*ucred
,
417 const union sockaddr_union
*sa
,
420 const struct nlmsghdr
*nl
= buffer
;
424 if (buffer_size
< ALIGN(sizeof(struct nlmsghdr
)))
429 /* Filter out fake data */
431 salen
!= sizeof(struct sockaddr_nl
) ||
432 sa
->nl
.nl_family
!= AF_NETLINK
||
433 sa
->nl
.nl_pid
!= 0) {
434 log_debug("Audit netlink message from invalid sender.");
438 if (!ucred
|| ucred
->pid
!= 0) {
439 log_debug("Audit netlink message with invalid credentials.");
443 if (!NLMSG_OK(nl
, buffer_size
)) {
444 log_error("Audit netlink message truncated.");
448 /* Ignore special Netlink messages */
449 if (IN_SET(nl
->nlmsg_type
, NLMSG_NOOP
, NLMSG_ERROR
))
452 /* Except AUDIT_USER, all messages below AUDIT_FIRST_USER_MSG are control messages, let's ignore those */
453 if (nl
->nlmsg_type
< AUDIT_FIRST_USER_MSG
&& nl
->nlmsg_type
!= AUDIT_USER
)
456 process_audit_string(s
, nl
->nlmsg_type
, NLMSG_DATA(nl
), nl
->nlmsg_len
- ALIGN(sizeof(struct nlmsghdr
)));
459 static int enable_audit(int fd
, bool b
) {
462 struct nlmsghdr header
;
463 uint8_t header_space
[NLMSG_HDRLEN
];
465 struct audit_status body
;
466 } _packed_ request
= {
467 .header
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
468 .header
.nlmsg_type
= AUDIT_SET
,
469 .header
.nlmsg_flags
= NLM_F_REQUEST
,
470 .header
.nlmsg_seq
= 1,
471 .header
.nlmsg_pid
= 0,
472 .body
.mask
= AUDIT_STATUS_ENABLED
,
475 union sockaddr_union sa
= {
476 .nl
.nl_family
= AF_NETLINK
,
479 struct iovec iovec
= {
480 .iov_base
= &request
,
481 .iov_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
487 .msg_namelen
= sizeof(sa
.nl
),
492 n
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
495 if (n
!= NLMSG_LENGTH(sizeof(struct audit_status
)))
498 /* We don't wait for the result here, we can't do anything
504 int server_open_audit(Server
*s
) {
507 if (s
->audit_fd
< 0) {
508 static const union sockaddr_union sa
= {
509 .nl
.nl_family
= AF_NETLINK
,
511 .nl
.nl_groups
= AUDIT_NLGRP_READLOG
,
514 s
->audit_fd
= socket(AF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, NETLINK_AUDIT
);
515 if (s
->audit_fd
< 0) {
516 if (ERRNO_IS_NOT_SUPPORTED(errno
))
517 log_debug("Audit not supported in the kernel.");
519 log_warning_errno(errno
, "Failed to create audit socket, ignoring: %m");
524 if (bind(s
->audit_fd
, &sa
.sa
, sizeof(sa
.nl
)) < 0) {
525 log_warning_errno(errno
,
526 "Failed to join audit multicast group. "
527 "The kernel is probably too old or multicast reading is not supported. "
529 s
->audit_fd
= safe_close(s
->audit_fd
);
533 (void) fd_nonblock(s
->audit_fd
, true);
535 r
= setsockopt_int(s
->audit_fd
, SOL_SOCKET
, SO_PASSCRED
, true);
537 return log_error_errno(r
, "Failed to set SO_PASSCRED on audit socket: %m");
539 r
= sd_event_add_io(s
->event
, &s
->audit_event_source
, s
->audit_fd
, EPOLLIN
, server_process_datagram
, s
);
541 return log_error_errno(r
, "Failed to add audit fd to event loop: %m");
543 if (s
->set_audit
>= 0) {
544 /* We are listening now, try to enable audit if configured so */
545 r
= enable_audit(s
->audit_fd
, s
->set_audit
);
547 log_warning_errno(r
, "Failed to issue audit enable call: %m");
548 else if (s
->set_audit
> 0)
549 log_debug("Auditing in kernel turned on.");
551 log_debug("Auditing in kernel turned off.");