windows-rs GetNamedSecurityInfoW error 87 - winapi

I'm trying to use windows-rs to use GetNamedSecurityInfoW microsoft api docs to read file permission information, but I keep getting error code 87 corresponds to ERROR_INVALID_PARAMETER. What have I done wrong? (I'm not experienced with rust or the windows api)
#[cfg(windows)]
pub unsafe fn get_file_perms(file: String) -> Result<()> {
use windows_sys::core::PCWSTR;
use windows_sys::Win32::Security::Authorization::GetNamedSecurityInfoW;
let file_u16 = file.encode_utf16().collect::<Vec<u16>>();
let lpfile: PCWSTR = file_u16.as_ptr() as PCWSTR;
let acl: *mut *mut windows_sys::Win32::Security::ACL = std::ptr::null_mut();
let security_descriptor: *mut windows_sys::Win32::Security::PSECURITY_DESCRIPTOR = std::ptr::null_mut();
let err = GetNamedSecurityInfoW(
lpfile,
windows_sys::Win32::Security::Authorization::SE_FILE_OBJECT,
windows_sys::Win32::Security::DACL_SECURITY_INFORMATION,
std::ptr::null_mut(),
std::ptr::null_mut(),
acl,
std::ptr::null_mut(),
security_descriptor,
);
if err != 0
{
println!("{}", err);
return Err(anyhow!("Failed to get file permissions"));
}
Ok(())
}`

GetNamedSecurityInfoW is an API call with somewhat complex semantics. Besides a description of the object, there's
a bitmask (SecurityInfo) describing the requested information
a set of output parameters (ppsidOwner, ppsidGroup, ppDacl, ppSacl) that provide access to structured data
the actual buffer holding the data (ppSecurityDescriptor).
On successful return, the system allocates memory, and transfers ownership to the caller through the final parameter. Depending on the requested information (DACL_SECURITY_INFORMATION) you will have to pass the addresses of pointers to the structured data (ppDacl in this case).
With that fixed, there are two more issues left: Making sure that the object name (pObjectName) is zero-terminated, and cleaning up the buffer the system allocated for us with a call to LocalFree. Note that any one of ppsidOwner, ppsidGroup, ppDacl, and ppSacl are valid only for as long as ppSecurityDescriptor is valid.
The following code fixes the immediate issue:
pub unsafe fn get_file_perms(file: String) -> Result<()> {
use windows_sys::Win32::Security::Authorization::GetNamedSecurityInfoW;
let file_u16 = file.encode_utf16().collect::<Vec<u16>>();
// Pointers that receive the output arguments
let mut acl = std::ptr::null_mut();
let mut security_descriptor = std::ptr::null_mut();
let err = GetNamedSecurityInfoW(
file_u16.as_ptr(),
windows_sys::Win32::Security::Authorization::SE_FILE_OBJECT,
windows_sys::Win32::Security::DACL_SECURITY_INFORMATION,
std::ptr::null_mut(),
std::ptr::null_mut(),
// Pass the *address* of the pointer
std::ptr::addr_of_mut!(acl),
std::ptr::null_mut(),
// Same here
std::ptr::addr_of_mut!(security_descriptor),
);
if err != 0 {
println!("{}", err);
return Err("Failed to get file permissions".into());
}
// At this point `acl` points into an access control list
// Cleanup up resources (should really be bound to a struct with a `Drop` impl)
windows_sys::Win32::System::Memory::LocalFree(security_descriptor as _);
Ok(())
}
As far as the interface goes, you should consider taking a Path/PathBuf instead. Since you are dealing with path names, a String will unduly restrict the input to the point of not being able to encode all potential paths.
Adding zero-termination, the function can be rewritten to this:
pub unsafe fn get_file_perms(file: impl AsRef<Path>) -> Result<()> {
let file_u16 = file
.as_ref()
.as_os_str()
.encode_wide()
.chain(once(0))
.collect::<Vec<_>>();
// ...

Related

Is reading register-sized data in `byteorder` efficient?

The crate in the title is byteorder.
Here is how we can read binary data from std::io::BufReader. BufReader implements the std::io::Read trait. There is an implementation of byteorder::ReadBytesExt for any type implementing Read. ReadBytesExt contains read_u16 and other methods that read binary data. This implementation:
fn read_u16<T: ByteOrder>(&mut self) -> Result<u16> {
let mut buf = [0; 2];
self.read_exact(&mut buf)?;
Ok(T::read_u16(&buf))
}
It passes a reference to buf to BufReader; I suppose it passes the address of buf in the stack. Hence the resulting u16 is transferred from the internal buffer of BufReader (memory) to buf above (memory), probably, using memcpy or something. Wouldn't it be more efficient if BufReader implemented ReadBytesExt by reading data from its internal buffer directly? Or the compiler optimizes buf away?
TL;DR: It's all up to the Optimization Gods, but it should be efficient.
The key optimization here is inlining, as usual, and the probabilities are on our side, but who knows...
As long as the call to read_exact is inlined, it should just work.
Firstly, it can be inlined. In Rust, "inner" calls are always statically dispatched -- there's no inheritance -- and therefore the type of the receiver (self) in self.read_exact is known at compile-time. As a result, the exact read_exact function being called is known at compile-time.
Of course, there's no telling whether it'll be inlined. The implementation is fairly short, so chances are good, but that's out of our hands.
Secondly, what happens if it's inlined? Magic!
You can see the implementation here:
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if self.buffer().len() >= buf.len() {
buf.copy_from_slice(&self.buffer()[..buf.len()]);
self.consume(buf.len());
return Ok(());
}
crate::io::default_read_exact(self, buf)
}
Once inlined, we therefore have:
fn read_u16<T: ByteOrder>(&mut self) -> Result<u16> {
let mut buf = [0; 2];
// self.read_exact(&mut buf)?;
if self.buffer().len() >= buf.len() {
buf.copy_from_slice(&self.buffer()[..buf.len()]);
self.consume(buf.len());
Ok(())
} else {
crate::io::default_read_exact(self, buf)
}?;
Ok(T::read_u16(&buf))
}
Needless to say, all those buf.len() calls should be replaced by 2.
fn read_u16<T: ByteOrder>(&mut self) -> Result<u16> {
let mut buf = [0; 2];
// self.read_exact(&mut buf)?;
if self.buffer().len() >= 2 {
buf.copy_from_slice(&self.buffer()[..2]);
self.consume(2);
Ok(())
} else {
crate::io::default_read_exact(self, buf)
}?;
Ok(T::read_u16(&buf))
}
So we're left with copy_from_slice, a memcpy invoked with a constant size (2).
The trick is that memcpy is so special that it's a builtin in most compilers, and it certainly is in LLVM. And it's a builtin specifically so that in special cases -- such as a constant size being specified which happen to be a register size -- its codegen can be specialized to... a mov instruction in the case of x86/x64.
So, as long as read_exact is inlined, then buf should live in a register from beginning to end... in the happy case.
In the cold path, when default_read_exact is called, then the compiler will need to use the stack and pass a slice. That's fine. It should not happen often.
If you find yourself repeatedly doing sequences of u16 reads, however... you may find yourself better served by reading larger arrays, to avoid the repeated if self.buffer().len() >= 2 checks.

Wrapping RefCell and Rc in a struct type

I would like to have a struct which has a writable field, but explicitly borrowable:
struct App<W: Clone<BorrowMut<Write>>> {
stdout: W,
}
... so it can internally use it:
impl<W: Clone<BorrowMut<Write>>> App<W> {
fn hello(&mut self) -> Result<()> {
Rc::clone(&self.stdout).borrow_mut().write(b"world\n")?;
Ok(())
}
}
I tried to pass it a cursor and then use it:
let mut cursor = Rc::new(RefCell::new(Cursor::new(vec![0])));
let mut app = App { stdout: cursor };
app.hello().expect("failed to write");
let mut line = String::new();
Rc::clone(&cursor).borrow_mut().read_line(&mut line).unwrap();
Rust barks:
error[E0107]: wrong number of type arguments: expected 0, found 1
--> src/bin/play.rs:6:21
|
6 | struct App<W: Clone<BorrowMut<Write>>> {
| ^^^^^^^^^^^^^^^^ unexpected type argument
My end goal: pass stdin, stdout and stderr to an App struct. In fn main, these would be real stdin/stdout/stderr. In tests, these could be cursors. Since I need to access these outside of App (e.g. in tests), I need multiple owners (thus Rc) and runtime mutable borrow (thus RefCount).
How can I implement this?
This isn't how you apply multiple constraints to a type parameter. Instead you use the + operator, like this: <W: Clone + Write + BorrowMut>
But, if you want BorrowMut to be an abstraction for RefCell, it won't work. The borrow_mut method of RefCell is not part of any trait so you will need to depend on RefCell directly in your data structure:
struct App<W: Clone + Write> {
stdout: Rc<RefCell<W>>,
}
Having said that, it's considered best practice not to put unneeded constraints on a struct. You can actually leave them off here, and just mention them on the impl later.
struct App<W> {
stdout: Rc<RefCell<W>>,
}
In order to access the contents of a Rc, you need to dereference with *. This can be a bit tricky in your case because there is a blanket impl of BorrowMut, which means that Rc has a different borrow_mut, which you definitely don't want.
impl<W: Clone + Write> App<W> {
fn hello(&mut self) -> Result<()> {
(*self.stdout).borrow_mut().write(b"world\n")?;
Ok(())
}
}
Again, when you use this, you'll need to dereference the Rc:
let cursor = Rc::new(RefCell::new(Cursor::new(vec![0])));
let mut app = App { stdout: cursor.clone() };
app.hello().expect("failed to write");
let mut line = String::new();
let mut cursor = (&*cursor).borrow_mut();
// move to the beginning or else there's nothing to read
cursor.set_position(0);
cursor.read_line(&mut line).unwrap();
println!("result = {:?}", line);
Also, notice that the Rc was cloned into the cursor. Otherwise it would be moved and you couldn't use it again later.

Transmuting u8 buffer to struct in Rust

I have a byte buffer of unknown size, and I want to create a local struct variable pointing to the memory of the beginning of the buffer. Following what I'd do in C, I tried a lot of different things in Rust and kept getting errors. This is my latest attempt:
use std::mem::{size_of, transmute};
#[repr(C, packed)]
struct MyStruct {
foo: u16,
bar: u8,
}
fn main() {
let v: Vec<u8> = vec![1, 2, 3];
let buffer = v.as_slice();
let s: MyStruct = unsafe { transmute(buffer[..size_of::<MyStruct>()]) };
}
I get an error:
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> src/main.rs:12:42
|
12 | let s: MyStruct = unsafe { transmute(buffer[..size_of::<MyStruct>()]) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
If you don't want to copy the data to the struct but instead leave it in place, you can use slice::align_to. This creates a &MyStruct instead:
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
struct MyStruct {
foo: u16,
bar: u8,
}
fn main() {
let v = vec![1u8, 2, 3];
// I copied this code from Stack Overflow
// without understanding why this case is safe.
let (head, body, _tail) = unsafe { v.align_to::<MyStruct>() };
assert!(head.is_empty(), "Data was not aligned");
let my_struct = &body[0];
println!("{:?}", my_struct);
}
Here, it's safe to use align_to to transmute some bytes to MyStruct because we've used repr(C, packed) and all of the types in MyStruct can be any arbitrary bytes.
See also:
How to read a struct from a file in Rust?
Can I take a byte array and deserialize it into a struct?
You can use methods on raw pointers and functions in std::ptr to directly read/write objects in place.
std::ptr::read
std::ptr::read_unaligned
std::ptr::write
std::ptr::write_unaligned
In your case:
fn main() {
let v: Vec<u8> = vec![1, 2, 3];
let s: MyStruct = unsafe { std::ptr::read(v.as_ptr() as *const _) };
println!("here is the struct: {:?}", s);
}
I would encourage you to wrap this in a reusable method and perform a length check on the source buffer before attempting the read.
I gave up on the transmute stuff. *mut (raw pointers) in Rust are pretty similar to C pointers, so this was easy:
#[repr(C, packed)] // necessary
#[derive(Debug, Copy, Clone)] // not necessary
struct MyStruct {
foo: u16,
bar: u8,
}
fn main() {
let v: Vec<u8> = vec![1, 2, 3];
let buffer = v.as_slice();
let mut s_safe: Option<&MyStruct> = None;
let c_buf = buffer.as_ptr();
let s = c_buf as *mut MyStruct;
unsafe {
let ref s2 = *s;
s_safe = Some(s2);
}
println!("here is the struct: {:?}", s_safe.unwrap());
}
The unsafe tag there is no joke, but the way I'm using this, I know my buffer is filled and take the proper precautions involving endianness later on.

ReadConsoleInputW wrapper and ownership

I want to wrap the ReadConsoleInputW Windows console method into the Read trait so that I can use the chars() method, but I need also to know which key modifiers are applied (control, alt/meta).
One solution (like the one used by the Unix console) is to encode key events into control characters or ANSI escape codes.
Another solution would be to keep the key modifiers around but I can't make it work because the chars() method consume/move the input:
struct InputBuffer {
handle: winapi::HANDLE,
ctrl: bool,
meta: bool,
}
impl Read for InputBuffer {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
// kernel32::ReadConsoleInputW(self.0, &mut rec, 1 as winapi::DWORD, &mut count);
// ...
if rec.EventType != winapi::KEY_EVENT {
continue;
}
let key_event = unsafe { rec.KeyEvent() };
// ...
self.ctrl = key_event.dwControlKeyState &
(winapi::LEFT_CTRL_PRESSED | winapi::RIGHT_CTRL_PRESSED) ==
(winapi::LEFT_CTRL_PRESSED | winapi::RIGHT_CTRL_PRESSED);
self.meta = ...;
let utf16 = key_event.UnicodeChar;
// ...
let (bytes, len) = try!(InputBuffer::wide_char_to_multi_byte(utf16));
return (&bytes[..len]).read(buf);
}
}
fn main() {
let handle = try!(get_std_handle(STDIN_FILENO));
let mut stdin = InputBuffer(handle);
let mut chars = stdin.chars(); // stdin moved here
loop {
let c = chars.next().unwrap();
let mut ch = try!(c);
if stdin.ctrl { // use of moved value
//...
}
// ...
}
}
How to do this in Rust?
You could put these flags into Rc<RefCell<somestruct>> and clone it before consuming stdin.
This is a common pattern that allows you to have "access" to the same data, from two places. Rc takes care of shared ownership, and RefCell checks if you don't have overlapping accesses.

Unable to create a vector and shuffle it

I'm trying to create a vector with the numbers 48 to 57 and then randomly shuffle it. I'm running into the following errors
error: the type of this value must be known in this context
let &mut slice = secret_num.as_mut_slice();
^~~~~~~~~~~~~~~~~~~~~~~~~
error: no method named `shuffle` found for type `rand::ThreadRng` in the current scope
rng.shuffle(&mut slice);
^~~~~~~
Here's the code:
extern crate rand;
fn main() {
//Main game loop
loop{
let mut secret_num = (48..58).collect();
let &mut slice = secret_num.as_mut_slice();
let mut rng = rand::thread_rng();
rng.shuffle(&mut slice);
println!("{:?}", secret_num);
break;
}
println!("Hello, world!");
}
collect needs to know what type you wish to collect into. From the looks of it, you want a Vec:
let mut secret_num: Vec<_> = (48..58).collect();
You don't want to use &mut in the declaration of this variable because that would make slice an unsized type, which isn't valid to have. In fact, this line is redundant.
let &mut slice = secret_num.as_mut_slice();
Traits must be brought into scope. The error message you are already getting should already be telling you this. Rust has pretty good error messages most of the time. You should read them:
help: items from traits can only be used if the trait is in scope;
the following trait is implemented but not in scope,
perhaps add a `use` for it:
help: candidate #1: `use rand::Rng`
There's no need for a loop at all; remove it. Produce an MCVE when asking a question to help you understand the source of the problem and others to answer it. In your real program, you should get the random number generator once before the loop to avoid overhead.
Since you originally asked the question, rand has reorganized their code. shuffle is now part of the SliceRandom trait.
use rand::seq::SliceRandom; // 0.6.5
fn main() {
let mut secret_num: Vec<_> = (48..58).collect();
let mut rng = rand::thread_rng();
secret_num.shuffle(&mut rng);
println!("{:?}", secret_num);
}

Resources