|
| 1 | +//! Unix peer credentials. |
| 2 | +
|
| 3 | +// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on |
| 4 | +// GitHub. |
| 5 | +// |
| 6 | +// For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13 |
| 7 | +// Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work. |
| 8 | + |
| 9 | +use libc::{gid_t, uid_t}; |
| 10 | + |
| 11 | +/// Credentials for a UNIX process for credentials passing. |
| 12 | +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] |
| 13 | +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
| 14 | +pub struct UCred { |
| 15 | + pub uid: uid_t, |
| 16 | + pub gid: gid_t, |
| 17 | +} |
| 18 | + |
| 19 | +#[cfg(any(target_os = "android", target_os = "linux"))] |
| 20 | +pub use self::impl_linux::peer_cred; |
| 21 | + |
| 22 | +#[cfg(any( |
| 23 | + target_os = "dragonfly", |
| 24 | + target_os = "freebsd", |
| 25 | + target_os = "ios", |
| 26 | + target_os = "macos", |
| 27 | + target_os = "openbsd" |
| 28 | +))] |
| 29 | +pub use self::impl_bsd::peer_cred; |
| 30 | + |
| 31 | +#[cfg(any(target_os = "linux", target_os = "android"))] |
| 32 | +pub mod impl_linux { |
| 33 | + use super::UCred; |
| 34 | + use crate::mem::MaybeUninit; |
| 35 | + use crate::os::unix::io::AsRawFd; |
| 36 | + use crate::os::unix::net::UnixStream; |
| 37 | + use crate::{io, mem}; |
| 38 | + |
| 39 | + pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> { |
| 40 | + use libc::{c_void, ucred}; |
| 41 | + |
| 42 | + let ucred_size = mem::size_of::<ucred>(); |
| 43 | + |
| 44 | + // Trivial sanity checks. |
| 45 | + assert!(mem::size_of::<u32>() <= mem::size_of::<usize>()); |
| 46 | + assert!(ucred_size <= u32::max_value() as usize); |
| 47 | + |
| 48 | + let mut ucred_size = ucred_size as u32; |
| 49 | + |
| 50 | + unsafe { |
| 51 | + let mut ucred: ucred = MaybeUninit::uninit().assume_init(); |
| 52 | + let ret = libc::getsockopt( |
| 53 | + socket.as_raw_fd(), |
| 54 | + libc::SOL_SOCKET, |
| 55 | + libc::SO_PEERCRED, |
| 56 | + &mut ucred as *mut ucred as *mut c_void, |
| 57 | + &mut ucred_size, |
| 58 | + ); |
| 59 | + |
| 60 | + if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() { |
| 61 | + Ok(UCred { uid: ucred.uid, gid: ucred.gid }) |
| 62 | + } else { |
| 63 | + Err(io::Error::last_os_error()) |
| 64 | + } |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +#[cfg(any( |
| 70 | + target_os = "dragonfly", |
| 71 | + target_os = "macos", |
| 72 | + target_os = "ios", |
| 73 | + target_os = "freebsd", |
| 74 | + target_os = "openbsd" |
| 75 | +))] |
| 76 | +pub mod impl_bsd { |
| 77 | + use super::UCred; |
| 78 | + use crate::io; |
| 79 | + use crate::mem::MaybeUninit; |
| 80 | + use crate::os::unix::io::AsRawFd; |
| 81 | + use crate::os::unix::net::UnixStream; |
| 82 | + |
| 83 | + pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> { |
| 84 | + unsafe { |
| 85 | + // Create `cred` and attempt to populate it. |
| 86 | + let mut cred: UCred = MaybeUninit::uninit().assume_init(); |
| 87 | + let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); |
| 88 | + |
| 89 | + if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) } |
| 90 | + } |
| 91 | + } |
| 92 | +} |
0 commit comments