Add windows permissions wrapper

This commit is contained in:
Emīls 2018-08-24 17:53:35 +01:00
parent 1b82b8da1c
commit a2dc227fe4
3 changed files with 308 additions and 22 deletions

View File

@ -16,4 +16,4 @@ log = "*"
bytes = "0.4"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }
winapi = { version = "0.3", features = ["winbase", "winnt", "accctrl", "aclapi", "securitybaseapi", "minwinbase", "winbase"] }

View File

@ -31,9 +31,10 @@ use bytes::{BufMut, Buf};
use tokio_named_pipes::NamedPipe;
#[cfg(windows)]
use winapi::um::minwinbase::SECURITY_ATTRIBUTES;
mod win_permissions;
#[cfg(windows)]
use std::ptr;
pub use win_permissions::SecurityAttributes;
/// For testing/examples
@ -75,7 +76,7 @@ pub fn dummy_endpoint() -> String {
pub struct Endpoint {
path: String,
#[cfg(windows)]
security_attributes: SecurityAttrWrap,
security_attributes: SecurityAttributes,
}
impl Endpoint {
@ -89,16 +90,16 @@ impl Endpoint {
/// Stream of incoming connections
#[cfg(windows)]
pub fn incoming(self, handle: Handle) -> io::Result<Incoming> {
pub fn incoming(mut self, handle: Handle) -> io::Result<Incoming> {
let pipe = self.inner(&handle)?;
Ok(
Incoming { inner: NamedPipeSupport { path: self.path, handle: handle.remote().clone(), pipe: pipe, security_attributes: self.security_attributes.0} }
Incoming { inner: NamedPipeSupport { path: self.path, handle: handle.remote().clone(), pipe: pipe, security_attributes: self.security_attributes} }
)
}
/// Inner platform-dependant state of the endpoint
#[cfg(windows)]
fn inner(&self, handle: &Handle) -> io::Result<NamedPipe> {
fn inner(&mut self, handle: &Handle) -> io::Result<NamedPipe> {
extern crate mio_named_pipes;
use std::os::windows::io::*;
use miow::pipe::NamedPipeBuilder;
@ -109,7 +110,7 @@ impl Endpoint {
.outbound(true)
.out_buffer_size(65536)
.in_buffer_size(65536)
.with_security_attributes(self.security_attributes.0)?
.with_security_attributes(self.security_attributes.as_ptr())?
.into_raw_handle()};
let mio_pipe = unsafe { mio_named_pipes::NamedPipe::from_raw_handle(raw_handle) };
@ -122,12 +123,9 @@ impl Endpoint {
tokio_uds::UnixListener::bind(&self.path, handle)
}
/// Sets the security attributes of the underlying named pipes. Note that if the pointer to the
/// security attributes is not null, it should be valid for the lifetime of this struct and the
/// lifetime of the returned `Incoming` struct.
#[cfg(windows)]
pub unsafe fn set_security_attributes(&mut self, security_attributes: *mut SECURITY_ATTRIBUTES) {
self.security_attributes = SecurityAttrWrap(security_attributes);
pub fn set_security_attributes(&mut self, security_attributes: SecurityAttributes) {
self.security_attributes = security_attributes;
}
/// Returns the path of the endpoint.
@ -141,17 +139,11 @@ impl Endpoint {
Endpoint {
path: path,
#[cfg(windows)]
security_attributes: SecurityAttrWrap(ptr::null_mut()),
security_attributes: SecurityAttributes::empty(),
}
}
}
// This is required as otherwise the pointer to the SECURITY_ATTRIBUTES does not implement Send
#[cfg(windows)]
struct SecurityAttrWrap ( *mut SECURITY_ATTRIBUTES );
#[cfg(windows)]
unsafe impl Send for SecurityAttrWrap{}
/// Remote connection data, if any available
pub struct RemoteId;
@ -160,7 +152,7 @@ struct NamedPipeSupport {
path: String,
handle: tokio_core::reactor::Remote,
pipe: NamedPipe,
security_attributes: *mut SECURITY_ATTRIBUTES,
security_attributes: SecurityAttributes,
}
#[cfg(windows)]
@ -182,7 +174,7 @@ impl NamedPipeSupport {
.outbound(true)
.out_buffer_size(65536)
.in_buffer_size(65536)
.with_security_attributes(self.security_attributes)?
.with_security_attributes(self.security_attributes.as_ptr())?
.into_raw_handle()};
let mio_pipe = unsafe { mio_named_pipes::NamedPipe::from_raw_handle(raw_handle) };
@ -341,6 +333,8 @@ mod tests {
use super::Endpoint;
use super::IpcConnection;
#[cfg(windows)]
use super::SecurityAttributes;
#[cfg(not(windows))]
fn random_pipe_path() -> String {
@ -404,4 +398,28 @@ mod tests {
assert_eq!(rx_msg, msg);
assert_eq!(other_rx_msg, msg);
}
#[cfg(windows)]
fn create_pipe_with_permissions(attr: SecurityAttributes) -> ::std::io::Result<()> {
let mut core = Core::new().expect("Failed to spawn an event loop");
let path = random_pipe_path();
let mut endpoint = Endpoint::new(path);
endpoint.set_security_attributes(attr);
endpoint.incoming(core.handle()).map(|_| ())
}
#[cfg(windows)]
#[test]
fn test_pipe_permissions() {
create_pipe_with_permissions(SecurityAttributes::empty()).expect("failed with no attributes");
create_pipe_with_permissions(SecurityAttributes::allow_everyone_create().unwrap())
.expect("failed with attributes for creating");
// create_pipe_with_permissions(SecurityAttributes::allow_everyone_create().unwrap())
// .expect("failed with attributes for creating");
// create_pipe_with_permissions(SecurityAttributes::allow_everyone_connect().unwrap())
// .expect("failed with attributes for connecting");
// create_pipe_with_permissions(SecurityAttributes::allow_everyone_connect().unwrap())
// .expect("failed with attributes for connecting");
}
}

268
src/win_permissions.rs Normal file
View File

@ -0,0 +1,268 @@
use winapi::um::winnt::*;
use winapi::um::accctrl::*;
use winapi::um::aclapi::*;
use winapi::um::securitybaseapi::*;
use winapi::um::minwinbase::{LPTR, SECURITY_ATTRIBUTES, PSECURITY_ATTRIBUTES};
use winapi::um::winbase::{LocalAlloc, LocalFree};
use winapi::shared::winerror::ERROR_SUCCESS;
use std::ptr;
use std::io;
use std::mem;
use std::marker;
pub struct SecurityAttributes {
attributes: Option<InnerAttributes>,
}
impl SecurityAttributes {
pub fn empty() -> SecurityAttributes {
SecurityAttributes { attributes: None }
}
pub fn allow_everyone_connect() -> io::Result<SecurityAttributes> {
let attributes = Some(InnerAttributes::allow_everyone(GENERIC_READ | FILE_WRITE_DATA)?);
Ok(SecurityAttributes { attributes })
}
pub fn allow_everyone_create() -> io::Result<SecurityAttributes> {
let attributes = Some(InnerAttributes::allow_everyone(GENERIC_READ | GENERIC_WRITE)?);
Ok(SecurityAttributes { attributes })
}
pub unsafe fn as_ptr(&mut self) -> PSECURITY_ATTRIBUTES {
match self.attributes.as_mut() {
Some(attributes) => attributes.as_ptr(),
None => ptr::null_mut(),
}
}
}
unsafe impl Send for SecurityAttributes {}
struct Sid {
sid_ptr: PSID
}
impl Sid {
fn everyone_sid() -> io::Result<Sid> {
let mut sid_ptr = ptr::null_mut();
let result = unsafe {
AllocateAndInitializeSid(
SECURITY_WORLD_SID_AUTHORITY.as_mut_ptr() as *mut _, 1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&mut sid_ptr)
};
if result == 0 {
Err(io::Error::last_os_error())
} else {
Ok(Sid{sid_ptr})
}
}
// Unsafe - the returned pointer is only valid for the lifetime of self.
unsafe fn as_ptr(&self) -> PSID {
self.sid_ptr
}
}
impl Drop for Sid {
fn drop(&mut self) {
if !self.sid_ptr.is_null() {
unsafe{ FreeSid(self.sid_ptr); }
}
}
}
struct AceWithSid<'a> {
explicit_access: EXPLICIT_ACCESS_W,
_marker: marker::PhantomData<&'a Sid>,
}
impl<'a> AceWithSid<'a> {
fn new(sid: &'a Sid, trustee_type: u32) -> AceWithSid<'a> {
let mut explicit_access = unsafe { mem::zeroed::<EXPLICIT_ACCESS_W>() };
explicit_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
explicit_access.Trustee.TrusteeType = trustee_type;
explicit_access.Trustee.ptstrName = unsafe { sid.as_ptr() as *mut _ };
AceWithSid{
explicit_access,
_marker: marker::PhantomData,
}
}
fn set_access_mode(&mut self, access_mode: u32) -> &mut Self {
self.explicit_access.grfAccessMode = access_mode;
self
}
fn set_access_permissions(&mut self, access_permissions: u32) -> &mut Self {
self.explicit_access.grfAccessPermissions = access_permissions;
self
}
fn allow_inheritance(&mut self, inheritance_flags: u32) -> &mut Self {
self.explicit_access.grfInheritance = inheritance_flags;
self
}
}
struct Acl {
acl_ptr: PACL,
}
impl Acl {
fn empty() -> io::Result<Acl> {
Self::new(&mut [])
}
fn new(entries: &mut [AceWithSid]) -> io::Result<Acl> {
let mut acl_ptr = ptr::null_mut();
let result = unsafe {
SetEntriesInAclW(entries.len() as u32,
entries.as_mut_ptr() as *mut _,
ptr::null_mut(), &mut acl_ptr)
};
if result != ERROR_SUCCESS {
return Err(io::Error::from_raw_os_error(result as i32));
}
Ok(Acl{acl_ptr})
}
unsafe fn as_ptr(&self) -> PACL {
self.acl_ptr
}
}
impl Drop for Acl {
fn drop(&mut self) {
if !self.acl_ptr.is_null() {
unsafe { LocalFree(self.acl_ptr as *mut _) };
}
}
}
struct SecurityDescriptor {
descriptor_ptr: PSECURITY_DESCRIPTOR,
}
impl SecurityDescriptor{
fn new() -> io::Result<Self> {
let descriptor_ptr = unsafe {
LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH)
};
if descriptor_ptr.is_null() {
return Err(io::Error::new(io::ErrorKind::Other,
"Failed to allocate security descriptor"));
}
if unsafe { InitializeSecurityDescriptor(
descriptor_ptr,
SECURITY_DESCRIPTOR_REVISION) == 0 }
{
return Err(io::Error::last_os_error());
};
Ok(SecurityDescriptor{descriptor_ptr})
}
fn set_dacl(&mut self, acl: &Acl) -> io::Result<()> {
if unsafe {
SetSecurityDescriptorDacl(
self.descriptor_ptr,
true as i32, acl.as_ptr(),
false as i32) == 0
}{
return Err(io::Error::last_os_error());
}
Ok(())
}
unsafe fn as_ptr(&self) -> PSECURITY_DESCRIPTOR {
self.descriptor_ptr
}
}
impl Drop for SecurityDescriptor {
fn drop(&mut self) {
if !self.descriptor_ptr.is_null() {
unsafe { LocalFree(self.descriptor_ptr) };
self.descriptor_ptr = ptr::null_mut();
}
}
}
struct InnerAttributes {
descriptor: SecurityDescriptor,
acl: Acl,
attrs: SECURITY_ATTRIBUTES,
}
impl InnerAttributes {
fn empty() -> io::Result<InnerAttributes> {
let descriptor = SecurityDescriptor::new()?;
let mut attrs = unsafe { mem::zeroed::<SECURITY_ATTRIBUTES>() };
attrs.nLength = mem::size_of::<SECURITY_ATTRIBUTES>() as u32;
attrs.lpSecurityDescriptor = unsafe {descriptor.as_ptr()};
attrs.bInheritHandle = false as i32;
let acl = Acl::empty().expect("this should never fail");
Ok(InnerAttributes{
acl,
descriptor,
attrs,
})
}
fn allow_everyone(permissions: u32) -> io::Result<InnerAttributes> {
let mut attributes = Self::empty()?;
let sid = Sid::everyone_sid()?;
println!("pisec");
let mut everyone_ace = AceWithSid::new(&sid, TRUSTEE_IS_WELL_KNOWN_GROUP);
everyone_ace.set_access_mode(SET_ACCESS)
.set_access_permissions(permissions)
.allow_inheritance(false as u32);
let mut entries = vec![everyone_ace];
attributes.acl = Acl::new(&mut entries)?;
attributes.descriptor.set_dacl(&attributes.acl)?;
// acl.acl_ptr = ptr::null_mut();
println!("ayy lmao");
Ok(attributes)
}
unsafe fn as_ptr(&mut self) -> PSECURITY_ATTRIBUTES {
&mut self.attrs as *mut _
}
}
#[cfg(test)]
mod test {
use super::SecurityAttributes;
#[test]
fn test_allow_everyone_everything() {
SecurityAttributes::allow_everyone_create()
.expect("failed to create security attributes that allow everyone to create a pipe");
}
#[test]
fn test_allow_eveyone_read_write() {
SecurityAttributes::allow_everyone_connect()
.expect("failed to create security attributes that allow everyone to read and write to/from a pipe");
}
}