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))]
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 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}