interprocess_docfix/os/unix/udsocket/
ancillary.rs

1use super::imports::*;
2use cfg_if::cfg_if;
3use std::{
4    borrow::Cow,
5    iter::{FromIterator, FusedIterator},
6    mem::size_of,
7};
8
9/// Ancillary data to be sent through a Unix domain socket or read from an input buffer.
10///
11/// Ancillary data gives unique possibilities to Unix domain sockets which no other POSIX API has: passing file descriptors between two processes which do not have a parent-child relationship. It also can be used to transfer credentials of a process reliably.
12#[derive(Clone, Debug, PartialEq, Eq, Hash)]
13pub enum AncillaryData<'a> {
14    /// One or more file descriptors to be sent.
15    FileDescriptors(Cow<'a, [c_int]>),
16    /// Credentials to be sent. The specified values are checked by the system when sent for all users except for the superuser – for senders, this means that the correct values need to be filled out, otherwise, an error is returned; for receivers, this means that the credentials are to be trusted for authentification purposes. For convenience, the [`credentials`] function provides a value which is known to be valid when sent.
17    ///
18    /// [`credentials`]: #method.credentials " "
19    #[cfg(any(doc, uds_ucred))]
20    #[cfg_attr( // uds_ucred template
21        feature = "doc_cfg",
22        doc(cfg(any(
23            all(
24                target_os = "linux",
25                any(
26                    target_env = "gnu",
27                    target_env = "musl",
28                    target_env = "musleabi",
29                    target_env = "musleabihf"
30                )
31            ),
32            target_os = "emscripten",
33            target_os = "redox"
34        )))
35    )]
36    Credentials {
37        /// The process identificator (PID) for the process.
38        pid: pid_t,
39        /// The user identificator (UID) of the user who started the process.
40        uid: uid_t,
41        /// The group identificator (GID) of the user who started the process.
42        gid: gid_t,
43    },
44}
45impl<'a> AncillaryData<'a> {
46    /// The size of a single `AncillaryData::Credentials` element when packed into the Unix ancillary data format. Useful for allocating a buffer when you expect to receive credentials.
47    pub const ENCODED_SIZE_OF_CREDENTIALS: usize = Self::_ENCODED_SIZE_OF_CREDENTIALS;
48    cfg_if! {
49        if #[cfg(uds_ucred)] {
50            const _ENCODED_SIZE_OF_CREDENTIALS: usize = size_of::<cmsghdr>() + size_of::<ucred>();
51        } /*else if #[cfg(uds_xucred)] {
52            const _ENCODED_SIZE_OF_CREDENTIALS: usize = size_of::<cmsghdr>() + size_of::<xucred>();
53        } */else if #[cfg(unix)] {
54            const _ENCODED_SIZE_OF_CREDENTIALS: usize = size_of::<cmsghdr>();
55        } else {
56            const _ENCODED_SIZE_OF_CREDENTIALS: usize = 0;
57        }
58    }
59
60    /// Calculates the size of an `AncillaryData::FileDescriptors` element with the specified amount of file descriptors when packed into the Unix ancillary data format. Useful for allocating a buffer when you expect to receive a specific amount of file descriptors.
61    pub const fn encoded_size_of_file_descriptors(num_descriptors: usize) -> usize {
62        #[cfg(not(unix))]
63        struct cmsghdr; // ???????????????
64        size_of::<cmsghdr>() + num_descriptors * size_of::<pid_t>()
65    }
66
67    /// Inexpensievly clones `self` by borrowing the `FileDescriptors` variant or copying the `Credentials` variant.
68    #[must_use]
69    pub fn clone_ref(&'a self) -> Self {
70        match *self {
71            Self::FileDescriptors(ref fds) => Self::FileDescriptors(Cow::Borrowed(fds)),
72            #[cfg(uds_ucred)]
73            Self::Credentials { pid, uid, gid } => Self::Credentials { pid, uid, gid },
74        }
75    }
76
77    /// Returns the size of an ancillary data element when packed into the Unix ancillary data format.
78    pub fn encoded_size(&self) -> usize {
79        match self {
80            Self::FileDescriptors(fds) => Self::encoded_size_of_file_descriptors(fds.len()),
81            #[cfg(uds_scm_credentials)]
82            Self::Credentials { .. } => Self::ENCODED_SIZE_OF_CREDENTIALS,
83        }
84    }
85
86    /// Encodes the ancillary data into `EncodedAncillaryData` which is ready to be sent via a Unix domain socket.
87    pub fn encode(op: impl IntoIterator<Item = Self>) -> EncodedAncillaryData<'static> {
88        let items = op.into_iter();
89        let mut buffer = Vec::with_capacity(
90            {
91                let size_hint = items.size_hint();
92                size_hint.1.unwrap_or(size_hint.0)
93                // If we assume that all ancillary data elements are credentials, we're more than fine.
94            } * Self::ENCODED_SIZE_OF_CREDENTIALS,
95        );
96        for i in items {
97            let mut cmsg_len = size_of::<cmsghdr>();
98            let cmsg_level_bytes = SOL_SOCKET.to_ne_bytes();
99            let cmsg_type_bytes;
100
101            match i {
102                AncillaryData::FileDescriptors(fds) => {
103                    cmsg_type_bytes = SCM_RIGHTS.to_ne_bytes();
104                    cmsg_len += fds.len() * 4;
105                    // #[cfg(target_pointer_width = "64")]
106                    // this was here, I don't even remember why, but that
107                    // wouldn't compile on a 32-bit machine
108                    let cmsg_len_bytes = cmsg_len.to_ne_bytes();
109                    buffer.extend_from_slice(&cmsg_len_bytes);
110                    buffer.extend_from_slice(&cmsg_level_bytes);
111                    buffer.extend_from_slice(&cmsg_type_bytes);
112                    for i in fds.iter().copied() {
113                        let desc_bytes = i.to_ne_bytes();
114                        buffer.extend_from_slice(&desc_bytes);
115                    }
116                }
117                #[cfg(uds_ucred)]
118                AncillaryData::Credentials { pid, uid, gid } => {
119                    cmsg_type_bytes = SCM_RIGHTS.to_ne_bytes();
120                    cmsg_len += size_of::<ucred>();
121                    // #[cfg(target_pointer_width = "64")]
122                    let cmsg_len_bytes = cmsg_len.to_ne_bytes();
123                    let pid_bytes = pid.to_ne_bytes();
124                    let uid_bytes = uid.to_ne_bytes();
125                    let gid_bytes = gid.to_ne_bytes();
126                    buffer.extend_from_slice(&cmsg_len_bytes);
127                    buffer.extend_from_slice(&cmsg_level_bytes);
128                    buffer.extend_from_slice(&cmsg_type_bytes);
129                    buffer.extend_from_slice(&pid_bytes);
130                    buffer.extend_from_slice(&uid_bytes);
131                    buffer.extend_from_slice(&gid_bytes);
132                }
133            }
134        }
135        EncodedAncillaryData(Cow::Owned(buffer))
136    }
137}
138impl AncillaryData<'static> {
139    /// Fetches the credentials of the process from the system and returns a value which can be safely sent to another process without the system complaining about an unauthorized attempt to impersonate another process/user/group.
140    ///
141    /// If you want to send credentials to another process, this is usually the function you need to obtain the desired ancillary payload.
142    #[cfg(any(doc, uds_ucred))]
143    #[cfg_attr( // uds_ucred template
144    feature = "doc_cfg",
145        doc(cfg(any(
146            all(
147                target_os = "linux",
148                any(
149                    target_env = "gnu",
150                    target_env = "musl",
151                    target_env = "musleabi",
152                    target_env = "musleabihf"
153                )
154            ),
155            target_os = "emscripten",
156            target_os = "redox"
157        )))
158    )]
159    pub fn credentials() -> Self {
160        Self::Credentials {
161            pid: unsafe { libc::getpid() },
162            uid: unsafe { libc::getuid() },
163            gid: unsafe { libc::getgid() },
164        }
165    }
166}
167
168/// A buffer used for sending ancillary data into Unix domain sockets.
169#[repr(transparent)]
170#[derive(Clone, Debug)]
171pub struct EncodedAncillaryData<'a>(pub Cow<'a, [u8]>);
172impl<'a> From<&'a [u8]> for EncodedAncillaryData<'a> {
173    fn from(op: &'a [u8]) -> Self {
174        Self(Cow::Borrowed(op))
175    }
176}
177impl From<Vec<u8>> for EncodedAncillaryData<'static> {
178    fn from(op: Vec<u8>) -> Self {
179        Self(Cow::Owned(op))
180    }
181}
182impl<'b> FromIterator<AncillaryData<'b>> for EncodedAncillaryData<'static> {
183    fn from_iter<I: IntoIterator<Item = AncillaryData<'b>>>(iter: I) -> Self {
184        AncillaryData::encode(iter)
185    }
186}
187impl<'b> From<Vec<AncillaryData<'b>>> for EncodedAncillaryData<'static> {
188    fn from(op: Vec<AncillaryData<'b>>) -> Self {
189        Self::from_iter(op)
190    }
191}
192impl<'b: 'c, 'c> From<&'c [AncillaryData<'b>]> for EncodedAncillaryData<'static> {
193    fn from(op: &'c [AncillaryData<'b>]) -> Self {
194        op.iter().map(AncillaryData::clone_ref).collect::<Self>()
195    }
196}
197impl<'a> AsRef<[u8]> for EncodedAncillaryData<'a> {
198    fn as_ref(&self) -> &[u8] {
199        &self.0
200    }
201}
202
203/// A buffer used for receiving ancillary data from Unix domain sockets.
204///
205/// The actual ancillary data can be obtained using the [`decode`] method.
206///
207/// # Example
208/// See [`UdStream`] or [`UdStreamListener`] for an example of receiving ancillary data.
209///
210/// [`decode`]: #method.decode " "
211/// [`UdStream`]: struct.UdStream.html#examples " "
212/// [`UdStreamListener`]: struct.UdStreamListener.html#examples " "
213#[derive(Debug)]
214pub enum AncillaryDataBuf<'a> {
215    /// The buffer's storage is borrowed.
216    Borrowed(&'a mut [u8]),
217    /// The buffer's storage is owned by the buffer itself.
218    Owned(Vec<u8>),
219}
220impl<'a> AncillaryDataBuf<'a> {
221    /// Creates an owned ancillary data buffer with the specified capacity.
222    pub fn owned_with_capacity(capacity: usize) -> Self {
223        Self::Owned(Vec::with_capacity(capacity))
224    }
225    /// Creates a decoder which decodes the ancillary data buffer into a friendly representation of its contents.
226    ///
227    /// All invalid ancillary data blocks are skipped – if there was garbage data in the buffer to begin with, the resulting buffer will either be empty or contain invalid credentials/file descriptors. This should normally never happen if the data is actually received from a Unix domain socket.
228    pub fn decode(&'a self) -> AncillaryDataDecoder<'a> {
229        AncillaryDataDecoder {
230            buffer: self.as_ref(),
231            i: 0,
232        }
233    }
234}
235impl<'a> From<&'a mut [u8]> for AncillaryDataBuf<'a> {
236    fn from(op: &'a mut [u8]) -> Self {
237        Self::Borrowed(op)
238    }
239}
240impl From<Vec<u8>> for AncillaryDataBuf<'static> {
241    fn from(op: Vec<u8>) -> Self {
242        Self::Owned(op)
243    }
244}
245impl<'a> From<&'a mut AncillaryDataBuf<'a>> for AncillaryDataBuf<'a> {
246    fn from(op: &'a mut AncillaryDataBuf<'a>) -> Self {
247        match op {
248            Self::Borrowed(slice) => Self::Borrowed(slice),
249            Self::Owned(vec) => Self::Borrowed(vec),
250        }
251    }
252}
253impl<'a> AsRef<[u8]> for AncillaryDataBuf<'a> {
254    fn as_ref(&self) -> &[u8] {
255        match self {
256            Self::Borrowed(slice) => slice,
257            Self::Owned(vec) => vec,
258        }
259    }
260}
261impl<'a> AsMut<[u8]> for AncillaryDataBuf<'a> {
262    fn as_mut(&mut self) -> &mut [u8] {
263        match self {
264            Self::Borrowed(slice) => slice,
265            Self::Owned(vec) => vec,
266        }
267    }
268}
269
270/// An iterator which decodes ancillary data from an ancillary data buffer.
271///
272/// This iterator is created by the [`decode`] method on [`AncillaryDataBuf`] – see its documentation for more.
273///
274/// [`AncillaryDataBuf`]: struct.AncillaryDataBuf.html " "
275/// [`decode`]: struct.AncillaryDataBuf.html#method.decode " "
276#[derive(Clone, Debug)]
277pub struct AncillaryDataDecoder<'a> {
278    buffer: &'a [u8],
279    i: usize,
280}
281impl<'a> From<&'a AncillaryDataBuf<'a>> for AncillaryDataDecoder<'a> {
282    fn from(buffer: &'a AncillaryDataBuf<'a>) -> Self {
283        buffer.decode()
284    }
285}
286impl<'a> Iterator for AncillaryDataDecoder<'a> {
287    type Item = AncillaryData<'static>;
288    fn next(&mut self) -> Option<Self::Item> {
289        fn u32_from_slice(bytes: &[u8]) -> u32 {
290            u32::from_ne_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
291        }
292        fn u64_from_slice(bytes: &[u8]) -> u64 {
293            u64::from_ne_bytes([
294                bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
295            ])
296        }
297        let bytes = self.buffer;
298        let end = bytes.len() - 1;
299
300        if matches!(bytes.len().checked_sub(self.i), Some(0) | None) {
301            self.i = end;
302            return None;
303        }
304
305        // The first field is the length, which is a size_t
306        #[cfg(target_pointer_width = "64")]
307        let element_size = {
308            if bytes.len() - self.i < 8 {
309                self.i = end;
310                return None;
311            }
312            u64_from_slice(&bytes[self.i..self.i + 8]) as usize
313        };
314        #[cfg(target_pointer_width = "32")]
315        let element_size = {
316            if bytes.len() - self.i < 4 {
317                self.i = end;
318                return None;
319            }
320            u32_from_slice(&bytes[self.i..self.i + 4]) as usize
321        };
322        // The cmsg_level field is always SOL_SOCKET – we don't need it, let's get the
323        // cmsg_type field right away by first getting the offset at which it's
324        // located:
325        #[cfg(target_pointer_width = "64")]
326        let type_offset: usize = 8 + 4; // 8 for cmsg_size, 4 for cmsg_level
327        #[cfg(target_pointer_width = "32")]
328        let type_offset: usize = 4 + 4; // 4 for cmsg_size, 4 for cmsg_level
329
330        // Now let's get the type itself:
331        let element_type = u32_from_slice(&bytes[self.i + type_offset..=self.i + type_offset + 4]);
332        // The size of cmsg_size, cmsg_level and cmsg_type together
333        let element_offset = type_offset + 4;
334
335        // Update the counter before returning.
336        self.i += element_offset // cmsg_size, cmsg_level and cmsg_type
337                + element_size; // data size
338
339        // SAFETY: those are ints lmao
340        match element_type as i32 {
341            SCM_RIGHTS => {
342                // We're reading one or multiple descriptors from the ancillary data payload.
343                // All descriptors are 4 bytes in size – leftover bytes are discarded thanks
344                // to integer division rules
345                let amount_of_descriptors = element_size / 4;
346                let mut descriptors = Vec::<c_int>::with_capacity(amount_of_descriptors);
347                let mut descriptor_offset = element_offset;
348                for _ in 0..amount_of_descriptors {
349                    descriptors.push(
350                        // SAFETY: see above
351                        u32_from_slice(&bytes[descriptor_offset..descriptor_offset + 4]) as i32,
352                    );
353                    descriptor_offset += 4;
354                }
355                Some(AncillaryData::FileDescriptors(Cow::Owned(descriptors)))
356            }
357            #[cfg(uds_ucred)]
358            SCM_CREDENTIALS => {
359                // We're reading a single ucred structure from the ancillary data payload.
360                // SAFETY: those are still ints
361                let pid_offset = element_offset;
362                let pid: pid_t = u32_from_slice(&bytes[pid_offset..pid_offset + 4]) as pid_t;
363                let uid_offset = pid_offset + 4;
364                let uid: uid_t = u32_from_slice(&bytes[uid_offset..uid_offset + 4]) as uid_t;
365                let gid_offset = uid_offset + 4;
366                let gid: gid_t = u32_from_slice(&bytes[gid_offset..gid_offset + 4]) as gid_t;
367                Some(AncillaryData::Credentials { pid, uid, gid })
368            }
369            _ => self.next(), // Do nothing if we hit corrupted data.
370        }
371    }
372}
373impl FusedIterator for AncillaryDataDecoder<'_> {}