safe-sid 0.1.0

Safe borrowed/owned wrappers over a Windows security identifier (SID).
# safe-sid

Safe wrapper for working with SIDs from the Windows API.

Provides the borrowed/owned pair `&Sid` and `SidBuf` along with safe helper functions. Byte-compatible with the Windows `SID` struct. Defines equality and ordering traits so they can be compared and keyed on.

Depends on the `windows` crate by default, but this can be reduced down to just `windows-core` by turning off default features.

## Usage

```toml
[dependencies]
safe-sid = "0.1"
```

Or for just the `windows-core` dependency:

```toml
[dependencies]
safe-sid = { version = "0.1", default-features = false }
```

### Build a SID by hand

```rust
let admins = SidBuf::new([0, 0, 0, 0, 0, 5], &[32, 544]).unwrap();
assert_eq!(admins.to_string(), "S-1-5-32-544");
```

### Build a well-known SID

```rust
let local_system = SidBuf::well_known(WinLocalSystemSid, None).unwrap();
assert_eq!(local_system.to_string(), "S-1-5-18");
```

### Pass a SID to a Windows API

```rust
// Just an example, use Sid::to_string() normally 
fn sid_to_string(sid: &Sid) -> Result<String> {
    let mut hlocal_str = PSTR::null();
    unsafe {
        ConvertSidToStringSidA(sid.as_psid(), &mut hlocal_str)?;
        let string_sid = CStr::from_ptr(hlocal_str.0 as *const _).to_str().unwrap().to_owned();
        LocalFree(Some(HLOCAL(hlocal_str.0 as *mut _)));
        Ok(string_sid)
    }
}
```

### Fill a `SidBuf` from a Windows API

Sometimes a SID comes from a Windows API that expects the caller to provide a buffer. You can unsafely acquire a mutable pointer, and are responsible for ensuring it is filled with a valid SID with a correctly matching length. 

Note that even if the SID is malformed, dropping `SidBuf` will still be safe.

```rust
fn lookup_account_name(name: &CStr) -> Result<SidBuf> {
    let mut sid_use = SID_NAME_USE::default();
    let mut sid_len = 0u32;
    let mut domain_len = 0u32;

    unsafe {
        if let Err(e) = LookupAccountNameA(
            PCSTR::null(), PCSTR(name.as_ptr() as *const _), None, &mut sid_len,
            None, &mut domain_len, &mut sid_use,
        ) && e.code() != HRESULT::from_win32(ERROR_INSUFFICIENT_BUFFER.0)
        {
            return Err(e);
        }

        // Create the SidBuf with enough space to receive the SID
        let mut sid = SidBuf::with_capacity(sid_len as usize);
        let mut domain = vec![0u8; domain_len as usize];
        LookupAccountNameA(
            PCSTR::null(), PCSTR(name.as_ptr() as *const _), Some(PSID(sid.as_mut_ptr())), &mut sid_len,
            Some(PSTR(domain.as_mut_ptr())), &mut domain_len, &mut sid_use,
        )?;
        Ok(sid)
    }
}
```


## License

Licensed under the [ISC License](LICENSE).