1 | use crate::error::ErrorStack; |
2 | use foreign_types::{ForeignType, ForeignTypeRef}; |
3 | use libc::{c_char, c_int, c_void}; |
4 | use std::any::Any; |
5 | use std::panic::{self, AssertUnwindSafe}; |
6 | use 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. |
12 | pub 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 | |
20 | impl<F> CallbackState<F> { |
21 | pub fn new(callback: F) -> Self { |
22 | CallbackState { |
23 | cb: Some(callback), |
24 | panic: None, |
25 | } |
26 | } |
27 | } |
28 | |
29 | impl<F> Drop for CallbackState<F> { |
30 | fn drop(&mut self) { |
31 | if let Some(panic: Box) = self.panic.take() { |
32 | panic::resume_unwind(payload: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`. |
40 | pub 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 |
46 | where |
47 | F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>, |
48 | { |
49 | let callback: &mut CallbackState = &mut *(cb_state as *mut CallbackState<F>); |
50 | |
51 | let result: Result, …> = panic::catch_unwind(AssertUnwindSafe(|| { |
52 | let pass_slice: &mut [u8] = slice::from_raw_parts_mut(data:buf as *mut u8, len:size as usize); |
53 | callback.cb.take().unwrap()(pass_slice) |
54 | })); |
55 | |
56 | match result { |
57 | Ok(Ok(len: usize)) => len as c_int, |
58 | Ok(Err(_)) => { |
59 | // FIXME restore error stack |
60 | 0 |
61 | } |
62 | Err(err: Box) => { |
63 | callback.panic = Some(err); |
64 | 0 |
65 | } |
66 | } |
67 | } |
68 | |
69 | pub 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 | } |
78 | impl<FT: ForeignType> ForeignTypeExt for FT {} |
79 | |
80 | pub 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 | } |
93 | impl<FT: ForeignTypeRef> ForeignTypeRefExt for FT {} |
94 | |