1
|
1 use libc::{c_char, c_int}; |
|
2 use std::{ptr}; |
|
3 use std::ffi::{CStr, CString}; |
|
4 |
|
5 use constants; |
|
6 use constants::*; |
|
7 use module::{PamItem, PamResult}; |
|
8 |
|
9 #[allow(missing_copy_implementations)] |
|
10 pub enum AppDataPtr {} |
|
11 |
|
12 #[repr(C)] |
|
13 struct PamMessage { |
|
14 msg_style: PamMessageStyle, |
|
15 msg: *const c_char, |
|
16 } |
|
17 |
|
18 #[repr(C)] |
|
19 struct PamResponse { |
|
20 resp: *const c_char, |
|
21 resp_retcode: AlwaysZero, |
|
22 } |
|
23 |
|
24 /// `PamConv` acts as a channel for communicating with user. |
|
25 /// |
|
26 /// Communication is mediated by the pam client (the application that invoked |
|
27 /// pam). Messages sent will be relayed to the user by the client, and response |
|
28 /// will be relayed back. |
|
29 #[repr(C)] |
|
30 pub struct PamConv { |
|
31 conv: extern fn(num_msg: c_int, |
|
32 pam_message: &&PamMessage, |
|
33 pam_response: &*mut PamResponse, |
|
34 appdata_ptr: *const AppDataPtr |
|
35 ) -> PamResultCode, |
|
36 appdata_ptr: *const AppDataPtr, |
|
37 } |
|
38 |
|
39 impl PamConv { |
|
40 /// Sends a message to the pam client. |
|
41 /// |
|
42 /// This will typically result in the user seeing a message or a prompt. |
|
43 /// There are several message styles available: |
|
44 /// |
|
45 /// - PAM_PROMPT_ECHO_OFF |
|
46 /// - PAM_PROMPT_ECHO_ON |
|
47 /// - PAM_ERROR_MSG |
|
48 /// - PAM_TEXT_INFO |
|
49 /// - PAM_RADIO_TYPE |
|
50 /// - PAM_BINARY_PROMPT |
|
51 /// |
|
52 /// Note that the user experience will depend on how the client implements |
|
53 /// these message styles - and not all applications implement all message |
|
54 /// styles. |
|
55 pub fn send(&self, style: PamMessageStyle, msg: &str) -> PamResult<Option<String>> { |
|
56 let resp_ptr: *mut PamResponse = ptr::null_mut(); |
|
57 let msg = PamMessage { |
|
58 msg_style: style, |
|
59 msg: CString::new(msg).unwrap().as_ptr(), |
|
60 }; |
|
61 |
|
62 let ret = (self.conv)(1, &&msg, &resp_ptr, self.appdata_ptr); |
|
63 |
|
64 if constants::PAM_SUCCESS == ret { |
|
65 let s = unsafe { resp_ptr.as_ref() } |
|
66 .and_then(|r| { |
|
67 if r.resp.is_null() { |
|
68 None |
|
69 } |
|
70 else { |
|
71 let bytes = unsafe { CStr::from_ptr(r.resp).to_bytes() }; |
|
72 String::from_utf8(bytes.to_vec()).ok() |
|
73 } |
|
74 }); |
|
75 Ok(s) |
|
76 } else { |
|
77 Err(ret) |
|
78 } |
|
79 } |
|
80 } |
|
81 |
|
82 impl PamItem for PamConv { |
|
83 fn item_type(_: Option<Self>) -> PamItemType { PAM_CONV } |
|
84 } |