forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of rust-lang#75148 - joechrisellis:master, r=Amanieu
Implementation of peer credentials for Unix sockets The code in `ucred.rs` is based on the work done in [PR 13](tokio-rs/tokio-uds#13) in the tokio-uds repository on GitHub. This commit is effectively a port to the stdlib, so credit to Martin Habovštiak (`@Kixunil)` and contributors for the meat of this work. 🥇 Happy to make changes as needed. 🙂
- Loading branch information
Showing
4 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
//! 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, pid_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 { | ||
/// The UID part of the peer credential. This is the effective UID of the process at the domain | ||
/// socket's endpoint. | ||
pub uid: uid_t, | ||
/// The GID part of the peer credential. This is the effective GID of the process at the domain | ||
/// socket's endpoint. | ||
pub gid: gid_t, | ||
/// The PID part of the peer credential. This field is optional because the PID part of the | ||
/// peer credentials is not supported on every platform. On platforms where the mechanism to | ||
/// discover the PID exists, this field will be populated to the PID of the process at the | ||
/// domain socket's endpoint. Otherwise, it will be set to None. | ||
pub pid: Option<pid_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::os::unix::io::AsRawFd; | ||
use crate::os::unix::net::UnixStream; | ||
use crate::{io, mem}; | ||
use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED}; | ||
|
||
pub fn peer_cred(socket: &UnixStream) -> io::Result<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 as usize); | ||
|
||
let mut ucred_size = ucred_size as socklen_t; | ||
let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 }; | ||
|
||
unsafe { | ||
let ret = getsockopt( | ||
socket.as_raw_fd(), | ||
SOL_SOCKET, | ||
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, pid: Some(ucred.pid) }) | ||
} 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::os::unix::io::AsRawFd; | ||
use crate::os::unix::net::UnixStream; | ||
|
||
pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> { | ||
let mut cred = UCred { uid: 1, gid: 1, pid: None }; | ||
unsafe { | ||
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()) } | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use crate::os::unix::net::UnixStream; | ||
use libc::{getegid, geteuid}; | ||
|
||
#[test] | ||
#[cfg(any( | ||
target_os = "android", | ||
target_os = "linux", | ||
target_os = "dragonfly", | ||
target_os = "freebsd", | ||
target_os = "ios", | ||
target_os = "macos", | ||
target_os = "openbsd" | ||
))] | ||
fn test_socket_pair() { | ||
// Create two connected sockets and get their peer credentials. They should be equal. | ||
let (sock_a, sock_b) = UnixStream::pair().unwrap(); | ||
let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap()); | ||
assert_eq!(cred_a, cred_b); | ||
|
||
// Check that the UID and GIDs match up. | ||
let uid = unsafe { geteuid() }; | ||
let gid = unsafe { getegid() }; | ||
assert_eq!(cred_a.uid, uid); | ||
assert_eq!(cred_a.gid, gid); | ||
} |