1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
pub mod credential;
mod tests;
use std::ffi::c_void;
use widestring::{U16CString, U16String};
use windows::*;
use wincredentials_bindings::Windows::Win32::{
Foundation::*, Security::Credentials::*, System::SystemInformation::*,
};
const NO_FLAGS: u32 = 0;
const GENERIC_CREDENTIAL: u32 = 1;
pub fn read_credential(target: &str) -> Result<credential::Credential> {
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,
NO_FLAGS,
cred_ptr,
)
.ok()?
};
let credential = credential::Credential {
secret: unsafe {
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<()> {
let filetime = Box::new(FILETIME {
dwLowDateTime: 0,
dwHighDateTime: 0,
});
let filetime: *mut FILETIME = Box::into_raw(filetime);
unsafe { GetSystemTimeAsFileTime(filetime) };
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("").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: CRED_FLAGS(NO_FLAGS),
Type: CRED_TYPE(GENERIC_CREDENTIAL),
TargetName: PWSTR(target_ptr as *mut u16),
Comment: PWSTR(std::ptr::null_mut() as *mut u16),
LastWritten: unsafe { *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),
};
unsafe { CredWriteW(&cred, NO_FLAGS).ok()? };
unsafe { drop(Box::from_raw(filetime)) }
Ok(())
}
pub fn delete_credential(target: &str) -> Result<()> {
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, NO_FLAGS).ok()? };
Ok(())
}