tokio_seqpacket/
ucred.rs

1use libc::{gid_t, pid_t, uid_t};
2use std::os::unix::io::AsRawFd;
3
4/// Credentials of a process
5#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
6pub struct UCred {
7	/// UID (user ID) of the process
8	uid: uid_t,
9	/// GID (group ID) of the process
10	gid: gid_t,
11	/// PID (process ID) of the process
12	pid: pid_t,
13}
14
15impl UCred {
16	/// Get the credentials of a connected peer for a Unix socket.
17	pub fn from_socket_peer<T: AsRawFd>(socket: &T) -> std::io::Result<Self> {
18		get_peer_cred(socket)
19	}
20
21	/// Gets UID (user ID) of the process.
22	pub fn uid(&self) -> uid_t {
23		self.uid
24	}
25
26	/// Gets GID (group ID) of the process.
27	pub fn gid(&self) -> gid_t {
28		self.gid
29	}
30
31	/// Gets PID (process ID) of the process.
32	///
33	/// This is only implemented under Linux, Android, iOS, macOS, Solaris and
34	/// Illumos. On other plaforms this will always return `None`.
35	pub fn pid(&self) -> Option<pid_t> {
36		if self.pid == 0 {
37			None
38		} else {
39			Some(self.pid)
40		}
41	}
42
43	#[cfg(any(target_os = "linux", target_os = "android"))]
44	pub(crate) fn from_scm_creds(raw: crate::ancillary::RawScmCreds) -> UCred {
45		UCred {
46			uid: raw.uid,
47			gid: raw.gid,
48			pid: raw.pid,
49		}
50	}
51
52	#[cfg(target_os = "netbsd")]
53	pub(crate) fn from_scm_creds(raw: crate::ancillary::RawScmCreds) -> UCred {
54		UCred {
55			uid: raw.sc_uid,
56			gid: raw.sc_gid,
57			pid: raw.sc_pid,
58		}
59	}
60
61	#[cfg(any(target_os = "linux", target_os = "android"))]
62	pub(crate) fn to_scm_creds(self) -> crate::ancillary::RawScmCreds {
63		crate::ancillary::RawScmCreds {
64			uid: self.uid,
65			gid: self.gid,
66			pid: self.pid,
67		}
68	}
69
70	#[cfg(target_os = "netbsd")]
71	pub(crate) fn to_scm_creds(self) -> crate::ancillary::RawScmCreds {
72		crate::ancillary::RawScmCreds {
73			sc_uid: self.uid,
74			sc_gid: self.gid,
75			sc_pid: self.pid,
76			sc_euid: self.uid,
77			sc_egid: self.gid,
78			sc_ngroups: 0,
79			sc_groups: [],
80		}
81	}
82}
83
84#[cfg(any(target_os = "linux", target_os = "android"))]
85fn get_peer_cred<T: AsRawFd>(sock: &T) -> std::io::Result<UCred> {
86	use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
87
88	let raw_fd = sock.as_raw_fd();
89
90	let mut ucred = ucred { pid: 0, uid: 0, gid: 0 };
91
92	let mut ucred_size = std::mem::size_of::<ucred>() as socklen_t;
93
94	let ret = unsafe {
95		getsockopt(
96			raw_fd,
97			SOL_SOCKET,
98			SO_PEERCRED,
99			&mut ucred as *mut ucred as *mut c_void,
100			&mut ucred_size,
101		)
102	};
103
104	if ret == 0 {
105		Ok(UCred {
106			uid: ucred.uid,
107			gid: ucred.gid,
108			pid: ucred.pid,
109		})
110	} else {
111		Err(std::io::Error::last_os_error())
112	}
113}
114
115#[cfg(any(
116	target_os = "dragonfly",
117	target_os = "freebsd",
118	target_os = "netbsd",
119	target_os = "openbsd"
120))]
121fn get_peer_cred<T: AsRawFd>(sock: &T) -> std::io::Result<UCred> {
122	let raw_fd = sock.as_raw_fd();
123
124	let mut uid = 0;
125	let mut gid = 0;
126
127	let ret = unsafe { libc::getpeereid(raw_fd, &mut uid, &mut gid) };
128
129	if ret == 0 {
130		Ok(UCred { uid, gid, pid: 0 })
131	} else {
132		Err(std::io::Error::last_os_error())
133	}
134}
135
136#[cfg(any(target_os = "macos", target_os = "ios"))]
137fn get_peer_cred<T: AsRawFd>(sock: &T) -> std::io::Result<UCred> {
138	let raw_fd = sock.as_raw_fd();
139
140	let mut uid = 0 as uid_t;
141	let mut gid = 0 as gid_t;
142	let mut pid = 0 as pid_t;
143	let mut pid_size = size_of::<pid_t>() as u32;
144
145	let ret = unsafe {
146		getsockopt(
147			raw_fd,
148			SOL_LOCAL,
149			LOCAL_PEEREPID,
150			pid.as_mut_ptr() as *mut c_void,
151			pid_size.as_mut_ptr(),
152		)
153	};
154	if ret != 0 {
155		return Err(std::io::Error::last_os_error());
156	}
157
158	let ret = unsafe { getpeereid(raw_fd, uid.as_mut_ptr(), gid.as_mut_ptr()) };
159
160	if ret == 0 {
161		Ok(UCred {
162			uid,
163			gid,
164			pid,
165		})
166	} else {
167		Err(std::io::Error::last_os_error())
168	}
169}
170
171#[cfg(any(target_os = "solaris", target_os = "illumos"))]
172fn get_peer_cred<T: AsRawFd>(sock: &T) -> std::io::Result<UCred> {
173	let raw_fd = sock.as_raw_fd();
174	let mut cred = std::ptr::null_mut();
175	unsafe {
176		let ret = libc::getpeerucred(raw_fd, &mut cred);
177
178		if ret == 0 {
179			let uid = libc::ucred_geteuid(cred);
180			let gid = libc::ucred_getegid(cred);
181			let pid = libc::ucred_getpid(cred);
182
183			libc::ucred_free(cred);
184
185			Ok(UCred {
186				uid,
187				gid,
188				pid,
189			})
190		} else {
191			Err(std::io::Error::last_os_error())
192		}
193	}
194}