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