use libc::{calloc, free, strdup, c_char, c_int, c_void, size_t};
use pam::{PamMessage, PamMessageStyle, PamResponse, PamReturnCode};
use std::ffi::{CStr, CString};
use std::mem;
use std::slice;
pub extern "C" fn converse(num_msg: c_int,
msg: *mut *mut PamMessage,
resp: *mut *mut PamResponse,
appdata_ptr: *mut c_void)
-> c_int {
unsafe {
*resp = calloc(num_msg as usize, mem::size_of::<PamResponse>() as size_t) as
*mut PamResponse;
if (*resp).is_null() {
return PamReturnCode::BUF_ERR as c_int;
}
}
let data: &[&str] = unsafe { slice::from_raw_parts(appdata_ptr as *const &str, 2) };
let mut result: PamReturnCode = PamReturnCode::SUCCESS;
for i in 0..num_msg as isize {
unsafe {
let m: &mut PamMessage = &mut **(msg.offset(i));
let r: &mut PamResponse = &mut *((*resp).offset(i));
match PamMessageStyle::from(m.msg_style) {
PamMessageStyle::PROMPT_ECHO_ON => {
if let Ok(username) = CString::new(data[0]) {
r.resp = strdup(username.as_ptr() as *const c_char);
} else {
result = PamReturnCode::CONV_ERR;
}
}
PamMessageStyle::PROMPT_ECHO_OFF => {
if let Ok(password) = CString::new(data[1]) {
r.resp = strdup(password.as_ptr() as *const c_char);
} else {
result = PamReturnCode::CONV_ERR;
}
}
PamMessageStyle::ERROR_MSG => {
result = PamReturnCode::CONV_ERR;
}
PamMessageStyle::TEXT_INFO => {
println!("PAM_TEXT_INFO: {}",
String::from_utf8_lossy(CStr::from_ptr(m.msg).to_bytes()));
}
}
}
if result != PamReturnCode::SUCCESS {
break;
}
}
if result != PamReturnCode::SUCCESS {
unsafe { free(*resp as *mut c_void) };
}
result as c_int
}