1use crate::net::unix;
2
3/// Credentials of a process.
4#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
5pub struct UCred {
6 /// PID (process ID) of the process.
7 pid: Option<unix::pid_t>,
8 /// UID (user ID) of the process.
9 uid: unix::uid_t,
10 /// GID (group ID) of the process.
11 gid: unix::gid_t,
12}
13
14impl UCred {
15 /// Gets UID (user ID) of the process.
16 pub fn uid(&self) -> unix::uid_t {
17 self.uid
18 }
19
20 /// Gets GID (group ID) of the process.
21 pub fn gid(&self) -> unix::gid_t {
22 self.gid
23 }
24
25 /// Gets PID (process ID) of the process.
26 ///
27 /// This is only implemented under Linux, Android, iOS, macOS, Solaris and
28 /// Illumos. On other platforms this will always return `None`.
29 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(target_os = "netbsd")]
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))]
54pub(crate) use self::impl_macos::get_peer_cred;
55
56#[cfg(any(target_os = "solaris", target_os = "illumos"))]
57pub(crate) use self::impl_solaris::get_peer_cred;
58
59#[cfg(target_os = "aix")]
60pub(crate) use self::impl_aix::get_peer_cred;
61
62#[cfg(any(target_os = "espidf", target_os = "vita"))]
63pub(crate) use self::impl_noproc::get_peer_cred;
64
65#[cfg(any(
66 target_os = "linux",
67 target_os = "redox",
68 target_os = "android",
69 target_os = "openbsd"
70))]
71pub(crate) mod impl_linux {
72 use crate::net::unix::{self, UnixStream};
73
74 use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED};
75 use std::{io, mem};
76
77 #[cfg(target_os = "openbsd")]
78 use libc::sockpeercred as ucred;
79 #[cfg(any(target_os = "linux", target_os = "redox", target_os = "android"))]
80 use libc::ucred;
81
82 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
83 use std::os::unix::io::AsRawFd;
84
85 unsafe {
86 let raw_fd = sock.as_raw_fd();
87
88 let mut ucred = ucred {
89 pid: 0,
90 uid: 0,
91 gid: 0,
92 };
93
94 let ucred_size = mem::size_of::<ucred>();
95
96 // These paranoid checks should be optimized-out
97 assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
98 assert!(ucred_size <= u32::MAX as usize);
99
100 let mut ucred_size = ucred_size as socklen_t;
101
102 let ret = getsockopt(
103 raw_fd,
104 SOL_SOCKET,
105 SO_PEERCRED,
106 &mut ucred as *mut ucred as *mut c_void,
107 &mut ucred_size,
108 );
109 if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
110 Ok(super::UCred {
111 uid: ucred.uid as unix::uid_t,
112 gid: ucred.gid as unix::gid_t,
113 pid: Some(ucred.pid as unix::pid_t),
114 })
115 } else {
116 Err(io::Error::last_os_error())
117 }
118 }
119 }
120}
121
122#[cfg(target_os = "netbsd")]
123pub(crate) mod impl_netbsd {
124 use crate::net::unix::{self, UnixStream};
125
126 use libc::{c_void, getsockopt, socklen_t, unpcbid, LOCAL_PEEREID, SOL_SOCKET};
127 use std::io;
128 use std::mem::size_of;
129 use std::os::unix::io::AsRawFd;
130
131 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
132 unsafe {
133 let raw_fd = sock.as_raw_fd();
134
135 let mut unpcbid = unpcbid {
136 unp_pid: 0,
137 unp_euid: 0,
138 unp_egid: 0,
139 };
140
141 let unpcbid_size = size_of::<unpcbid>();
142 let mut unpcbid_size = unpcbid_size as socklen_t;
143
144 let ret = getsockopt(
145 raw_fd,
146 SOL_SOCKET,
147 LOCAL_PEEREID,
148 &mut unpcbid as *mut unpcbid as *mut c_void,
149 &mut unpcbid_size,
150 );
151 if ret == 0 && unpcbid_size as usize == size_of::<unpcbid>() {
152 Ok(super::UCred {
153 uid: unpcbid.unp_euid as unix::uid_t,
154 gid: unpcbid.unp_egid as unix::gid_t,
155 pid: Some(unpcbid.unp_pid as unix::pid_t),
156 })
157 } else {
158 Err(io::Error::last_os_error())
159 }
160 }
161 }
162}
163
164#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
165pub(crate) mod impl_bsd {
166 use crate::net::unix::{self, UnixStream};
167
168 use libc::getpeereid;
169 use std::io;
170 use std::mem::MaybeUninit;
171 use std::os::unix::io::AsRawFd;
172
173 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
174 unsafe {
175 let raw_fd = sock.as_raw_fd();
176
177 let mut uid = MaybeUninit::uninit();
178 let mut gid = MaybeUninit::uninit();
179
180 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
181
182 if ret == 0 {
183 Ok(super::UCred {
184 uid: uid.assume_init() as unix::uid_t,
185 gid: gid.assume_init() as unix::gid_t,
186 pid: None,
187 })
188 } else {
189 Err(io::Error::last_os_error())
190 }
191 }
192 }
193}
194
195#[cfg(any(
196 target_os = "macos",
197 target_os = "ios",
198 target_os = "tvos",
199 target_os = "watchos"
200))]
201pub(crate) mod impl_macos {
202 use crate::net::unix::{self, UnixStream};
203
204 use libc::{c_void, getpeereid, getsockopt, pid_t, LOCAL_PEEREPID, SOL_LOCAL};
205 use std::io;
206 use std::mem::size_of;
207 use std::mem::MaybeUninit;
208 use std::os::unix::io::AsRawFd;
209
210 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
211 unsafe {
212 let raw_fd = sock.as_raw_fd();
213
214 let mut uid = MaybeUninit::uninit();
215 let mut gid = MaybeUninit::uninit();
216 let mut pid: MaybeUninit<pid_t> = MaybeUninit::uninit();
217 let mut pid_size: MaybeUninit<u32> = MaybeUninit::new(size_of::<pid_t>() as u32);
218
219 if getsockopt(
220 raw_fd,
221 SOL_LOCAL,
222 LOCAL_PEEREPID,
223 pid.as_mut_ptr() as *mut c_void,
224 pid_size.as_mut_ptr(),
225 ) != 0
226 {
227 return Err(io::Error::last_os_error());
228 }
229
230 assert!(pid_size.assume_init() == (size_of::<pid_t>() as u32));
231
232 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
233
234 if ret == 0 {
235 Ok(super::UCred {
236 uid: uid.assume_init() as unix::uid_t,
237 gid: gid.assume_init() as unix::gid_t,
238 pid: Some(pid.assume_init() as unix::pid_t),
239 })
240 } else {
241 Err(io::Error::last_os_error())
242 }
243 }
244 }
245}
246
247#[cfg(any(target_os = "solaris", target_os = "illumos"))]
248pub(crate) mod impl_solaris {
249 use crate::net::unix::{self, UnixStream};
250 use std::io;
251 use std::os::unix::io::AsRawFd;
252 use std::ptr;
253
254 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
255 unsafe {
256 let raw_fd = sock.as_raw_fd();
257
258 let mut cred = ptr::null_mut();
259 let ret = libc::getpeerucred(raw_fd, &mut cred);
260
261 if ret == 0 {
262 let uid = libc::ucred_geteuid(cred);
263 let gid = libc::ucred_getegid(cred);
264 let pid = libc::ucred_getpid(cred);
265
266 libc::ucred_free(cred);
267
268 Ok(super::UCred {
269 uid: uid as unix::uid_t,
270 gid: gid as unix::gid_t,
271 pid: Some(pid as unix::pid_t),
272 })
273 } else {
274 Err(io::Error::last_os_error())
275 }
276 }
277 }
278}
279
280#[cfg(target_os = "aix")]
281pub(crate) mod impl_aix {
282 use crate::net::unix::UnixStream;
283 use std::io;
284 use std::os::unix::io::AsRawFd;
285
286 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
287 unsafe {
288 let raw_fd = sock.as_raw_fd();
289
290 let mut uid = std::mem::MaybeUninit::uninit();
291 let mut gid = std::mem::MaybeUninit::uninit();
292
293 let ret = libc::getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
294
295 if ret == 0 {
296 Ok(super::UCred {
297 uid: uid.assume_init(),
298 gid: gid.assume_init(),
299 pid: None,
300 })
301 } else {
302 Err(io::Error::last_os_error())
303 }
304 }
305 }
306}
307
308#[cfg(any(target_os = "espidf", target_os = "vita"))]
309pub(crate) mod impl_noproc {
310 use crate::net::unix::UnixStream;
311 use std::io;
312
313 pub(crate) fn get_peer_cred(_sock: &UnixStream) -> io::Result<super::UCred> {
314 Ok(super::UCred {
315 uid: 0,
316 gid: 0,
317 pid: None,
318 })
319 }
320}
321