@@ -202,8 +202,7 @@ impl Listen for DomainSocketListener {
202
202
format_error ! ( "Failed to set stream as blocking" , err) ;
203
203
None
204
204
} else {
205
- let ucred = stream
206
- . peer_cred ( )
205
+ let ucred = peer_credentials:: peer_cred ( & stream)
207
206
. map_err ( |err| {
208
207
format_error ! (
209
208
"Failed to grab peer credentials metadata from UnixStream" ,
@@ -260,3 +259,128 @@ impl DomainSocketListenerBuilder {
260
259
} ) ?)
261
260
}
262
261
}
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