binaryninja/
secrets_provider.rsuse binaryninjacore_sys::*;
use std::ffi::{c_char, c_void, CStr};
use std::fmt::Debug;
use std::ptr::NonNull;
use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner};
use crate::string::{BnString, IntoCStr};
pub trait SecretsProvider {
fn has_data(&mut self, key: &str) -> bool;
fn get_data(&mut self, key: &str) -> String;
fn store_data(&mut self, key: &str, data: &str) -> bool;
fn delete_data(&mut self, key: &str) -> bool;
}
#[repr(transparent)]
pub struct CoreSecretsProvider {
handle: NonNull<BNSecretsProvider>,
}
impl CoreSecretsProvider {
pub(crate) unsafe fn from_raw(handle: NonNull<BNSecretsProvider>) -> Self {
Self { handle }
}
pub fn new<C: SecretsProvider>(name: &str, callback: C) -> Self {
let name = name.to_cstr();
let callback = Box::leak(Box::new(callback));
let mut callbacks = BNSecretsProviderCallbacks {
context: callback as *mut C as *mut c_void,
hasData: Some(cb_has_data::<C>),
getData: Some(cb_get_data::<C>),
storeData: Some(cb_store_data::<C>),
deleteData: Some(cb_delete_data::<C>),
};
let result = unsafe { BNRegisterSecretsProvider(name.as_ptr(), &mut callbacks) };
unsafe { Self::from_raw(NonNull::new(result).unwrap()) }
}
pub fn all() -> Array<CoreSecretsProvider> {
let mut count = 0;
let result = unsafe { BNGetSecretsProviderList(&mut count) };
assert!(!result.is_null());
unsafe { Array::new(result, count, ()) }
}
pub fn by_name(name: &str) -> Option<CoreSecretsProvider> {
let name = name.to_cstr();
let result = unsafe { BNGetSecretsProviderByName(name.as_ptr()) };
NonNull::new(result).map(|h| unsafe { Self::from_raw(h) })
}
pub fn name(&self) -> String {
let result = unsafe { BNGetSecretsProviderName(self.handle.as_ptr()) };
assert!(!result.is_null());
unsafe { BnString::into_string(result) }
}
pub fn has_data(&self, key: &str) -> bool {
let key = key.to_cstr();
unsafe { BNSecretsProviderHasData(self.handle.as_ptr(), key.as_ptr()) }
}
pub fn get_data(&self, key: &str) -> String {
let key = key.to_cstr();
let result = unsafe { BNGetSecretsProviderData(self.handle.as_ptr(), key.as_ptr()) };
unsafe { BnString::into_string(result) }
}
pub fn store_data(&self, key: &str, value: &str) -> bool {
let key = key.to_cstr();
let value = value.to_cstr();
unsafe { BNStoreSecretsProviderData(self.handle.as_ptr(), key.as_ptr(), value.as_ptr()) }
}
pub fn delete_data(&self, key: &str) -> bool {
let key = key.to_cstr();
unsafe { BNDeleteSecretsProviderData(self.handle.as_ptr(), key.as_ptr()) }
}
}
impl Debug for CoreSecretsProvider {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CoreSecretsProvider")
.field("name", &self.name())
.finish()
}
}
impl CoreArrayProvider for CoreSecretsProvider {
type Raw = *mut BNSecretsProvider;
type Context = ();
type Wrapped<'a> = Self;
}
unsafe impl CoreArrayProviderInner for CoreSecretsProvider {
unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
BNFreeSecretsProviderList(raw)
}
unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
let raw_ptr = NonNull::new(*raw).unwrap();
Self::from_raw(raw_ptr)
}
}
unsafe extern "C" fn cb_has_data<C: SecretsProvider>(
ctxt: *mut c_void,
key: *const c_char,
) -> bool {
let ctxt: &mut C = &mut *(ctxt as *mut C);
ctxt.has_data(&CStr::from_ptr(key).to_string_lossy())
}
unsafe extern "C" fn cb_get_data<C: SecretsProvider>(
ctxt: *mut c_void,
key: *const c_char,
) -> *mut c_char {
let ctxt: &mut C = &mut *(ctxt as *mut C);
let result = ctxt.get_data(&CStr::from_ptr(key).to_string_lossy());
BnString::into_raw(BnString::new(result))
}
unsafe extern "C" fn cb_store_data<C: SecretsProvider>(
ctxt: *mut c_void,
key: *const c_char,
data: *const c_char,
) -> bool {
let ctxt: &mut C = &mut *(ctxt as *mut C);
let key = CStr::from_ptr(key).to_string_lossy();
let data = CStr::from_ptr(data).to_string_lossy();
ctxt.store_data(&key, &data)
}
unsafe extern "C" fn cb_delete_data<C: SecretsProvider>(
ctxt: *mut c_void,
key: *const c_char,
) -> bool {
let ctxt: &mut C = &mut *(ctxt as *mut C);
ctxt.delete_data(&CStr::from_ptr(key).to_string_lossy())
}