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