use libc::{gid_t, pid_t, uid_t}; /// Credentials of a process #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] pub struct UCred { /// PID (process ID) of the process pid: Option, /// UID (user ID) of the process uid: uid_t, /// GID (group ID) of the process gid: gid_t, } impl UCred { /// Gets UID (user ID) of the process. pub fn uid(&self) -> uid_t { self.uid } /// Gets GID (group ID) of the process. pub fn gid(&self) -> gid_t { self.gid } /// Gets PID (process ID) of the process. /// /// This is only implemented under Linux, Android, iOS, macOS, Solaris and /// Illumos. On other plaforms this will always return `None`. pub fn pid(&self) -> Option { self.pid } } #[cfg(any(target_os = "linux", target_os = "android"))] pub(crate) use self::impl_linux::get_peer_cred; #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd" ))] pub(crate) use self::impl_bsd::get_peer_cred; #[cfg(any(target_os = "macos", target_os = "ios"))] pub(crate) use self::impl_macos::get_peer_cred; #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub(crate) use self::impl_solaris::get_peer_cred; #[cfg(any(target_os = "linux", target_os = "android"))] pub(crate) mod impl_linux { use crate::net::unix::UnixStream; use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED}; use std::{io, mem}; use libc::ucred; pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result { use std::os::unix::io::AsRawFd; unsafe { let raw_fd = sock.as_raw_fd(); let mut ucred = ucred { pid: 0, uid: 0, gid: 0, }; let ucred_size = mem::size_of::(); // These paranoid checks should be optimized-out assert!(mem::size_of::() <= mem::size_of::()); assert!(ucred_size <= u32::max_value() as usize); let mut ucred_size = ucred_size as socklen_t; let ret = getsockopt( raw_fd, SOL_SOCKET, SO_PEERCRED, &mut ucred as *mut ucred as *mut c_void, &mut ucred_size, ); if ret == 0 && ucred_size as usize == mem::size_of::() { Ok(super::UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid), }) } else { Err(io::Error::last_os_error()) } } } } #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd" ))] pub(crate) mod impl_bsd { use crate::net::unix::UnixStream; use libc::getpeereid; use std::io; use std::mem::MaybeUninit; use std::os::unix::io::AsRawFd; pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result { unsafe { let raw_fd = sock.as_raw_fd(); let mut uid = MaybeUninit::uninit(); let mut gid = MaybeUninit::uninit(); let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr()); if ret == 0 { Ok(super::UCred { uid: uid.assume_init(), gid: gid.assume_init(), pid: None, }) } else { Err(io::Error::last_os_error()) } } } } #[cfg(any(target_os = "macos", target_os = "ios"))] pub(crate) mod impl_macos { use crate::net::unix::UnixStream; use libc::{c_void, getpeereid, getsockopt, pid_t, LOCAL_PEEREPID, SOL_LOCAL}; use std::io; use std::mem::size_of; use std::mem::MaybeUninit; use std::os::unix::io::AsRawFd; pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result { unsafe { let raw_fd = sock.as_raw_fd(); let mut uid = MaybeUninit::uninit(); let mut gid = MaybeUninit::uninit(); let mut pid: MaybeUninit = MaybeUninit::uninit(); let mut pid_size: MaybeUninit = MaybeUninit::new(size_of::() as u32); if getsockopt( raw_fd, SOL_LOCAL, LOCAL_PEEREPID, pid.as_mut_ptr() as *mut c_void, pid_size.as_mut_ptr(), ) != 0 { return Err(io::Error::last_os_error()); } assert!(pid_size.assume_init() == (size_of::() as u32)); let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr()); if ret == 0 { Ok(super::UCred { uid: uid.assume_init(), gid: gid.assume_init(), pid: Some(pid.assume_init()), }) } else { Err(io::Error::last_os_error()) } } } } #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub(crate) mod impl_solaris { use crate::net::unix::UnixStream; use std::io; use std::os::unix::io::AsRawFd; use std::ptr; pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result { unsafe { let raw_fd = sock.as_raw_fd(); let mut cred = ptr::null_mut(); let ret = libc::getpeerucred(raw_fd, &mut cred); if ret == 0 { let uid = libc::ucred_geteuid(cred); let gid = libc::ucred_getegid(cred); let pid = libc::ucred_getpid(cred); libc::ucred_free(cred); Ok(super::UCred { uid, gid, pid: Some(pid), }) } else { Err(io::Error::last_os_error()) } } } }