]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/audit-util.c
units: Order ldconfig after systemd-tmpfiles-setup.service
[thirdparty/systemd.git] / src / basic / audit-util.c
CommitLineData
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
20int 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
50int 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
74static 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
112bool 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}