1 use libc::{gid_t, uid_t};
2 
3 /// Credentials of a process
4 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
5 pub 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"))]
13 pub(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 ))]
23 pub(crate) use self::impl_macos::get_peer_cred;
24 
25 #[cfg(any(target_os = "solaris", target_os = "illumos"))]
26 pub(crate) use self::impl_solaris::get_peer_cred;
27 
28 #[cfg(any(target_os = "linux", target_os = "android"))]
29 pub(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 
get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>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 ))]
84 pub(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 
get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>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", target_os = "illumos"))]
114 pub(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" {
ucred_free(cred: *mut ucred_t)124         fn ucred_free(cred: *mut ucred_t);
ucred_geteuid(cred: *const ucred_t) -> super::uid_t125         fn ucred_geteuid(cred: *const ucred_t) -> super::uid_t;
ucred_getegid(cred: *const ucred_t) -> super::gid_t126         fn ucred_getegid(cred: *const ucred_t) -> super::gid_t;
127 
getpeerucred(fd: std::os::raw::c_int, cred: *mut *mut ucred_t) -> std::os::raw::c_int128         fn getpeerucred(fd: std::os::raw::c_int, cred: *mut *mut ucred_t) -> std::os::raw::c_int;
129     }
130 
get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>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 }
152