saluki_io/net/unix/
linux.rs

1use std::io;
2
3use bytes::BufMut;
4use socket2::{MaybeUninitSlice, MsgHdrMut, SockAddr, SockAddrStorage, SockRef};
5
6use super::ancillary::{ControlMessage, SocketCredentialsAncillaryData};
7use crate::net::addr::{ConnectionAddress, ProcessCredentials};
8
9/// Enables the `SO_PASSCRED` option on the given socket.
10///
11/// ## Errors
12///
13/// If the underlying system call fails, an error is returned.
14pub fn enable_uds_socket_credentials<'sock, S>(socket: &'sock S) -> io::Result<()>
15where
16    SockRef<'sock>: From<&'sock S>,
17{
18    let sock_ref = SockRef::from(socket);
19    sock_ref.set_passcred(true)
20}
21
22pub(super) fn uds_recvmsg<'sock, S, B: BufMut>(socket: &'sock S, buf: &mut B) -> io::Result<(usize, ConnectionAddress)>
23where
24    SockRef<'sock>: From<&'sock S>,
25{
26    let sock_ref = SockRef::from(socket);
27
28    // Create the message header struct that will be populated by the call to `recvmsg`, which includes the peer
29    // address, message data, and any ancillary (out-of-band) data.
30    //
31    // SAFETY: We're allocating `sockaddr_storage`, which is always large enough to hold any address family's socket
32    // address structure.
33    let sock_storage = SockAddrStorage::zeroed();
34    let sock_storage_len = sock_storage.size_of();
35    let mut sock_addr = unsafe { SockAddr::new(sock_storage, sock_storage_len) };
36
37    let mut ancillary_data = SocketCredentialsAncillaryData::new();
38
39    let data_buf = unsafe { MaybeUninitSlice::new(buf.chunk_mut().as_uninit_slice_mut()) };
40    let mut data_bufs = [data_buf];
41
42    let mut msg_hdr = MsgHdrMut::new()
43        .with_addr(&mut sock_addr)
44        .with_buffers(&mut data_bufs)
45        .with_control(ancillary_data.as_mut_uninit());
46
47    let n = sock_ref.recvmsg(&mut msg_hdr, libc::MSG_CMSG_CLOEXEC)?;
48
49    // If we got any socket credentials back, parse them.
50    let control_len = msg_hdr.control_len();
51
52    let maybe_process_creds = if control_len > 0 {
53        unsafe {
54            ancillary_data.set_len(control_len);
55            let messages = ancillary_data.messages();
56            messages
57                .map(|m| match m {
58                    ControlMessage::Credentials(creds) => ProcessCredentials {
59                        pid: creds.pid,
60                        uid: creds.uid,
61                        gid: creds.gid,
62                    },
63                })
64                .next()
65        }
66    } else {
67        None
68    };
69
70    let conn_addr = ConnectionAddress::ProcessLike(maybe_process_creds);
71
72    // Finally, update our buffer to reflect the bytes we've read.
73    unsafe {
74        buf.advance_mut(n);
75    }
76
77    Ok((n, conn_addr))
78}