@@ -205,6 +205,18 @@ cfg_if! {
205
205
}
206
206
impl Eq for UnixCredentials { }
207
207
208
+ impl From <libc:: ucred> for UnixCredentials {
209
+ fn from( cred: libc:: ucred) -> Self {
210
+ UnixCredentials ( cred)
211
+ }
212
+ }
213
+
214
+ impl Into <libc:: ucred> for UnixCredentials {
215
+ fn into( self ) -> libc:: ucred {
216
+ self . 0
217
+ }
218
+ }
219
+
208
220
impl fmt:: Debug for UnixCredentials {
209
221
fn fmt( & self , f: & mut fmt:: Formatter ) -> fmt:: Result {
210
222
f. debug_struct( "UnixCredentials" )
@@ -359,7 +371,7 @@ impl<T> CmsgSpace<T> {
359
371
}
360
372
}
361
373
362
- #[ allow ( missing_debug_implementations ) ]
374
+ #[ derive ( Debug ) ]
363
375
pub struct RecvMsg < ' a > {
364
376
// The number of bytes received.
365
377
pub bytes : usize ,
@@ -374,15 +386,14 @@ impl<'a> RecvMsg<'a> {
374
386
pub fn cmsgs ( & self ) -> CmsgIterator {
375
387
CmsgIterator {
376
388
buf : self . cmsg_buffer ,
377
- next : 0
378
389
}
379
390
}
380
391
}
381
392
382
- #[ allow ( missing_debug_implementations ) ]
393
+ #[ derive ( Debug ) ]
383
394
pub struct CmsgIterator < ' a > {
395
+ /// Control message buffer to decode from. Must adhere to cmsg alignment.
384
396
buf : & ' a [ u8 ] ,
385
- next : usize ,
386
397
}
387
398
388
399
impl < ' a > Iterator for CmsgIterator < ' a > {
@@ -392,53 +403,27 @@ impl<'a> Iterator for CmsgIterator<'a> {
392
403
// although we handle the invariants in slightly different places to
393
404
// get a better iterator interface.
394
405
fn next ( & mut self ) -> Option < ControlMessage < ' a > > {
395
- let sizeof_cmsghdr = mem:: size_of :: < cmsghdr > ( ) ;
396
- if self . buf . len ( ) < sizeof_cmsghdr {
406
+ if self . buf . len ( ) == 0 {
407
+ // The iterator assumes that `self.buf` always contains exactly the
408
+ // bytes we need, so we're at the end when the buffer is empty.
397
409
return None ;
398
410
}
399
- let cmsg: & ' a cmsghdr = unsafe { & * ( self . buf . as_ptr ( ) as * const cmsghdr ) } ;
400
411
401
- // This check is only in the glibc implementation of CMSG_NXTHDR
402
- // (although it claims the kernel header checks this), but such
403
- // a structure is clearly invalid, either way.
404
- let cmsg_len = cmsg. cmsg_len as usize ;
405
- if cmsg_len < sizeof_cmsghdr {
406
- return None ;
407
- }
408
- let len = cmsg_len - sizeof_cmsghdr;
409
- let aligned_cmsg_len = if self . next == 0 {
410
- // CMSG_FIRSTHDR
411
- cmsg_len
412
- } else {
413
- // CMSG_NXTHDR
414
- cmsg_align ( cmsg_len)
412
+ // Safe if: `self.buf` is `cmsghdr`-aligned.
413
+ let cmsg: & ' a cmsghdr = unsafe {
414
+ & * ( self . buf [ ..mem:: size_of :: < cmsghdr > ( ) ] . as_ptr ( ) as * const cmsghdr )
415
415
} ;
416
416
417
+ let cmsg_len = cmsg. cmsg_len as usize ;
418
+
417
419
// Advance our internal pointer.
418
- if aligned_cmsg_len > self . buf . len ( ) {
419
- return None ;
420
- }
421
- let cmsg_data = & self . buf [ cmsg_align ( sizeof_cmsghdr) ..cmsg_len] ;
422
- self . buf = & self . buf [ aligned_cmsg_len..] ;
423
- self . next += 1 ;
424
-
425
- match ( cmsg. cmsg_level , cmsg. cmsg_type ) {
426
- ( libc:: SOL_SOCKET , libc:: SCM_RIGHTS ) => unsafe {
427
- Some ( ControlMessage :: ScmRights (
428
- slice:: from_raw_parts ( cmsg_data. as_ptr ( ) as * const _ ,
429
- cmsg_data. len ( ) / mem:: size_of :: < RawFd > ( ) ) ) )
430
- } ,
431
- ( libc:: SOL_SOCKET , libc:: SCM_TIMESTAMP ) => unsafe {
432
- Some ( ControlMessage :: ScmTimestamp (
433
- & * ( cmsg_data. as_ptr ( ) as * const _ ) ) )
434
- } ,
435
- ( _, _) => unsafe {
436
- Some ( ControlMessage :: Unknown ( UnknownCmsg (
437
- cmsg,
438
- slice:: from_raw_parts (
439
- cmsg_data. as_ptr ( ) as * const _ ,
440
- len) ) ) )
441
- }
420
+ let cmsg_data = & self . buf [ cmsg_align ( mem:: size_of :: < cmsghdr > ( ) ) ..cmsg_len] ;
421
+ self . buf = & self . buf [ cmsg_align ( cmsg_len) ..] ;
422
+
423
+ // Safe if: `cmsg_data` contains the expected (amount of) content. This
424
+ // is verified by the kernel.
425
+ unsafe {
426
+ Some ( ControlMessage :: decode_from ( cmsg, cmsg_data) )
442
427
}
443
428
}
444
429
}
@@ -459,6 +444,20 @@ pub enum ControlMessage<'a> {
459
444
/// or fail with `EINVAL`. Instead, you can put all fds to be passed into a single `ScmRights`
460
445
/// message.
461
446
ScmRights ( & ' a [ RawFd ] ) ,
447
+ /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
448
+ /// a process connected to the socket.
449
+ ///
450
+ /// This is similar to the socket option `SO_PEERCRED`, but requires a
451
+ /// process to explicitly send its credentials. A process running as root is
452
+ /// allowed to specify any credentials, while credentials sent by other
453
+ /// processes are verified by the kernel.
454
+ ///
455
+ /// For further information, please refer to the
456
+ /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page.
457
+ // FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials`
458
+ // and put that in here instead of a raw ucred.
459
+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
460
+ ScmCredentials ( & ' a libc:: ucred ) ,
462
461
/// A message of type `SCM_TIMESTAMP`, containing the time the
463
462
/// packet was received by the kernel.
464
463
///
@@ -527,6 +526,7 @@ pub enum ControlMessage<'a> {
527
526
/// nix::unistd::close(in_socket).unwrap();
528
527
/// ```
529
528
ScmTimestamp ( & ' a TimeVal ) ,
529
+ /// Catch-all variant for unimplemented cmsg types.
530
530
#[ doc( hidden) ]
531
531
Unknown ( UnknownCmsg < ' a > ) ,
532
532
}
@@ -558,6 +558,10 @@ impl<'a> ControlMessage<'a> {
558
558
ControlMessage :: ScmRights ( fds) => {
559
559
mem:: size_of_val ( fds)
560
560
} ,
561
+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
562
+ ControlMessage :: ScmCredentials ( creds) => {
563
+ mem:: size_of_val ( creds)
564
+ }
561
565
ControlMessage :: ScmTimestamp ( t) => {
562
566
mem:: size_of_val ( t)
563
567
} ,
@@ -567,57 +571,87 @@ impl<'a> ControlMessage<'a> {
567
571
}
568
572
}
569
573
574
+ /// Returns the value to put into the `cmsg_type` field of the header.
575
+ fn cmsg_type ( & self ) -> libc:: c_int {
576
+ match * self {
577
+ ControlMessage :: ScmRights ( _) => libc:: SCM_RIGHTS ,
578
+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
579
+ ControlMessage :: ScmCredentials ( _) => libc:: SCM_CREDENTIALS ,
580
+ ControlMessage :: ScmTimestamp ( _) => libc:: SCM_TIMESTAMP ,
581
+ ControlMessage :: Unknown ( ref cmsg) => cmsg. 0 . cmsg_type ,
582
+ }
583
+ }
584
+
570
585
// Unsafe: start and end of buffer must be cmsg_align'd. Updates
571
586
// the provided slice; panics if the buffer is too small.
572
587
unsafe fn encode_into ( & self , buf : & mut [ u8 ] ) {
573
- match * self {
574
- ControlMessage :: ScmRights ( fds) => {
575
- let cmsg = cmsghdr {
576
- cmsg_len : self . len ( ) as _ ,
577
- cmsg_level : libc:: SOL_SOCKET ,
578
- cmsg_type : libc:: SCM_RIGHTS ,
579
- ..mem:: uninitialized ( )
580
- } ;
581
- let buf = copy_bytes ( & cmsg, buf) ;
582
-
583
- let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
584
- mem:: size_of_val ( & cmsg) ;
585
- let buf = pad_bytes ( padlen, buf) ;
586
-
587
- let buf = copy_bytes ( fds, buf) ;
588
-
589
- let padlen = self . space ( ) - self . len ( ) ;
590
- pad_bytes ( padlen, buf) ;
591
- } ,
592
- ControlMessage :: ScmTimestamp ( t) => {
593
- let cmsg = cmsghdr {
594
- cmsg_len : self . len ( ) as _ ,
595
- cmsg_level : libc:: SOL_SOCKET ,
596
- cmsg_type : libc:: SCM_TIMESTAMP ,
597
- ..mem:: uninitialized ( )
598
- } ;
599
- let buf = copy_bytes ( & cmsg, buf) ;
600
-
601
- let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
602
- mem:: size_of_val ( & cmsg) ;
603
- let buf = pad_bytes ( padlen, buf) ;
604
-
605
- let buf = copy_bytes ( t, buf) ;
606
-
607
- let padlen = self . space ( ) - self . len ( ) ;
608
- pad_bytes ( padlen, buf) ;
609
- } ,
610
- ControlMessage :: Unknown ( UnknownCmsg ( orig_cmsg, bytes) ) => {
611
- let buf = copy_bytes ( orig_cmsg, buf) ;
588
+ let final_buf = if let ControlMessage :: Unknown ( ref cmsg) = * self {
589
+ let & UnknownCmsg ( orig_cmsg, bytes) = cmsg;
590
+
591
+ let buf = copy_bytes ( orig_cmsg, buf) ;
612
592
613
- let padlen = cmsg_align ( mem:: size_of_val ( & orig_cmsg) ) -
614
- mem:: size_of_val ( & orig_cmsg) ;
615
- let buf = pad_bytes ( padlen, buf) ;
593
+ let padlen = cmsg_align ( mem:: size_of_val ( & orig_cmsg) ) -
594
+ mem:: size_of_val ( & orig_cmsg) ;
595
+ let buf = pad_bytes ( padlen, buf) ;
616
596
617
- let buf = copy_bytes ( bytes, buf) ;
597
+ copy_bytes ( bytes, buf)
598
+ } else {
599
+ let cmsg = cmsghdr {
600
+ cmsg_len : self . len ( ) as _ ,
601
+ cmsg_level : libc:: SOL_SOCKET ,
602
+ cmsg_type : self . cmsg_type ( ) ,
603
+ ..mem:: zeroed ( ) // zero out platform-dependent padding fields
604
+ } ;
605
+ let buf = copy_bytes ( & cmsg, buf) ;
606
+
607
+ let padlen = cmsg_align ( mem:: size_of_val ( & cmsg) ) -
608
+ mem:: size_of_val ( & cmsg) ;
609
+ let buf = pad_bytes ( padlen, buf) ;
610
+
611
+ match * self {
612
+ ControlMessage :: ScmRights ( fds) => {
613
+ copy_bytes ( fds, buf)
614
+ } ,
615
+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
616
+ ControlMessage :: ScmCredentials ( creds) => {
617
+ copy_bytes ( creds, buf)
618
+ }
619
+ ControlMessage :: ScmTimestamp ( t) => {
620
+ copy_bytes ( t, buf)
621
+ } ,
622
+ ControlMessage :: Unknown ( _) => unreachable ! ( ) ,
623
+ }
624
+ } ;
618
625
619
- let padlen = self . space ( ) - self . len ( ) ;
620
- pad_bytes ( padlen, buf) ;
626
+ let padlen = self . space ( ) - self . len ( ) ;
627
+ pad_bytes ( padlen, final_buf) ;
628
+ }
629
+
630
+ /// Decodes a `ControlMessage` from raw bytes.
631
+ ///
632
+ /// This is only safe to call if the data is correct for the message type
633
+ /// specified in the header. Normally, the kernel ensures that this is the
634
+ /// case. "Correct" in this case includes correct length, alignment and
635
+ /// actual content.
636
+ unsafe fn decode_from ( header : & ' a cmsghdr , data : & ' a [ u8 ] ) -> ControlMessage < ' a > {
637
+ match ( header. cmsg_level , header. cmsg_type ) {
638
+ ( libc:: SOL_SOCKET , libc:: SCM_RIGHTS ) => {
639
+ ControlMessage :: ScmRights (
640
+ slice:: from_raw_parts ( data. as_ptr ( ) as * const _ ,
641
+ data. len ( ) / mem:: size_of :: < RawFd > ( ) ) )
642
+ } ,
643
+ #[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
644
+ ( libc:: SOL_SOCKET , libc:: SCM_CREDENTIALS ) => {
645
+ ControlMessage :: ScmCredentials (
646
+ & * ( data. as_ptr ( ) as * const _ )
647
+ )
648
+ }
649
+ ( libc:: SOL_SOCKET , libc:: SCM_TIMESTAMP ) => {
650
+ ControlMessage :: ScmTimestamp (
651
+ & * ( data. as_ptr ( ) as * const _ ) )
652
+ } ,
653
+ ( _, _) => {
654
+ ControlMessage :: Unknown ( UnknownCmsg ( header, data) )
621
655
}
622
656
}
623
657
}
0 commit comments