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 }
|