pam/
conv.rs

1use libc::{c_char, c_int};
2use std::ffi::{CStr, CString};
3use std::ptr;
4
5use constants::PamResultCode;
6use constants::PamMessageStyle;
7use items::Item;
8use module::PamResult;
9
10#[repr(C)]
11struct PamMessage {
12    msg_style: PamMessageStyle,
13    msg: *const c_char,
14}
15
16#[repr(C)]
17struct PamResponse {
18    resp: *const c_char,
19    resp_retcode: libc::c_int, // Unused - always zero
20}
21
22/// `PamConv` acts as a channel for communicating with user.
23///
24/// Communication is mediated by the pam client (the application that invoked
25/// pam).  Messages sent will be relayed to the user by the client, and response
26/// will be relayed back.
27#[repr(C)]
28pub struct Inner {
29    conv: extern "C" fn(
30        num_msg: c_int,
31        pam_message: &&PamMessage,
32        pam_response: &mut *const PamResponse,
33        appdata_ptr: *const libc::c_void,
34    ) -> PamResultCode,
35    appdata_ptr: *const libc::c_void,
36}
37
38pub struct Conv<'a>(&'a Inner);
39
40impl<'a> Conv<'a> {
41    /// Sends a message to the pam client.
42    ///
43    /// This will typically result in the user seeing a message or a prompt.
44    /// There are several message styles available:
45    ///
46    /// - PAM_PROMPT_ECHO_OFF
47    /// - PAM_PROMPT_ECHO_ON
48    /// - PAM_ERROR_MSG
49    /// - PAM_TEXT_INFO
50    /// - PAM_RADIO_TYPE
51    /// - PAM_BINARY_PROMPT
52    ///
53    /// Note that the user experience will depend on how the client implements
54    /// these message styles - and not all applications implement all message
55    /// styles.
56    pub fn send(&self, style: PamMessageStyle, msg: &str) -> PamResult<Option<&CStr>> {
57        let mut resp_ptr: *const PamResponse = ptr::null();
58        let msg_cstr = CString::new(msg).unwrap();
59        let msg = PamMessage {
60            msg_style: style,
61            msg: msg_cstr.as_ptr(),
62        };
63
64        let ret = (self.0.conv)(1, &&msg, &mut resp_ptr, self.0.appdata_ptr);
65
66        if PamResultCode::PAM_SUCCESS == ret {
67            // PamResponse.resp is null for styles that don't return user input like PAM_TEXT_INFO
68            let response = unsafe { (*resp_ptr).resp };
69            if response.is_null() {
70                Ok(None)
71            } else {
72                Ok(Some(unsafe { CStr::from_ptr(response) }))
73            }
74        } else {
75            Err(ret)
76        }
77    }
78}
79
80impl<'a> Item for Conv<'a> {
81    type Raw = Inner;
82
83    fn type_id() -> crate::items::ItemType {
84        crate::items::ItemType::Conv
85    }
86
87    unsafe fn from_raw(raw: *const Self::Raw) -> Self {
88        Self(&*raw)
89    }
90
91    fn into_raw(self) -> *const Self::Raw {
92        self.0 as _
93    }
94}