Mercurial > crates > nonstick
diff src/conv.rs @ 1:b195a14058bb
initial commit
author | Jesse Hallett <jesse@galois.com> |
---|---|
date | Thu, 05 Mar 2015 16:25:10 -0800 |
parents | |
children | 2ec97116d72c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/conv.rs Thu Mar 05 16:25:10 2015 -0800 @@ -0,0 +1,84 @@ +use libc::{c_char, c_int}; +use std::{ptr}; +use std::ffi::{CStr, CString}; + +use constants; +use constants::*; +use module::{PamItem, PamResult}; + +#[allow(missing_copy_implementations)] +pub enum AppDataPtr {} + +#[repr(C)] +struct PamMessage { + msg_style: PamMessageStyle, + msg: *const c_char, +} + +#[repr(C)] +struct PamResponse { + resp: *const c_char, + resp_retcode: AlwaysZero, +} + +/// `PamConv` acts as a channel for communicating with user. +/// +/// Communication is mediated by the pam client (the application that invoked +/// pam). Messages sent will be relayed to the user by the client, and response +/// will be relayed back. +#[repr(C)] +pub struct PamConv { + conv: extern fn(num_msg: c_int, + pam_message: &&PamMessage, + pam_response: &*mut PamResponse, + appdata_ptr: *const AppDataPtr + ) -> PamResultCode, + appdata_ptr: *const AppDataPtr, +} + +impl PamConv { + /// Sends a message to the pam client. + /// + /// This will typically result in the user seeing a message or a prompt. + /// There are several message styles available: + /// + /// - PAM_PROMPT_ECHO_OFF + /// - PAM_PROMPT_ECHO_ON + /// - PAM_ERROR_MSG + /// - PAM_TEXT_INFO + /// - PAM_RADIO_TYPE + /// - PAM_BINARY_PROMPT + /// + /// Note that the user experience will depend on how the client implements + /// these message styles - and not all applications implement all message + /// styles. + pub fn send(&self, style: PamMessageStyle, msg: &str) -> PamResult<Option<String>> { + let resp_ptr: *mut PamResponse = ptr::null_mut(); + let msg = PamMessage { + msg_style: style, + msg: CString::new(msg).unwrap().as_ptr(), + }; + + let ret = (self.conv)(1, &&msg, &resp_ptr, self.appdata_ptr); + + if constants::PAM_SUCCESS == ret { + let s = unsafe { resp_ptr.as_ref() } + .and_then(|r| { + if r.resp.is_null() { + None + } + else { + let bytes = unsafe { CStr::from_ptr(r.resp).to_bytes() }; + String::from_utf8(bytes.to_vec()).ok() + } + }); + Ok(s) + } else { + Err(ret) + } + } +} + +impl PamItem for PamConv { + fn item_type(_: Option<Self>) -> PamItemType { PAM_CONV } +}