Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fc8744d

Browse files
author
Joe Ellis
committedSep 21, 2020
Cherry-pick Rust standard library peer credentials feature into Parsec
The code introduced in this patch has been cherry-picked from the following PR: rust-lang/rust#75148 At the time of writing (16/09/20), this patch is in the nightly Rust channel. To avoid needing to use the nightly compiler to build Parsec, this patch includes the change from the standard library to allow us to use this feature 'early'. Once the feature hits the stable branch, it should be safe to revert this commit with `git revert`. Signed-off-by: Joe Ellis <[email protected]>
1 parent d1c59cf commit fc8744d

File tree

2 files changed

+139
-5
lines changed

2 files changed

+139
-5
lines changed
 

‎src/authenticators/unix_peer_credentials_authenticator/mod.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ impl Authenticate for UnixPeerCredentialsAuthenticator {
8888
mod test {
8989
use super::super::Authenticate;
9090
use super::UnixPeerCredentialsAuthenticator;
91+
use crate::front::domain_socket::peer_credentials;
9192
use crate::front::listener::ConnectionMetadata;
9293
use parsec_interface::requests::request::RequestAuth;
9394
use parsec_interface::requests::ResponseStatus;
@@ -102,7 +103,10 @@ mod test {
102103

103104
// Create two connected sockets.
104105
let (sock_a, _sock_b) = UnixStream::pair().unwrap();
105-
let (cred_a, _cred_b) = (sock_a.peer_cred().unwrap(), _sock_b.peer_cred().unwrap());
106+
let (cred_a, _cred_b) = (
107+
peer_credentials::peer_cred(&sock_a).unwrap(),
108+
peer_credentials::peer_cred(&_sock_b).unwrap(),
109+
);
106110

107111
let authenticator = UnixPeerCredentialsAuthenticator {};
108112

@@ -128,7 +132,10 @@ mod test {
128132

129133
// Create two connected sockets.
130134
let (sock_a, _sock_b) = UnixStream::pair().unwrap();
131-
let (cred_a, _cred_b) = (sock_a.peer_cred().unwrap(), _sock_b.peer_cred().unwrap());
135+
let (cred_a, _cred_b) = (
136+
peer_credentials::peer_cred(&sock_a).unwrap(),
137+
peer_credentials::peer_cred(&_sock_b).unwrap(),
138+
);
132139

133140
let authenticator = UnixPeerCredentialsAuthenticator {};
134141

@@ -150,7 +157,10 @@ mod test {
150157

151158
// Create two connected sockets.
152159
let (sock_a, _sock_b) = UnixStream::pair().unwrap();
153-
let (cred_a, _cred_b) = (sock_a.peer_cred().unwrap(), _sock_b.peer_cred().unwrap());
160+
let (cred_a, _cred_b) = (
161+
peer_credentials::peer_cred(&sock_a).unwrap(),
162+
peer_credentials::peer_cred(&_sock_b).unwrap(),
163+
);
154164

155165
let authenticator = UnixPeerCredentialsAuthenticator {};
156166

‎src/front/domain_socket.rs

+126-2
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,7 @@ impl Listen for DomainSocketListener {
202202
format_error!("Failed to set stream as blocking", err);
203203
None
204204
} else {
205-
let ucred = stream
206-
.peer_cred()
205+
let ucred = peer_credentials::peer_cred(&stream)
207206
.map_err(|err| {
208207
format_error!(
209208
"Failed to grab peer credentials metadata from UnixStream",
@@ -260,3 +259,128 @@ impl DomainSocketListenerBuilder {
260259
})?)
261260
}
262261
}
262+
263+
// == IMPORTANT NOTE ==
264+
//
265+
// The code below has been cherry-picked from the following PR:
266+
//
267+
// https://github.com/rust-lang/rust/pull/75148
268+
//
269+
// At the time of writing (16/09/20), this patch is in the nightly Rust channel. To avoid needing
270+
// to use the nightly compiler to build Parsec, we have instead opted to cherry-pick the change
271+
// from the patch to allow us to use this feature 'early'.
272+
//
273+
// Once the feature hits stable, it should be safe to revert the commit that introduced the changes
274+
// below with `git revert`. You can find the stabilizing Rust issue here:
275+
//
276+
// https://github.com/rust-lang/rust/issues/42839
277+
278+
/// Implementation of peer credentials fetching for Unix domain socket.
279+
pub mod peer_credentials {
280+
use libc::{gid_t, pid_t, uid_t};
281+
282+
/// Credentials for a UNIX process for credentials passing.
283+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
284+
pub struct UCred {
285+
/// The UID part of the peer credential. This is the effective UID of the process at the domain
286+
/// socket's endpoint.
287+
pub uid: uid_t,
288+
/// The GID part of the peer credential. This is the effective GID of the process at the domain
289+
/// socket's endpoint.
290+
pub gid: gid_t,
291+
/// The PID part of the peer credential. This field is optional because the PID part of the
292+
/// peer credentials is not supported on every platform. On platforms where the mechanism to
293+
/// discover the PID exists, this field will be populated to the PID of the process at the
294+
/// domain socket's endpoint. Otherwise, it will be set to None.
295+
pub pid: Option<pid_t>,
296+
}
297+
298+
#[cfg(any(target_os = "android", target_os = "linux"))]
299+
pub use self::impl_linux::peer_cred;
300+
301+
#[cfg(any(
302+
target_os = "dragonfly",
303+
target_os = "freebsd",
304+
target_os = "ios",
305+
target_os = "macos",
306+
target_os = "openbsd"
307+
))]
308+
pub use self::impl_bsd::peer_cred;
309+
310+
#[cfg(any(target_os = "linux", target_os = "android"))]
311+
#[allow(missing_docs, trivial_casts)] // docs not required; only used for selective compilation.
312+
pub mod impl_linux {
313+
use super::UCred;
314+
use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
315+
use std::os::unix::io::AsRawFd;
316+
use std::os::unix::net::UnixStream;
317+
use std::{io, mem};
318+
319+
pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
320+
let ucred_size = mem::size_of::<ucred>();
321+
322+
// Trivial sanity checks.
323+
assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
324+
assert!(ucred_size <= u32::MAX as usize);
325+
326+
let mut ucred_size = ucred_size as socklen_t;
327+
let mut ucred: ucred = ucred {
328+
pid: 1,
329+
uid: 1,
330+
gid: 1,
331+
};
332+
333+
unsafe {
334+
let ret = getsockopt(
335+
socket.as_raw_fd(),
336+
SOL_SOCKET,
337+
SO_PEERCRED,
338+
&mut ucred as *mut ucred as *mut c_void,
339+
&mut ucred_size,
340+
);
341+
342+
if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
343+
Ok(UCred {
344+
uid: ucred.uid,
345+
gid: ucred.gid,
346+
pid: Some(ucred.pid),
347+
})
348+
} else {
349+
Err(io::Error::last_os_error())
350+
}
351+
}
352+
}
353+
}
354+
355+
#[cfg(any(
356+
target_os = "dragonfly",
357+
target_os = "macos",
358+
target_os = "ios",
359+
target_os = "freebsd",
360+
target_os = "openbsd"
361+
))]
362+
#[allow(missing_docs)] // docs not required; only used for selective compilation.
363+
pub mod impl_bsd {
364+
use super::UCred;
365+
use std::io;
366+
use std::os::unix::io::AsRawFd;
367+
use std::os::unix::net::UnixStream;
368+
369+
pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
370+
let mut cred = UCred {
371+
uid: 1,
372+
gid: 1,
373+
pid: None,
374+
};
375+
unsafe {
376+
let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
377+
378+
if ret == 0 {
379+
Ok(cred)
380+
} else {
381+
Err(io::Error::last_os_error())
382+
}
383+
}
384+
}
385+
}
386+
}

0 commit comments

Comments
 (0)
Please sign in to comment.