use libc::{c_int, c_char, c_void}; use std::any::Any; use std::cell::UnsafeCell; use std::panic::{self, AssertUnwindSafe}; use std::slice; use 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); } } } pub unsafe extern fn invoke_passwd_cb_old(buf: *mut c_char, size: c_int, _rwflag: c_int, cb_state: *mut c_void) -> c_int where F: FnOnce(&mut [c_char]) -> usize { let callback = &mut *(cb_state as *mut CallbackState); let result = panic::catch_unwind(AssertUnwindSafe(|| { let pass_slice = slice::from_raw_parts_mut(buf, size as usize); callback.cb.take().unwrap()(pass_slice) })); match result { Ok(len) => len as c_int, Err(err) => { callback.panic = Some(err); 0 } } } /// Password callback function, passed to private key loading functions. /// /// `cb_state` is expected to be a pointer to a `CallbackState`. pub unsafe extern 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 } } } /// This is intended to be used as the inner type for `FooRef` types converted from raw C pointers. /// It has an `UnsafeCell` internally to inform the compiler about aliasability and doesn't /// implement `Copy`, so it can't be dereferenced. pub struct Opaque(UnsafeCell<()>);