-
Notifications
You must be signed in to change notification settings - Fork 25
WIP Implementation of peer credentials. #13
Changes from 6 commits
7270717
e0da3a9
49c09e8
23941f9
c25564d
1efd6b3
db78129
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
use libc::{uid_t, gid_t}; | ||
|
||
/// Credentials of a process | ||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] | ||
pub struct UCred { | ||
/// UID (user ID) of the process | ||
pub uid: uid_t, | ||
/// GID (group ID) of the process | ||
pub gid: gid_t, | ||
} | ||
|
||
#[cfg(target_os = "linux")] | ||
pub use self::impl_linux::get_peer_cred; | ||
|
||
#[cfg(target_os = "macos")] | ||
pub use self::impl_macos::get_peer_cred; | ||
|
||
#[cfg(target_os = "linux")] | ||
pub mod impl_linux { | ||
use libc::{getsockopt, SOL_SOCKET, SO_PEERCRED, c_void}; | ||
use std::{io, mem}; | ||
use UnixStream; | ||
use std::os::unix::io::AsRawFd; | ||
|
||
use libc::ucred; | ||
|
||
pub fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { | ||
unsafe { | ||
let raw_fd = sock.as_raw_fd(); | ||
|
||
let mut ucred = ucred { pid: 0, uid: 0, gid: 0 }; | ||
|
||
let ucred_size = mem::size_of::<ucred>(); | ||
|
||
// These paranoid checks should be optimized-out | ||
assert!(mem::size_of::<u32>() <= mem::size_of::<usize>()); | ||
assert!(ucred_size <= u32::max_value() as usize); | ||
|
||
let mut ucred_size = ucred_size as u32; | ||
|
||
let ret = getsockopt(raw_fd, SOL_SOCKET, SO_PEERCRED, &mut ucred as *mut ucred as *mut c_void, &mut ucred_size); | ||
if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() { | ||
Ok(super::UCred { | ||
uid: ucred.uid, | ||
gid: ucred.gid, | ||
}) | ||
} else { | ||
Err(io::Error::last_os_error()) | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))] | ||
pub mod impl_macos { | ||
use libc::getpeereid; | ||
use std::{io, mem}; | ||
use UnixStream; | ||
use std::os::unix::io::AsRawFd; | ||
|
||
pub fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> { | ||
unsafe { | ||
let raw_fd = sock.as_raw_fd(); | ||
|
||
let mut cred: super::UCred = mem::uninitialized(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It could be. But I see no point. My reasoning is that the code is already There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? Is that some kind of standard? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because I see no reason to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant I guess that syscall only overwrites it, so the reason would be performance. I agree it's negligible, so I accept zeroig. I'm just interested to know whether there is some difference between using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nah those are the same. With libc I tend to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, OK. I prefer "safe" version in this case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be udpated to using |
||
|
||
let ret = getpeereid(raw_fd, &mut cred.uid, &mut cred.gid); | ||
|
||
if ret == 0 { | ||
Ok(cred) | ||
} else { | ||
Err(io::Error::last_os_error()) | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be added via an extension trait if it's platform-specific?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about it too. I'm not sure if Rust runs on any platform that has
UnixStream
but no way of getting peer credentials. Solaris seems to have different implementation, but I have no machine to test it.If I wanted to use a trait how to name it? LinuxAndMacPeerCredentials seems long to me. I wouldn't separate them provided there can be a common trait for both. (And I'm actually currently working on code that should be Linux/macOS.) On the other hand, Linux has possibility to provide pid too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think all other unices have an implementation of this function? If that's the case then this should just remove the
#[cfg]
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Digging into the topic more I found that:
getsockopt
should be usedgetpeereid
getpeerucred
I know of no other unix used in the wild with Rust.
So maybe we can just remove
#[cfg]
. However, it'd be nice to implement this for Solaris too. But as I said, I have nothing to test it on.Also,
macos
cfg will have to be changed to#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This either needs to be ungated to cause compile failures on other platforms to necessitate an implementation, or it needs an extension trait. I don't mind which, but there's no middle between those tw.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'll go with ungated. Gating pushes the compilation error to consumer, so there'd still be the error. If you have some explanation about why compile error in this crate is better than at consumer, I'm interested in learning it. (I personally don't mind using the one you choose.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't have a cfg here then we're claiming it's available on all unices, both in the code and in the documentation. At that point we need an assertion as such, which is to attempt to compile the code on all platforms.