1use libc::{gid_t, pid_t, uid_t};
8
9#[unstable(feature = "peer_credentials_unix_socket", issue = "42839")]
11#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
12pub struct UCred {
13 pub uid: uid_t,
16 pub gid: gid_t,
19 pub pid: Option<pid_t>,
24}
25
26#[cfg(target_vendor = "apple")]
27pub(super) use self::impl_apple::peer_cred;
28#[cfg(any(
29 target_os = "dragonfly",
30 target_os = "freebsd",
31 target_os = "openbsd",
32 target_os = "netbsd",
33 target_os = "nto",
34 target_os = "qnx"
35))]
36pub(super) use self::impl_bsd::peer_cred;
37#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
38pub(super) use self::impl_linux::peer_cred;
39
40#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
41mod impl_linux {
42 use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred};
43
44 use super::UCred;
45 use crate::io;
46 use crate::os::unix::io::AsRawFd;
47 use crate::os::unix::net::UnixStream;
48
49 pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
50 let ucred_size = size_of::<ucred>();
51
52 assert!(size_of::<u32>() <= size_of::<usize>());
54 assert!(ucred_size <= u32::MAX as usize);
55
56 let mut ucred_size = ucred_size as socklen_t;
57 let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
58
59 unsafe {
60 let ret = getsockopt(
61 socket.as_raw_fd(),
62 SOL_SOCKET,
63 SO_PEERCRED,
64 (&raw mut ucred) as *mut c_void,
65 &mut ucred_size,
66 );
67
68 if ret == 0 && ucred_size as usize == size_of::<ucred>() {
69 Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
70 } else {
71 Err(io::Error::last_os_error())
72 }
73 }
74 }
75}
76
77#[cfg(any(
78 target_os = "dragonfly",
79 target_os = "freebsd",
80 target_os = "openbsd",
81 target_os = "netbsd",
82 target_os = "nto",
83 target_os = "qnx",
84))]
85mod impl_bsd {
86 use super::UCred;
87 use crate::io;
88 use crate::os::unix::io::AsRawFd;
89 use crate::os::unix::net::UnixStream;
90
91 pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
92 let mut cred = UCred { uid: 1, gid: 1, pid: None };
93 unsafe {
94 let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
95
96 if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
97 }
98 }
99}
100
101#[cfg(target_vendor = "apple")]
102mod impl_apple {
103 use libc::{LOCAL_PEERPID, SOL_LOCAL, c_void, getpeereid, getsockopt, pid_t, socklen_t};
104
105 use super::UCred;
106 use crate::io;
107 use crate::os::unix::io::AsRawFd;
108 use crate::os::unix::net::UnixStream;
109
110 pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
111 let mut cred = UCred { uid: 1, gid: 1, pid: None };
112 unsafe {
113 let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
114
115 if ret != 0 {
116 return Err(io::Error::last_os_error());
117 }
118
119 let mut pid: pid_t = 1;
120 let mut pid_size = size_of::<pid_t>() as socklen_t;
121
122 let ret = getsockopt(
123 socket.as_raw_fd(),
124 SOL_LOCAL,
125 LOCAL_PEERPID,
126 (&raw mut pid) as *mut c_void,
127 &mut pid_size,
128 );
129
130 if ret == 0 && pid_size as usize == size_of::<pid_t>() {
131 cred.pid = Some(pid);
132 Ok(cred)
133 } else {
134 Err(io::Error::last_os_error())
135 }
136 }
137 }
138}