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(target_os = "linux", target_os = "android", target_os = "openbsd"))] 35 pub(crate) use self::impl_linux::get_peer_cred; 36 37 #[cfg(any(target_os = "netbsd"))] 38 pub(crate) use self::impl_netbsd::get_peer_cred; 39 40 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 41 pub(crate) use self::impl_bsd::get_peer_cred; 42 43 #[cfg(any(target_os = "macos", target_os = "ios"))] 44 pub(crate) use self::impl_macos::get_peer_cred; 45 46 #[cfg(any(target_os = "solaris", target_os = "illumos"))] 47 pub(crate) use self::impl_solaris::get_peer_cred; 48 49 #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))] 50 pub(crate) mod impl_linux { 51 use crate::net::unix::{self, UnixStream}; 52 53 use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED}; 54 use std::{io, mem}; 55 56 #[cfg(target_os = "openbsd")] 57 use libc::sockpeercred as ucred; 58 #[cfg(any(target_os = "linux", target_os = "android"))] 59 use libc::ucred; 60 get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>61 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { 62 use std::os::unix::io::AsRawFd; 63 64 unsafe { 65 let raw_fd = sock.as_raw_fd(); 66 67 let mut ucred = ucred { 68 pid: 0, 69 uid: 0, 70 gid: 0, 71 }; 72 73 let ucred_size = mem::size_of::<ucred>(); 74 75 // These paranoid checks should be optimized-out 76 assert!(mem::size_of::<u32>() <= mem::size_of::<usize>()); 77 assert!(ucred_size <= u32::MAX as usize); 78 79 let mut ucred_size = ucred_size as socklen_t; 80 81 let ret = getsockopt( 82 raw_fd, 83 SOL_SOCKET, 84 SO_PEERCRED, 85 &mut ucred as *mut ucred as *mut c_void, 86 &mut ucred_size, 87 ); 88 if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() { 89 Ok(super::UCred { 90 uid: ucred.uid as unix::uid_t, 91 gid: ucred.gid as unix::gid_t, 92 pid: Some(ucred.pid as unix::pid_t), 93 }) 94 } else { 95 Err(io::Error::last_os_error()) 96 } 97 } 98 } 99 } 100 101 #[cfg(any(target_os = "netbsd"))] 102 pub(crate) mod impl_netbsd { 103 use crate::net::unix::{self, UnixStream}; 104 105 use libc::{c_void, getsockopt, socklen_t, unpcbid, LOCAL_PEEREID, SOL_SOCKET}; 106 use std::io; 107 use std::mem::size_of; 108 use std::os::unix::io::AsRawFd; 109 get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>110 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { 111 unsafe { 112 let raw_fd = sock.as_raw_fd(); 113 114 let mut unpcbid = unpcbid { 115 unp_pid: 0, 116 unp_euid: 0, 117 unp_egid: 0, 118 }; 119 120 let unpcbid_size = size_of::<unpcbid>(); 121 let mut unpcbid_size = unpcbid_size as socklen_t; 122 123 let ret = getsockopt( 124 raw_fd, 125 SOL_SOCKET, 126 LOCAL_PEEREID, 127 &mut unpcbid as *mut unpcbid as *mut c_void, 128 &mut unpcbid_size, 129 ); 130 if ret == 0 && unpcbid_size as usize == size_of::<unpcbid>() { 131 Ok(super::UCred { 132 uid: unpcbid.unp_euid as unix::uid_t, 133 gid: unpcbid.unp_egid as unix::gid_t, 134 pid: Some(unpcbid.unp_pid as unix::pid_t), 135 }) 136 } else { 137 Err(io::Error::last_os_error()) 138 } 139 } 140 } 141 } 142 143 #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 144 pub(crate) mod impl_bsd { 145 use crate::net::unix::{self, UnixStream}; 146 147 use libc::getpeereid; 148 use std::io; 149 use std::mem::MaybeUninit; 150 use std::os::unix::io::AsRawFd; 151 get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>152 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { 153 unsafe { 154 let raw_fd = sock.as_raw_fd(); 155 156 let mut uid = MaybeUninit::uninit(); 157 let mut gid = MaybeUninit::uninit(); 158 159 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr()); 160 161 if ret == 0 { 162 Ok(super::UCred { 163 uid: uid.assume_init() as unix::uid_t, 164 gid: gid.assume_init() as unix::gid_t, 165 pid: None, 166 }) 167 } else { 168 Err(io::Error::last_os_error()) 169 } 170 } 171 } 172 } 173 174 #[cfg(any(target_os = "macos", target_os = "ios"))] 175 pub(crate) mod impl_macos { 176 use crate::net::unix::{self, UnixStream}; 177 178 use libc::{c_void, getpeereid, getsockopt, pid_t, LOCAL_PEEREPID, SOL_LOCAL}; 179 use std::io; 180 use std::mem::size_of; 181 use std::mem::MaybeUninit; 182 use std::os::unix::io::AsRawFd; 183 get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>184 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { 185 unsafe { 186 let raw_fd = sock.as_raw_fd(); 187 188 let mut uid = MaybeUninit::uninit(); 189 let mut gid = MaybeUninit::uninit(); 190 let mut pid: MaybeUninit<pid_t> = MaybeUninit::uninit(); 191 let mut pid_size: MaybeUninit<u32> = MaybeUninit::new(size_of::<pid_t>() as u32); 192 193 if getsockopt( 194 raw_fd, 195 SOL_LOCAL, 196 LOCAL_PEEREPID, 197 pid.as_mut_ptr() as *mut c_void, 198 pid_size.as_mut_ptr(), 199 ) != 0 200 { 201 return Err(io::Error::last_os_error()); 202 } 203 204 assert!(pid_size.assume_init() == (size_of::<pid_t>() as u32)); 205 206 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr()); 207 208 if ret == 0 { 209 Ok(super::UCred { 210 uid: uid.assume_init() as unix::uid_t, 211 gid: gid.assume_init() as unix::gid_t, 212 pid: Some(pid.assume_init() as unix::pid_t), 213 }) 214 } else { 215 Err(io::Error::last_os_error()) 216 } 217 } 218 } 219 } 220 221 #[cfg(any(target_os = "solaris", target_os = "illumos"))] 222 pub(crate) mod impl_solaris { 223 use crate::net::unix::{self, UnixStream}; 224 use std::io; 225 use std::os::unix::io::AsRawFd; 226 use std::ptr; 227 get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>228 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { 229 unsafe { 230 let raw_fd = sock.as_raw_fd(); 231 232 let mut cred = ptr::null_mut(); 233 let ret = libc::getpeerucred(raw_fd, &mut cred); 234 235 if ret == 0 { 236 let uid = libc::ucred_geteuid(cred); 237 let gid = libc::ucred_getegid(cred); 238 let pid = libc::ucred_getpid(cred); 239 240 libc::ucred_free(cred); 241 242 Ok(super::UCred { 243 uid: uid as unix::uid_t, 244 gid: gid as unix::gid_t, 245 pid: Some(pid as unix::pid_t), 246 }) 247 } else { 248 Err(io::Error::last_os_error()) 249 } 250 } 251 } 252 } 253