Skip to content

Commit ba9529c

Browse files
author
Joe Ellis
committed
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 08982e9 commit ba9529c

File tree

1 file changed

+123
-4
lines changed

1 file changed

+123
-4
lines changed

src/front/domain_socket.rs

+123-4
Original file line numberDiff line numberDiff line change
@@ -252,14 +252,12 @@ impl DomainSocketListenerBuilder {
252252
impl GetMetadata for UnixStream {
253253
#[cfg(feature = "unix-peer-credentials-authenticator")]
254254
fn metadata(&self) -> Option<ConnectionMetadata> {
255-
let ucred = self
256-
.peer_cred()
255+
let ucred = peer_credentials::peer_cred(self)
257256
.map_err(|err| {
258257
format_error!(
259258
"Failed to grab peer credentials metadata from UnixStream",
260259
err
261-
);
262-
err
260+
)
263261
})
264262
.ok()?;
265263

@@ -275,3 +273,124 @@ impl GetMetadata for UnixStream {
275273
None
276274
}
277275
}
276+
277+
// == IMPORTANT NOTE ==
278+
//
279+
// The code below has been cherry-picked from the following PR:
280+
//
281+
// https://github.com/rust-lang/rust/pull/75148
282+
//
283+
// At the time of writing (16/09/20), this patch is in the nightly Rust channel. To avoid needing
284+
// to use the nightly compiler to build Parsec, we have instead opted to cherry-pick the change
285+
// from the patch to allow us to use this feature 'early'.
286+
//
287+
// Once the feature hits stable, it should be safe to revert the commit that introduced the changes
288+
// below with `git revert`.
289+
290+
#[cfg(feature = "unix-peer-credentials-authenticator")]
291+
mod peer_credentials {
292+
use libc::{gid_t, pid_t, uid_t};
293+
294+
/// Credentials for a UNIX process for credentials passing.
295+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
296+
pub struct UCred {
297+
/// The UID part of the peer credential. This is the effective UID of the process at the domain
298+
/// socket's endpoint.
299+
pub uid: uid_t,
300+
/// The GID part of the peer credential. This is the effective GID of the process at the domain
301+
/// socket's endpoint.
302+
pub gid: gid_t,
303+
/// The PID part of the peer credential. This field is optional because the PID part of the
304+
/// peer credentials is not supported on every platform. On platforms where the mechanism to
305+
/// discover the PID exists, this field will be populated to the PID of the process at the
306+
/// domain socket's endpoint. Otherwise, it will be set to None.
307+
pub pid: Option<pid_t>,
308+
}
309+
310+
#[cfg(any(target_os = "android", target_os = "linux"))]
311+
pub use self::impl_linux::peer_cred;
312+
313+
#[cfg(any(
314+
target_os = "dragonfly",
315+
target_os = "freebsd",
316+
target_os = "ios",
317+
target_os = "macos",
318+
target_os = "openbsd"
319+
))]
320+
pub use self::impl_bsd::peer_cred;
321+
322+
#[cfg(any(target_os = "linux", target_os = "android"))]
323+
pub mod impl_linux {
324+
use super::UCred;
325+
use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
326+
use std::os::unix::io::AsRawFd;
327+
use std::os::unix::net::UnixStream;
328+
use std::{io, mem};
329+
330+
pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
331+
let ucred_size = mem::size_of::<ucred>();
332+
333+
// Trivial sanity checks.
334+
assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
335+
assert!(ucred_size <= u32::MAX as usize);
336+
337+
let mut ucred_size = ucred_size as socklen_t;
338+
let mut ucred: ucred = ucred {
339+
pid: 1,
340+
uid: 1,
341+
gid: 1,
342+
};
343+
344+
unsafe {
345+
let ret = getsockopt(
346+
socket.as_raw_fd(),
347+
SOL_SOCKET,
348+
SO_PEERCRED,
349+
&mut ucred as *mut ucred as *mut c_void,
350+
&mut ucred_size,
351+
);
352+
353+
if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
354+
Ok(UCred {
355+
uid: ucred.uid,
356+
gid: ucred.gid,
357+
pid: Some(ucred.pid),
358+
})
359+
} else {
360+
Err(io::Error::last_os_error())
361+
}
362+
}
363+
}
364+
}
365+
366+
#[cfg(any(
367+
target_os = "dragonfly",
368+
target_os = "macos",
369+
target_os = "ios",
370+
target_os = "freebsd",
371+
target_os = "openbsd"
372+
))]
373+
pub mod impl_bsd {
374+
use super::UCred;
375+
use std::io;
376+
use std::os::unix::io::AsRawFd;
377+
use std::os::unix::net::UnixStream;
378+
379+
pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
380+
let mut cred = UCred {
381+
uid: 1,
382+
gid: 1,
383+
pid: None,
384+
};
385+
unsafe {
386+
let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
387+
388+
if ret == 0 {
389+
Ok(cred)
390+
} else {
391+
Err(io::Error::last_os_error())
392+
}
393+
}
394+
}
395+
}
396+
}

0 commit comments

Comments
 (0)