Skip to content

Commit ed20eff

Browse files
author
Joe Ellis
committed
Implementation of peer credentials for Unix sockets
The code in `ucred.rs` is based on the work done in PR 13 in the tokio-uds repository on GitHub. Link below for reference: tokio-rs/tokio-uds#13 Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work!
1 parent 5bc8b18 commit ed20eff

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

library/std/src/sys/unix/ext/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ pub mod process;
3737
pub mod raw;
3838
pub mod thread;
3939

40+
#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
41+
#[cfg(any(
42+
target_os = "android",
43+
target_os = "linux",
44+
target_os = "dragonfly",
45+
target_os = "freebsd",
46+
target_os = "ios",
47+
target_os = "macos",
48+
target_os = "openbsd"
49+
))]
50+
pub mod ucred;
51+
4052
/// A prelude for conveniently writing platform-specific code.
4153
///
4254
/// Includes all extension traits, and some important type definitions.

library/std/src/sys/unix/ext/net.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,29 @@ use crate::sys::{self, cvt};
3030
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
3131
use crate::time::Duration;
3232

33+
#[cfg(any(
34+
target_os = "android",
35+
target_os = "linux",
36+
target_os = "dragonfly",
37+
target_os = "freebsd",
38+
target_os = "ios",
39+
target_os = "macos",
40+
target_os = "openbsd"
41+
))]
42+
use crate::os::unix::ucred;
43+
44+
#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
45+
#[cfg(any(
46+
target_os = "android",
47+
target_os = "linux",
48+
target_os = "dragonfly",
49+
target_os = "freebsd",
50+
target_os = "ios",
51+
target_os = "macos",
52+
target_os = "openbsd"
53+
))]
54+
pub use ucred::UCred;
55+
3356
#[cfg(any(
3457
target_os = "linux",
3558
target_os = "android",
@@ -405,6 +428,24 @@ impl UnixStream {
405428
SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
406429
}
407430

431+
/// Gets the peer credentials for this Unix domain socket.
432+
///
433+
/// # Examples
434+
///
435+
/// ```no_run
436+
/// use std::os::unix::net::UnixStream;
437+
///
438+
/// fn main() -> std::io::Result<()> {
439+
/// let socket = UnixStream::connect("/tmp/sock")?;
440+
/// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials");
441+
/// Ok(())
442+
/// }
443+
/// ```
444+
#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
445+
pub fn peer_cred(&self) -> io::Result<UCred> {
446+
ucred::peer_cred(self)
447+
}
448+
408449
/// Sets the read timeout for the socket.
409450
///
410451
/// If the provided value is [`None`], then [`read`] calls will block

library/std/src/sys/unix/ext/ucred.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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, 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+
pub uid: uid_t,
16+
pub gid: gid_t,
17+
}
18+
19+
#[cfg(any(target_os = "android", target_os = "linux"))]
20+
pub use self::impl_linux::peer_cred;
21+
22+
#[cfg(any(
23+
target_os = "dragonfly",
24+
target_os = "freebsd",
25+
target_os = "ios",
26+
target_os = "macos",
27+
target_os = "openbsd"
28+
))]
29+
pub use self::impl_bsd::peer_cred;
30+
31+
#[cfg(any(target_os = "linux", target_os = "android"))]
32+
pub mod impl_linux {
33+
use super::UCred;
34+
use crate::mem::MaybeUninit;
35+
use crate::os::unix::io::AsRawFd;
36+
use crate::os::unix::net::UnixStream;
37+
use crate::{io, mem};
38+
39+
pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
40+
use libc::{c_void, ucred};
41+
42+
let ucred_size = mem::size_of::<ucred>();
43+
44+
// Trivial sanity checks.
45+
assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
46+
assert!(ucred_size <= u32::max_value() as usize);
47+
48+
let mut ucred_size = ucred_size as u32;
49+
50+
unsafe {
51+
let mut ucred: ucred = MaybeUninit::uninit().assume_init();
52+
let ret = libc::getsockopt(
53+
socket.as_raw_fd(),
54+
libc::SOL_SOCKET,
55+
libc::SO_PEERCRED,
56+
&mut ucred as *mut ucred as *mut c_void,
57+
&mut ucred_size,
58+
);
59+
60+
if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
61+
Ok(UCred { uid: ucred.uid, gid: ucred.gid })
62+
} else {
63+
Err(io::Error::last_os_error())
64+
}
65+
}
66+
}
67+
}
68+
69+
#[cfg(any(
70+
target_os = "dragonfly",
71+
target_os = "macos",
72+
target_os = "ios",
73+
target_os = "freebsd",
74+
target_os = "openbsd"
75+
))]
76+
pub mod impl_bsd {
77+
use super::UCred;
78+
use crate::io;
79+
use crate::mem::MaybeUninit;
80+
use crate::os::unix::io::AsRawFd;
81+
use crate::os::unix::net::UnixStream;
82+
83+
pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
84+
unsafe {
85+
// Create `cred` and attempt to populate it.
86+
let mut cred: UCred = MaybeUninit::uninit().assume_init();
87+
let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
88+
89+
if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)