Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 43 additions & 14 deletions library/std/src/sys/unix/ext/ucred.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,12 @@ pub struct UCred {
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use self::impl_linux::peer_cred;

#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "openbsd"
))]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
pub use self::impl_bsd::peer_cred;

#[cfg(any(target_os = "macos", target_os = "ios",))]
pub use self::impl_mac::peer_cred;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod impl_linux {
use super::UCred;
Expand Down Expand Up @@ -73,13 +70,7 @@ pub mod impl_linux {
}
}

#[cfg(any(
target_os = "dragonfly",
target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "openbsd"
))]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
pub mod impl_bsd {
use super::UCred;
use crate::io;
Expand All @@ -95,3 +86,41 @@ pub mod impl_bsd {
}
}
}

#[cfg(any(target_os = "macos", target_os = "ios",))]
pub mod impl_mac {
use super::UCred;
use crate::os::unix::io::AsRawFd;
use crate::os::unix::net::UnixStream;
use crate::{io, mem};
use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL};

pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
let mut cred = UCred { uid: 1, gid: 1, pid: None };
unsafe {
let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);

if ret != 0 {
return Err(io::Error::last_os_error());
}

let mut pid: pid_t = 1;
let mut pid_size = mem::size_of::<pid_t>() as socklen_t;

let ret = getsockopt(
socket.as_raw_fd(),
SOL_LOCAL,
LOCAL_PEERPID,
&mut pid as *mut pid_t as *mut c_void,
&mut pid_size,
);

if ret == 0 && pid_size as usize == mem::size_of::<pid_t>() {
cred.pid = Some(pid);
Ok(cred)
} else {
Err(io::Error::last_os_error())
}
}
}
}
15 changes: 14 additions & 1 deletion library/std/src/sys/unix/ext/ucred/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::os::unix::net::UnixStream;
use libc::{getegid, geteuid};
use libc::{getegid, geteuid, getpid};

#[test]
#[cfg(any(
Expand All @@ -23,3 +23,16 @@ fn test_socket_pair() {
assert_eq!(cred_a.uid, uid);
assert_eq!(cred_a.gid, gid);
}

#[test]
#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))]
fn test_socket_pair_pids(arg: Type) -> RetType {
// Create two connected sockets and get their peer credentials.
let (sock_a, sock_b) = UnixStream::pair().unwrap();
let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());

// On supported platforms (see the cfg above), the credentials should always include the PID.
let pid = unsafe { getpid() };
assert_eq!(cred_a.pid, Some(pid));
assert_eq!(cred_b.pid, Some(pid));
}