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