pub mod credential;
mod tests;
use std::ffi::c_void;
use widestring::{U16CString, U16String};
use windows::Win32::Security::Credentials::{
CRED_FLAGS, CRED_PERSIST, CRED_TYPE, CREDENTIALW, CredDeleteW, CredFree, CredReadW, CredWriteW,
};
use windows::Win32::System::SystemInformation::GetSystemTimeAsFileTime;
use windows::core::PWSTR;
const NO_FLAGS: CRED_FLAGS = CRED_FLAGS(0);
const GENERIC_CREDENTIAL: CRED_TYPE = CRED_TYPE(1);
pub fn read_credential(target: &str) -> Result<credential::Credential, Box<dyn std::error::Error>> {
let target_cstr = U16CString::from_str(target).unwrap();
let target_ptr = target_cstr.as_ptr();
let mut cred: *mut CREDENTIALW = std::ptr::null_mut();
let cred_ptr: *mut *mut CREDENTIALW = &mut cred;
unsafe {
CredReadW(
PWSTR(target_ptr as *mut u16),
GENERIC_CREDENTIAL,
None,
cred_ptr,
)?
};
let credential = unsafe {
credential::Credential {
username: if (*cred).UserName.0.is_null() {
"".to_string()
} else {
U16CString::from_ptr_str((*cred).UserName.0 as *const u16).to_string_lossy()
},
secret: U16String::from_ptr(
(*cred).CredentialBlob as *const u16,
(*cred).CredentialBlobSize as usize / 2,
)
.to_string_lossy(),
}
};
unsafe { CredFree(cred as *const c_void) };
Ok(credential)
}
pub fn write_credential(
target: &str,
val: credential::Credential,
) -> Result<(), Box<dyn std::error::Error>> {
unsafe {
let filetime = GetSystemTimeAsFileTime();
let secret_len = val.secret.len();
let target_cstr = U16CString::from_str(target).unwrap();
let secret_cstr = U16CString::from_str(val.secret).unwrap();
let user_cstr = U16CString::from_str(val.username).unwrap();
let target_ptr = target_cstr.as_ptr();
let secret_ptr = secret_cstr.as_ptr();
let user_ptr = user_cstr.as_ptr();
let cred = CREDENTIALW {
Flags: NO_FLAGS,
Type: GENERIC_CREDENTIAL,
TargetName: PWSTR(target_ptr as *mut u16),
Comment: PWSTR(std::ptr::null_mut() as *mut u16),
LastWritten: filetime,
CredentialBlobSize: secret_len as u32 * 2,
CredentialBlob: secret_ptr as *mut u8,
Persist: CRED_PERSIST(1),
AttributeCount: 0,
Attributes: std::ptr::null_mut(),
TargetAlias: PWSTR(std::ptr::null_mut() as *mut u16),
UserName: PWSTR(user_ptr as *mut u16),
};
CredWriteW(&cred, NO_FLAGS.0)?
};
Ok(())
}
pub fn delete_credential(target: &str) -> Result<(), Box<dyn std::error::Error>> {
let target_cstr = U16CString::from_str(target).unwrap();
let target_ptr = target_cstr.as_ptr();
unsafe { CredDeleteW(PWSTR(target_ptr as *mut u16), GENERIC_CREDENTIAL, None)? };
Ok(())
}