Skip to content

Commit 06b5d33

Browse files
bors[bot]asomers
andauthored
Merge #1482
1482: Add support for LOCAL_PEER_CRED r=asomers a=asomers On FreeBSD and its derivatives, this socket option gets the credentials of the connected peer. Co-authored-by: Alan Somers <[email protected]>
2 parents a7e86b2 + 0d3bc08 commit 06b5d33

File tree

4 files changed

+103
-20
lines changed

4 files changed

+103
-20
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
66
## [Unreleased] - ReleaseDate
77
### Added
88

9+
- Added the `LocalPeerCred` sockopt.
10+
(#[1482](https://github.com/nix-rust/nix/pull/1482))
911
- Added `TimeSpec::from_duration` and `TimeSpec::from_timespec`
1012
(#[1465](https://github.com/nix-rust/nix/pull/1465))
1113
- Added `IPV6_V6ONLY` sockopt.

src/sys/socket/mod.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,38 @@ cfg_if! {
358358
}
359359
}
360360

361+
cfg_if!{
362+
if #[cfg(any(
363+
target_os = "dragonfly",
364+
target_os = "freebsd",
365+
target_os = "macos",
366+
target_os = "ios"
367+
))] {
368+
/// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred)
369+
#[repr(transparent)]
370+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
371+
pub struct XuCred(libc::xucred);
372+
373+
impl XuCred {
374+
/// Structure layout version
375+
pub fn version(&self) -> u32 {
376+
self.0.cr_version
377+
}
378+
379+
/// Effective user ID
380+
pub fn uid(&self) -> libc::uid_t {
381+
self.0.cr_uid
382+
}
383+
384+
/// Returns a list of group identifiers (the first one being the
385+
/// effective GID)
386+
pub fn groups(&self) -> &[libc::gid_t] {
387+
&self.0.cr_groups
388+
}
389+
}
390+
}
391+
}
392+
361393
/// Request for multicast socket operations
362394
///
363395
/// This is a wrapper type around `ip_mreq`.

