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