about summary refs log tree commit diff
path: root/library/std/src/sys/unix/ext
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/unix/ext')
-rw-r--r--library/std/src/sys/unix/ext/mod.rs12
-rw-r--r--library/std/src/sys/unix/ext/net.rs41
-rw-r--r--library/std/src/sys/unix/ext/ucred.rs92
3 files changed, 145 insertions, 0 deletions
diff --git a/library/std/src/sys/unix/ext/mod.rs b/library/std/src/sys/unix/ext/mod.rs
index cbdb1c10049..f4354688098 100644
--- a/library/std/src/sys/unix/ext/mod.rs
+++ b/library/std/src/sys/unix/ext/mod.rs
@@ -37,6 +37,18 @@ pub mod process;
 pub mod raw;
 pub mod thread;
 
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+pub mod ucred;
+
 /// A prelude for conveniently writing platform-specific code.
 ///
 /// Includes all extension traits, and some important type definitions.
diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs
index 0e07106f5ce..930a6797000 100644
--- a/library/std/src/sys/unix/ext/net.rs
+++ b/library/std/src/sys/unix/ext/net.rs
@@ -31,6 +31,29 @@ use crate::sys_common::{self, AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
 #[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+use crate::os::unix::ucred;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+pub use ucred::UCred;
+
+#[cfg(any(
     target_os = "linux",
     target_os = "android",
     target_os = "dragonfly",
@@ -405,6 +428,24 @@ impl UnixStream {
         SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
     }
 
+    /// Gets the peer credentials for this Unix domain socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+    pub fn peer_cred(&self) -> io::Result<UCred> {
+        ucred::peer_cred(self)
+    }
+
     /// Sets the read timeout for the socket.
     ///
     /// If the provided value is [`None`], then [`read`] calls will block
diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs
new file mode 100644
index 00000000000..dec97ade126
--- /dev/null
+++ b/library/std/src/sys/unix/ext/ucred.rs
@@ -0,0 +1,92 @@
+//! Unix peer credentials.
+
+// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on
+//       GitHub.
+//
+//       For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13
+//       Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work.
+
+use libc::{gid_t, uid_t};
+
+/// Credentials for a UNIX process for credentials passing.
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct UCred {
+    pub uid: uid_t,
+    pub gid: gid_t,
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::impl_linux::peer_cred;
+
+#[cfg(any(
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+pub use self::impl_bsd::peer_cred;
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub mod impl_linux {
+    use super::UCred;
+    use crate::mem::MaybeUninit;
+    use crate::os::unix::io::AsRawFd;
+    use crate::os::unix::net::UnixStream;
+    use crate::{io, mem};
+
+    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+        use libc::{c_void, ucred};
+
+        let ucred_size = mem::size_of::<ucred>();
+
+        // Trivial sanity checks.
+        assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
+        assert!(ucred_size <= u32::max_value() as usize);
+
+        let mut ucred_size = ucred_size as u32;
+
+        unsafe {
+            let mut ucred: ucred = MaybeUninit::uninit().assume_init();
+            let ret = libc::getsockopt(
+                socket.as_raw_fd(),
+                libc::SOL_SOCKET,
+                libc::SO_PEERCRED,
+                &mut ucred as *mut ucred as *mut c_void,
+                &mut ucred_size,
+            );
+
+            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
+                Ok(UCred { uid: ucred.uid, gid: ucred.gid })
+            } else {
+                Err(io::Error::last_os_error())
+            }
+        }
+    }
+}
+
+#[cfg(any(
+    target_os = "dragonfly",
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "openbsd"
+))]
+pub mod impl_bsd {
+    use super::UCred;
+    use crate::io;
+    use crate::mem::MaybeUninit;
+    use crate::os::unix::io::AsRawFd;
+    use crate::os::unix::net::UnixStream;
+
+    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+        unsafe {
+            // Create `cred` and attempt to populate it.
+            let mut cred: UCred = MaybeUninit::uninit().assume_init();
+            let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+            if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
+        }
+    }
+}