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(any(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(target_os = "macos", target_os = "ios"))]
49pub(crate) use self::impl_macos::get_peer_cred;
50
51#[cfg(any(target_os = "solaris", target_os = "illumos"))]
52pub(crate) use self::impl_solaris::get_peer_cred;
53
54#[cfg(target_os = "aix")]
55pub(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))]
63pub(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"))]
115pub(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"))]
157pub(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"))]
188pub(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"))]
235pub(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")]
268pub(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