@@ -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