Skip to content

Commit

Permalink
Convert Unix{Datagram,Stream}::{set_}passcred() to per-OS traits
Browse files Browse the repository at this point in the history
These methods are the pre-stabilized API for obtaining peer credentials
from an `AF_UNIX` socket, part of the `unix_socket_ancillary_data` feature.

Their current behavior is to get/set one of the `SO_PASSCRED` (Linux),
`LOCAL_CREDS_PERSISTENT` (FreeBSD), or `LOCAL_CREDS` (NetBSD) socket
options. On other targets the `{set_}passcred()` methods do not exist.

There are two problems with this approach:

1. Having public methods only exist for certain targets isn't permitted
   in a stable `std` API.

2. These options have generally similar purposes, but they are non-POSIX
   and their details can differ in subtle and surprising ways (such as
   whether they continue to be set after the next call to `recvmsg()`).

Splitting into OS-specific extension traits is the preferred solution to
both problems.
  • Loading branch information
jmillikin committed Nov 8, 2023
1 parent 7adc89b commit b9eb55c
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 136 deletions.
1 change: 1 addition & 0 deletions library/std/src/os/freebsd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
#![stable(feature = "raw_ext", since = "1.1.0")]

pub mod fs;
pub mod net;
pub mod raw;
65 changes: 65 additions & 0 deletions library/std/src/os/freebsd/net.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! FreeBSD-specific networking functionality.
#![unstable(feature = "unix_socket_ancillary_data", issue = "76915")]

use crate::io;
use crate::os::unix::net;
use crate::sealed::Sealed;
use crate::sys_common::AsInner;

/// OpenBSD-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
/// and [`UnixStream`].
///
/// [`UnixDatagram`]: net::UnixDatagram
/// [`UnixStream`]: net::UnixStream
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub trait UnixSocketExt: Sealed {
/// Query the current setting of socket option `LOCAL_CREDS`.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
fn local_creds_persistent(&self) -> io::Result<bool>;

/// Enable or disable socket option `LOCAL_CREDS`.
///
/// This option enables the credentials of the sending process to be
/// received as a control message in [`AncillaryData`].
///
/// [`AncillaryData`]: net::AncillaryData
///
/// # Examples
///
/// ```no_run
/// #![feature(unix_socket_ancillary_data)]
/// use std::os::freebsd::net::UnixSocketExt;
/// use std::os::unix::net::UnixDatagram;
///
/// fn main() -> std::io::Result<()> {
/// let sock = UnixDatagram::unbound()?;
/// sock.set_local_creds_persistent(true).expect("set_local_creds_persistent failed");
/// Ok(())
/// }
/// ```
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()>;
}

#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
impl UnixSocketExt for net::UnixDatagram {
fn local_creds_persistent(&self) -> io::Result<bool> {
self.as_inner().local_creds_persistent()
}

fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> {
self.as_inner().set_local_creds_persistent(local_creds_persistent)
}
}

#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
impl UnixSocketExt for net::UnixStream {
fn local_creds_persistent(&self) -> io::Result<bool> {
self.as_inner().local_creds_persistent()
}

fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> {
self.as_inner().set_local_creds_persistent(local_creds_persistent)
}
}
3 changes: 3 additions & 0 deletions library/std/src/os/linux/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@
#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
pub use crate::os::net::linux_ext::addr::SocketAddrExt;

#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub use crate::os::net::linux_ext::socket::UnixSocketExt;

#[unstable(feature = "tcp_quickack", issue = "96256")]
pub use crate::os::net::linux_ext::tcp::TcpStreamExt;
3 changes: 3 additions & 0 deletions library/std/src/os/net/linux_ext/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
pub(crate) mod addr;

#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub(crate) mod socket;

#[unstable(feature = "tcp_quickack", issue = "96256")]
pub(crate) mod tcp;

Expand Down
63 changes: 63 additions & 0 deletions library/std/src/os/net/linux_ext/socket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! Linux and Android-specific socket functionality.
use crate::io;
use crate::os::unix::net;
use crate::sealed::Sealed;
use crate::sys_common::AsInner;

/// Linux-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
/// and [`UnixStream`].
///
/// [`UnixDatagram`]: net::UnixDatagram
/// [`UnixStream`]: net::UnixStream
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub trait UnixSocketExt: Sealed {
/// Query the current setting of socket option `SO_PASSCRED`.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
fn passcred(&self) -> io::Result<bool>;

/// Enable or disable socket option `SO_PASSCRED`.
///
/// This option enables the credentials of the sending process to be
/// received as a control message in [`AncillaryData`].
///
/// [`AncillaryData`]: net::AncillaryData
///
/// # Examples
///
/// ```no_run
/// #![feature(unix_socket_ancillary_data)]
/// use std::os::linux::net::UnixSocketExt;
/// use std::os::unix::net::UnixDatagram;
///
/// fn main() -> std::io::Result<()> {
/// let sock = UnixDatagram::unbound()?;
/// sock.set_passcred(true).expect("set_passcred failed");
/// Ok(())
/// }
/// ```
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
fn set_passcred(&self, passcred: bool) -> io::Result<()>;
}

