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