Skip to content

Commit 3bc3806

Browse files
committed
implement rust SecretsProvider
1 parent da698e7 commit 3bc3806

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

rust/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub mod platform;
155155
pub mod rc;
156156
pub mod references;
157157
pub mod relocation;
158+
pub mod secretsprovider;
158159
pub mod section;
159160
pub mod segment;
160161
pub mod settings;

rust/src/secretsprovider.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
use core::{ffi, mem, ptr};
2+
3+
use binaryninjacore_sys::*;
4+
5+
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner};
6+
use crate::string::{BnStrCompatible, BnString};
7+
8+
/// Struct for storing secrets (e.g. tokens) in a system-specific manner
9+
#[repr(transparent)]
10+
pub struct SecretsProvider {
11+
handle: ptr::NonNull<BNSecretsProvider>,
12+
}
13+
14+
impl SecretsProvider {
15+
pub(crate) unsafe fn from_raw(handle: ptr::NonNull<BNSecretsProvider>) -> Self {
16+
Self { handle }
17+
}
18+
19+
pub(crate) unsafe fn ref_from_raw(handle: &*mut BNSecretsProvider) -> &Self {
20+
assert!(!handle.is_null());
21+
mem::transmute(handle)
22+
}
23+
24+
#[allow(clippy::mut_from_ref)]
25+
pub(crate) unsafe fn as_raw(&self) -> &mut BNSecretsProvider {
26+
&mut *self.handle.as_ptr()
27+
}
28+
29+
/// Register a new provider
30+
pub fn new<N: IntoSecretsProviderName, C: SecretsProviderCallback>(
31+
name: N,
32+
callback: C,
33+
) -> Self {
34+
// SAFETY: once create SecretsProvider is never dropped
35+
let name = name.secrets_provider_name();
36+
let callback = Box::leak(Box::new(callback));
37+
let mut callbacks = BNSecretsProviderCallbacks {
38+
context: callback as *mut C as *mut ffi::c_void,
39+
hasData: Some(cb_has_data::<C>),
40+
getData: Some(cb_get_data::<C>),
41+
storeData: Some(cb_store_data::<C>),
42+
deleteData: Some(cb_delete_data::<C>),
43+
};
44+
let result = unsafe { BNRegisterSecretsProvider(name.as_ptr(), &mut callbacks) };
45+
unsafe { Self::from_raw(ptr::NonNull::new(result).unwrap()) }
46+
}
47+
48+
/// Retrieve the list of providers
49+
pub fn all() -> Array<SecretsProvider> {
50+
let mut count = 0;
51+
let result = unsafe { BNGetSecretsProviderList(&mut count) };
52+
assert!(!result.is_null());
53+
unsafe { Array::new(result, count, ()) }
54+
}
55+
56+
/// Retrieve a provider by name
57+
pub fn by_name<S: BnStrCompatible>(name: S) -> Option<SecretsProvider> {
58+
let name = name.into_bytes_with_nul();
59+
let result =
60+
unsafe { BNGetSecretsProviderByName(name.as_ref().as_ptr() as *const ffi::c_char) };
61+
ptr::NonNull::new(result).map(|h| unsafe { Self::from_raw(h) })
62+
}
63+
64+
pub fn name(&self) -> BnString {
65+
let result = unsafe { BNGetSecretsProviderName(self.as_raw()) };
66+
assert!(!result.is_null());
67+
unsafe { BnString::from_raw(result) }
68+
}
69+
70+
/// Check if data for a specific key exists, but do not retrieve it
71+
pub fn has_data<S: BnStrCompatible>(&self, key: S) -> bool {
72+
let key = key.into_bytes_with_nul();
73+
unsafe {
74+
BNSecretsProviderHasData(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char)
75+
}
76+
}
77+
78+
/// Retrieve data for the given key, if it exists
79+
pub fn get_data<S: BnStrCompatible>(&self, key: S) -> Option<BnString> {
80+
let key = key.into_bytes_with_nul();
81+
let result = unsafe {
82+
BNGetSecretsProviderData(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char)
83+
};
84+
(!result.is_null()).then(|| unsafe { BnString::from_raw(result) })
85+
}
86+
87+
/// Store data with the given key
88+
pub fn store_data<K: BnStrCompatible, V: BnStrCompatible>(&self, key: K, value: V) -> bool {
89+
let key = key.into_bytes_with_nul();
90+
let value = value.into_bytes_with_nul();
91+
unsafe {
92+
BNStoreSecretsProviderData(
93+
self.as_raw(),
94+
key.as_ref().as_ptr() as *const ffi::c_char,
95+
value.as_ref().as_ptr() as *const ffi::c_char,
96+
)
97+
}
98+
}
99+
100+
/// Delete stored data with the given key
101+
pub fn delete_data<S: BnStrCompatible>(&self, key: S) -> bool {
102+
let key = key.into_bytes_with_nul();
103+
unsafe {
104+
BNDeleteSecretsProviderData(self.as_raw(), key.as_ref().as_ptr() as *const ffi::c_char)
105+
}
106+
}
107+
}
108+
109+
impl CoreArrayProvider for SecretsProvider {
110+
type Raw = *mut BNSecretsProvider;
111+
type Context = ();
112+
type Wrapped<'a> = &'a Self;
113+
}
114+
115+
unsafe impl CoreArrayProviderInner for SecretsProvider {
116+
unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
117+
BNFreeSecretsProviderList(raw)
118+
}
119+
120+
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
121+
Self::ref_from_raw(raw)
122+
}
123+
}
124+
125+
pub trait IntoSecretsProviderName {
126+
fn secrets_provider_name(self) -> BnString;
127+
}
128+
129+
impl<S: BnStrCompatible> IntoSecretsProviderName for S {
130+
fn secrets_provider_name(self) -> BnString {
131+
BnString::new(self)
132+
}
133+
}
134+
135+
impl IntoSecretsProviderName for &SecretsProvider {
136+
fn secrets_provider_name(self) -> BnString {
137+
self.name()
138+
}
139+
}
140+
141+
pub trait SecretsProviderCallback {
142+
fn has_data(&mut self, key: &str) -> bool;
143+
fn get_data(&mut self, key: &str) -> String;
144+
fn store_data(&mut self, key: &str, data: &str) -> bool;
145+
fn delete_data(&mut self, key: &str) -> bool;
146+
}
147+
148+
unsafe extern "C" fn cb_has_data<C: SecretsProviderCallback>(
149+
ctxt: *mut ffi::c_void,
150+
key: *const ffi::c_char,
151+
) -> bool {
152+
let ctxt: &mut C = &mut *(ctxt as *mut C);
153+
ctxt.has_data(&ffi::CStr::from_ptr(key).to_string_lossy())
154+
}
155+
156+
unsafe extern "C" fn cb_get_data<C: SecretsProviderCallback>(
157+
ctxt: *mut ffi::c_void,
158+
key: *const ffi::c_char,
159+
) -> *mut ffi::c_char {
160+
let ctxt: &mut C = &mut *(ctxt as *mut C);
161+
let result = ctxt.get_data(&ffi::CStr::from_ptr(key).to_string_lossy());
162+
BnString::new(result).into_raw()
163+
}
164+
165+
unsafe extern "C" fn cb_store_data<C: SecretsProviderCallback>(
166+
ctxt: *mut ffi::c_void,
167+
key: *const ffi::c_char,
168+
data: *const ffi::c_char,
169+
) -> bool {
170+
let ctxt: &mut C = &mut *(ctxt as *mut C);
171+
let key = ffi::CStr::from_ptr(key).to_string_lossy();
172+
let data = ffi::CStr::from_ptr(data).to_string_lossy();
173+
ctxt.store_data(&key, &data)
174+
}
175+
176+
unsafe extern "C" fn cb_delete_data<C: SecretsProviderCallback>(
177+
ctxt: *mut ffi::c_void,
178+
key: *const ffi::c_char,
179+
) -> bool {
180+
let ctxt: &mut C = &mut *(ctxt as *mut C);
181+
ctxt.delete_data(&ffi::CStr::from_ptr(key).to_string_lossy())
182+
}

0 commit comments

Comments
 (0)