@@ -252,14 +252,12 @@ impl DomainSocketListenerBuilder {
252
252
impl GetMetadata for UnixStream {
253
253
#[ cfg( feature = "unix-peer-credentials-authenticator" ) ]
254
254
fn metadata ( & self ) -> Option < ConnectionMetadata > {
255
- let ucred = self
256
- . peer_cred ( )
255
+ let ucred = peer_credentials:: peer_cred ( self )
257
256
. map_err ( |err| {
258
257
format_error ! (
259
258
"Failed to grab peer credentials metadata from UnixStream" ,
260
259
err
261
- ) ;
262
- err
260
+ )
263
261
} )
264
262
. ok ( ) ?;
265
263
@@ -275,3 +273,124 @@ impl GetMetadata for UnixStream {
275
273
None
276
274
}
277
275
}
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