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