broker_tokio/net/unix/
ucred.rs

1use libc::{gid_t, uid_t};
2
3/// Credentials of a process
4#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
5pub struct UCred {
6    /// UID (user ID) of the process
7    pub uid: uid_t,
8    /// GID (group ID) of the process
9    pub gid: gid_t,
10}
11
12#[cfg(any(target_os = "linux", target_os = "android"))]
13pub(crate) use self::impl_linux::get_peer_cred;
14
15#[cfg(any(
16    target_os = "dragonfly",
17    target_os = "macos",
18    target_os = "ios",
19    target_os = "freebsd",
20    target_os = "netbsd",
21    target_os = "openbsd"
22))]
23pub(crate) use self::impl_macos::get_peer_cred;
24
25#[cfg(any(target_os = "solaris"))]
26pub(crate) use self::impl_solaris::get_peer_cred;
27
28#[cfg(any(target_os = "linux", target_os = "android"))]
29pub(crate) mod impl_linux {
30    use crate::net::unix::UnixStream;
31
32    use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED};
33    use std::{io, mem};
34
35    use libc::ucred;
36
37    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
38        use std::os::unix::io::AsRawFd;
39
40        unsafe {
41            let raw_fd = sock.as_raw_fd();
42
43            let mut ucred = ucred {
44                pid: 0,
45                uid: 0,
46                gid: 0,
47            };
48
49            let ucred_size = mem::size_of::<ucred>();
50
51            // These paranoid checks should be optimized-out
52            assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
53            assert!(ucred_size <= u32::max_value() as usize);
54
55            let mut ucred_size = ucred_size as socklen_t;
56
57            let ret = getsockopt(
58                raw_fd,
59                SOL_SOCKET,
60                SO_PEERCRED,
61                &mut ucred as *mut ucred as *mut c_void,
62                &mut ucred_size,
63            );
64            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
65                Ok(super::UCred {
66                    uid: ucred.uid,
67                    gid: ucred.gid,
68                })
69            } else {
70                Err(io::Error::last_os_error())
71            }
72        }
73    }
74}
75
76#[cfg(any(
77    target_os = "dragonfly",
78    target_os = "macos",
79    target_os = "ios",
80    target_os = "freebsd",
81    target_os = "netbsd",
82    target_os = "openbsd"
83))]
84pub(crate) mod impl_macos {
85    use crate::net::unix::UnixStream;
86
87    use libc::getpeereid;
88    use std::io;
89    use std::mem::MaybeUninit;
90    use std::os::unix::io::AsRawFd;
91
92    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
93        unsafe {
94            let raw_fd = sock.as_raw_fd();
95
96            let mut uid = MaybeUninit::uninit();
97            let mut gid = MaybeUninit::uninit();
98
99            let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr());
100
101            if ret == 0 {
102                Ok(super::UCred {
103                    uid: uid.assume_init(),
104                    gid: gid.assume_init(),
105                })
106            } else {
107                Err(io::Error::last_os_error())
108            }
109        }
110    }
111}
112
113#[cfg(any(target_os = "solaris"))]
114pub(crate) mod impl_solaris {
115    use crate::net::unix::UnixStream;
116    use std::io;
117    use std::os::unix::io::AsRawFd;
118    use std::ptr;
119
120    #[allow(non_camel_case_types)]
121    enum ucred_t {}
122
123    extern "C" {
124        fn ucred_free(cred: *mut ucred_t);
125        fn ucred_geteuid(cred: *const ucred_t) -> super::uid_t;
126        fn ucred_getegid(cred: *const ucred_t) -> super::gid_t;
127
128        fn getpeerucred(fd: std::os::raw::c_int, cred: *mut *mut ucred_t) -> std::os::raw::c_int;
129    }
130
131    pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
132        unsafe {
133            let raw_fd = sock.as_raw_fd();
134
135            let mut cred = ptr::null_mut::<*mut ucred_t>() as *mut ucred_t;
136
137            let ret = getpeerucred(raw_fd, &mut cred);
138
139            if ret == 0 {
140                let uid = ucred_geteuid(cred);
141                let gid = ucred_getegid(cred);
142
143                ucred_free(cred);
144
145                Ok(super::UCred { uid, gid })
146            } else {
147                Err(io::Error::last_os_error())
148            }
149        }
150    }
151}