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, pid_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 | /// The UID part of the peer credential. This is the effective UID of the process at the domain |
16 | /// socket's endpoint. |
17 | pub uid: uid_t, |
18 | /// The GID part of the peer credential. This is the effective GID of the process at the domain |
19 | /// socket's endpoint. |
20 | pub gid: gid_t, |
21 | /// The PID part of the peer credential. This field is optional because the PID part of the |
22 | /// peer credentials is not supported on every platform. On platforms where the mechanism to |
23 | /// discover the PID exists, this field will be populated to the PID of the process at the |
24 | /// domain socket's endpoint. Otherwise, it will be set to None. |
25 | pub pid: Option<pid_t>, |
26 | } |
27 | |
28 | #[cfg (any(target_os = "android" , target_os = "linux" ))] |
29 | pub use self::impl_linux::peer_cred; |
30 | |
31 | #[cfg (any( |
32 | target_os = "dragonfly" , |
33 | target_os = "freebsd" , |
34 | target_os = "openbsd" , |
35 | target_os = "netbsd" |
36 | ))] |
37 | pub use self::impl_bsd::peer_cred; |
38 | |
39 | #[cfg (any(target_os = "macos" , target_os = "ios" , target_os = "tvos" , target_os = "watchos" ))] |
40 | pub use self::impl_mac::peer_cred; |
41 | |
42 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
43 | pub mod impl_linux { |
44 | use super::UCred; |
45 | use crate::os::unix::io::AsRawFd; |
46 | use crate::os::unix::net::UnixStream; |
47 | use crate::{io, mem}; |
48 | use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED}; |
49 | |
50 | pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> { |
51 | let ucred_size = mem::size_of::<ucred>(); |
52 | |
53 | // Trivial sanity checks. |
54 | assert!(mem::size_of::<u32>() <= mem::size_of::<usize>()); |
55 | assert!(ucred_size <= u32::MAX as usize); |
56 | |
57 | let mut ucred_size = ucred_size as socklen_t; |
58 | let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 }; |
59 | |
60 | unsafe { |
61 | let ret = getsockopt( |
62 | socket.as_raw_fd(), |
63 | SOL_SOCKET, |
64 | SO_PEERCRED, |
65 | &mut ucred as *mut ucred as *mut c_void, |
66 | &mut ucred_size, |
67 | ); |
68 | |
69 | if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() { |
70 | Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) }) |
71 | } else { |
72 | Err(io::Error::last_os_error()) |
73 | } |
74 | } |
75 | } |
76 | } |
77 | |
78 | #[cfg (any( |
79 | target_os = "dragonfly" , |
80 | target_os = "freebsd" , |
81 | target_os = "openbsd" , |
82 | target_os = "netbsd" , |
83 | target_os = "nto" , |
84 | ))] |
85 | pub mod 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 (any(target_os = "macos" , target_os = "ios" , target_os = "tvos" , target_os = "watchos" ))] |
102 | pub mod impl_mac { |
103 | use super::UCred; |
104 | use crate::os::unix::io::AsRawFd; |
105 | use crate::os::unix::net::UnixStream; |
106 | use crate::{io, mem}; |
107 | use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL}; |
108 | |
109 | pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> { |
110 | let mut cred = UCred { uid: 1, gid: 1, pid: None }; |
111 | unsafe { |
112 | let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); |
113 | |
114 | if ret != 0 { |
115 | return Err(io::Error::last_os_error()); |
116 | } |
117 | |
118 | let mut pid: pid_t = 1; |
119 | let mut pid_size = mem::size_of::<pid_t>() as socklen_t; |
120 | |
121 | let ret = getsockopt( |
122 | socket.as_raw_fd(), |
123 | SOL_LOCAL, |
124 | LOCAL_PEERPID, |
125 | &mut pid as *mut pid_t as *mut c_void, |
126 | &mut pid_size, |
127 | ); |
128 | |
129 | if ret == 0 && pid_size as usize == mem::size_of::<pid_t>() { |
130 | cred.pid = Some(pid); |
131 | Ok(cred) |
132 | } else { |
133 | Err(io::Error::last_os_error()) |
134 | } |
135 | } |
136 | } |
137 | } |
138 | |