Skip to main content

roowho2_lib/server/rwhod/
audit_watcher.rs

1use std::os::fd::{FromRawFd, IntoRawFd, OwnedFd};
2
3use futures_util::stream::StreamExt;
4use netlink_packet_audit::AuditMessage;
5use netlink_proto::sys::TokioSocket;
6use tokio::sync::mpsc;
7
8/// `AUDIT_USER_START` is emitted when a PAM session is opened
9const AUDIT_USER_START: u16 = 1105;
10/// `AUDIT_USER_END` is emitted when a PAM session is closed
11const AUDIT_USER_END: u16 = 1106;
12
13/// Listens for audit messages on the systemd-provided netlink socket and sends a
14/// notification on the provided channel whenever a user session is opened or closed,
15/// indicating that there rwhod status may have changed.
16pub async fn audit_change_notifier(sender: mpsc::Sender<()>, socket_fd: OwnedFd) {
17    // SAFETY: `socket_fd` is a systemd-provided netlink socket, already
18    // bound and subscribed to the audit multicast group.
19    let socket = unsafe { TokioSocket::from_raw_fd(socket_fd.into_raw_fd()) };
20
21    let (connection, _handle, mut messages) = netlink_proto::from_socket_with_codec::<
22        AuditMessage,
23        TokioSocket,
24        netlink_packet_audit::NetlinkAuditCodec,
25    >(socket);
26
27    tokio::spawn(connection);
28
29    tracing::info!("Listening for realtime session updates via the Linux audit log");
30
31    loop {
32        match messages.next().await {
33            Some((msg, _addr))
34                if matches!(msg.header.message_type, AUDIT_USER_START | AUDIT_USER_END) =>
35            {
36                tracing::debug!("Received session-related audit message: {:?}", msg);
37                if sender.send(()).await.is_err() {
38                    tracing::debug!("Realtime update receiver dropped, stopping audit watcher");
39                    return;
40                }
41            }
42            Some((msg, _addr)) => {
43                tracing::trace!(
44                    "Ignoring audit message unrelated to sessions (type {})",
45                    msg.header.message_type
46                );
47            }
48            None => {
49                tracing::warn!(
50                    "Audit netlink connection closed unexpectedly; realtime updates disabled \
51                     for the rest of this run"
52                );
53                return;
54            }
55        }
56    }
57}