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> {
32 self.pid
33 }
34}
35
36#[cfg(any(
37 target_os = "linux",
38 target_os = "redox",
39 target_os = "android",
40 target_os = "openbsd",
41 target_os = "haiku",
42 target_os = "cygwin"
43))]
44pub(crate) use self::impl_linux::get_peer_cred;
45
46#[cfg(target_os = "netbsd")]
47pub(crate) use self::impl_netbsd::get_peer_cred;
48
49#[cfg(target_os = "dragonfly")]
50pub(crate) use self::impl_dragonfly::get_peer_cred;
51
52#[cfg(target_os = "freebsd")]
53pub(crate) use self::impl_freebsd::get_peer_cred;
54
55#[cfg(any(
56 target_os = "macos",
57 target_os = "ios",
58 target_os = "tvos",
59 target_os = "watchos",
60 target_os = "visionos"
61))]
62pub(crate) use self::impl_macos::get_peer_cred;
63
64#[cfg(any(target_os = "solaris", target_os = "illumos"))]
65pub(crate) use self::impl_solaris::get_peer_cred;
66
67#[cfg(target_os = "aix")]
68pub(crate) use self::impl_aix::get_peer_cred;
69
70#[cfg(any(
71 target_os = "espidf",
72 target_os = "nuttx",
73 target_os = "vita",
74 target_os = "hurd"
75))]
76pub(crate) use self::impl_noproc::get_peer_cred;
77
78#[cfg(target_os = "nto")]
79pub(crate) use self::impl_nto::get_peer_cred;
80
81#[cfg(any(
82 target_os = "linux",
83 target_os = "redox",
84 target_os = "android",
85 target_os = "openbsd",
86 target_os = "haiku",
87 target_os = "cygwin"
88))]
89pub(crate) mod impl_linux {
90 use crate::net::unix::{self, UnixStream};
91
92 use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED};
93 use std::{io, mem};
94
95 #[cfg(target_os = "openbsd")]
96 use libc::sockpeercred as ucred;
97 #[cfg(any(
98 target_os = "linux",
99 target_os = "redox",
100 target_os = "android",
101 target_os = "haiku",
102 target_os = "cygwin"
103 ))]
104 use libc::ucred;
105
106 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
107 use std::os::unix::io::AsRawFd;
108
109 unsafe {
110 let raw_fd = sock.as_raw_fd();
111
112 let mut ucred = ucred {
113 pid: 0,
114 uid: 0,
115 gid: 0,
116 };
117
118 let ucred_size = mem::size_of::<ucred>();
119
120 assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
122 assert!(ucred_size <= u32::MAX as usize);
123
124 let mut ucred_size = ucred_size as socklen_t;
125
126 let ret = getsockopt(
127 raw_fd,
128 SOL_SOCKET,
129 SO_PEERCRED,
130 &mut ucred as *mut ucred as *mut c_void,
131 &mut ucred_size,
132 );
133 if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
134 Ok(super::UCred {
135 uid: ucred.uid as unix::uid_t,
136 gid: ucred.gid as unix::gid_t,
137 pid: Some(ucred.pid as unix::pid_t),
138 })
139 } else {
140 Err(io::Error::last_os_error())
141 }
142 }
143 }
144}
145
146#[cfg(any(target_os = "netbsd", target_os = "nto"))]
147pub(crate) mod impl_netbsd {
148 use crate::net::unix::{self, UnixStream};
149
150 use libc::{c_void, getsockopt, socklen_t, unpcbid, LOCAL_PEEREID, SOL_SOCKET};
151 use std::io;
152 use std::mem::size_of;
153 use std::os::unix::io::AsRawFd;
154
155 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
156 unsafe {
157 let raw_fd = sock.as_raw_fd();
158
159 let mut unpcbid = unpcbid {
160 unp_pid: 0,
161 unp_euid: 0,
162 unp_egid: 0,
163 };
164
165 let unpcbid_size = size_of::<unpcbid>();
166 let mut unpcbid_size = unpcbid_size as socklen_t;
167
168 let ret = getsockopt(
169 raw_fd,
170 SOL_SOCKET,
171 LOCAL_PEEREID,
172 &mut unpcbid as *mut unpcbid as *mut c_void,
173 &mut unpcbid_size,
174 );
175 if ret == 0 && unpcbid_size as usize == size_of::<unpcbid>() {
176 Ok(super::UCred {
177 uid: unpcbid.unp_euid as unix::uid_t,
178 gid: unpcbid.unp_egid as unix::gid_t,
179 pid: Some(unpcbid.unp_pid as unix::pid_t),
180 })
181 } else {
182 Err(io::Error::last_os_error())
183 }
184 }
185 }
186}
187
188#[cfg(target_os = "dragonfly")]
189pub(crate) mod impl_dragonfly {
190 use crate::net::unix::{self, UnixStream};
191
192 use libc::getpeereid;
193 use std::io;
194 use std::mem::MaybeUninit;
195 use std::os::unix::io::AsRawFd;
196
197 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
198 unsafe {
199 let raw_fd = sock.as_raw_fd();
200
201 let mut uid = MaybeUninit::uninit();
202 let mut gid = MaybeUninit::uninit();
203
204 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
205
206 if ret == 0 {
207 Ok(super::UCred {
208 uid: uid.assume_init() as unix::uid_t,
209 gid: gid.assume_init() as unix::gid_t,
210 pid: None,
211 })
212 } else {
213 Err(io::Error::last_os_error())
214 }
215 }
216 }
217}
218
219#[cfg(target_os = "freebsd")]
220pub(crate) mod impl_freebsd {
221 use crate::net::unix::{self, UnixStream};
222
223 use libc::{c_void, getsockopt, socklen_t, xucred, LOCAL_PEERCRED, XUCRED_VERSION};
224 use std::io;
225 use std::mem::{size_of, MaybeUninit};
226 use std::os::unix::io::AsRawFd;
227
228 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
229 const SOL_LOCAL: libc::c_int = 0;
232
233 unsafe {
234 let raw_fd = sock.as_raw_fd();
235
236 let mut xucred = MaybeUninit::<xucred>::zeroed();
237 let mut len = size_of::<xucred>() as socklen_t;
238
239 let ret = getsockopt(
240 raw_fd,
241 SOL_LOCAL,
242 LOCAL_PEERCRED,
243 xucred.as_mut_ptr() as *mut c_void,
244 &mut len,
245 );
246
247 if ret != 0 {
248 return Err(io::Error::last_os_error());
249 }
250 if len as usize != size_of::<xucred>() {
251 return Err(io::Error::new(
252 io::ErrorKind::InvalidData,
253 "unexpected xucred size from LOCAL_PEERCRED",
254 ));
255 }
256
257 let xucred = xucred.assume_init();
258
259 if xucred.cr_version != XUCRED_VERSION {
262 return Err(io::Error::new(
263 io::ErrorKind::InvalidData,
264 "unexpected xucred version from LOCAL_PEERCRED",
265 ));
266 }
267
268 let pid = match xucred.cr_pid__c_anonymous_union.cr_pid {
272 0 => None,
273 p => Some(p as unix::pid_t),
274 };
275
276 Ok(super::UCred {
279 uid: xucred.cr_uid as unix::uid_t,
280 gid: xucred.cr_groups[0] as unix::gid_t,
281 pid,
282 })
283 }
284 }
285}
286
287#[cfg(any(
288 target_os = "macos",
289 target_os = "ios",
290 target_os = "tvos",
291 target_os = "watchos",
292 target_os = "visionos"
293))]
294pub(crate) mod impl_macos {
295 use crate::net::unix::{self, UnixStream};
296
297 use libc::{c_void, getpeereid, getsockopt, pid_t, LOCAL_PEEREPID, SOL_LOCAL};
298 use std::io;
299 use std::mem::size_of;
300 use std::mem::MaybeUninit;
301 use std::os::unix::io::AsRawFd;
302
303 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
304 unsafe {
305 let raw_fd = sock.as_raw_fd();
306
307 let mut uid = MaybeUninit::uninit();
308 let mut gid = MaybeUninit::uninit();
309 let mut pid: MaybeUninit<pid_t> = MaybeUninit::uninit();
310 let mut pid_size: MaybeUninit<u32> = MaybeUninit::new(size_of::<pid_t>() as u32);
311
312 if getsockopt(
313 raw_fd,
314 SOL_LOCAL,
315 LOCAL_PEEREPID,
316 pid.as_mut_ptr() as *mut c_void,
317 pid_size.as_mut_ptr(),
318 ) != 0
319 {
320 return Err(io::Error::last_os_error());
321 }
322
323 assert!(pid_size.assume_init() == (size_of::<pid_t>() as u32));
324
325 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
326
327 if ret == 0 {
328 Ok(super::UCred {
329 uid: uid.assume_init() as unix::uid_t,
330 gid: gid.assume_init() as unix::gid_t,
331 pid: Some(pid.assume_init() as unix::pid_t),
332 })
333 } else {
334 Err(io::Error::last_os_error())
335 }
336 }
337 }
338}
339
340#[cfg(any(target_os = "solaris", target_os = "illumos"))]
341pub(crate) mod impl_solaris {
342 use crate::net::unix::{self, UnixStream};
343 use std::io;
344 use std::os::unix::io::AsRawFd;
345 use std::ptr;
346
347 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
348 unsafe {
349 let raw_fd = sock.as_raw_fd();
350
351 let mut cred = ptr::null_mut();
352 let ret = libc::getpeerucred(raw_fd, &mut cred);
353
354 if ret == 0 {
355 let uid = libc::ucred_geteuid(cred);
356 let gid = libc::ucred_getegid(cred);
357 let pid = libc::ucred_getpid(cred);
358
359 libc::ucred_free(cred);
360
361 Ok(super::UCred {
362 uid: uid as unix::uid_t,
363 gid: gid as unix::gid_t,
364 pid: Some(pid as unix::pid_t),
365 })
366 } else {
367 Err(io::Error::last_os_error())
368 }
369 }
370 }
371}
372
373#[cfg(target_os = "aix")]
374pub(crate) mod impl_aix {
375 use crate::net::unix::UnixStream;
376 use std::io;
377 use std::os::unix::io::AsRawFd;
378
379 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
380 unsafe {
381 let raw_fd = sock.as_raw_fd();
382
383 let mut uid = std::mem::MaybeUninit::uninit();
384 let mut gid = std::mem::MaybeUninit::uninit();
385
386 let ret = libc::getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
387
388 if ret == 0 {
389 Ok(super::UCred {
390 uid: uid.assume_init(),
391 gid: gid.assume_init(),
392 pid: None,
393 })
394 } else {
395 Err(io::Error::last_os_error())
396 }
397 }
398 }
399}
400
401#[cfg(any(
402 target_os = "espidf",
403 target_os = "nuttx",
404 target_os = "vita",
405 target_os = "hurd"
406))]
407pub(crate) mod impl_noproc {
408 use crate::net::unix::UnixStream;
409 use std::io;
410
411 pub(crate) fn get_peer_cred(_sock: &UnixStream) -> io::Result<super::UCred> {
412 Ok(super::UCred {
413 uid: 0,
414 gid: 0,
415 pid: None,
416 })
417 }
418}
419
420#[cfg(target_os = "nto")]
421pub(crate) mod impl_nto {
422 use crate::net::unix::{self, UnixStream};
423
424 use libc::getpeereid;
425 use std::io;
426 use std::mem::MaybeUninit;
427 use std::os::unix::io::AsRawFd;
428
429 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
430 unsafe {
431 let raw_fd = sock.as_raw_fd();
432
433 let mut uid = MaybeUninit::uninit();
434 let mut gid = MaybeUninit::uninit();
435
436 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
437
438 if ret == 0 {
439 Ok(super::UCred {
440 uid: uid.assume_init() as unix::uid_t,
441 gid: gid.assume_init() as unix::gid_t,
442 pid: None,
443 })
444 } else {
445 Err(io::Error::last_os_error())
446 }
447 }
448 }
449}