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 "audit-type.h"
24 #include "journald-audit.h"
26 #include "string-util.h"
28 typedef struct MapField
{
29 const char *audit_field
;
30 const char *journal_field
;
31 int (*map
)(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
);
34 static int map_simple_field(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
) {
35 _cleanup_free_
char *c
= NULL
;
36 size_t l
= 0, allocated
= 0;
46 c
= malloc(allocated
);
51 for (e
= *p
; *e
!= ' ' && *e
!= 0; e
++) {
52 if (!GREEDY_REALLOC(c
, allocated
, l
+2))
60 if (!GREEDY_REALLOC(*iov
, *n_iov_allocated
, *n_iov
+ 1))
63 (*iov
)[*n_iov
].iov_base
= c
;
64 (*iov
)[*n_iov
].iov_len
= l
;
73 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
) {
74 _cleanup_free_
char *c
= NULL
;
83 /* The kernel formats string fields in one of two formats. */
86 /* Normal quoted syntax */
92 l
= strlen(field
) + (e
- s
);
97 *((char*) mempcpy(stpcpy(c
, field
), s
, e
- s
)) = 0;
101 } else if (unhexchar(**p
) >= 0) {
102 /* Hexadecimal escaping */
103 size_t allocated
= 0;
107 c
= malloc(allocated
);
112 for (e
= *p
; *e
!= ' ' && *e
!= 0; e
+= 2) {
124 x
= ((uint8_t) a
<< 4 | (uint8_t) b
);
126 if (filter_printable
&& x
< (uint8_t) ' ')
129 if (!GREEDY_REALLOC(c
, allocated
, l
+2))
139 if (!GREEDY_REALLOC(*iov
, *n_iov_allocated
, *n_iov
+ 1))
142 (*iov
)[*n_iov
].iov_base
= c
;
143 (*iov
)[*n_iov
].iov_len
= l
;
152 static int map_string_field(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
) {
153 return map_string_field_internal(field
, p
, iov
, n_iov_allocated
, n_iov
, false);
156 static int map_string_field_printable(const char *field
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
) {
157 return map_string_field_internal(field
, p
, iov
, n_iov_allocated
, n_iov
, true);
160 static int map_generic_field(const char *prefix
, const char **p
, struct iovec
**iov
, size_t *n_iov_allocated
, unsigned *n_iov
) {
165 /* Implements fallback mappings for all fields we don't know */
167 for (e
= *p
; e
< *p
+ 16; e
++) {
169 if (*e
== 0 || *e
== ' ')
175 if (!((*e
>= 'a' && *e
<= 'z') ||
176 (*e
>= 'A' && *e
<= 'Z') ||
177 (*e
>= '0' && *e
<= '9') ||
178 *e
== '_' || *e
== '-'))
182 if (e
<= *p
|| e
>= *p
+ 16)
185 c
= alloca(strlen(prefix
) + (e
- *p
) + 2);
187 t
= stpcpy(c
, prefix
);
188 for (f
= *p
; f
< e
; f
++) {
191 if (*f
>= 'a' && *f
<= 'z')
192 x
= (*f
- 'a') + 'A'; /* uppercase */
194 x
= '_'; /* dashes → underscores */
204 r
= map_simple_field(c
, &e
, iov
, n_iov_allocated
, n_iov
);
212 /* Kernel fields are those occurring in the audit string before
213 * msg='. All of these fields are trusted, hence carry the "_" prefix.
214 * We try to translate the fields we know into our native names. The
215 * other's are generically mapped to _AUDIT_FIELD_XYZ= */
216 static const MapField map_fields_kernel
[] = {
218 /* First, we map certain well-known audit fields into native
219 * well-known fields */
220 { "pid=", "_PID=", map_simple_field
},
221 { "ppid=", "_PPID=", map_simple_field
},
222 { "uid=", "_UID=", map_simple_field
},
223 { "euid=", "_EUID=", map_simple_field
},
224 { "fsuid=", "_FSUID=", map_simple_field
},
225 { "gid=", "_GID=", map_simple_field
},
226 { "egid=", "_EGID=", map_simple_field
},
227 { "fsgid=", "_FSGID=", map_simple_field
},
228 { "tty=", "_TTY=", map_simple_field
},
229 { "ses=", "_AUDIT_SESSION=", map_simple_field
},
230 { "auid=", "_AUDIT_LOGINUID=", map_simple_field
},
231 { "subj=", "_SELINUX_CONTEXT=", map_simple_field
},
232 { "comm=", "_COMM=", map_string_field
},
233 { "exe=", "_EXE=", map_string_field
},
234 { "proctitle=", "_CMDLINE=", map_string_field_printable
},
236 /* Some fields don't map to native well-known fields. However,
237 * we know that they are string fields, hence let's undo
238 * string field escaping for them, though we stick to the
239 * generic field names. */
240 { "path=", "_AUDIT_FIELD_PATH=", map_string_field
},
241 { "dev=", "_AUDIT_FIELD_DEV=", map_string_field
},
242 { "name=", "_AUDIT_FIELD_NAME=", map_string_field
},
246 /* Userspace fields are those occurring in the audit string after
247 * msg='. All of these fields are untrusted, hence carry no "_"
248 * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
249 static const MapField map_fields_userspace
[] = {
250 { "cwd=", "AUDIT_FIELD_CWD=", map_string_field
},
251 { "cmd=", "AUDIT_FIELD_CMD=", map_string_field
},
252 { "acct=", "AUDIT_FIELD_ACCT=", map_string_field
},
253 { "exe=", "AUDIT_FIELD_EXE=", map_string_field
},
254 { "comm=", "AUDIT_FIELD_COMM=", map_string_field
},
258 static int map_all_fields(
260 const MapField map_fields
[],
264 size_t *n_iov_allocated
,
271 assert(n_iov_allocated
);
279 p
+= strspn(p
, WHITESPACE
);
285 v
= startswith(p
, "msg='");
290 /* Userspace message. It's enclosed in
291 simple quotation marks, is not
292 escaped, but the last field in the
293 line, hence let's remove the
294 quotation mark, and apply the
295 userspace mapping instead of the
298 e
= endswith(v
, "'");
300 return 0; /* don't continue splitting up if the final quotation mark is missing */
302 c
= strndupa(v
, e
- v
);
303 return map_all_fields(c
, map_fields_userspace
, "AUDIT_FIELD_", false, iov
, n_iov_allocated
, n_iov
);
307 /* Try to map the kernel fields to our own names */
308 for (m
= map_fields
; m
->audit_field
; m
++) {
309 v
= startswith(p
, m
->audit_field
);
313 r
= m
->map(m
->journal_field
, &v
, iov
, n_iov_allocated
, n_iov
);
315 return log_debug_errno(r
, "Failed to parse audit array: %m");
325 r
= map_generic_field(prefix
, &p
, iov
, n_iov_allocated
, n_iov
);
327 return log_debug_errno(r
, "Failed to parse audit array: %m");
330 /* Couldn't process as generic field, let's just skip over it */
331 p
+= strcspn(p
, WHITESPACE
);
336 static void process_audit_string(Server
*s
, int type
, const char *data
, size_t size
) {
337 _cleanup_free_
struct iovec
*iov
= NULL
;
338 size_t n_iov_allocated
= 0;
339 unsigned n_iov
= 0, k
;
340 uint64_t seconds
, msec
, id
;
341 const char *p
, *type_name
;
343 char id_field
[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
344 type_field
[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
345 source_time_field
[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t
)];
356 /* Note that the input buffer is NUL terminated, but let's
357 * check whether there is a spurious NUL byte */
358 if (memchr(data
, 0, size
))
361 p
= startswith(data
, "audit");
365 if (sscanf(p
, "(%" PRIu64
".%" PRIu64
":%" PRIu64
"):%n",
373 p
+= strspn(p
, WHITESPACE
);
378 n_iov_allocated
= N_IOVEC_META_FIELDS
+ 7;
379 iov
= new(struct iovec
, n_iov_allocated
);
385 IOVEC_SET_STRING(iov
[n_iov
++], "_TRANSPORT=audit");
387 sprintf(source_time_field
, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64
,
388 (usec_t
) seconds
* USEC_PER_SEC
+ (usec_t
) msec
* USEC_PER_MSEC
);
389 IOVEC_SET_STRING(iov
[n_iov
++], source_time_field
);
391 sprintf(type_field
, "_AUDIT_TYPE=%i", type
);
392 IOVEC_SET_STRING(iov
[n_iov
++], type_field
);
394 sprintf(id_field
, "_AUDIT_ID=%" PRIu64
, id
);
395 IOVEC_SET_STRING(iov
[n_iov
++], id_field
);
397 assert_cc(32 == LOG_AUTH
);
398 IOVEC_SET_STRING(iov
[n_iov
++], "SYSLOG_FACILITY=32");
399 IOVEC_SET_STRING(iov
[n_iov
++], "SYSLOG_IDENTIFIER=audit");
401 type_name
= audit_type_name_alloca(type
);
403 m
= strjoina("MESSAGE=", type_name
, " ", p
);
404 IOVEC_SET_STRING(iov
[n_iov
++], m
);
408 map_all_fields(p
, map_fields_kernel
, "_AUDIT_FIELD_", true, &iov
, &n_iov_allocated
, &n_iov
);
410 if (!GREEDY_REALLOC(iov
, n_iov_allocated
, n_iov
+ N_IOVEC_META_FIELDS
)) {
415 server_dispatch_message(s
, iov
, n_iov
, n_iov_allocated
, NULL
, NULL
, NULL
, 0, NULL
, LOG_NOTICE
, 0);
418 /* free() all entries that map_all_fields() added. All others
419 * are allocated on the stack or are constant. */
421 for (; z
< n_iov
; z
++)
422 free(iov
[z
].iov_base
);
425 void server_process_audit_message(
429 const struct ucred
*ucred
,
430 const union sockaddr_union
*sa
,
433 const struct nlmsghdr
*nl
= buffer
;
437 if (buffer_size
< ALIGN(sizeof(struct nlmsghdr
)))
442 /* Filter out fake data */
444 salen
!= sizeof(struct sockaddr_nl
) ||
445 sa
->nl
.nl_family
!= AF_NETLINK
||
446 sa
->nl
.nl_pid
!= 0) {
447 log_debug("Audit netlink message from invalid sender.");
451 if (!ucred
|| ucred
->pid
!= 0) {
452 log_debug("Audit netlink message with invalid credentials.");
456 if (!NLMSG_OK(nl
, buffer_size
)) {
457 log_error("Audit netlink message truncated.");
461 /* Ignore special Netlink messages */
462 if (IN_SET(nl
->nlmsg_type
, NLMSG_NOOP
, NLMSG_ERROR
))
465 /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
466 if (nl
->nlmsg_type
< AUDIT_FIRST_USER_MSG
)
469 process_audit_string(s
, nl
->nlmsg_type
, NLMSG_DATA(nl
), nl
->nlmsg_len
- ALIGN(sizeof(struct nlmsghdr
)));
472 static int enable_audit(int fd
, bool b
) {
475 struct nlmsghdr header
;
476 uint8_t header_space
[NLMSG_HDRLEN
];
478 struct audit_status body
;
479 } _packed_ request
= {
480 .header
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
481 .header
.nlmsg_type
= AUDIT_SET
,
482 .header
.nlmsg_flags
= NLM_F_REQUEST
,
483 .header
.nlmsg_seq
= 1,
484 .header
.nlmsg_pid
= 0,
485 .body
.mask
= AUDIT_STATUS_ENABLED
,
488 union sockaddr_union sa
= {
489 .nl
.nl_family
= AF_NETLINK
,
492 struct iovec iovec
= {
493 .iov_base
= &request
,
494 .iov_len
= NLMSG_LENGTH(sizeof(struct audit_status
)),
500 .msg_namelen
= sizeof(sa
.nl
),
505 n
= sendmsg(fd
, &mh
, MSG_NOSIGNAL
);
508 if (n
!= NLMSG_LENGTH(sizeof(struct audit_status
)))
511 /* We don't wait for the result here, we can't do anything
517 int server_open_audit(Server
*s
) {
518 static const int one
= 1;
521 if (s
->audit_fd
< 0) {
522 static const union sockaddr_union sa
= {
523 .nl
.nl_family
= AF_NETLINK
,
525 .nl
.nl_groups
= AUDIT_NLGRP_READLOG
,
528 s
->audit_fd
= socket(AF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, NETLINK_AUDIT
);
529 if (s
->audit_fd
< 0) {
530 if (errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
)
531 log_debug("Audit not supported in the kernel.");
533 log_warning_errno(errno
, "Failed to create audit socket, ignoring: %m");
538 if (bind(s
->audit_fd
, &sa
.sa
, sizeof(sa
.nl
)) < 0) {
539 log_warning_errno(errno
,
540 "Failed to join audit multicast group. "
541 "The kernel is probably too old or multicast reading is not supported. "
543 s
->audit_fd
= safe_close(s
->audit_fd
);
547 fd_nonblock(s
->audit_fd
, 1);
549 r
= setsockopt(s
->audit_fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
));
551 return log_error_errno(errno
, "Failed to set SO_PASSCRED on audit socket: %m");
553 r
= sd_event_add_io(s
->event
, &s
->audit_event_source
, s
->audit_fd
, EPOLLIN
, server_process_datagram
, s
);
555 return log_error_errno(r
, "Failed to add audit fd to event loop: %m");
557 /* We are listening now, try to enable audit */
558 r
= enable_audit(s
->audit_fd
, true);
560 log_warning_errno(r
, "Failed to issue audit enable call: %m");