kenobi-windows 0.3.1

A Windows Negotiate implementation.
use std::{ffi::c_void, ops::Deref, sync::LazyLock};

use windows::{
    Win32::Security::Authentication::Identity::{
        FreeContextBuffer, QuerySecurityPackageInfoW, SecBuffer, SecPkgContext_NativeNamesW,
    },
    core::PCWSTR,
};

use crate::NEGOTIATE;

const FALLBACK_BUFFER_SIZE: u32 = 48256;
static MAX_TOKEN_BUFFER_SIZE: LazyLock<windows_result::Result<u32>> = LazyLock::new(get_max_buffer_size);
fn get_max_buffer_size() -> windows_result::Result<u32> {
    let buf = unsafe { QuerySecurityPackageInfoW(NEGOTIATE)? };
    let size = unsafe { (*buf).cbMaxToken };
    unsafe { FreeContextBuffer(buf as *mut c_void)? };
    Ok(size)
}

pub struct NonResizableVec {
    arr: &'static mut [u8],
    length: u32,
}
impl NonResizableVec {
    fn length_or_fallback() -> u32 {
        *MAX_TOKEN_BUFFER_SIZE.as_ref().unwrap_or(&FALLBACK_BUFFER_SIZE)
    }
    pub fn new() -> Self {
        let length = Self::length_or_fallback();
        let alloc = vec![0u8; length as usize].into_boxed_slice();
        let arr = Box::leak(alloc);
        NonResizableVec { arr, length }
    }
    pub fn resize_max(&mut self) {
        self.length = Self::length_or_fallback();
    }
    pub fn as_slice(&self) -> &[u8] {
        &self.arr[..self.length as usize]
    }
    pub fn set_length(&mut self, length: u32) {
        if length as usize > self.arr.len() {
            panic!()
        } else {
            self.length = length;
        }
    }
    pub fn sec_buffer(&mut self, buffer_type: u32) -> SecBuffer {
        SecBuffer {
            cbBuffer: self.length,
            BufferType: buffer_type,
            pvBuffer: self.arr.as_mut_ptr() as *mut c_void,
        }
    }
}
impl Deref for NonResizableVec {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        self.as_slice()
    }
}
impl std::fmt::Debug for NonResizableVec {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.as_slice().fmt(f)
    }
}
impl Drop for NonResizableVec {
    fn drop(&mut self) {
        let _ = unsafe { Box::from_raw(self.arr.as_mut_ptr()) };
    }
}

pub struct NativeNamesHandle(SecPkgContext_NativeNamesW);
impl NativeNamesHandle {
    pub fn client(&self) -> String {
        let client = self.0.sClientName;
        unsafe { PCWSTR(client).to_string() }.expect("name returned was not UTF-16 compatible")
    }
    pub(crate) unsafe fn from_raw(handle: SecPkgContext_NativeNamesW) -> Self {
        Self(handle)
    }
}
impl Drop for NativeNamesHandle {
    fn drop(&mut self) {
        let _ = unsafe { FreeContextBuffer(self.0.sClientName.cast()) };
        let _ = unsafe { FreeContextBuffer(self.0.sServerName.cast()) };
    }
}
unsafe impl Send for NativeNamesHandle {}
unsafe impl Sync for NativeNamesHandle {}