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