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