]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/audit-util.c
7f86f84fa353fb86e70126ea3704ff91724878d6
[thirdparty/systemd.git] / src / basic / audit-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <linux/audit.h>
5 #include <linux/netlink.h>
6 #include <stdio.h>
7 #include <sys/socket.h>
8
9 #include "alloc-util.h"
10 #include "audit-util.h"
11 #include "fd-util.h"
12 #include "fileio.h"
13 #include "iovec-util.h"
14 #include "macro.h"
15 #include "parse-util.h"
16 #include "process-util.h"
17 #include "socket-util.h"
18 #include "user-util.h"
19
20 int audit_session_from_pid(pid_t pid, uint32_t *id) {
21 _cleanup_free_ char *s = NULL;
22 const char *p;
23 uint32_t u;
24 int r;
25
26 assert(id);
27
28 /* We don't convert ENOENT to ESRCH here, since we can't
29 * really distinguish between "audit is not available in the
30 * kernel" and "the process does not exist", both which will
31 * result in ENOENT. */
32
33 p = procfs_file_alloca(pid, "sessionid");
34
35 r = read_one_line_file(p, &s);
36 if (r < 0)
37 return r;
38
39 r = safe_atou32(s, &u);
40 if (r < 0)
41 return r;
42
43 if (!audit_session_is_valid(u))
44 return -ENODATA;
45
46 *id = u;
47 return 0;
48 }
49
50 int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
51 _cleanup_free_ char *s = NULL;
52 const char *p;
53 uid_t u;
54 int r;
55
56 assert(uid);
57
58 p = procfs_file_alloca(pid, "loginuid");
59
60 r = read_one_line_file(p, &s);
61 if (r < 0)
62 return r;
63
64 r = parse_uid(s, &u);
65 if (r == -ENXIO) /* the UID was -1 */
66 return -ENODATA;
67 if (r < 0)
68 return r;
69
70 *uid = u;
71 return 0;
72 }
73
74 static int try_audit_request(int fd) {
75 struct iovec iov;
76 struct msghdr mh;
77 ssize_t n;
78
79 assert(fd >= 0);
80
81 struct {
82 struct nlmsghdr hdr;
83 struct nlmsgerr err;
84 } _packed_ msg = {
85 .hdr.nlmsg_len = NLMSG_LENGTH(0),
86 .hdr.nlmsg_type = AUDIT_GET_FEATURE,
87 .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
88 };
89 iov = IOVEC_MAKE(&msg, msg.hdr.nlmsg_len);
90 mh = (struct msghdr) {
91 .msg_iov = &iov,
92 .msg_iovlen = 1,
93 };
94
95 if (sendmsg(fd, &mh, MSG_NOSIGNAL) < 0)
96 return -errno;
97
98 iov.iov_len = sizeof(msg);
99
100 n = recvmsg_safe(fd, &mh, 0);
101 if (n < 0)
102 return n;
103 if (n != NLMSG_LENGTH(sizeof(struct nlmsgerr)))
104 return -EIO;
105
106 if (msg.hdr.nlmsg_type != NLMSG_ERROR)
107 return -EINVAL;
108
109 return msg.err.error;
110 }
111
112 bool use_audit(void) {
113 static int cached_use = -1;
114 int r;
115
116 if (cached_use < 0) {
117 int fd;
118
119 fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
120 if (fd < 0) {
121 cached_use = !IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT, EPERM);
122 if (!cached_use)
123 log_debug_errno(errno, "Won't talk to audit: %m");
124 } else {
125 /* If we try and use the audit fd but get -ECONNREFUSED, it is because
126 * we are not in the initial user namespace, and the kernel does not
127 * have support for audit outside of the initial user namespace
128 * (see https://elixir.bootlin.com/linux/latest/C/ident/audit_netlink_ok).
129 *
130 * If we receive any other error, do not disable audit because we are not
131 * sure that the error indicates that audit will not work in general. */
132 r = try_audit_request(fd);
133 if (r < 0) {
134 cached_use = r != -ECONNREFUSED;
135 log_debug_errno(r, cached_use ?
136 "Failed to make request on audit fd, ignoring: %m" :
137 "Won't talk to audit: %m");
138 } else
139 cached_use = true;
140
141 safe_close(fd);
142 }
143 }
144
145 return cached_use;
146 }