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 | ))] |
40 | pub(crate) use self::impl_linux::get_peer_cred; |
41 | |
42 | #[cfg (target_os = "netbsd" )] |
43 | pub(crate) use self::impl_netbsd::get_peer_cred; |
44 | |
45 | #[cfg (any(target_os = "dragonfly" , target_os = "freebsd" ))] |
46 | pub(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 | ))] |
54 | pub(crate) use self::impl_macos::get_peer_cred; |
55 | |
56 | #[cfg (any(target_os = "solaris" , target_os = "illumos" ))] |
57 | pub(crate) use self::impl_solaris::get_peer_cred; |
58 | |
59 | #[cfg (target_os = "aix" )] |
60 | pub(crate) use self::impl_aix::get_peer_cred; |
61 | |
62 | #[cfg (any(target_os = "espidf" , target_os = "vita" ))] |
63 | pub(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 | ))] |
71 | pub(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" )] |
123 | pub(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" ))] |
165 | pub(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 | ))] |
201 | pub(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" ))] |
248 | pub(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" )] |
281 | pub(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" ))] |
309 | pub(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 | |