1use super::{SocketAddr, sockaddr_un};
4use crate::io::{self, IoSlice, IoSliceMut};
5use crate::marker::PhantomData;
6use crate::mem::zeroed;
7use crate::os::unix::io::RawFd;
8use crate::path::Path;
9use crate::ptr::{eq, read_unaligned};
10use crate::slice::from_raw_parts;
11use crate::sys::net::Socket;
12
13#[cfg(all(
15 doc,
16 not(target_os = "linux"),
17 not(target_os = "android"),
18 not(target_os = "netbsd"),
19 not(target_os = "freebsd")
20))]
21#[allow(non_camel_case_types)]
22mod libc {
23 pub use core::ffi::c_int;
24 pub struct ucred;
25 pub struct cmsghdr;
26 pub struct sockcred2;
27 pub type pid_t = i32;
28 pub type gid_t = u32;
29 pub type uid_t = u32;
30}
31
32pub(super) fn recv_vectored_with_ancillary_from(
33 socket: &Socket,
34 bufs: &mut [IoSliceMut<'_>],
35 ancillary: &mut SocketAncillary<'_>,
36) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
37 unsafe {
38 let mut msg_name: libc::sockaddr_un = zeroed();
39 let mut msg: libc::msghdr = zeroed();
40 msg.msg_name = (&raw mut msg_name) as *mut _;
41 msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
42 msg.msg_iov = bufs.as_mut_ptr().cast();
43 msg.msg_iovlen = bufs.len() as _;
44 msg.msg_controllen = ancillary.buffer.len() as _;
45 if msg.msg_controllen > 0 {
47 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
48 }
49
50 let count = socket.recv_msg(&mut msg)?;
51
52 ancillary.length = msg.msg_controllen as usize;
53 ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
54
55 let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
56 let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
57
58 Ok((count, truncated, addr))
59 }
60}
61
62pub(super) fn send_vectored_with_ancillary_to(
63 socket: &Socket,
64 path: Option<&Path>,
65 bufs: &[IoSlice<'_>],
66 ancillary: &mut SocketAncillary<'_>,
67) -> io::Result<usize> {
68 unsafe {
69 let (mut msg_name, msg_namelen) =
70 if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
71
72 let mut msg: libc::msghdr = zeroed();
73 msg.msg_name = (&raw mut msg_name) as *mut _;
74 msg.msg_namelen = msg_namelen;
75 msg.msg_iov = bufs.as_ptr() as *mut _;
76 msg.msg_iovlen = bufs.len() as _;
77 msg.msg_controllen = ancillary.length as _;
78 if msg.msg_controllen > 0 {
80 msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
81 }
82
83 ancillary.truncated = false;
84
85 socket.send_msg(&mut msg)
86 }
87}
88
89fn add_to_ancillary_data<T>(
90 buffer: &mut [u8],
91 length: &mut usize,
92 source: &[T],
93 cmsg_level: libc::c_int,
94 cmsg_type: libc::c_int,
95) -> bool {
96 #[cfg(not(target_os = "freebsd"))]
97 let cmsg_size = source.len().checked_mul(size_of::<T>());
98 #[cfg(target_os = "freebsd")]
99 let cmsg_size = Some(unsafe { libc::SOCKCRED2SIZE(1) });
100
101 let source_len = if let Some(source_len) = cmsg_size {
102 if let Ok(source_len) = u32::try_from(source_len) {
103 source_len
104 } else {
105 return false;
106 }
107 } else {
108 return false;
109 };
110
111 unsafe {
112 let additional_space = libc::CMSG_SPACE(source_len) as usize;
113
114 let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
115 new_length
116 } else {
117 return false;
118 };
119
120 if new_length > buffer.len() {
121 return false;
122 }
123
124 buffer[*length..new_length].fill(0);
125
126 *length = new_length;
127
128 let mut msg: libc::msghdr = zeroed();
129 msg.msg_control = buffer.as_mut_ptr().cast();
130 msg.msg_controllen = *length as _;
131
132 let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
133 let mut previous_cmsg = cmsg;
134 while !cmsg.is_null() {
135 previous_cmsg = cmsg;
136 cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
137
138 if eq(cmsg, previous_cmsg) {
142 break;
143 }
144 }
145
146 if previous_cmsg.is_null() {
147 return false;
148 }
149
150 (*previous_cmsg).cmsg_level = cmsg_level;
151 (*previous_cmsg).cmsg_type = cmsg_type;
152 (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as _;
153
154 let data = libc::CMSG_DATA(previous_cmsg).cast();
155
156 libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
157 }
158 true
159}
160
161struct AncillaryDataIter<'a, T> {
162 data: &'a [u8],
163 phantom: PhantomData<T>,
164}
165
166impl<'a, T> AncillaryDataIter<'a, T> {
167 unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
173 AncillaryDataIter { data, phantom: PhantomData }
174 }
175}
176
177impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
178 type Item = T;
179
180 fn next(&mut self) -> Option<T> {
181 if size_of::<T>() <= self.data.len() {
182 unsafe {
183 let unit = read_unaligned(self.data.as_ptr().cast());
184 self.data = &self.data[size_of::<T>()..];
185 Some(unit)
186 }
187 } else {
188 None
189 }
190 }
191}
192
193#[cfg(all(
194 doc,
195 not(target_os = "android"),
196 not(target_os = "linux"),
197 not(target_os = "netbsd"),
198 not(target_os = "freebsd")
199))]
200#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
201#[derive(Clone)]
202pub struct SocketCred(());
203
204#[cfg(any(target_os = "android", target_os = "linux",))]
206#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
207#[derive(Clone)]
208pub struct SocketCred(libc::ucred);
209
210#[cfg(target_os = "netbsd")]
211#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
212#[derive(Clone)]
213pub struct SocketCred(libc::sockcred);
214
215#[cfg(target_os = "freebsd")]
216#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
217#[derive(Clone)]
218pub struct SocketCred(libc::sockcred2);
219
220#[doc(cfg(any(target_os = "android", target_os = "linux")))]
221#[cfg(any(target_os = "android", target_os = "linux"))]
222impl SocketCred {
223 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
227 #[must_use]
228 pub fn new() -> SocketCred {
229 SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
230 }
231
232 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
234 pub fn set_pid(&mut self, pid: libc::pid_t) {
235 self.0.pid = pid;
236 }
237
238 #[must_use]
240 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
241 pub fn get_pid(&self) -> libc::pid_t {
242 self.0.pid
243 }
244
245 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
247 pub fn set_uid(&mut self, uid: libc::uid_t) {
248 self.0.uid = uid;
249 }
250
251 #[must_use]
253 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
254 pub fn get_uid(&self) -> libc::uid_t {
255 self.0.uid
256 }
257
258 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
260 pub fn set_gid(&mut self, gid: libc::gid_t) {
261 self.0.gid = gid;
262 }
263
264 #[must_use]
266 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
267 pub fn get_gid(&self) -> libc::gid_t {
268 self.0.gid
269 }
270}
271
272#[cfg(target_os = "freebsd")]
273impl SocketCred {
274 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
278 #[must_use]
279 pub fn new() -> SocketCred {
280 SocketCred(libc::sockcred2 {
281 sc_version: 0,
282 sc_pid: 0,
283 sc_uid: 0,
284 sc_euid: 0,
285 sc_gid: 0,
286 sc_egid: 0,
287 sc_ngroups: 0,
288 sc_groups: [0; 1],
289 })
290 }
291
292 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
294 pub fn set_pid(&mut self, pid: libc::pid_t) {
295 self.0.sc_pid = pid;
296 }
297
298 #[must_use]
300 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
301 pub fn get_pid(&self) -> libc::pid_t {
302 self.0.sc_pid
303 }
304
305 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
307 pub fn set_uid(&mut self, uid: libc::uid_t) {
308 self.0.sc_euid = uid;
309 }
310
311 #[must_use]
313 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
314 pub fn get_uid(&self) -> libc::uid_t {
315 self.0.sc_euid
316 }
317
318 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
320 pub fn set_gid(&mut self, gid: libc::gid_t) {
321 self.0.sc_egid = gid;
322 }
323
324 #[must_use]
326 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
327 pub fn get_gid(&self) -> libc::gid_t {
328 self.0.sc_egid
329 }
330}
331
332#[cfg(target_os = "netbsd")]
333impl SocketCred {
334 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
338 pub fn new() -> SocketCred {
339 SocketCred(libc::sockcred {
340 sc_pid: 0,
341 sc_uid: 0,
342 sc_euid: 0,
343 sc_gid: 0,
344 sc_egid: 0,
345 sc_ngroups: 0,
346 sc_groups: [0u32; 1],
347 })
348 }
349
350 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
352 pub fn set_pid(&mut self, pid: libc::pid_t) {
353 self.0.sc_pid = pid;
354 }
355
356 #[must_use]
358 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
359 pub fn get_pid(&self) -> libc::pid_t {
360 self.0.sc_pid
361 }
362
363 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
365 pub fn set_uid(&mut self, uid: libc::uid_t) {
366 self.0.sc_uid = uid;
367 }
368
369 #[must_use]
371 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
372 pub fn get_uid(&self) -> libc::uid_t {
373 self.0.sc_uid
374 }
375
376 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
378 pub fn set_gid(&mut self, gid: libc::gid_t) {
379 self.0.sc_gid = gid;
380 }
381
382 #[must_use]
384 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
385 pub fn get_gid(&self) -> libc::gid_t {
386 self.0.sc_gid
387 }
388}
389
390#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
394pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
395
396#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
397impl<'a> Iterator for ScmRights<'a> {
398 type Item = RawFd;
399
400 fn next(&mut self) -> Option<RawFd> {
401 self.0.next()
402 }
403}
404
405#[cfg(all(
406 doc,
407 not(target_os = "android"),
408 not(target_os = "linux"),
409 not(target_os = "netbsd"),
410 not(target_os = "freebsd")
411))]
412#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
413pub struct ScmCredentials<'a>(AncillaryDataIter<'a, ()>);
414
415#[cfg(any(target_os = "android", target_os = "linux",))]
419#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
420pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
421
422#[cfg(target_os = "freebsd")]
423#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
424pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred2>);
425
426#[cfg(target_os = "netbsd")]
427#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
428pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::sockcred>);
429
430#[cfg(any(
431 doc,
432 target_os = "android",
433 target_os = "linux",
434 target_os = "netbsd",
435 target_os = "freebsd"
436))]
437#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
438impl<'a> Iterator for ScmCredentials<'a> {
439 type Item = SocketCred;
440
441 fn next(&mut self) -> Option<SocketCred> {
442 Some(SocketCred(self.0.next()?))
443 }
444}
445
446#[non_exhaustive]
448#[derive(Debug)]
449#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
450pub enum AncillaryError {
451 Unknown { cmsg_level: i32, cmsg_type: i32 },
452}
453
454#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
456pub enum AncillaryData<'a> {
457 ScmRights(ScmRights<'a>),
458 #[cfg(any(
459 doc,
460 target_os = "android",
461 target_os = "linux",
462 target_os = "netbsd",
463 target_os = "freebsd"
464 ))]
465 ScmCredentials(ScmCredentials<'a>),
466}
467
468impl<'a> AncillaryData<'a> {
469 unsafe fn as_rights(data: &'a [u8]) -> Self {
476 let ancillary_data_iter = AncillaryDataIter::new(data);
477 let scm_rights = ScmRights(ancillary_data_iter);
478 AncillaryData::ScmRights(scm_rights)
479 }
480
481 #[cfg(any(
488 doc,
489 target_os = "android",
490 target_os = "linux",
491 target_os = "netbsd",
492 target_os = "freebsd"
493 ))]
494 unsafe fn as_credentials(data: &'a [u8]) -> Self {
495 let ancillary_data_iter = AncillaryDataIter::new(data);
496 let scm_credentials = ScmCredentials(ancillary_data_iter);
497 AncillaryData::ScmCredentials(scm_credentials)
498 }
499
500 fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
501 unsafe {
502 let cmsg_len_zero = libc::CMSG_LEN(0) as usize;
503 let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero;
504 let data = libc::CMSG_DATA(cmsg).cast();
505 let data = from_raw_parts(data, data_len);
506
507 match (*cmsg).cmsg_level {
508 libc::SOL_SOCKET => match (*cmsg).cmsg_type {
509 libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
510 #[cfg(any(target_os = "android", target_os = "linux",))]
511 libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
512 #[cfg(target_os = "freebsd")]
513 libc::SCM_CREDS2 => Ok(AncillaryData::as_credentials(data)),
514 #[cfg(target_os = "netbsd")]
515 libc::SCM_CREDS => Ok(AncillaryData::as_credentials(data)),
516 cmsg_type => {
517 Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
518 }
519 },
520 cmsg_level => {
521 Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
522 }
523 }
524 }
525 }
526}
527
528#[must_use = "iterators are lazy and do nothing unless consumed"]
530#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
531pub struct Messages<'a> {
532 buffer: &'a [u8],
533 current: Option<&'a libc::cmsghdr>,
534}
535
536#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
537impl<'a> Iterator for Messages<'a> {
538 type Item = Result<AncillaryData<'a>, AncillaryError>;
539
540 fn next(&mut self) -> Option<Self::Item> {
541 unsafe {
542 let mut msg: libc::msghdr = zeroed();
543 msg.msg_control = self.buffer.as_ptr() as *mut _;
544 msg.msg_controllen = self.buffer.len() as _;
545
546 let cmsg = if let Some(current) = self.current {
547 libc::CMSG_NXTHDR(&msg, current)
548 } else {
549 libc::CMSG_FIRSTHDR(&msg)
550 };
551
552 let cmsg = cmsg.as_ref()?;
553
554 if let Some(current) = self.current {
558 if eq(current, cmsg) {
559 return None;
560 }
561 }
562
563 self.current = Some(cmsg);
564 let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
565 Some(ancillary_result)
566 }
567 }
568}
569
570#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
600#[derive(Debug)]
601pub struct SocketAncillary<'a> {
602 buffer: &'a mut [u8],
603 length: usize,
604 truncated: bool,
605}
606
607impl<'a> SocketAncillary<'a> {
608 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
620 pub fn new(buffer: &'a mut [u8]) -> Self {
621 SocketAncillary { buffer, length: 0, truncated: false }
622 }
623
624 #[must_use]
626 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
627 pub fn capacity(&self) -> usize {
628 self.buffer.len()
629 }
630
631 #[must_use]
633 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
634 pub fn is_empty(&self) -> bool {
635 self.length == 0
636 }
637
638 #[must_use]
640 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
641 pub fn len(&self) -> usize {
642 self.length
643 }
644
645 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
647 pub fn messages(&self) -> Messages<'_> {
648 Messages { buffer: &self.buffer[..self.length], current: None }
649 }
650
651 #[must_use]
675 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
676 pub fn truncated(&self) -> bool {
677 self.truncated
678 }
679
680 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
709 pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
710 self.truncated = false;
711 add_to_ancillary_data(
712 &mut self.buffer,
713 &mut self.length,
714 fds,
715 libc::SOL_SOCKET,
716 libc::SCM_RIGHTS,
717 )
718 }
719
720 #[cfg(any(
728 doc,
729 target_os = "android",
730 target_os = "linux",
731 target_os = "netbsd",
732 target_os = "freebsd"
733 ))]
734 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
735 pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
736 self.truncated = false;
737 add_to_ancillary_data(
738 &mut self.buffer,
739 &mut self.length,
740 creds,
741 libc::SOL_SOCKET,
742 #[cfg(not(any(target_os = "netbsd", target_os = "freebsd")))]
743 libc::SCM_CREDENTIALS,
744 #[cfg(target_os = "freebsd")]
745 libc::SCM_CREDS2,
746 #[cfg(target_os = "netbsd")]
747 libc::SCM_CREDS,
748 )
749 }
750
751 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
794 pub fn clear(&mut self) {
795 self.length = 0;
796 self.truncated = false;
797 }
798}