use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_void}; use std::any::Any; use std::panic::{self, AssertUnwindSafe}; use std::slice; use crate::error::ErrorStack; /// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI /// frames are on the stack). /// /// When dropped, checks if the callback has panicked, and resumes unwinding if so. pub struct CallbackState { /// The user callback. Taken out of the `Option` when called. cb: Option, /// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL /// returns. panic: Option>, } impl CallbackState { pub fn new(callback: F) -> Self { CallbackState { cb: Some(callback), panic: None, } } } impl Drop for CallbackState { fn drop(&mut self) { if let Some(panic) = self.panic.take() { panic::resume_unwind(panic); } } } /// Password callback function, passed to private key loading functions. /// /// `cb_state` is expected to be a pointer to a `CallbackState`. pub unsafe extern "C" fn invoke_passwd_cb( buf: *mut c_char, size: c_int, _rwflag: c_int, cb_state: *mut c_void, ) -> c_int where F: FnOnce(&mut [u8]) -> Result, { let callback = &mut *(cb_state as *mut CallbackState); let result = panic::catch_unwind(AssertUnwindSafe(|| { let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize); callback.cb.take().unwrap()(pass_slice) })); match result { Ok(Ok(len)) => len as c_int, Ok(Err(_)) => { // FIXME restore error stack 0 } Err(err) => { callback.panic = Some(err); 0 } } } pub trait ForeignTypeExt: ForeignType { unsafe fn from_ptr_opt(ptr: *mut Self::CType) -> Option { if ptr.is_null() { None } else { Some(Self::from_ptr(ptr)) } } } impl ForeignTypeExt for FT {} pub trait ForeignTypeRefExt: ForeignTypeRef { unsafe fn from_const_ptr<'a>(ptr: *const Self::CType) -> &'a Self { Self::from_ptr(ptr as *mut Self::CType) } unsafe fn from_const_ptr_opt<'a>(ptr: *const Self::CType) -> Option<&'a Self> { if ptr.is_null() { None } else { Some(Self::from_const_ptr(ptr as *mut Self::CType)) } } } impl ForeignTypeRefExt for FT {}