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