tokio/net/unix/
ucred.rs

1use crate::net::unix;
2
3/// Credentials of a process.
4#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
5pub struct UCred {
6    /// PID (process ID) of the process.
7    pid: Option<unix::pid_t>,
8    /// UID (user ID) of the process.
9    uid: unix::uid_t,
10    /// GID (group ID) of the process.
11    gid: unix::gid_t,
12}
13
14impl UCred {
15    /// Gets UID (user ID) of the process.
16    pub fn uid(&self) -> unix::uid_t {
17        self.uid
18    }
19
20    /// Gets GID (group ID) of the process.
21    pub fn gid(&self) -> unix::gid_t {
22        self.gid
23    }
24
25    /// Gets PID (process ID) of the process.
26    ///
27    /// This is only implemented under Linux, Android, iOS, macOS, Solaris and
28    /// Illumos. On other platforms this will always return `None`.
29    pub fn pid(&self) -> Option<unix::pid_t> {
30        self.pid
31    }
32}
33
34#[cfg(any(
35    target_os = "linux",
36    target_os = "redox",
37    target_os = "android",
38    target_os = "openbsd",
39    target_os = "haiku"
40))]
41pub(crate) use self::impl_linux::get_peer_cred;
42
43#[cfg(any(target_os = "netbsd", target_os = "nto"))]
44pub(crate) use self::impl_netbsd::get_peer_cred;
45
46#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
47pub(crate) use self::impl_bsd::get_peer_cred;
48
49#[cfg(any(
50    target_os = "macos",
51    target_os = "ios",
52    target_os = "tvos",
53    target_os = "watchos",
54    target_os = "visionos"
55))]
56pub(crate) use self::impl_macos::get_peer_cred;
57
58#[cfg(any(target_os = "solaris", target_os = "illumos"))]
59pub(crate) use self::impl_solaris::get_peer_cred;
60
61#[cfg(target_os = "aix")]
62pub(crate) use self::impl_aix::get_peer_cred;
63
64#[cfg(any(target_os = "espidf", target_os = "vita"))]
65pub(crate) use self::impl_noproc::get_peer_cred;
66
67#[cfg(any(
68    target_os = "linux",
69    target_os = "redox",
70    target_os = "android",
71    target_os = "openbsd",
72    target_os = "haiku"
73))]
74pub(crate) mod impl_linux {
75    use crate::net::unix::{self, UnixStream};
76
77    use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED};
78    use std::{io, mem};
79
80    #[cfg(target_os = "openbsd")]
81    use libc::sockpeercred as ucred;
82    #[cfg(any(
83        target_os = "linux",
84        target_os = "redox",
85        target_os = "android",
86        target_os = "haiku"
87    ))]
88    use libc::ucred;
89
90    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
91        use std::os::unix::io::AsRawFd;
92
93        unsafe {
94            let raw_fd = sock.as_raw_fd();
95
96            let mut ucred = ucred {
97                pid: 0,
98                uid: 0,
99                gid: 0,
100            };
101
102            let ucred_size = mem::size_of::<ucred>();
103
104            // These paranoid checks should be optimized-out
105            assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
106            assert!(ucred_size <= u32::MAX as usize);
107
108            let mut ucred_size = ucred_size as socklen_t;
109
110            let ret = getsockopt(
111                raw_fd,
112                SOL_SOCKET,
113                SO_PEERCRED,
114                &mut ucred as *mut ucred as *mut c_void,
115                &mut ucred_size,
116            );
117            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
118                Ok(super::UCred {
119                    uid: ucred.uid as unix::uid_t,
120                    gid: ucred.gid as unix::gid_t,
121                    pid: Some(ucred.pid as unix::pid_t),
122                })
123            } else {
124                Err(io::Error::last_os_error())
125            }
126        }
127    }
128}
129
130#[cfg(any(target_os = "netbsd", target_os = "nto"))]
131pub(crate) mod impl_netbsd {
132    use crate::net::unix::{self, UnixStream};
133
134    use libc::{c_void, getsockopt, socklen_t, unpcbid, LOCAL_PEEREID, SOL_SOCKET};
135    use std::io;
136    use std::mem::size_of;
137    use std::os::unix::io::AsRawFd;
138
139    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
140        unsafe {
141            let raw_fd = sock.as_raw_fd();
142
143            let mut unpcbid = unpcbid {
144                unp_pid: 0,
145                unp_euid: 0,
146                unp_egid: 0,
147            };
148
149            let unpcbid_size = size_of::<unpcbid>();
150            let mut unpcbid_size = unpcbid_size as socklen_t;
151
152            let ret = getsockopt(
153                raw_fd,
154                SOL_SOCKET,
155                LOCAL_PEEREID,
156                &mut unpcbid as *mut unpcbid as *mut c_void,
157                &mut unpcbid_size,
158            );
159            if ret == 0 && unpcbid_size as usize == size_of::<unpcbid>() {
160                Ok(super::UCred {
161                    uid: unpcbid.unp_euid as unix::uid_t,
162                    gid: unpcbid.unp_egid as unix::gid_t,
163                    pid: Some(unpcbid.unp_pid as unix::pid_t),
164                })
165            } else {
166                Err(io::Error::last_os_error())
167            }
168        }
169    }
170}
171
172#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
173pub(crate) mod impl_bsd {
174    use crate::net::unix::{self, UnixStream};
175
176    use libc::getpeereid;
177    use std::io;
178    use std::mem::MaybeUninit;
179    use std::os::unix::io::AsRawFd;
180
181    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
182        unsafe {
183            let raw_fd = sock.as_raw_fd();
184
185            let mut uid = MaybeUninit::uninit();
186            let mut gid = MaybeUninit::uninit();
187
188            let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
189
190            if ret == 0 {
191                Ok(super::UCred {
192                    uid: uid.assume_init() as unix::uid_t,
193                    gid: gid.assume_init() as unix::gid_t,
194                    pid: None,
195                })
196            } else {
197                Err(io::Error::last_os_error())
198            }
199        }
200    }
201}
202
203#[cfg(any(
204    target_os = "macos",
205    target_os = "ios",
206    target_os = "tvos",
207    target_os = "watchos",
208    target_os = "visionos"
209))]
210pub(crate) mod impl_macos {
211    use crate::net::unix::{self, UnixStream};
212
213    use libc::{c_void, getpeereid, getsockopt, pid_t, LOCAL_PEEREPID, SOL_LOCAL};
214    use std::io;
215    use std::mem::size_of;
216    use std::mem::MaybeUninit;
217    use std::os::unix::io::AsRawFd;
218
219    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
220        unsafe {
221            let raw_fd = sock.as_raw_fd();
222
223            let mut uid = MaybeUninit::uninit();
224            let mut gid = MaybeUninit::uninit();
225            let mut pid: MaybeUninit<pid_t> = MaybeUninit::uninit();
226            let mut pid_size: MaybeUninit<u32> = MaybeUninit::new(size_of::<pid_t>() as u32);
227
228            if getsockopt(
229                raw_fd,
230                SOL_LOCAL,
231                LOCAL_PEEREPID,
232                pid.as_mut_ptr() as *mut c_void,
233                pid_size.as_mut_ptr(),
234            ) != 0
235            {
236                return Err(io::Error::last_os_error());
237            }
238
239            assert!(pid_size.assume_init() == (size_of::<pid_t>() as u32));
240
241            let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
242
243            if ret == 0 {
244                Ok(super::UCred {
245                    uid: uid.assume_init() as unix::uid_t,
246                    gid: gid.assume_init() as unix::gid_t,
247                    pid: Some(pid.assume_init() as unix::pid_t),
248                })
249            } else {
250                Err(io::Error::last_os_error())
251            }
252        }
253    }
254}
255
256#[cfg(any(target_os = "solaris", target_os = "illumos"))]
257pub(crate) mod impl_solaris {
258    use crate::net::unix::{self, UnixStream};
259    use std::io;
260    use std::os::unix::io::AsRawFd;
261    use std::ptr;
262
263    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
264        unsafe {
265            let raw_fd = sock.as_raw_fd();
266
267            let mut cred = ptr::null_mut();
268            let ret = libc::getpeerucred(raw_fd, &mut cred);
269
270            if ret == 0 {
271                let uid = libc::ucred_geteuid(cred);
272                let gid = libc::ucred_getegid(cred);
273                let pid = libc::ucred_getpid(cred);
274
275                libc::ucred_free(cred);
276
277                Ok(super::UCred {
278                    uid: uid as unix::uid_t,
279                    gid: gid as unix::gid_t,
280                    pid: Some(pid as unix::pid_t),
281                })
282            } else {
283                Err(io::Error::last_os_error())
284            }
285        }
286    }
287}
288
289#[cfg(target_os = "aix")]
290pub(crate) mod impl_aix {
291    use crate::net::unix::UnixStream;
292    use std::io;
293    use std::os::unix::io::AsRawFd;
294
295    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
296        unsafe {
297            let raw_fd = sock.as_raw_fd();
298
299            let mut uid = std::mem::MaybeUninit::uninit();
300            let mut gid = std::mem::MaybeUninit::uninit();
301
302            let ret = libc::getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
303
304            if ret == 0 {
305                Ok(super::UCred {
306                    uid: uid.assume_init(),
307                    gid: gid.assume_init(),
308                    pid: None,
309                })
310            } else {
311                Err(io::Error::last_os_error())
312            }
313        }
314    }
315}
316
317#[cfg(any(target_os = "espidf", target_os = "vita"))]
318pub(crate) mod impl_noproc {
319    use crate::net::unix::UnixStream;
320    use std::io;
321
322    pub(crate) fn get_peer_cred(_sock: &UnixStream) -> io::Result<super::UCred> {
323        Ok(super::UCred {
324            uid: 0,
325            gid: 0,
326            pid: None,
327        })
328    }
329}