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