1use crate::net::unix;
2
3#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
5pub struct UCred {
6 pid: Option<unix::pid_t>,
8 uid: unix::uid_t,
10 gid: unix::gid_t,
12}
13
14impl UCred {
15 pub fn uid(&self) -> unix::uid_t {
17 self.uid
18 }
19
20 pub fn gid(&self) -> unix::gid_t {
22 self.gid
23 }
24
25 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 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}