1 use libc::{gid_t, uid_t}; 2 3 /// Credentials of a process 4 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] 5 pub struct UCred { 6 /// UID (user ID) of the process 7 pub uid: uid_t, 8 /// GID (group ID) of the process 9 pub gid: gid_t, 10 } 11 12 #[cfg(any(target_os = "linux", target_os = "android"))] 13 pub(crate) use self::impl_linux::get_peer_cred; 14 15 #[cfg(any( 16 target_os = "dragonfly", 17 target_os = "macos", 18 target_os = "ios", 19 target_os = "freebsd", 20 target_os = "netbsd", 21 target_os = "openbsd" 22 ))] 23 pub(crate) use self::impl_macos::get_peer_cred; 24 25 #[cfg(any(target_os = "solaris", target_os = "illumos"))] 26 pub(crate) use self::impl_solaris::get_peer_cred; 27 28 #[cfg(any(target_os = "linux", target_os = "android"))] 29 pub(crate) mod impl_linux { 30 use crate::net::unix::UnixStream; 31 32 use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED}; 33 use std::{io, mem}; 34 35 use libc::ucred; 36 get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>37 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { 38 use std::os::unix::io::AsRawFd; 39 40 unsafe { 41 let raw_fd = sock.as_raw_fd(); 42 43 let mut ucred = ucred { 44 pid: 0, 45 uid: 0, 46 gid: 0, 47 }; 48 49 let ucred_size = mem::size_of::<ucred>(); 50 51 // These paranoid checks should be optimized-out 52 assert!(mem::size_of::<u32>() <= mem::size_of::<usize>()); 53 assert!(ucred_size <= u32::max_value() as usize); 54 55 let mut ucred_size = ucred_size as socklen_t; 56 57 let ret = getsockopt( 58 raw_fd, 59 SOL_SOCKET, 60 SO_PEERCRED, 61 &mut ucred as *mut ucred as *mut c_void, 62 &mut ucred_size, 63 ); 64 if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() { 65 Ok(super::UCred { 66 uid: ucred.uid, 67 gid: ucred.gid, 68 }) 69 } else { 70 Err(io::Error::last_os_error()) 71 } 72 } 73 } 74 } 75 76 #[cfg(any( 77 target_os = "dragonfly", 78 target_os = "macos", 79 target_os = "ios", 80 target_os = "freebsd", 81 target_os = "netbsd", 82 target_os = "openbsd" 83 ))] 84 pub(crate) mod impl_macos { 85 use crate::net::unix::UnixStream; 86 87 use libc::getpeereid; 88 use std::io; 89 use std::mem::MaybeUninit; 90 use std::os::unix::io::AsRawFd; 91 get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>92 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { 93 unsafe { 94 let raw_fd = sock.as_raw_fd(); 95 96 let mut uid = MaybeUninit::uninit(); 97 let mut gid = MaybeUninit::uninit(); 98 99 let ret = getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr()); 100 101 if ret == 0 { 102 Ok(super::UCred { 103 uid: uid.assume_init(), 104 gid: gid.assume_init(), 105 }) 106 } else { 107 Err(io::Error::last_os_error()) 108 } 109 } 110 } 111 } 112 113 #[cfg(any(target_os = "solaris", target_os = "illumos"))] 114 pub(crate) mod impl_solaris { 115 use crate::net::unix::UnixStream; 116 use std::io; 117 use std::os::unix::io::AsRawFd; 118 use std::ptr; 119 120 #[allow(non_camel_case_types)] 121 enum ucred_t {} 122 123 extern "C" { ucred_free(cred: *mut ucred_t)124 fn ucred_free(cred: *mut ucred_t); ucred_geteuid(cred: *const ucred_t) -> super::uid_t125 fn ucred_geteuid(cred: *const ucred_t) -> super::uid_t; ucred_getegid(cred: *const ucred_t) -> super::gid_t126 fn ucred_getegid(cred: *const ucred_t) -> super::gid_t; 127 getpeerucred(fd: std::os::raw::c_int, cred: *mut *mut ucred_t) -> std::os::raw::c_int128 fn getpeerucred(fd: std::os::raw::c_int, cred: *mut *mut ucred_t) -> std::os::raw::c_int; 129 } 130 get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred>131 pub(crate) fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { 132 unsafe { 133 let raw_fd = sock.as_raw_fd(); 134 135 let mut cred = ptr::null_mut::<*mut ucred_t>() as *mut ucred_t; 136 137 let ret = getpeerucred(raw_fd, &mut cred); 138 139 if ret == 0 { 140 let uid = ucred_geteuid(cred); 141 let gid = ucred_getegid(cred); 142 143 ucred_free(cred); 144 145 Ok(super::UCred { uid, gid }) 146 } else { 147 Err(io::Error::last_os_error()) 148 } 149 } 150 } 151 } 152