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