]> git.proxmox.com Git - cargo.git/blob - vendor/openssl-0.9.23/src/util.rs
New upstream version 0.24.0
[cargo.git] / vendor / openssl-0.9.23 / src / util.rs
1 use libc::{c_int, c_char, c_void};
2 use std::any::Any;
3 use std::panic::{self, AssertUnwindSafe};
4 use std::slice;
5
6 use error::ErrorStack;
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<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) = self.panic.take() {
32 panic::resume_unwind(panic);
33 }
34 }
35 }
36
37 pub unsafe extern "C" fn invoke_passwd_cb_old<F>(
38 buf: *mut c_char,
39 size: c_int,
40 _rwflag: c_int,
41 cb_state: *mut c_void,
42 ) -> c_int
43 where
44 F: FnOnce(&mut [c_char]) -> usize,
45 {
46 let callback = &mut *(cb_state as *mut CallbackState<F>);
47
48 let result = panic::catch_unwind(AssertUnwindSafe(|| {
49 let pass_slice = slice::from_raw_parts_mut(buf, size as usize);
50 callback.cb.take().unwrap()(pass_slice)
51 }));
52
53 match result {
54 Ok(len) => len as c_int,
55 Err(err) => {
56 callback.panic = Some(err);
57 0
58 }
59 }
60 }
61
62 /// Password callback function, passed to private key loading functions.
63 ///
64 /// `cb_state` is expected to be a pointer to a `CallbackState`.
65 pub unsafe extern "C" fn invoke_passwd_cb<F>(
66 buf: *mut c_char,
67 size: c_int,
68 _rwflag: c_int,
69 cb_state: *mut c_void,
70 ) -> c_int
71 where
72 F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
73 {
74 let callback = &mut *(cb_state as *mut CallbackState<F>);
75
76 let result = panic::catch_unwind(AssertUnwindSafe(|| {
77 let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize);
78 callback.cb.take().unwrap()(pass_slice)
79 }));
80
81 match result {
82 Ok(Ok(len)) => len as c_int,
83 Ok(Err(_)) => {
84 // FIXME restore error stack
85 0
86 }
87 Err(err) => {
88 callback.panic = Some(err);
89 0
90 }
91 }
92 }