Skip to main content

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")]
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    target_os = "qnx"
35))]
36pub(super) use self::impl_bsd::peer_cred;
37#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
38pub(super) use self::impl_linux::peer_cred;
39
40#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
41mod impl_linux {
42    use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred};
43
44    use super::UCred;
45    use crate::io;
46    use crate::os::unix::io::AsRawFd;
47    use crate::os::unix::net::UnixStream;
48
49    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
50        let ucred_size = size_of::<ucred>();
51
52        // Trivial sanity checks.
53        assert!(size_of::<u32>() <= size_of::<usize>());
54        assert!(ucred_size <= u32::MAX as usize);
55
56        let mut ucred_size = ucred_size as socklen_t;
57        let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
58
59        unsafe {
60            let ret = getsockopt(
61                socket.as_raw_fd(),
62                SOL_SOCKET,
63                SO_PEERCRED,
64                (&raw mut ucred) as *mut c_void,
65                &mut ucred_size,
66            );
67
68            if ret == 0 && ucred_size as usize == size_of::<ucred>() {
69                Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
70            } else {
71                Err(io::Error::last_os_error())
72            }
73        }
74    }
75}
76
77#[cfg(any(
78    target_os = "dragonfly",
79    target_os = "freebsd",
80    target_os = "openbsd",
81    target_os = "netbsd",
82    target_os = "nto",
83    target_os = "qnx",
84))]
85mod impl_bsd {
86    use super::UCred;
87    use crate::io;
88    use crate::os::unix::io::AsRawFd;
89    use crate::os::unix::net::UnixStream;
90
91    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
92        let mut cred = UCred { uid: 1, gid: 1, pid: None };
93        unsafe {
94            let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
95
96            if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
97        }
98    }
99}
100
101#[cfg(target_vendor = "apple")]
102mod impl_apple {
103    use libc::{LOCAL_PEERPID, SOL_LOCAL, c_void, getpeereid, getsockopt, pid_t, socklen_t};
104
105    use super::UCred;
106    use crate::io;
107    use crate::os::unix::io::AsRawFd;
108    use crate::os::unix::net::UnixStream;
109
110    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
111        let mut cred = UCred { uid: 1, gid: 1, pid: None };
112        unsafe {
113            let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
114
115            if ret != 0 {
116                return Err(io::Error::last_os_error());
117            }
118
119            let mut pid: pid_t = 1;
120            let mut pid_size = size_of::<pid_t>() as socklen_t;
121
122            let ret = getsockopt(
123                socket.as_raw_fd(),
124                SOL_LOCAL,
125                LOCAL_PEERPID,
126                (&raw mut pid) as *mut c_void,
127                &mut pid_size,
128            );
129
130            if ret == 0 && pid_size as usize == size_of::<pid_t>() {
131                cred.pid = Some(pid);
132                Ok(cred)
133            } else {
134                Err(io::Error::last_os_error())
135            }
136        }
137    }
138}