1use crate::error::ErrorStack; 2use foreign_types::{ForeignType, ForeignTypeRef}; 3use libc::{c_char, c_int, c_void}; 4use std::any::Any; 5use std::panic::{self, AssertUnwindSafe}; 6use std::slice; 7 8/// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI 9/// frames are on the stack). 10/// 11/// When dropped, checks if the callback has panicked, and resumes unwinding if so. 12pub struct CallbackState<F> { 13 /// The user callback. Taken out of the `Option` when called. 14 cb: Option<F>, 15 /// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL 16 /// returns. 17 panic: Option<Box<dyn Any + Send + 'static>>, 18} 19 20impl<F> CallbackState<F> { 21 pub fn new(callback: F) -> Self { 22 CallbackState { 23 cb: Some(callback), 24 panic: None, 25 } 26 } 27} 28 29impl<F> Drop for CallbackState<F> { 30 fn drop(&mut self) { 31 if let Some(panic) = self.panic.take() { 32 panic::resume_unwind(panic); 33 } 34 } 35} 36 37/// Password callback function, passed to private key loading functions. 38/// 39/// `cb_state` is expected to be a pointer to a `CallbackState`. 40pub unsafe extern "C" fn invoke_passwd_cb<F>( 41 buf: *mut c_char, 42 size: c_int, 43 _rwflag: c_int, 44 cb_state: *mut c_void, 45) -> c_int 46where 47 F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>, 48{ 49 let callback = &mut *(cb_state as *mut CallbackState<F>); 50 51 let result = panic::catch_unwind(AssertUnwindSafe(|| { 52 let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize); 53 callback.cb.take().unwrap()(pass_slice) 54 })); 55 56 match result { 57 Ok(Ok(len)) => len as c_int, 58 Ok(Err(_)) => { 59 // FIXME restore error stack 60 0 61 } 62 Err(err) => { 63 callback.panic = Some(err); 64 0 65 } 66 } 67} 68 69pub trait ForeignTypeExt: ForeignType { 70 unsafe fn from_ptr_opt(ptr: *mut Self::CType) -> Option<Self> { 71 if ptr.is_null() { 72 None 73 } else { 74 Some(Self::from_ptr(ptr)) 75 } 76 } 77} 78impl<FT: ForeignType> ForeignTypeExt for FT {} 79 80pub trait ForeignTypeRefExt: ForeignTypeRef { 81 unsafe fn from_const_ptr<'a>(ptr: *const Self::CType) -> &'a Self { 82 Self::from_ptr(ptr as *mut Self::CType) 83 } 84 85 unsafe fn from_const_ptr_opt<'a>(ptr: *const Self::CType) -> Option<&'a Self> { 86 if ptr.is_null() { 87 None 88 } else { 89 Some(Self::from_const_ptr(ptr as *mut Self::CType)) 90 } 91 } 92} 93impl<FT: ForeignTypeRef> ForeignTypeRefExt for FT {} 94