| 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 | |