#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
impl UnixSocketExt for net::UnixDatagram {
fn passcred(&self) -> io::Result<bool> {
self.as_inner().passcred()
}

fn set_passcred(&self, passcred: bool) -> io::Result<()> {
self.as_inner().set_passcred(passcred)
}
}

#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
impl UnixSocketExt for net::UnixStream {
fn passcred(&self) -> io::Result<bool> {
self.as_inner().passcred()
}

fn set_passcred(&self, passcred: bool) -> io::Result<()> {
self.as_inner().set_passcred(passcred)
}
}
1 change: 1 addition & 0 deletions library/std/src/os/netbsd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
#![stable(feature = "raw_ext", since = "1.1.0")]

pub mod fs;
pub mod net;
pub mod raw;
65 changes: 65 additions & 0 deletions library/std/src/os/netbsd/net.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! OpenBSD-specific networking functionality.
#![unstable(feature = "unix_socket_ancillary_data", issue = "76915")]

use crate::io;
use crate::os::unix::net;
use crate::sealed::Sealed;
use crate::sys_common::AsInner;

/// OpenBSD-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
/// and [`UnixStream`].
///
/// [`UnixDatagram`]: net::UnixDatagram
/// [`UnixStream`]: net::UnixStream
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub trait UnixSocketExt: Sealed {
/// Query the current setting of socket option `LOCAL_CREDS`.
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
fn local_creds(&self) -> io::Result<bool>;

/// Enable or disable socket option `LOCAL_CREDS`.
///
/// This option enables the credentials of the sending process to be
/// received as a control message in [`AncillaryData`].
///
/// [`AncillaryData`]: net::AncillaryData
///
/// # Examples
///
/// ```no_run
/// #![feature(unix_socket_ancillary_data)]
/// use std::os::netbsd::net::UnixSocketExt;
/// use std::os::unix::net::UnixDatagram;
///
/// fn main() -> std::io::Result<()> {
/// let sock = UnixDatagram::unbound()?;
/// sock.set_local_creds(true).expect("set_local_creds failed");
/// Ok(())
/// }
/// ```
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
fn set_local_creds(&self, local_creds: bool) -> io::Result<()>;
}

#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
impl UnixSocketExt for net::UnixDatagram {
fn local_creds(&self) -> io::Result<bool> {
self.as_inner().local_creds()
}

fn set_local_creds(&self, local_creds: bool) -> io::Result<()> {
self.as_inner().set_local_creds(local_creds)
}
}

#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
impl UnixSocketExt for net::UnixStream {
fn local_creds(&self) -> io::Result<bool> {
self.as_inner().local_creds()
}

fn set_local_creds(&self, local_creds: bool) -> io::Result<()> {
self.as_inner().set_local_creds(local_creds)
}
}
75 changes: 12 additions & 63 deletions library/std/src/os/unix/net/datagram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::io::{IoSlice, IoSliceMut};
use crate::net::Shutdown;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::path::Path;
use crate::sealed::Sealed;
use crate::sys::cvt;
use crate::sys::net::Socket;
use crate::sys_common::{AsInner, FromInner, IntoInner};
Expand Down Expand Up @@ -54,6 +55,10 @@ const MSG_NOSIGNAL: libc::c_int = 0x0;
#[stable(feature = "unix_socket", since = "1.10.0")]
pub struct UnixDatagram(Socket);

/// Allows extension traits within `std`.
#[unstable(feature = "sealed", issue = "none")]
impl Sealed for UnixDatagram {}

#[stable(feature = "unix_socket", since = "1.10.0")]
impl fmt::Debug for UnixDatagram {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -802,69 +807,6 @@ impl UnixDatagram {
self.0.set_nonblocking(nonblocking)
}

/// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
///
/// Set the socket option `SO_PASSCRED`.
///
/// # Examples
///
#[cfg_attr(
any(
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd",
),
doc = "```no_run"
)]
#[cfg_attr(
not(any(
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
)),
doc = "```ignore"
)]
/// #![feature(unix_socket_ancillary_data)]
/// use std::os::unix::net::UnixDatagram;
///
/// fn main() -> std::io::Result<()> {
/// let sock = UnixDatagram::unbound()?;
/// sock.set_passcred(true).expect("set_passcred function failed");
/// Ok(())
/// }
/// ```
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
self.0.set_passcred(passcred)
}

/// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
/// This value can be change by [`set_passcred`].
///
/// Get the socket option `SO_PASSCRED`.
///
/// [`set_passcred`]: UnixDatagram::set_passcred
#[cfg(any(
doc,
target_os = "android",
target_os = "linux",
target_os = "netbsd",
target_os = "freebsd"
))]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn passcred(&self) -> io::Result<bool> {
self.0.passcred()
}

/// Set the id of the socket for network filtering purpose
///
#[cfg_attr(
Expand Down Expand Up @@ -1037,3 +979,10 @@ impl From<OwnedFd> for UnixDatagram {
unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
}
}

impl AsInner<Socket> for UnixDatagram {
#[inline]
fn as_inner(&self) -> &Socket {
&self.0
}
}
Loading

0 comments on commit b9eb55c

Please sign in to comment.