#
std/os/unix/net/
ucred.rs

    1// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on
    2//       GitHub.
    3//
    4//       For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13
    5//       Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work.
    6
    7use libc::{gid_t, pid_t, uid_t};
    8
    9/// Credentials for a UNIX process for credentials passing.
    10#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
    11#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    12pub struct UCred {
    13    /// The UID part of the peer credential. This is the effective UID of the process at the domain
    14    /// socket's endpoint.
    15    pub uid: uid_t,
    16    /// The GID part of the peer credential. This is the effective GID of the process at the domain
    17    /// socket's endpoint.
    18    pub gid: gid_t,
    19    /// The PID part of the peer credential. This field is optional because the PID part of the
    20    /// peer credentials is not supported on every platform. On platforms where the mechanism to
    21    /// discover the PID exists, this field will be populated to the PID of the process at the
    22    /// domain socket's endpoint. Otherwise, it will be set to None.
    23    pub pid: Option<pid_t>,
    24}
    25
    26#[cfg(target_vendor = "apple")]
    27pub(super) use self::impl_apple::peer_cred;
    28#[cfg(any(
    29    target_os = "dragonfly",
    30    target_os = "freebsd",
    31    target_os = "openbsd",
    32    target_os = "netbsd",
    33    target_os = "nto"
    34))]
    35pub(super) use self::impl_bsd::peer_cred;
    36#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
    37pub(super) use self::impl_linux::peer_cred;
    38
    39#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
    40mod impl_linux {
    41    use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred};
    42
    43    use super::UCred;
    44    use crate::io;
    45    use crate::os::unix::io::AsRawFd;
    46    use crate::os::unix::net::UnixStream;
    47
    48    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
    49        let ucred_size = size_of::<ucred>();
    50
    51        // Trivial sanity checks.
    52        assert!(size_of::<u32>() <= size_of::<usize>());
    53        assert!(ucred_size <= u32::MAX as usize);
    54
    55        let mut ucred_size = ucred_size as socklen_t;
    56        let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
    57
    58        unsafe {
    59            let ret = getsockopt(
    60                socket.as_raw_fd(),
    61                SOL_SOCKET,
    62                SO_PEERCRED,
    63                (&raw mut ucred) as *mut c_void,
    64                &mut ucred_size,
    65            );
    66
    67            if ret == 0 && ucred_size as usize == size_of::<ucred>() {
    68                Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
    69            } else {
    70                Err(io::Error::last_os_error())
    71            }
    72        }
    73    }
    74}
    75
    76#[cfg(any(
    77    target_os = "dragonfly",
    78    target_os = "freebsd",
    79    target_os = "openbsd",
    80    target_os = "netbsd",
    81    target_os = "nto",
    82))]
    83mod impl_bsd {
    84    use super::UCred;
    85    use crate::io;
    86    use crate::os::unix::io::AsRawFd;
    87    use crate::os::unix::net::UnixStream;
    88
    89    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
    90        let mut cred = UCred { uid: 1, gid: 1, pid: None };
    91        unsafe {
    92            let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
    93
    94            if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
    95        }
    96    }
    97}
    98
    99#[cfg(target_vendor = "apple")]
    100mod impl_apple {
    101    use libc::{LOCAL_PEERPID, SOL_LOCAL, c_void, getpeereid, getsockopt, pid_t, socklen_t};
    102
    103    use super::UCred;
    104    use crate::io;
    105    use crate::os::unix::io::AsRawFd;
    106    use crate::os::unix::net::UnixStream;
    107
    108    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
    109        let mut cred = UCred { uid: 1, gid: 1, pid: None };
    110        unsafe {
    111            let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
    112
    113            if ret != 0 {
    114                return Err(io::Error::last_os_error());
    115            }
    116
    117            let mut pid: pid_t = 1;
    118            let mut pid_size = size_of::<pid_t>() as socklen_t;
    119
    120            let ret = getsockopt(
    121                socket.as_raw_fd(),
    122                SOL_LOCAL,
    123                LOCAL_PEERPID,
    124                (&raw mut pid) as *mut c_void,
    125                &mut pid_size,
    126            );
    127
    128            if ret == 0 && pid_size as usize == size_of::<pid_t>() {
    129                cred.pid = Some(pid);
    130                Ok(cred)
    131            } else {
    132                Err(io::Error::last_os_error())
    133            }
    134        }
    135    }
    136}