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 = "fuchsia",
72 target_os = "espidf",
73 target_os = "nuttx",
74 target_os = "vita",
75 target_os = "hurd"
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(any(target_os = "netbsd", target_os = "nto"))]
148pub(crate) mod impl_netbsd {
149 use crate::net::unix::{self, UnixStream};
150
151 use libc::{c_void, getsockopt, socklen_t, unpcbid, LOCAL_PEEREID, SOL_SOCKET};
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 unsafe {
158 let raw_fd = sock.as_raw_fd();
159
160 let mut unpcbid = unpcbid {
161 unp_pid: 0,
162 unp_euid: 0,
163 unp_egid: 0,
164 };
165
166 let unpcbid_size = size_of::<unpcbid>();
167 let mut unpcbid_size = unpcbid_size as socklen_t;
168
169 let ret = getsockopt(
170 raw_fd,
171 SOL_SOCKET,
172 LOCAL_PEEREID,
173 &mut unpcbid as *mut unpcbid as *mut c_void,
174 &mut unpcbid_size,
175 );
176 if ret == 0 && unpcbid_size as usize == size_of::<unpcbid>() {
177 Ok(super::UCred {
178 uid: unpcbid.unp_euid as unix::uid_t,
179 gid: unpcbid.unp_egid as unix::gid_t,
180 pid: Some(unpcbid.unp_pid as unix::pid_t),
181 })
182 } else {
183 Err(io::Error::last_os_error())
184 }
185 }
186 }
187}
188
189#[cfg(target_os = "dragonfly")]
190pub(crate) mod impl_dragonfly {
191 use crate::net::unix::{self, UnixStream};
192
193 use libc::getpeereid;
194 use std::io;
195 use std::mem::MaybeUninit;
196 use std::os::unix::io::AsRawFd;
197
198 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
199 unsafe {
200 let raw_fd = sock.as_raw_fd();
201
202 let mut uid = MaybeUninit::uninit();
203 let mut gid = MaybeUninit::uninit();
204
205 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
206
207 if ret == 0 {
208 Ok(super::UCred {
209 uid: uid.assume_init() as unix::uid_t,
210 gid: gid.assume_init() as unix::gid_t,
211 pid: None,
212 })
213 } else {
214 Err(io::Error::last_os_error())
215 }
216 }
217 }
218}
219
220#[cfg(target_os = "freebsd")]
221pub(crate) mod impl_freebsd {
222 use crate::net::unix::{self, UnixStream};
223
224 use libc::{c_void, getsockopt, socklen_t, xucred, LOCAL_PEERCRED, XUCRED_VERSION};
225 use std::io;
226 use std::mem::{size_of, MaybeUninit};
227 use std::os::unix::io::AsRawFd;
228
229 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
230 const SOL_LOCAL: libc::c_int = 0;
233
234 unsafe {
235 let raw_fd = sock.as_raw_fd();
236
237 let mut xucred = MaybeUninit::<xucred>::zeroed();
238 let mut len = size_of::<xucred>() as socklen_t;
239
240 let ret = getsockopt(
241 raw_fd,
242 SOL_LOCAL,
243 LOCAL_PEERCRED,
244 xucred.as_mut_ptr() as *mut c_void,
245 &mut len,
246 );
247
248 if ret != 0 {
249 return Err(io::Error::last_os_error());
250 }
251 if len as usize != size_of::<xucred>() {
252 return Err(io::Error::new(
253 io::ErrorKind::InvalidData,
254 "unexpected xucred size from LOCAL_PEERCRED",
255 ));
256 }
257
258 let xucred = xucred.assume_init();
259
260 if xucred.cr_version != XUCRED_VERSION {
263 return Err(io::Error::new(
264 io::ErrorKind::InvalidData,
265 "unexpected xucred version from LOCAL_PEERCRED",
266 ));
267 }
268
269 let pid = match xucred.cr_pid__c_anonymous_union.cr_pid {
273 0 => None,
274 p => Some(p as unix::pid_t),
275 };
276
277 Ok(super::UCred {
280 uid: xucred.cr_uid as unix::uid_t,
281 gid: xucred.cr_groups[0] as unix::gid_t,
282 pid,
283 })
284 }
285 }
286}
287
288#[cfg(any(
289 target_os = "macos",
290 target_os = "ios",
291 target_os = "tvos",
292 target_os = "watchos",
293 target_os = "visionos"
294))]
295pub(crate) mod impl_macos {
296 use crate::net::unix::{self, UnixStream};
297
298 use libc::{c_void, getpeereid, getsockopt, pid_t, LOCAL_PEEREPID, SOL_LOCAL};
299 use std::io;
300 use std::mem::size_of;
301 use std::mem::MaybeUninit;
302 use std::os::unix::io::AsRawFd;
303
304 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
305 unsafe {
306 let raw_fd = sock.as_raw_fd();
307
308 let mut uid = MaybeUninit::uninit();
309 let mut gid = MaybeUninit::uninit();
310 let mut pid: MaybeUninit<pid_t> = MaybeUninit::uninit();
311 let mut pid_size: MaybeUninit<u32> = MaybeUninit::new(size_of::<pid_t>() as u32);
312
313 if getsockopt(
314 raw_fd,
315 SOL_LOCAL,
316 LOCAL_PEEREPID,
317 pid.as_mut_ptr() as *mut c_void,
318 pid_size.as_mut_ptr(),
319 ) != 0
320 {
321 return Err(io::Error::last_os_error());
322 }
323
324 assert!(pid_size.assume_init() == (size_of::<pid_t>() as u32));
325
326 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
327
328 if ret == 0 {
329 Ok(super::UCred {
330 uid: uid.assume_init() as unix::uid_t,
331 gid: gid.assume_init() as unix::gid_t,
332 pid: Some(pid.assume_init() as unix::pid_t),
333 })
334 } else {
335 Err(io::Error::last_os_error())
336 }
337 }
338 }
339}
340
341#[cfg(any(target_os = "solaris", target_os = "illumos"))]
342pub(crate) mod impl_solaris {
343 use crate::net::unix::{self, UnixStream};
344 use std::io;
345 use std::os::unix::io::AsRawFd;
346 use std::ptr;
347
348 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
349 unsafe {
350 let raw_fd = sock.as_raw_fd();
351
352 let mut cred = ptr::null_mut();
353 let ret = libc::getpeerucred(raw_fd, &mut cred);
354
355 if ret == 0 {
356 let uid = libc::ucred_geteuid(cred);
357 let gid = libc::ucred_getegid(cred);
358 let pid = libc::ucred_getpid(cred);
359
360 libc::ucred_free(cred);
361
362 Ok(super::UCred {
363 uid: uid as unix::uid_t,
364 gid: gid as unix::gid_t,
365 pid: Some(pid as unix::pid_t),
366 })
367 } else {
368 Err(io::Error::last_os_error())
369 }
370 }
371 }
372}
373
374#[cfg(target_os = "aix")]
375pub(crate) mod impl_aix {
376 use crate::net::unix::UnixStream;
377 use std::io;
378 use std::os::unix::io::AsRawFd;
379
380 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
381 unsafe {
382 let raw_fd = sock.as_raw_fd();
383
384 let mut uid = std::mem::MaybeUninit::uninit();
385 let mut gid = std::mem::MaybeUninit::uninit();
386
387 let ret = libc::getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
388
389 if ret == 0 {
390 Ok(super::UCred {
391 uid: uid.assume_init(),
392 gid: gid.assume_init(),
393 pid: None,
394 })
395 } else {
396 Err(io::Error::last_os_error())
397 }
398 }
399 }
400}
401
402#[cfg(any(
403 target_os = "fuchsia",
404 target_os = "espidf",
405 target_os = "nuttx",
406 target_os = "vita",
407 target_os = "hurd"
408))]
409pub(crate) mod impl_noproc {
410 use crate::net::unix::UnixStream;
411 use std::io;
412
413 pub(crate) fn get_peer_cred(_sock: &UnixStream) -> io::Result<super::UCred> {
414 Ok(super::UCred {
415 uid: 0,
416 gid: 0,
417 pid: None,
418 })
419 }
420}
421
422#[cfg(target_os = "nto")]
423pub(crate) mod impl_nto {
424 use crate::net::unix::{self, UnixStream};
425
426 use libc::getpeereid;
427 use std::io;
428 use std::mem::MaybeUninit;
429 use std::os::unix::io::AsRawFd;
430
431 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
432 unsafe {
433 let raw_fd = sock.as_raw_fd();
434
435 let mut uid = MaybeUninit::uninit();
436 let mut gid = MaybeUninit::uninit();
437
438 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
439
440 if ret == 0 {
441 Ok(super::UCred {
442 uid: uid.assume_init() as unix::uid_t,
443 gid: gid.assume_init() as unix::gid_t,
444 pid: None,
445 })
446 } else {
447 Err(io::Error::last_os_error())
448 }
449 }
450 }
451}