]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
d7832d2c | 2 | |
d7832d2c | 3 | #include <errno.h> |
362235bf | 4 | #include <linux/audit.h> |
11c3a366 | 5 | #include <linux/netlink.h> |
d7832d2c | 6 | #include <stdio.h> |
11c3a366 | 7 | #include <sys/socket.h> |
d7832d2c | 8 | |
b5efdb8a | 9 | #include "alloc-util.h" |
430f0182 | 10 | #include "audit-util.h" |
3ffd4af2 | 11 | #include "fd-util.h" |
a5c32cff | 12 | #include "fileio.h" |
bd1ae178 | 13 | #include "iovec-util.h" |
3ffd4af2 | 14 | #include "macro.h" |
6bedfcbb | 15 | #include "parse-util.h" |
3ffd4af2 | 16 | #include "process-util.h" |
362235bf | 17 | #include "socket-util.h" |
b1d4f8e1 | 18 | #include "user-util.h" |
d7832d2c KS |
19 | |
20 | int audit_session_from_pid(pid_t pid, uint32_t *id) { | |
5b12334d LP |
21 | _cleanup_free_ char *s = NULL; |
22 | const char *p; | |
d7832d2c KS |
23 | uint32_t u; |
24 | int r; | |
25 | ||
26 | assert(id); | |
27 | ||
d7e46e01 | 28 | /* We don't convert ENOENT to ESRCH here, since we can't |
5238e957 | 29 | * really distinguish between "audit is not available in the |
d7e46e01 LP |
30 | * kernel" and "the process does not exist", both which will |
31 | * result in ENOENT. */ | |
32 | ||
b68fa010 | 33 | p = procfs_file_alloca(pid, "sessionid"); |
d7832d2c | 34 | |
5b12334d | 35 | r = read_one_line_file(p, &s); |
d7832d2c KS |
36 | if (r < 0) |
37 | return r; | |
38 | ||
39 | r = safe_atou32(s, &u); | |
d7832d2c KS |
40 | if (r < 0) |
41 | return r; | |
42 | ||
3a87a86e | 43 | if (!audit_session_is_valid(u)) |
d7e46e01 | 44 | return -ENODATA; |
d7832d2c KS |
45 | |
46 | *id = u; | |
47 | return 0; | |
48 | } | |
49 | ||
50 | int audit_loginuid_from_pid(pid_t pid, uid_t *uid) { | |
5b12334d LP |
51 | _cleanup_free_ char *s = NULL; |
52 | const char *p; | |
d7832d2c KS |
53 | uid_t u; |
54 | int r; | |
55 | ||
56 | assert(uid); | |
57 | ||
b68fa010 | 58 | p = procfs_file_alloca(pid, "loginuid"); |
d7832d2c | 59 | |
5b12334d | 60 | r = read_one_line_file(p, &s); |
d7832d2c KS |
61 | if (r < 0) |
62 | return r; | |
63 | ||
64 | r = parse_uid(s, &u); | |
d7e46e01 LP |
65 | if (r == -ENXIO) /* the UID was -1 */ |
66 | return -ENODATA; | |
d7832d2c KS |
67 | if (r < 0) |
68 | return r; | |
69 | ||
3a87a86e | 70 | *uid = u; |
d7832d2c KS |
71 | return 0; |
72 | } | |
cfb1f5df | 73 | |
362235bf NR |
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 | }; | |
0347b9fd | 89 | iov = IOVEC_MAKE(&msg, msg.hdr.nlmsg_len); |
362235bf NR |
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) | |
190a0953 | 102 | return n; |
362235bf NR |
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 | ||
cfb1f5df LP |
112 | bool use_audit(void) { |
113 | static int cached_use = -1; | |
362235bf | 114 | int r; |
cfb1f5df LP |
115 | |
116 | if (cached_use < 0) { | |
117 | int fd; | |
118 | ||
119 | fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT); | |
f006b30b GS |
120 | if (fd < 0) { |
121 | cached_use = !IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT, EPERM); | |
13bb68bb ZJS |
122 | if (!cached_use) |
123 | log_debug_errno(errno, "Won't talk to audit: %m"); | |
124 | } else { | |
362235bf NR |
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 | ||
cfb1f5df LP |
141 | safe_close(fd); |
142 | } | |
143 | } | |
144 | ||
145 | return cached_use; | |
146 | } |