1
use std::os::fd::{FromRawFd, IntoRawFd, OwnedFd};
2

            
3
use futures_util::stream::StreamExt;
4
use netlink_packet_audit::AuditMessage;
5
use netlink_proto::sys::TokioSocket;
6
use tokio::sync::mpsc;
7

            
8
/// `AUDIT_USER_START` is emitted when a PAM session is opened
9
const AUDIT_USER_START: u16 = 1105;
10
/// `AUDIT_USER_END` is emitted when a PAM session is closed
11
const 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.
16
pub 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
}