]> git.lizzy.rs Git - rust.git/blob - library/std/src/os/unix/ucred.rs
Auto merge of #93397 - joshtriplett:sort-floats, r=Amanieu
[rust.git] / library / std / src / os / unix / ucred.rs
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 = "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 ))]
84 pub mod impl_bsd {
85     use super::UCred;
86     use crate::io;
87     use crate::os::unix::io::AsRawFd;
88     use crate::os::unix::net::UnixStream;
89
90     pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
91         let mut cred = UCred { uid: 1, gid: 1, pid: None };
92         unsafe {
93             let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
94
95             if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
96         }
97     }
98 }
99
100 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
101 pub mod impl_mac {
102     use super::UCred;
103     use crate::os::unix::io::AsRawFd;
104     use crate::os::unix::net::UnixStream;
105     use crate::{io, mem};
106     use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL};
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 = mem::size_of::<pid_t>() as socklen_t;
119
120             let ret = getsockopt(
121                 socket.as_raw_fd(),
122                 SOL_LOCAL,
123                 LOCAL_PEERPID,
124                 &mut pid as *mut pid_t as *mut c_void,
125                 &mut pid_size,
126             );
127
128             if ret == 0 && pid_size as usize == mem::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 }