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