src/sys/socket/sockopt.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const TCP_CA_NAME_MAX: usize = 16;
3030
/// # Arguments
3131
///
3232
/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for.
33-
/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
33+
/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets*
3434
/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
3535
/// and more. Please refer to your system manual for more options. Will be passed as the second
3636
/// argument (`level`) to the `setsockopt` call.
@@ -41,7 +41,7 @@ const TCP_CA_NAME_MAX: usize = 16;
4141
/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
4242
/// `bool`, `SetUsize` for `usize`, etc.).
4343
macro_rules! setsockopt_impl {
44-
($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
44+
($name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
4545
impl SetSockOpt for $name {
4646
type Val = $ty;
4747

@@ -82,7 +82,7 @@ macro_rules! setsockopt_impl {
8282
/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
8383
/// `bool`, `GetUsize` for `usize`, etc.).
8484
macro_rules! getsockopt_impl {
85-
($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
85+
($name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
8686
impl GetSockOpt for $name {
8787
type Val = $ty;
8888

@@ -117,7 +117,7 @@ macro_rules! getsockopt_impl {
117117
/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
118118
/// both of them.
119119
/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
120-
/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
120+
/// * `$level:expr` : socket layer, or a `protocol level`: could be *raw sockets*
121121
/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
122122
/// and more. Please refer to your system manual for more options. Will be passed as the second
123123
/// argument (`level`) to the `getsockopt`/`setsockopt` call.
@@ -128,81 +128,81 @@ macro_rules! getsockopt_impl {
128128
/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
129129
/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
130130
macro_rules! sockopt_impl {
131-
(GetOnly, $name:ident, $level:path, $flag:path, bool) => {
131+
(GetOnly, $name:ident, $level:expr, $flag:path, bool) => {
132132
sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
133133
};
134134

135-
(GetOnly, $name:ident, $level:path, $flag:path, u8) => {
135+
(GetOnly, $name:ident, $level:expr, $flag:path, u8) => {
136136
sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
137137
};
138138

139-
(GetOnly, $name:ident, $level:path, $flag:path, usize) => {
139+
(GetOnly, $name:ident, $level:expr, $flag:path, usize) => {
140140
sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
141141
};
142142

143-
(SetOnly, $name:ident, $level:path, $flag:path, bool) => {
143+
(SetOnly, $name:ident, $level:expr, $flag:path, bool) => {
144144
sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
145145
};
146146

147-
(SetOnly, $name:ident, $level:path, $flag:path, u8) => {
147+
(SetOnly, $name:ident, $level:expr, $flag:path, u8) => {
148148
sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
149149
};
150150

151-
(SetOnly, $name:ident, $level:path, $flag:path, usize) => {
151+
(SetOnly, $name:ident, $level:expr, $flag:path, usize) => {
152152
sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
153153
};
154154

155-
(Both, $name:ident, $level:path, $flag:path, bool) => {
155+
(Both, $name:ident, $level:expr, $flag:path, bool) => {
156156
sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
157157
};
158158

159-
(Both, $name:ident, $level:path, $flag:path, u8) => {
159+
(Both, $name:ident, $level:expr, $flag:path, u8) => {
160160
sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
161161
};
162162

163-
(Both, $name:ident, $level:path, $flag:path, usize) => {
163+
(Both, $name:ident, $level:expr, $flag:path, usize) => {
164164
sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
165165
};
166166

167-
(Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => {
167+
(Both, $name:ident, $level:expr, $flag:path, OsString<$array:ty>) => {
168168
sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString);
169169
};
170170

171171
/*
172172
* Matchers with generic getter types must be placed at the end, so
173173
* they'll only match _after_ specialized matchers fail
174174
*/
175-
(GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
175+
(GetOnly, $name:ident, $level:expr, $flag:path, $ty:ty) => {
176176
sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
177177
};
178178

179-
(GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
179+
(GetOnly, $name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty) => {
180180
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
181181
pub struct $name;
182182

183183
getsockopt_impl!($name, $level, $flag, $ty, $getter);
184184
};
185185

186-
(SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
186+
(SetOnly, $name:ident, $level:expr, $flag:path, $ty:ty) => {
187187
sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
188188
};
189189

190-
(SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
190+
(SetOnly, $name:ident, $level:expr, $flag:path, $ty:ty, $setter:ty) => {
191191
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
192192
pub struct $name;
193193

194194
setsockopt_impl!($name, $level, $flag, $ty, $setter);
195195
};
196196

197-
(Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
197+
(Both, $name:ident, $level:expr, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
198198
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
199199
pub struct $name;
200200

201201
setsockopt_impl!($name, $level, $flag, $ty, $setter);
202202
getsockopt_impl!($name, $level, $flag, $ty, $getter);
203203
};
204204

205-
(Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
205+
(Both, $name:ident, $level:expr, $flag:path, $ty:ty) => {
206206
sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
207207
};
208208
}
@@ -246,6 +246,14 @@ sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
246246
sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
247247
sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32);
248248
sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
249+
#[cfg(any(
250+
target_os = "dragonfly",
251+
target_os = "freebsd",
252+
target_os = "macos",
253+
target_os = "ios"
254+
))]
255+
// Get the credentials of the peer process of a connected unix domain socket.
256+
sockopt_impl!(GetOnly, LocalPeerCred, 0, libc::LOCAL_PEERCRED, super::XuCred);
249257
#[cfg(any(target_os = "android", target_os = "linux"))]
250258
sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
251259
#[cfg(any(target_os = "ios",

test/sys/test_sockopt.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,47 @@ use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, S
33
#[cfg(any(target_os = "android", target_os = "linux"))]
44
use crate::*;
55

6+
// NB: FreeBSD supports LOCAL_PEERCRED for SOCK_SEQPACKET, but OSX does not.
7+
#[cfg(any(
8+
target_os = "dragonfly",
9+
target_os = "freebsd",
10+
))]
11+
#[test]
12+
pub fn test_local_peercred_seqpacket() {
13+
use nix::{
14+
unistd::{Gid, Uid},
15+
sys::socket::socketpair
16+
};
17+
18+
let (fd1, _fd2) = socketpair(AddressFamily::Unix, SockType::SeqPacket, None,
19+
SockFlag::empty()).unwrap();
20+
let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap();
21+
assert_eq!(xucred.version(), 0);
22+
assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
23+
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
24+
}
25+
26+
#[cfg(any(
27+
target_os = "dragonfly",
28+
target_os = "freebsd",
29+
target_os = "macos",
30+
target_os = "ios"
31+
))]
32+
#[test]
33+
pub fn test_local_peercred_stream() {
34+
use nix::{
35+
unistd::{Gid, Uid},
36+
sys::socket::socketpair
37+
};
38+
39+
let (fd1, _fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None,
40+
SockFlag::empty()).unwrap();
41+
let xucred = getsockopt(fd1, sockopt::LocalPeerCred).unwrap();
42+
assert_eq!(xucred.version(), 0);
43+
assert_eq!(Uid::from_raw(xucred.uid()), Uid::current());
44+
assert_eq!(Gid::from_raw(xucred.groups()[0]), Gid::current());
45+
}
46+
647
#[cfg(target_os = "linux")]
748
#[test]
849
fn is_so_mark_functional() {

0 commit comments

Comments
 (0)